Torque3D Documentation / _generateds / guiDebugger.cpp

guiDebugger.cpp

Engine/source/gui/editor/guiDebugger.cpp

More...

Public Variables

Public Functions

ConsoleDocClass(DbgFileView , "@brief Remnant from ancient script debugger (TGE days?)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "Possibly useful <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an editor <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tooltip.\n\n</a>" "@internal" )
DefineEngineMethod(DbgFileView , clearBreakPositions , void , () , "()" "Clear all break points in the current file." )
DefineEngineMethod(DbgFileView , findString , bool , (const char *findThis) , "(string findThis)" "Find the specified string in the currently viewed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> and " "scroll it into view." )
DefineEngineMethod(DbgFileView , getCurrentLine , const char * , () , "()" "Get the currently executing <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> and line, <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">any.\n\n</a>" " @returns A string containing the file, <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> tab, and then the line number." " Use getField() with this." )
DefineEngineMethod(DbgFileView , open , bool , (const char *filename) , "(string filename)" "Open <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">viewing.\n\n</a>" "@note This loads the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> from the local system." )
DefineEngineMethod(DbgFileView , removeBreak , void , (U32 line) , "(int line)" "Remove <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> breakpoint from the specified line." )
DefineEngineMethod(DbgFileView , setBreak , void , (U32 line) , "(int line)" "Set <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> breakpoint at the specified line." )
DefineEngineMethod(DbgFileView , setBreakPosition , void , (U32 line) , "(int line)" "Set <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> breakpoint at the specified line." )
DefineEngineMethod(DbgFileView , setCurrentLine , void , (S32 line, bool selected) , "(int line, bool selected)" "Set the current highlighted line." )
const char *
itoa(S32 i)

Detailed Description

Public Variables

S32 gFileXOffset 

Public Functions

ConsoleDocClass(DbgFileView , "@brief Remnant from ancient script debugger (TGE days?)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "Possibly useful <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an editor <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tooltip.\n\n</a>" "@internal" )

DefineEngineMethod(DbgFileView , clearBreakPositions , void , () , "()" "Clear all break points in the current file." )

DefineEngineMethod(DbgFileView , findString , bool , (const char *findThis) , "(string findThis)" "Find the specified string in the currently viewed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> and " "scroll it into view." )

DefineEngineMethod(DbgFileView , getCurrentLine , const char * , () , "()" "Get the currently executing <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> and line, <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">any.\n\n</a>" " @returns A string containing the file, <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> tab, and then the line number." " Use getField() with this." )

DefineEngineMethod(DbgFileView , open , bool , (const char *filename) , "(string filename)" "Open <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">viewing.\n\n</a>" "@note This loads the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> from the local system." )

DefineEngineMethod(DbgFileView , removeBreak , void , (U32 line) , "(int line)" "Remove <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> breakpoint from the specified line." )

DefineEngineMethod(DbgFileView , setBreak , void , (U32 line) , "(int line)" "Set <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> breakpoint at the specified line." )

DefineEngineMethod(DbgFileView , setBreakPosition , void , (U32 line) , "(int line)" "Set <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> breakpoint at the specified line." )

DefineEngineMethod(DbgFileView , setCurrentLine , void , (S32 line, bool selected) , "(int line, bool selected)" "Set the current highlighted line." )

IMPLEMENT_CONOBJECT(DbgFileView )

itoa(S32 i)

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "gui/editor/guiDebugger.h"
 26
 27#include "gui/core/guiCanvas.h"
 28#include "console/engineAPI.h"
 29#include "gfx/gfxDrawUtil.h"
 30#include "core/volume.h"
 31
 32
 33IMPLEMENT_CONOBJECT(DbgFileView);
 34
 35ConsoleDocClass( DbgFileView,
 36   "@brief Remnant from ancient script debugger (TGE days?)\n\n"
 37   "Possibly useful for an editor tooltip.\n\n"
 38   "@internal"
 39);
 40
 41static const char* itoa(S32 i)
 42{
 43   static char buf[32];
 44   dSprintf(buf, sizeof(buf), "%d", i);
 45   return buf;
 46}
 47
 48DbgFileView::~DbgFileView()
 49{
 50   clear();
 51}
 52
 53DbgFileView::DbgFileView()
 54{
 55   VECTOR_SET_ASSOCIATION(mFileView);
 56
 57   mFileName = NULL;
 58   mPCFileName = NULL;
 59   mPCCurrentLine = -1;
 60
 61   mBlockStart = -1;
 62   mBlockEnd = -1;
 63
 64   mFindString[0] = '\0';
 65   mFindLineNumber = -1;
 66
 67   mSize.set(1, 0);
 68   mbMouseDragging = false;
 69   mMouseDownChar = -1;
 70   mMouseOverVariable[0] = '\0';
 71   mMouseOverValue[0] = '\0';
 72   mMouseVarStart = -1;
 73   mMouseVarEnd = -1;
 74}
 75
 76DefineEngineMethod(DbgFileView, setCurrentLine, void, (S32 line, bool selected), , "(int line, bool selected)"
 77              "Set the current highlighted line.")
 78{
 79   object->setCurrentLine(line, selected);
 80}
 81
 82DefineEngineMethod(DbgFileView, getCurrentLine, const char *, (), , "()"
 83              "Get the currently executing file and line, if any.\n\n"
 84              "@returns A string containing the file, a tab, and then the line number."
 85              " Use getField() with this.")
 86{
 87   S32 lineNum;
 88   const char *file = object->getCurrentLine(lineNum);
 89   char* ret = Con::getReturnBuffer(256);
 90   dSprintf(ret, sizeof(ret), "%s\t%d", file, lineNum);
 91   return ret;
 92}
 93
 94DefineEngineMethod(DbgFileView, open, bool, (const char * filename), , "(string filename)"
 95              "Open a file for viewing.\n\n"
 96              "@note This loads the file from the local system.")
 97{
 98   return object->openFile(filename);
 99}
100
101DefineEngineMethod(DbgFileView, clearBreakPositions, void, (), , "()"
102              "Clear all break points in the current file.")
103{
104   object->clearBreakPositions();
105}
106
107DefineEngineMethod(DbgFileView, setBreakPosition, void, (U32 line), , "(int line)"
108              "Set a breakpoint at the specified line.")
109{
110   object->setBreakPosition(line);
111}
112
113DefineEngineMethod(DbgFileView, setBreak, void, (U32 line), , "(int line)"
114              "Set a breakpoint at the specified line.")
115{
116   object->setBreakPointStatus(line, true);
117}
118
119DefineEngineMethod(DbgFileView, removeBreak, void, (U32 line), , "(int line)"
120              "Remove a breakpoint from the specified line.")
121{
122   object->setBreakPointStatus(line, false);
123}
124
125DefineEngineMethod(DbgFileView, findString, bool, (const char * findThis), , "(string findThis)"
126              "Find the specified string in the currently viewed file and "
127              "scroll it into view.")
128{
129   return object->findString(findThis);
130}
131
132//this value is the offset used in the ::onRender() method...
133static S32 gFileXOffset = 44;
134
135void DbgFileView::AdjustCellSize()
136{
137   if (! bool(mFont))
138      return;
139   S32 maxWidth = 1;
140   for (U32 i = 0; i < mFileView.size(); i++)
141   {
142      S32 cellWidth = gFileXOffset + mFont->getStrWidth((const UTF8 *)mFileView[i].text);
143      maxWidth = getMax(maxWidth, cellWidth);
144   }
145
146   mCellSize.set(maxWidth, mFont->getHeight() + 2);
147   setSize(mSize);
148}
149
150bool DbgFileView::onWake()
151{
152   if (! Parent::onWake())
153      return false;
154
155   //clear the mouse over var
156   mMouseOverVariable[0] = '\0';
157   mbMouseDragging = false;
158
159   //adjust the cellwidth to the maximum line length
160   AdjustCellSize();
161   mSize.set(1, mFileView.size());
162
163   return true;
164}
165
166void DbgFileView::addLine(const char *string, U32 strLen)
167{
168   // first compute the size
169   U32 size = 1; // for null
170   for(U32 i = 0; i < strLen; i++)
171   {
172      if(string[i] == '\t')
173         size += 3;
174      else if(string[i] != '\r')
175         size++;
176   }
177   FileLine fl;
178   fl.breakPosition = false;
179   fl.breakOnLine = false;
180   if(size)
181   {
182      fl.text = (char *) dMalloc(size);
183
184      U32 dstIndex = 0;
185      for(U32 i = 0; i < strLen; i++)
186      {
187         if(string[i] == '\t')
188         {
189            fl.text[dstIndex] = ' ';
190            fl.text[dstIndex + 1] = ' ';
191            fl.text[dstIndex + 2] = ' ';
192            dstIndex += 3;
193         }
194         else if(string[i] != '\r')
195            fl.text[dstIndex++] = string[i];
196      }
197      fl.text[dstIndex] = 0;
198   }
199   else
200      fl.text = NULL;
201   mFileView.push_back(fl);
202}
203
204void DbgFileView::clear()
205{
206   for(Vector<FileLine>::iterator i = mFileView.begin(); i != mFileView.end(); i++)
207      dFree(i->text);
208   mFileView.clear();
209}
210
211bool DbgFileView::findString(const char *text)
212{
213   //make sure we have a valid string to find
214   if (!text || !text[0])
215      return false;
216
217   //see which line we start searching from
218   S32 curLine = 0;
219   bool searchAgain = false;
220   if (mFindLineNumber >= 0 && !dStricmp(mFindString, text))
221   {
222      searchAgain = true;
223      curLine = mFindLineNumber;
224   }
225   else
226      mFindLineNumber = -1;
227
228   //copy the search text
229   dStrncpy(mFindString, text, 255);
230   S32 length = dStrlen(mFindString);
231
232   //loop through looking for the next instance
233   while (curLine < mFileView.size())
234   {
235      char *curText;
236      if (curLine == mFindLineNumber && mBlockStart >= 0)
237         curText = &mFileView[curLine].text[mBlockStart + 1];
238      else
239         curText = &mFileView[curLine].text[0];
240
241      //search for the string (the hard way... - apparently dStrupr is broken...
242      char *found = NULL;
243      char *curTextPtr = curText;
244      while (*curTextPtr != '\0')
245      {
246         if (!dStrnicmp(mFindString, curTextPtr, length))
247         {
248            found = curTextPtr;
249            break;
250         }
251         else
252            curTextPtr++;
253      }
254
255      //did we find it?
256      if (found)
257      {
258         //scroll first
259         mFindLineNumber = curLine;
260         scrollToLine(mFindLineNumber + 1);
261
262         //then hilite
263         mBlockStart = (S32)(found - &mFileView[curLine].text[0]);
264         mBlockEnd = mBlockStart + length;
265
266         return true;
267      }
268      else
269         curLine++;
270   }
271
272   //didn't find anything - reset the vars for the next search
273   mBlockStart = -1;
274   mBlockEnd = -1;
275   mFindLineNumber = -1;
276
277   setSelectedCell(Point2I(-1, -1));
278   return false;
279}
280
281void DbgFileView::setCurrentLine(S32 lineNumber, bool setCurrentLine)
282{
283   //update the line number
284   if (setCurrentLine)
285   {
286      mPCFileName = mFileName;
287      mPCCurrentLine = lineNumber;
288      mBlockStart = -1;
289      mBlockEnd = -1;
290      if (lineNumber >= 0)
291         scrollToLine(mPCCurrentLine);
292   }
293   else
294   {
295      scrollToLine(lineNumber);
296   }
297}
298
299const char* DbgFileView::getCurrentLine(S32 &lineNumber)
300{
301   lineNumber = mPCCurrentLine;
302   return mPCFileName;
303}
304
305bool DbgFileView::openFile(const char *fileName)
306{
307   if ((! fileName) || (! fileName[0]))
308      return false;
309
310   StringTableEntry newFile = StringTable->insert(fileName);
311   if (mFileName == newFile)
312      return true;
313
314   void *data = NULL;
315   U32 dataSize = 0;
316   Torque::FS::ReadFile(fileName, data, dataSize, true);
317   if(data == NULL)
318   {
319      Con::printf("DbgFileView: unable to open file %s.", fileName);
320      return false;
321   }
322
323   //copy the file name
324   mFileName = newFile;
325
326   //clear the old mFileView
327   clear();
328   setSize(Point2I(1, 0));
329
330   //begin reading and parsing at each '\n'
331   char *parsePtr = (char *)data;
332   for(;;) {
333      char *tempPtr = dStrchr(parsePtr, '\n');
334      if(tempPtr)
335         addLine(parsePtr, tempPtr - parsePtr);
336      else if(parsePtr[0])
337         addLine(parsePtr, dStrlen(parsePtr));
338      if(!tempPtr)
339         break;
340      parsePtr = tempPtr + 1;
341   }
342   //delete the buffer
343   delete [] static_cast<char*>(data);
344
345   //set the file size
346   AdjustCellSize();
347   setSize(Point2I(1, mFileView.size()));
348
349   return true;
350}
351
352void DbgFileView::scrollToLine(S32 lineNumber)
353{
354   GuiControl *parent = getParent();
355   if (! parent)
356      return;
357
358   S32 yOffset = (lineNumber - 1) * mCellSize.y;
359
360   //see if the line is already visible
361   if (! (yOffset + getPosition().y >= 0 && yOffset + getPosition().y < parent->getHeight() - mCellSize.y))
362   {
363      //reposition the control
364      S32 newYOffset = getMin(0, getMax(parent->getHeight() - getHeight(), (mCellSize.y * 4) - yOffset));
365      setPosition(Point2I(getPosition().x, newYOffset));
366   }
367
368   //hilite the line
369   cellSelected(Point2I(0, lineNumber - 1));
370}
371
372S32 DbgFileView::findMouseOverChar(const char *text, S32 stringPosition)
373{
374   static char tempBuf[512];
375   char *bufPtr = &tempBuf[1];
376
377   // Handle the empty string correctly.
378   if (text[0] == '\0') {
379      return -1;
380   }
381
382   // Copy the line's text into the scratch buffer.
383   dStrncpy(tempBuf, text, 512);
384
385   // Make sure we have a null terminator.
386   tempBuf[511] = '\0';
387
388   // Loop over the characters...
389   bool found = false;
390   bool finished = false;
391   do {
392      // Note the current character, then replace it with EOL.
393      char c = *bufPtr;
394      *bufPtr = '\0';
395      // Is the resulting string long enough to include the current
396      // mouse position?
397      if ((S32)mFont->getStrWidth((const UTF8 *)tempBuf) > stringPosition) {
398         // Yep.
399         // Restore the character.
400         *bufPtr = c;
401         // Set bufPtr to point to the char under the mouse.
402         bufPtr--;
403         // Bail.
404         found = true;
405         finished = true;
406      }
407      else {
408         // Nope.
409         // Restore the character.
410         *bufPtr = c;
411         // Move on to the next character.
412         bufPtr++;
413         // Bail if EOL.
414         if (*bufPtr == '\0') finished = true;
415      }
416   } while (!finished);
417
418   // Did we find a character under the mouse?
419   if (found) {
420      // If so, return its position.
421      return bufPtr - tempBuf;
422   }
423   // If not, return -1.
424   else return -1;
425}
426
427bool DbgFileView::findMouseOverVariable()
428{
429   GuiCanvas *root = getRoot();
430   AssertFatal(root, "Unable to get the root Canvas.");
431
432   Point2I curMouse = root->getCursorPos();
433   Point2I pt = globalToLocalCoord(curMouse);
434
435   //find out which cell was hit
436   Point2I cell((pt.x < 0 ? -1 : pt.x / mCellSize.x), (pt.y < 0 ? -1 : pt.y / mCellSize.y));
437   if(cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
438   {
439      S32 stringPosition = pt.x - gFileXOffset;
440      char tempBuf[256], *varNamePtr = &tempBuf[1];
441      dStrcpy(tempBuf, mFileView[cell.y].text, 256);
442
443      //find the current mouse over char
444      S32 charNum = findMouseOverChar(mFileView[cell.y].text, stringPosition);
445      if (charNum >= 0)
446      {
447         varNamePtr = &tempBuf[charNum];
448      }
449      else
450      {
451         mMouseOverVariable[0] = '\0';
452         mMouseOverValue[0] = '\0';
453         return false;
454      }
455
456      //now make sure we can go from the current cursor mPosition to the beginning of a var name
457      bool found = false;
458      while (varNamePtr >= &tempBuf[0])
459      {
460         if (*varNamePtr == '%' || *varNamePtr == '$')
461         {
462            found = true;
463            break;
464         }
465         else if ((dToupper(*varNamePtr) >= 'A' && dToupper(*varNamePtr) <= 'Z') ||
466                  (*varNamePtr >= '0' && *varNamePtr <= '9') || *varNamePtr == '_' || *varNamePtr == ':')
467         {
468            varNamePtr--;
469         }
470         else
471         {
472            break;
473         }
474      }
475
476      //mouse wasn't over a possible variable name
477      if (! found)
478      {
479         mMouseOverVariable[0] = '\0';
480         mMouseOverValue[0] = '\0';
481         return false;
482      }
483
484      //set the var char start positions
485      mMouseVarStart = varNamePtr - tempBuf;
486
487      //now copy the (possible) var name into the buf
488      char *tempPtr = &mMouseOverVariable[0];
489
490      //copy the leading '%' or '$'
491      *tempPtr++ = *varNamePtr++;
492
493      //now copy letters and numbers until the end of the name
494      while ((dToupper(*varNamePtr) >= 'A' && dToupper(*varNamePtr) <= 'Z') ||
495                  (*varNamePtr >= '0' && *varNamePtr <= '9') || *varNamePtr == '_' || *varNamePtr == ':')
496      {
497         *tempPtr++ = *varNamePtr++;
498      }
499      *tempPtr = '\0';
500
501      //set the var char end positions
502      mMouseVarEnd = varNamePtr - tempBuf;
503
504      return true;
505   }
506   return false;
507}
508
509void DbgFileView::clearBreakPositions()
510{
511   for(Vector<FileLine>::iterator i = mFileView.begin(); i != mFileView.end(); i++)
512   {
513      i->breakPosition = false;
514      i->breakOnLine = false;
515   }
516}
517
518void DbgFileView::setBreakPosition(U32 line)
519{
520   if(line > mFileView.size())
521      return;
522   mFileView[line-1].breakPosition = true;
523}
524
525void DbgFileView::setBreakPointStatus(U32 line, bool set)
526{
527   if(line > mFileView.size())
528      return;
529   mFileView[line-1].breakOnLine = set;
530}
531
532void DbgFileView::onPreRender()
533{
534   setUpdate();
535   char oldVar[256];
536   dStrcpy(oldVar, mMouseOverVariable, 256);
537   bool found = findMouseOverVariable();
538   if (found && mPCCurrentLine >= 0)
539   {
540      //send the query only when the var changes
541      if (dStricmp(oldVar, mMouseOverVariable))
542         Con::executef("DbgSetCursorWatch", mMouseOverVariable);
543   }
544   else
545      Con::executef("DbgSetCursorWatch", "");
546}
547
548void DbgFileView::onMouseDown(const GuiEvent &event)
549{
550   if (! mActive)
551   {
552      Parent::onMouseDown(event);
553      return;
554   }
555
556   Point2I pt = globalToLocalCoord(event.mousePoint);
557   bool doubleClick = (event.mouseClickCount > 1);
558
559   //find out which cell was hit
560   Point2I cell((pt.x < 0 ? -1 : pt.x / mCellSize.x), (pt.y < 0 ? -1 : pt.y / mCellSize.y));
561   if(cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
562   {
563      //if we clicked on the breakpoint mark
564      if (pt.x >= 0 && pt.x <= 12)
565      {
566         //toggle the break point
567         if (mFileView[cell.y].breakPosition)
568         {
569            if (mFileView[cell.y].breakOnLine)
570               Con::executef(this, "onRemoveBreakPoint", itoa(cell.y + 1));
571            else
572               Con::executef(this, "onSetBreakPoint", itoa(cell.y + 1));
573         }
574      }
575      else
576      {
577         Point2I prevSelected = mSelectedCell;
578         Parent::onMouseDown(event);
579         mBlockStart= -1;
580         mBlockEnd = -1;
581
582         //open the file view
583         if (mSelectedCell.y == prevSelected.y && doubleClick && mMouseOverVariable[0])
584         {
585            Con::executef(this, "onSetWatch", mMouseOverVariable);
586            mBlockStart = mMouseVarStart;
587            mBlockEnd = mMouseVarEnd;
588         }
589         else
590         {
591            S32 stringPosition = pt.x - gFileXOffset;
592
593            //find which character we're over
594            S32 charNum = findMouseOverChar(mFileView[mSelectedCell.y].text, stringPosition);
595            if (charNum >= 0)
596            {
597               //lock the mouse
598               mouseLock();
599               setFirstResponder();
600
601               //set the block hilite start and end
602               mbMouseDragging = true;
603               mMouseDownChar = charNum;
604            }
605         }
606      }
607   }
608   else
609   {
610      Parent::onMouseDown(event);
611   }
612}
613
614void DbgFileView::onMouseDragged(const GuiEvent &event)
615{
616   if (mbMouseDragging)
617   {
618      Point2I pt = globalToLocalCoord(event.mousePoint);
619      S32 stringPosition = pt.x - gFileXOffset;
620
621      //find which character we're over
622      S32 charNum = findMouseOverChar(mFileView[mSelectedCell.y].text, stringPosition);
623      if (charNum >= 0)
624      {
625         if (charNum < mMouseDownChar)
626         {
627
628            mBlockEnd = mMouseDownChar + 1;
629            mBlockStart = charNum;
630         }
631         else
632         {
633            mBlockEnd = charNum + 1;
634            mBlockStart = mMouseDownChar;
635         }
636      }
637
638      //otherwise, the cursor is past the end of the string
639      else
640      {
641         mBlockStart = mMouseDownChar;
642         mBlockEnd = dStrlen(mFileView[mSelectedCell.y].text) + 1;
643      }
644   }
645}
646
647void DbgFileView::onMouseUp(const GuiEvent &)
648{
649   //unlock the mouse
650   mouseUnlock();
651
652   mbMouseDragging = false;
653}
654
655void DbgFileView::onRenderCell(Point2I offset, Point2I cell, bool selected, bool)
656{
657   Point2I cellOffset = offset;
658   cellOffset.x += 4;
659
660   //draw the break point marks
661   if (mFileView[cell.y].breakOnLine)
662   {
663      GFX->getDrawUtil()->setBitmapModulation(mProfile->mFontColorHL);
664      GFX->getDrawUtil()->drawText(mFont, cellOffset, "#");
665   }
666   else if (mFileView[cell.y].breakPosition)
667   {
668      GFX->getDrawUtil()->setBitmapModulation(mProfile->mFontColor);
669      GFX->getDrawUtil()->drawText(mFont, cellOffset, "-");
670   }
671   cellOffset.x += 8;
672
673   //draw in the "current line" indicator
674   if (mFileName == mPCFileName && (cell.y + 1 == mPCCurrentLine))
675   {
676      GFX->getDrawUtil()->setBitmapModulation(mProfile->mFontColorHL);
677      GFX->getDrawUtil()->drawText(mFont, cellOffset, "=>");
678   }
679
680   //by this time, the cellOffset has been incremented by 44 - the value of gFileXOffset
681   cellOffset.x += 32;
682
683   //hilite the line if selected
684   if (selected)
685   {
686      if (mBlockStart == -1)
687      {
688         GFX->getDrawUtil()->drawRectFill(RectI(cellOffset.x - 2, cellOffset.y - 3,
689                                 mCellSize.x + 4, mCellSize.y + 6), mProfile->mFillColorHL);
690      }
691      else if (mBlockStart >= 0 && mBlockEnd > mBlockStart && mBlockEnd <= S32(dStrlen(mFileView[cell.y].text) + 1))
692      {
693         S32 startPos, endPos;
694         char tempBuf[256];
695         dStrcpy(tempBuf, mFileView[cell.y].text, 256);
696
697         //get the end coord
698         tempBuf[mBlockEnd] = '\0';
699         endPos = mFont->getStrWidth((const UTF8 *)tempBuf);
700
701         //get the start coord
702         tempBuf[mBlockStart] = '\0';
703         startPos = mFont->getStrWidth((const UTF8 *)tempBuf);
704
705         //draw the hilite
706         GFX->getDrawUtil()->drawRectFill(RectI(cellOffset.x + startPos, cellOffset.y - 3, endPos - startPos + 2, mCellSize.y + 6), mProfile->mFillColorHL);
707      }
708   }
709
710   //draw the line of text
711   GFX->getDrawUtil()->setBitmapModulation(mFileView[cell.y].breakOnLine ? mProfile->mFontColorHL : mProfile->mFontColor);
712   GFX->getDrawUtil()->drawText(mFont, cellOffset, mFileView[cell.y].text);
713}
714