guiDebugger.cpp
Engine/source/gui/editor/guiDebugger.cpp
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." )
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