guiControl.cc 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "console/consoleTypes.h"
  23. #include "console/console.h"
  24. #include "console/consoleInternal.h"
  25. #include "console/codeBlock.h"
  26. #include "platform/event.h"
  27. #include "graphics/gBitmap.h"
  28. #include "graphics/dgl.h"
  29. #include "input/actionMap.h"
  30. #include "gui/guiCanvas.h"
  31. #include "gui/guiControl.h"
  32. #include "gui/guiDefaultControlRender.h"
  33. #include "gui/editor/guiEditCtrl.h"
  34. #include "string/unicode.h"
  35. #include "collection/vector.h"
  36. #ifndef _FRAMEALLOCATOR_H_
  37. #include "memory/frameAllocator.h"
  38. #endif
  39. //------------------------------------------------------------------------------
  40. IMPLEMENT_CONOBJECT(GuiControl);
  41. //used to locate the next/prev responder when tab is pressed
  42. S32 GuiControl::smCursorChanged = -1;
  43. GuiControl *GuiControl::smPrevResponder = NULL;
  44. GuiControl *GuiControl::smCurResponder = NULL;
  45. GuiEditCtrl *GuiControl::smEditorHandle = NULL;
  46. bool GuiControl::smDesignTime = false;
  47. GuiControl::GuiControl()
  48. {
  49. mLayer = 0;
  50. mBounds.set(0, 0, 64, 64);
  51. mMinExtent.set(8, 2); // MM: Reduced to 8x2 so GuiControl can be used as a separator.
  52. mProfile = NULL;
  53. mConsoleVariable = StringTable->EmptyString;
  54. mConsoleCommand = StringTable->EmptyString;
  55. mAltConsoleCommand = StringTable->EmptyString;
  56. mAcceleratorKey = StringTable->EmptyString;
  57. mLangTableName = StringTable->EmptyString;
  58. mLangTable = NULL;
  59. mFirstResponder = NULL;
  60. mCanSaveFieldDictionary = false;
  61. mVisible = true;
  62. mActive = false;
  63. mAwake = false;
  64. mCanSave = true;
  65. mHorizSizing = horizResizeRight;
  66. mVertSizing = vertResizeBottom;
  67. mTooltipProfile = NULL;
  68. mTooltip = StringTable->EmptyString;
  69. mTipHoverTime = 1000;
  70. mTooltipWidth = 250;
  71. mIsContainer = false;
  72. }
  73. GuiControl::~GuiControl()
  74. {
  75. }
  76. bool GuiControl::onAdd()
  77. {
  78. // Let Parent Do Work.
  79. if(!Parent::onAdd())
  80. return false;
  81. // Grab the classname of this object
  82. const char *cName = getClassName();
  83. // if we're a pure GuiControl, then we're a container by default.
  84. if(dStrcmp("GuiControl", cName) == 0)
  85. mIsContainer = true;
  86. // Clamp to minExtent
  87. mBounds.extent.x = getMax( mMinExtent.x, mBounds.extent.x );
  88. mBounds.extent.y = getMax( mMinExtent.y, mBounds.extent.y );
  89. // Add to root group.
  90. Sim::getGuiGroup()->addObject(this);
  91. // Return Success.
  92. return true;
  93. }
  94. void GuiControl::onChildAdded( GuiControl *child )
  95. {
  96. // Base class does not make use of this
  97. }
  98. static EnumTable::Enums horzEnums[] =
  99. {
  100. { GuiControl::horizResizeRight, "right" },
  101. { GuiControl::horizResizeWidth, "width" },
  102. { GuiControl::horizResizeLeft, "left" },
  103. { GuiControl::horizResizeCenter, "center" },
  104. { GuiControl::horizResizeRelative, "relative" }
  105. };
  106. static EnumTable gHorizSizingTable(5, &horzEnums[0]);
  107. static EnumTable::Enums vertEnums[] =
  108. {
  109. { GuiControl::vertResizeBottom, "bottom" },
  110. { GuiControl::vertResizeHeight, "height" },
  111. { GuiControl::vertResizeTop, "top" },
  112. { GuiControl::vertResizeCenter, "center" },
  113. { GuiControl::vertResizeRelative, "relative" }
  114. };
  115. static EnumTable gVertSizingTable(5, &vertEnums[0]);
  116. void GuiControl::initPersistFields()
  117. {
  118. Parent::initPersistFields();
  119. // Things relevant only to the editor.
  120. addGroup("Gui Editing");
  121. addField("isContainer", TypeBool, Offset(mIsContainer, GuiControl));
  122. endGroup("Gui Editing");
  123. // Parent Group.
  124. addGroup("GuiControl");
  125. addField("Profile", TypeGuiProfile, Offset(mProfile, GuiControl));
  126. addField("HorizSizing", TypeEnum, Offset(mHorizSizing, GuiControl), 1, &gHorizSizingTable);
  127. addField("VertSizing", TypeEnum, Offset(mVertSizing, GuiControl), 1, &gVertSizingTable);
  128. addField("Position", TypePoint2I, Offset(mBounds.point, GuiControl));
  129. addField("Extent", TypePoint2I, Offset(mBounds.extent, GuiControl));
  130. addField("MinExtent", TypePoint2I, Offset(mMinExtent, GuiControl));
  131. addField("canSave", TypeBool, Offset(mCanSave, GuiControl));
  132. addField("Visible", TypeBool, Offset(mVisible, GuiControl));
  133. addDepricatedField("Modal");
  134. addDepricatedField("SetFirstResponder");
  135. addField("Variable", TypeString, Offset(mConsoleVariable, GuiControl));
  136. addField("Command", TypeString, Offset(mConsoleCommand, GuiControl));
  137. addField("AltCommand", TypeString, Offset(mAltConsoleCommand, GuiControl));
  138. addField("Accelerator", TypeString, Offset(mAcceleratorKey, GuiControl));
  139. addField("Active", TypeBool, Offset(mActive, GuiControl));
  140. endGroup("GuiControl");
  141. addGroup("ToolTip");
  142. addField("tooltipprofile", TypeGuiProfile, Offset(mTooltipProfile, GuiControl));
  143. addField("tooltip", TypeString, Offset(mTooltip, GuiControl));
  144. addField("tooltipWidth", TypeS32, Offset(mTooltipWidth, GuiControl));
  145. addField("hovertime", TypeS32, Offset(mTipHoverTime, GuiControl));
  146. endGroup("ToolTip");
  147. addGroup("Localization");
  148. addField("langTableMod", TypeString, Offset(mLangTableName, GuiControl));
  149. endGroup("Localization");
  150. }
  151. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  152. LangTable * GuiControl::getGUILangTable()
  153. {
  154. if(mLangTable)
  155. return mLangTable;
  156. if(mLangTableName && *mLangTableName)
  157. {
  158. mLangTable = (LangTable *)getModLangTable((const UTF8*)mLangTableName);
  159. return mLangTable;
  160. }
  161. GuiControl *parent = getParent();
  162. if(parent)
  163. return parent->getGUILangTable();
  164. return NULL;
  165. }
  166. const UTF8 * GuiControl::getGUIString(S32 id)
  167. {
  168. LangTable *lt = getGUILangTable();
  169. if(lt)
  170. return lt->getString(id);
  171. return NULL;
  172. }
  173. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  174. void GuiControl::addObject(SimObject *object)
  175. {
  176. GuiControl *ctrl = dynamic_cast<GuiControl *>(object);
  177. if(!ctrl)
  178. {
  179. AssertWarn(0, "GuiControl::addObject: attempted to add NON GuiControl to set");
  180. return;
  181. }
  182. if(object->getGroup() == this)
  183. return;
  184. Parent::addObject(object);
  185. AssertFatal(!ctrl->isAwake(), "GuiControl::addObject: object is already awake before add");
  186. if(mAwake)
  187. ctrl->awaken();
  188. // If we are a child, notify our parent that we've been removed
  189. GuiControl *parent = ctrl->getParent();
  190. if( parent )
  191. parent->onChildAdded( ctrl );
  192. }
  193. void GuiControl::removeObject(SimObject *object)
  194. {
  195. AssertFatal(mAwake == static_cast<GuiControl*>(object)->isAwake(), "GuiControl::removeObject: child control wake state is bad");
  196. if (mAwake)
  197. static_cast<GuiControl*>(object)->sleep();
  198. Parent::removeObject(object);
  199. }
  200. GuiControl *GuiControl::getParent()
  201. {
  202. SimObject *obj = getGroup();
  203. if (GuiControl* gui = dynamic_cast<GuiControl*>(obj))
  204. return gui;
  205. return 0;
  206. }
  207. GuiCanvas *GuiControl::getRoot()
  208. {
  209. GuiControl *root = NULL;
  210. GuiControl *parent = getParent();
  211. while (parent)
  212. {
  213. root = parent;
  214. parent = parent->getParent();
  215. }
  216. if (root)
  217. return dynamic_cast<GuiCanvas*>(root);
  218. else
  219. return NULL;
  220. }
  221. void GuiControl::inspectPreApply()
  222. {
  223. if(smDesignTime && smEditorHandle)
  224. smEditorHandle->controlInspectPreApply(this);
  225. // The canvas never sleeps
  226. if(mAwake && dynamic_cast<GuiCanvas*>(this) == NULL )
  227. {
  228. onSleep(); // release all our resources.
  229. mAwake = true;
  230. }
  231. }
  232. void GuiControl::inspectPostApply()
  233. {
  234. // Shhhhhhh, you don't want to wake the canvas!
  235. if(mAwake && dynamic_cast<GuiCanvas*>(this) == NULL )
  236. {
  237. mAwake = false;
  238. onWake();
  239. }
  240. if(smDesignTime && smEditorHandle)
  241. smEditorHandle->controlInspectPostApply(this);
  242. }
  243. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  244. Point2I GuiControl::localToGlobalCoord(const Point2I &src)
  245. {
  246. Point2I ret = src;
  247. ret += mBounds.point;
  248. GuiControl *walk = getParent();
  249. while(walk)
  250. {
  251. ret += walk->getPosition();
  252. walk = walk->getParent();
  253. }
  254. return ret;
  255. }
  256. Point2I GuiControl::globalToLocalCoord(const Point2I &src)
  257. {
  258. Point2I ret = src;
  259. ret -= mBounds.point;
  260. GuiControl *walk = getParent();
  261. while(walk)
  262. {
  263. ret -= walk->getPosition();
  264. walk = walk->getParent();
  265. }
  266. return ret;
  267. }
  268. //----------------------------------------------------------------
  269. void GuiControl::resize(const Point2I &newPosition, const Point2I &newExtent)
  270. {
  271. Point2I actualNewExtent = Point2I(getMax(mMinExtent.x, newExtent.x),
  272. getMax(mMinExtent.y, newExtent.y));
  273. // only do the child control resizing stuff if you really need to.
  274. bool extentChanged = (actualNewExtent != mBounds.extent);
  275. if (extentChanged) {
  276. //call set update both before and after
  277. setUpdate();
  278. iterator i;
  279. for(i = begin(); i != end(); i++)
  280. {
  281. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  282. ctrl->parentResized(mBounds.extent, actualNewExtent);
  283. }
  284. mBounds.set(newPosition, actualNewExtent);
  285. GuiControl *parent = getParent();
  286. if (parent)
  287. parent->childResized(this);
  288. setUpdate();
  289. }
  290. else {
  291. mBounds.point = newPosition;
  292. }
  293. }
  294. void GuiControl::setPosition( const Point2I &newPosition )
  295. {
  296. resize( newPosition, mBounds.extent );
  297. }
  298. void GuiControl::setExtent( const Point2I &newExtent )
  299. {
  300. resize( mBounds.point, newExtent );
  301. }
  302. void GuiControl::setBounds( const RectI &newBounds )
  303. {
  304. resize( newBounds.point, newBounds.extent );
  305. }
  306. void GuiControl::setLeft( S32 newLeft )
  307. {
  308. resize( Point2I( newLeft, mBounds.point.y), mBounds.extent );
  309. }
  310. void GuiControl::setTop( S32 newTop )
  311. {
  312. resize( Point2I( mBounds.point.x, newTop ), mBounds.extent );
  313. }
  314. void GuiControl::setWidth( S32 newWidth )
  315. {
  316. resize( mBounds.point, Point2I( newWidth, mBounds.extent.y ) );
  317. }
  318. void GuiControl::setHeight( S32 newHeight )
  319. {
  320. resize( mBounds.point, Point2I( mBounds.extent.x, newHeight ) );
  321. }
  322. void GuiControl::childResized(GuiControl *child)
  323. {
  324. // default to do nothing...
  325. }
  326. void GuiControl::parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent)
  327. {
  328. Point2I newPosition = getPosition();
  329. Point2I newExtent = getExtent();
  330. S32 deltaX = newParentExtent.x - oldParentExtent.x;
  331. S32 deltaY = newParentExtent.y - oldParentExtent.y;
  332. if (mHorizSizing == horizResizeCenter)
  333. newPosition.x = (newParentExtent.x - mBounds.extent.x) >> 1;
  334. else if (mHorizSizing == horizResizeWidth)
  335. newExtent.x += deltaX;
  336. else if (mHorizSizing == horizResizeLeft)
  337. newPosition.x += deltaX;
  338. else if (mHorizSizing == horizResizeRelative && oldParentExtent.x != 0)
  339. {
  340. S32 newLeft = (newPosition.x * newParentExtent.x) / oldParentExtent.x;
  341. S32 newRight = ((newPosition.x + newExtent.x) * newParentExtent.x) / oldParentExtent.x;
  342. newPosition.x = newLeft;
  343. newExtent.x = newRight - newLeft;
  344. }
  345. if (mVertSizing == vertResizeCenter)
  346. newPosition.y = (newParentExtent.y - mBounds.extent.y) >> 1;
  347. else if (mVertSizing == vertResizeHeight)
  348. newExtent.y += deltaY;
  349. else if (mVertSizing == vertResizeTop)
  350. newPosition.y += deltaY;
  351. else if(mVertSizing == vertResizeRelative && oldParentExtent.y != 0)
  352. {
  353. S32 newTop = (newPosition.y * newParentExtent.y) / oldParentExtent.y;
  354. S32 newBottom = ((newPosition.y + newExtent.y) * newParentExtent.y) / oldParentExtent.y;
  355. newPosition.y = newTop;
  356. newExtent.y = newBottom - newTop;
  357. }
  358. // Resizing Re factor [9/18/2006]
  359. // Only resize if our minExtent is satisfied with it.
  360. //if( newExtent.x >= mMinExtent.x && newExtent.y >= mMinExtent.y )
  361. resize(newPosition, newExtent);
  362. }
  363. //----------------------------------------------------------------
  364. void GuiControl::onRender(Point2I offset, const RectI &updateRect)
  365. {
  366. RectI ctrlRect(offset, mBounds.extent);
  367. dglSetBitmapModulation( mProfile->mFontColor );
  368. //if opaque, fill the update rect with the fill color
  369. if (mProfile->mOpaque)
  370. dglDrawRectFill( ctrlRect, mProfile->mFillColor );
  371. //if there's a border, draw the border
  372. if (mProfile->mBorder)
  373. renderBorder(ctrlRect, mProfile);
  374. renderChildControls(offset, updateRect);
  375. }
  376. bool GuiControl::renderTooltip(Point2I cursorPos, const char* tipText )
  377. {
  378. #ifndef TORQUE_OS_IOS
  379. // Short Circuit.
  380. if (!mAwake)
  381. return false;
  382. if ( dStrlen( mTooltip ) == 0 && ( tipText == NULL || dStrlen( tipText ) == 0 ) )
  383. return false;
  384. const char* renderTip = mTooltip;
  385. if( tipText != NULL )
  386. renderTip = tipText;
  387. // Finish if no root.
  388. GuiCanvas *root = getRoot();
  389. if ( !root )
  390. return false;
  391. if (!mTooltipProfile)
  392. mTooltipProfile = mProfile;
  393. GFont *font = mTooltipProfile->mFont;
  394. // Set text bounds.
  395. Point2I textBounds( 0, 0 );
  396. // Fetch the width of a space.
  397. const S32 spaceWidth = (S32)font->getStrWidth(" ");
  398. // Fetch the maximum allowed tooltip extent.
  399. const S32 maxTooltipWidth = mTooltipWidth;
  400. // Fetch word count.
  401. const S32 wordCount = StringUnit::getUnitCount( renderTip, " " );
  402. // Reset line storage.
  403. const S32 tooltipLineStride = (S32)font->getHeight() + 4;
  404. const S32 maxTooltipLines = 20;
  405. S32 tooltipLineCount = 0;
  406. S32 tooltipLineWidth = 0;
  407. FrameTemp<StringBuffer> tooltipLines( maxTooltipLines );
  408. // Reset word indexing.
  409. S32 wordStartIndex = 0;
  410. S32 wordEndIndex = 0;
  411. // Search for end word.
  412. while( true )
  413. {
  414. // Do we have any words left?
  415. if ( wordEndIndex < wordCount )
  416. {
  417. // Yes, so fetch the word.
  418. const char* pWord = StringUnit::getUnit( renderTip, wordEndIndex, " " );
  419. // Add word length.
  420. const S32 wordLength = (S32)font->getStrWidth( pWord ) + spaceWidth;
  421. // Do we still have room?
  422. if ( (tooltipLineWidth + wordLength) < maxTooltipWidth )
  423. {
  424. // Yes, so add word length.
  425. tooltipLineWidth += wordLength;
  426. // Next word.
  427. wordEndIndex++;
  428. continue;
  429. }
  430. // Do we have any lines left?
  431. if ( tooltipLineCount < maxTooltipLines )
  432. {
  433. // Yes, so insert line.
  434. tooltipLines[tooltipLineCount++] = StringUnit::getUnits( renderTip, wordStartIndex, wordEndIndex-1, " " );
  435. // Update horizontal text bounds.
  436. if ( tooltipLineWidth > textBounds.x )
  437. textBounds.x = tooltipLineWidth;
  438. }
  439. // Set new line length.
  440. tooltipLineWidth = wordLength;
  441. // Set word start.
  442. wordStartIndex = wordEndIndex;
  443. // Next word.
  444. wordEndIndex++;
  445. continue;
  446. }
  447. // Do we have any words left?
  448. if ( wordStartIndex < wordCount )
  449. {
  450. // Yes, so do we have any lines left?
  451. if ( tooltipLineCount < maxTooltipLines )
  452. {
  453. // Yes, so insert line.
  454. tooltipLines[tooltipLineCount++] = StringUnit::getUnits( renderTip, wordStartIndex, wordCount-1, " " );
  455. // Update horizontal text bounds.
  456. if ( tooltipLineWidth > textBounds.x )
  457. textBounds.x = tooltipLineWidth;
  458. }
  459. }
  460. break;
  461. }
  462. // Controls the size of the inside (gutter) tooltip region.
  463. const S32 tooltipGutterSize = 5;
  464. // Adjust text bounds.
  465. textBounds.x += tooltipGutterSize * 2;
  466. textBounds.y = (((S32)font->getHeight() + 4) * tooltipLineCount - 4) + (tooltipGutterSize * 2);
  467. // Adjust to tooltip is always on-screen.
  468. Point2I screensize = Platform::getWindowSize();
  469. Point2I offset = cursorPos;
  470. offset.y += 22;
  471. if (screensize.x < (offset.x + textBounds.x))
  472. offset.x = screensize.x - textBounds.x;
  473. if(screensize.y < (offset.y + textBounds.y) )
  474. offset.y = screensize.y - textBounds.y;
  475. // Fetch the old clip.
  476. RectI oldClip = dglGetClipRect();
  477. // Set rectangle for the box, and set the clip rectangle.
  478. RectI rect(offset, textBounds);
  479. dglSetClipRect(rect);
  480. // Draw Filler bit, then border on top of that
  481. dglDrawRectFill(rect, mTooltipProfile->mFillColor );
  482. dglDrawRect( rect, mTooltipProfile->mBorderColor );
  483. // Draw the text centered in the tool tip box
  484. dglSetBitmapModulation( mTooltipProfile->mFontColor );
  485. Point2I start( tooltipGutterSize, tooltipGutterSize );
  486. for ( S32 lineIndex = 0; lineIndex < tooltipLineCount; lineIndex++ )
  487. {
  488. dglDrawText( font, start + offset, tooltipLines[lineIndex].getPtr8(), mProfile->mFontColors );
  489. offset.y += tooltipLineStride;
  490. }
  491. dglSetClipRect( oldClip );
  492. #endif
  493. return true;
  494. }
  495. void GuiControl::renderChildControls(Point2I offset, const RectI &updateRect)
  496. {
  497. // offset is the upper-left corner of this control in screen coordinates
  498. // updateRect is the intersection rectangle in screen coords of the control
  499. // hierarchy. This can be set as the clip rectangle in most cases.
  500. RectI clipRect = updateRect;
  501. S32 size = objectList.size();
  502. S32 size_cpy = size;
  503. //-Mat look through our vector all normal-like, trying to use an iterator sometimes gives us
  504. //bad cast on good objects
  505. for( S32 count = 0; count < objectList.size(); count++ )
  506. {
  507. GuiControl *ctrl = (GuiControl *)objectList[count];
  508. if( ctrl == NULL ) {
  509. Con::errorf( "GuiControl::renderChildControls() object %i is NULL", count );
  510. continue;
  511. }
  512. if (ctrl->mVisible)
  513. {
  514. Point2I childPosition = offset + ctrl->getPosition();
  515. RectI childClip(childPosition, ctrl->getExtent());
  516. if (childClip.intersect(clipRect))
  517. {
  518. dglSetClipRect(childClip);
  519. glDisable(GL_CULL_FACE);
  520. ctrl->onRender(childPosition, childClip);
  521. }
  522. }
  523. size_cpy = objectList.size(); // CHRIS: i know its wierd but the size of the list changes sometimes during execution of this loop
  524. if(size != size_cpy)
  525. {
  526. size = size_cpy;
  527. count--; // CHRIS: just to make sure one wasnt skipped.
  528. }
  529. }
  530. }
  531. void GuiControl::setUpdateRegion(Point2I pos, Point2I ext)
  532. {
  533. Point2I upos = localToGlobalCoord(pos);
  534. GuiCanvas *root = getRoot();
  535. if (root)
  536. {
  537. root->addUpdateRegion(upos, ext);
  538. }
  539. }
  540. void GuiControl::setUpdate()
  541. {
  542. setUpdateRegion(Point2I(0,0), mBounds.extent);
  543. }
  544. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  545. void GuiControl::awaken()
  546. {
  547. AssertFatal(!mAwake, "GuiControl::awaken: control is already awake");
  548. if(mAwake)
  549. return;
  550. iterator i;
  551. for(i = begin(); i != end(); i++)
  552. {
  553. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  554. AssertFatal(!ctrl->isAwake(), "GuiControl::awaken: child control is already awake");
  555. if(!ctrl->isAwake())
  556. ctrl->awaken();
  557. }
  558. AssertFatal(!mAwake, "GuiControl::awaken: should not be awake here");
  559. if(!mAwake)
  560. {
  561. if(!onWake())
  562. {
  563. Con::errorf(ConsoleLogEntry::General, "GuiControl::awaken: failed onWake for obj: %s", getName());
  564. AssertFatal(0, "GuiControl::awaken: failed onWake");
  565. deleteObject();
  566. }
  567. }
  568. }
  569. void GuiControl::sleep()
  570. {
  571. AssertFatal(mAwake, "GuiControl::sleep: control is not awake");
  572. if(!mAwake)
  573. return;
  574. iterator i;
  575. for(i = begin(); i != end(); i++)
  576. {
  577. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  578. AssertFatal(ctrl->isAwake(), "GuiControl::sleep: child control is already asleep");
  579. if(ctrl->isAwake())
  580. ctrl->sleep();
  581. }
  582. AssertFatal(mAwake, "GuiControl::sleep: should not be asleep here");
  583. if(mAwake)
  584. onSleep();
  585. }
  586. void GuiControl::preRender()
  587. {
  588. AssertFatal(mAwake, "GuiControl::preRender: control is not awake");
  589. if(!mAwake)
  590. return;
  591. iterator i;
  592. for(i = begin(); i != end(); i++)
  593. {
  594. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  595. ctrl->preRender();
  596. }
  597. onPreRender();
  598. }
  599. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  600. bool GuiControl::onWake()
  601. {
  602. AssertFatal( !mAwake, "GuiControl::onWake: control is already awake" );
  603. if( mAwake )
  604. return false;
  605. // [tom, 4/18/2005] Cause mLangTable to be refreshed in case it was changed
  606. mLangTable = NULL;
  607. // Grab the classname of this object
  608. const char *cName = getClassName();
  609. //make sure we have a profile
  610. if( !mProfile )
  611. {
  612. // Ensure the classname is a valid name...
  613. if( cName && cName[0] )
  614. {
  615. S32 pos = 0;
  616. for( pos = 0; pos <= (S32)dStrlen( cName ); pos++ )
  617. if( !dStrncmp( cName + pos, "Ctrl", 4 ) )
  618. break;
  619. if( pos != 0 ) {
  620. char buff[255];
  621. dStrncpy( buff, cName, pos );
  622. buff[pos] = '\0';
  623. dStrcat( buff, "Profile\0" );
  624. SimObject *obj = Sim::findObject( buff );
  625. if( obj )
  626. mProfile = dynamic_cast<GuiControlProfile*>( obj );
  627. }
  628. }
  629. // Ok lets check to see if that worked
  630. if( !mProfile ) {
  631. SimObject *obj = Sim::findObject( "GuiDefaultProfile" );
  632. if( obj )
  633. mProfile = dynamic_cast<GuiControlProfile*>(obj);
  634. }
  635. AssertFatal( mProfile, avar( "GuiControl: %s created with no profile.", getName() ) );
  636. }
  637. //set the flag
  638. mAwake = true;
  639. //set the layer
  640. GuiCanvas *root = getRoot();
  641. AssertFatal(root, "Unable to get the root Canvas.");
  642. GuiControl *parent = getParent();
  643. if (parent && parent != root)
  644. mLayer = parent->mLayer;
  645. //make sure the first responder exists
  646. if (! mFirstResponder)
  647. mFirstResponder = findFirstTabable();
  648. //see if we should force this control to be the first responder
  649. //if (mProfile->mTabable && mProfile->mCanKeyFocus)
  650. // setFirstResponder();
  651. //increment the profile
  652. mProfile->incRefCount();
  653. // Only invoke script callbacks if we have a namespace in which to do so
  654. // This will suppress warnings
  655. if( isMethod("onWake") )
  656. Con::executef(this, 1, "onWake");
  657. return true;
  658. }
  659. void GuiControl::onSleep()
  660. {
  661. AssertFatal(mAwake, "GuiControl::onSleep: control is not awake");
  662. if(!mAwake)
  663. return;
  664. //decrement the profile referrence
  665. if( mProfile != NULL )
  666. mProfile->decRefCount();
  667. clearFirstResponder();
  668. mouseUnlock();
  669. // Only invoke script callbacks if we have a namespace in which to do so
  670. // This will suppress warnings
  671. if( isMethod("onSleep") )
  672. Con::executef(this, 1, "onSleep");
  673. // Set Flag
  674. mAwake = false;
  675. }
  676. void GuiControl::setControlProfile(GuiControlProfile *prof)
  677. {
  678. AssertFatal(prof, "GuiControl::setControlProfile: invalid profile");
  679. if(prof == mProfile)
  680. return;
  681. if(mAwake)
  682. mProfile->decRefCount();
  683. mProfile = prof;
  684. if(mAwake)
  685. mProfile->incRefCount();
  686. }
  687. void GuiControl::onPreRender()
  688. {
  689. // do nothing.
  690. }
  691. //-----------------------------------------------------------------------------
  692. // checks up the parent hierarchy - if anyone above us is not savable returns false
  693. // otherwise, returns true.
  694. //-----------------------------------------------------------------------------
  695. bool GuiControl::getCanSaveParent()
  696. {
  697. GuiControl *walk = this;
  698. while(walk)
  699. {
  700. if(!walk->getCanSave())
  701. return false;
  702. walk = walk->getParent();
  703. }
  704. return true;
  705. }
  706. //-----------------------------------------------------------------------------
  707. // Can we Save to a TorqueScript file?
  708. //-----------------------------------------------------------------------------
  709. bool GuiControl::getCanSave()
  710. {
  711. return mCanSave;
  712. }
  713. //-----------------------------------------------------------------------------
  714. // Sets whether we can save out to a file (TorqueScript)
  715. //-----------------------------------------------------------------------------
  716. void GuiControl::setCanSave(bool bCanSave)
  717. {
  718. mCanSave = bCanSave;
  719. }
  720. ConsoleMethod( GuiControl, setCanSave, void, 3,3,"(bool canSave) Sets whether this control can serialize itself to the hard disk\n"
  721. "@param Flag setting\n"
  722. "@return No Return Value")
  723. {
  724. object->setCanSave( dAtob( argv[2] ) );
  725. }
  726. ////////////////////////////////////////////////////////////////////////////////////////////////////
  727. // checks out mCanSave flag, if true just passes along to our parent,
  728. // if false, then we return without writing. Note, also, that
  729. // if our parent is not writeable, then we should not be writable...
  730. ////////////////////////////////////////////////////////////////////////////////////////////////////
  731. void GuiControl::write(Stream &stream, U32 tabStop, U32 flags)
  732. {
  733. //note: this will return false if either we, or any of our parents, are non-save controls
  734. bool bCanSave = getCanSaveParent();
  735. if(bCanSave)
  736. {
  737. Parent::write(stream, tabStop, flags);
  738. }
  739. }
  740. ConsoleMethod(GuiControl, pointInControl, bool, 4,4,"(int x, int y) Check if point id in the control\n"
  741. "@param x Point x coordinate in parent coords\n"
  742. "@param y Point y coordinate in parent coords\n"
  743. "@return Returns true if the point is in the control, false otherwise")
  744. {
  745. Point2I kPoint(dAtoi(argv[2]), dAtoi(argv[3]));
  746. return object->pointInControl(kPoint);
  747. }
  748. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  749. ConsoleMethod( GuiControl, addGuiControl, void, 3, 3, "(int controlId) Adds the gui control\n"
  750. "@param controlId integer ID of the control to add\n"
  751. "@return No Return value")
  752. {
  753. GuiControl *ctrl = dynamic_cast<GuiControl *>(Sim::findObject(argv[2]));
  754. if(ctrl)
  755. {
  756. object->addObject(ctrl);
  757. }
  758. }
  759. //-----------------------------------------------------------------------------
  760. // Make Sure Child 1 is Ordered Just Under Child 2.
  761. //-----------------------------------------------------------------------------
  762. ConsoleMethod(GuiControl, reorderChild, void, 4,4," (child1, child2) uses simset reorder to push child 1 after child 2 - both must already be child controls of this control")
  763. {
  764. GuiControl* pControl = dynamic_cast<GuiControl*>(Sim::findObject(dAtoi(argv[2])));
  765. GuiControl* pTarget = dynamic_cast<GuiControl*>(Sim::findObject(dAtoi(argv[3])));
  766. if(pControl && pTarget)
  767. {
  768. object->reOrder(pControl,pTarget);
  769. }
  770. }
  771. ConsoleMethod( GuiControl, getParent, S32, 2, 2, "() @return Returns the Id of the parent control")
  772. {
  773. GuiControl* pParent = object->getParent();
  774. if(pParent)
  775. {
  776. return pParent->getId();
  777. }
  778. return 0;
  779. }
  780. ConsoleMethod( GuiControl, setValue, void, 3, 3, "( value ) Use the setValue method to set the control specific value to value. Purpose and type varies by control type.\n"
  781. "@param value Some control specific value.\n"
  782. "@return No return value")
  783. {
  784. object->setScriptValue(argv[2]);
  785. }
  786. ConsoleMethod( GuiControl, getValue, const char*, 2, 2, "() Use the getValue method to get the control-specific 'value' for this control.\n"
  787. "@return Returns a control-specific specific value. Varies by control")
  788. {
  789. return object->getScriptValue();
  790. }
  791. ConsoleMethod( GuiControl, setActive, void, 3, 3, "( isActive ) Use the setActive method to (de)activate this control. Once active, a control can accept inputs. Controls automatically re-shade/skin themselves to reflect their active/inactive state.\n"
  792. "@param isActive A boolean value. f isActive is true, this control is activated, else it is set to inactive.\n"
  793. "@return No return value")
  794. {
  795. object->setActive(dAtob(argv[2]));
  796. }
  797. ConsoleMethod( GuiControl, isActive, bool, 2, 2, "() Use the isActive method to determine if this control is active.\n"
  798. "An inactive control may visible, but will not accept inputs. It will also normally re-shade or re-skin itself to reflect its inactive state\n"
  799. "@return Returns true if this control is active.")
  800. {
  801. return object->isActive();
  802. }
  803. ConsoleMethod( GuiControl, setVisible, void, 3, 3, "( isVisible ) Use the setVisible method to (un)hide this control.\n"
  804. "@param isVisible A boolean value. If true, the control will be made visible, otherwise the control will be hidden.\n"
  805. "@return No return value")
  806. {
  807. object->setVisible(dAtob(argv[2]));
  808. }
  809. ConsoleMethod( GuiControl, makeFirstResponder, void, 3, 3, "( isFirst ) Use the makeFirstResponder method to force this control to become the first responder.\n"
  810. "@param isFirst A boolean value. If true, then this control become first reponder and at captures inputs before all other controls, excluding dialogs above this control.\n"
  811. "@return No return value")
  812. {
  813. object->makeFirstResponder(dAtob(argv[2]));
  814. }
  815. ConsoleMethod( GuiControl, isVisible, bool, 2, 2, "() Use the isVisible method to determine if this control is visible.\n"
  816. "This can return true, even if the entire control covered by another. This merely means that the control will render if not covered\n"
  817. "@return Returns true if the control is visible.")
  818. {
  819. return object->isVisible();
  820. }
  821. ConsoleMethod( GuiControl, isAwake, bool, 2, 2, "() Use the isAwake method to determine if this control is awake.\n"
  822. "@return Returns true if this control is awake and ready to display")
  823. {
  824. return object->isAwake();
  825. }
  826. ConsoleMethod( GuiControl, setProfile, void, 3, 3, "(GuiControlProfile p) Sets the currently used from for the GuiControl\n"
  827. "@param p The profile you wish to set the control to use\n"
  828. "@return No return value")
  829. {
  830. GuiControlProfile * profile;
  831. if(Sim::findObject(argv[2], profile))
  832. object->setControlProfile(profile);
  833. }
  834. ConsoleMethod( GuiControl, resize, void, 6, 6, "(int x, int y, int w, int h) Resizes the control to the given dimensions")
  835. {
  836. Point2I newPos(dAtoi(argv[2]), dAtoi(argv[3]));
  837. Point2I newExt(dAtoi(argv[4]), dAtoi(argv[5]));
  838. object->resize(newPos, newExt);
  839. }
  840. ConsoleMethod( GuiControl, getPosition, const char*, 2, 2, "() @return A string set up as \"<pos.x> <pos.y>\"")
  841. {
  842. char *retBuffer = Con::getReturnBuffer(64);
  843. const Point2I &pos = object->getPosition();
  844. dSprintf(retBuffer, 64, "%d %d", pos.x, pos.y);
  845. return retBuffer;
  846. }
  847. ConsoleMethod( GuiControl, getCenter, const char*, 2, 2, "() @return Returns center of control, as space seperated ints")
  848. {
  849. char *retBuffer = Con::getReturnBuffer(64);
  850. const Point2I pos = object->getPosition();
  851. const Point2I ext = object->getExtent();
  852. Point2I center(pos.x + ext.x/2, pos.y + ext.y/2);
  853. dSprintf(retBuffer, 64, "%d %d", center.x, center.y);
  854. return retBuffer;
  855. }
  856. ConsoleMethod( GuiControl, setCenter, void, 4, 4, "(int x, int y) Sets control position, by center - coords are local not global\n"
  857. "@return No Return value.")
  858. {
  859. const Point2I ext = object->getExtent();
  860. Point2I newpos(dAtoi(argv[2])-ext.x/2, dAtoi(argv[3])-ext.y/2);
  861. object->setPosition(newpos);
  862. }
  863. ConsoleMethod( GuiControl, getGlobalCenter, const char*, 2, 2, "@return Returns center of control, as space seperated ints")
  864. {
  865. char *retBuffer = Con::getReturnBuffer(64);
  866. const Point2I tl(0,0);
  867. Point2I pos = object->localToGlobalCoord(tl);
  868. const Point2I ext = object->getExtent();
  869. Point2I center(pos.x + ext.x/2, pos.y + ext.y/2);
  870. dSprintf(retBuffer, 64, "%d %d", center.x, center.y);
  871. return retBuffer;
  872. }
  873. ConsoleMethod( GuiControl, getGlobalPosition, const char*, 2, 2, "() @return Returns the control's position converted to global coordinates (position as space-separted integers)")
  874. {
  875. char *retBuffer = Con::getReturnBuffer(64);
  876. const Point2I pos(0,0);
  877. Point2I gPos = object->localToGlobalCoord(pos);
  878. dSprintf(retBuffer, 64, "%d %d", gPos.x, gPos.y);
  879. return retBuffer;
  880. }
  881. ConsoleMethod( GuiControl, setPositionGlobal, void, 4, 4, "(int x, int y) Sets the control's position in global space\n"
  882. "@return No return value")
  883. {
  884. //see if we can turn the x/y into ints directly,
  885. Point2I gPos(dAtoi(argv[2]), dAtoi(argv[3]));
  886. Point2I lPosOffset = object->globalToLocalCoord(gPos);
  887. lPosOffset.x += object->mBounds.point.x;
  888. lPosOffset.y += object->mBounds.point.y;
  889. object->mBounds.set(lPosOffset,object->mBounds.extent);
  890. }
  891. ConsoleMethod( GuiControl, setPosition, void, 4, 4, "(int x, int y) Sets the current control position in local space\n"
  892. "@return No Return Value.")
  893. {
  894. //see if we can turn the x/y into ints directly,
  895. Point2I lPos(dAtoi(argv[2]), dAtoi(argv[3]));
  896. object->mBounds.set(lPos,object->mBounds.extent);
  897. }
  898. ConsoleMethod( GuiControl, getExtent, const char*, 2, 2, "Get the width and height of the control.\n"
  899. "@return The height and width as a string with space-separated integers")
  900. {
  901. char *retBuffer = Con::getReturnBuffer(64);
  902. const Point2I &ext = object->getExtent();
  903. dSprintf(retBuffer, 64, "%d %d", ext.x, ext.y);
  904. return retBuffer;
  905. }
  906. ConsoleMethod( GuiControl, setExtent, void, 4, 4, "(int width, int height) Sets the width & height of the control.\n"
  907. "@return No Return Value.")
  908. {
  909. Point2I kExt(dAtoi(argv[2]), dAtoi(argv[3]));
  910. object->setExtent(kExt);
  911. }
  912. ConsoleMethod( GuiControl, getMinExtent, const char*, 2, 2, "() Get the minimum allowed size of the control.\n"
  913. "@return Returns the minimum extent as a string with space separated point values <width> <height>")
  914. {
  915. char *retBuffer = Con::getReturnBuffer(64);
  916. const Point2I &minExt = object->getMinExtent();
  917. dSprintf(retBuffer, 64, "%d %d", minExt.x, minExt.y);
  918. return retBuffer;
  919. }
  920. void GuiControl::onRemove()
  921. {
  922. clearFirstResponder();
  923. Parent::onRemove();
  924. // If we are a child, notify our parent that we've been removed
  925. GuiControl *parent = getParent();
  926. if( parent )
  927. parent->onChildRemoved( this );
  928. }
  929. void GuiControl::onChildRemoved( GuiControl *child )
  930. {
  931. // Base does nothing with this
  932. }
  933. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  934. const char *GuiControl::getScriptValue()
  935. {
  936. return NULL;
  937. }
  938. void GuiControl::setScriptValue(const char *value)
  939. {
  940. }
  941. void GuiControl::setConsoleVariable(const char *variable)
  942. {
  943. if (variable)
  944. {
  945. mConsoleVariable = StringTable->insert(variable);
  946. }
  947. else
  948. {
  949. mConsoleVariable = StringTable->EmptyString;
  950. }
  951. }
  952. //-----------------------------------------------------------------------------
  953. // finds and returns the first immediate child of ours whose
  954. // internal name matches the passed String. returns Null if not found.
  955. //-----------------------------------------------------------------------------
  956. void GuiControl::setConsoleCommand(const char *newCmd)
  957. {
  958. if (newCmd)
  959. mConsoleCommand = StringTable->insert(newCmd);
  960. else
  961. mConsoleCommand = StringTable->EmptyString;
  962. }
  963. const char * GuiControl::getConsoleCommand()
  964. {
  965. return mConsoleCommand;
  966. }
  967. void GuiControl::setSizing(S32 horz, S32 vert)
  968. {
  969. mHorizSizing = horz;
  970. mVertSizing = vert;
  971. }
  972. void GuiControl::setVariable(const char *value)
  973. {
  974. if (mConsoleVariable[0])
  975. Con::setVariable(mConsoleVariable, value);
  976. }
  977. void GuiControl::setIntVariable(S32 value)
  978. {
  979. if (mConsoleVariable[0])
  980. Con::setIntVariable(mConsoleVariable, value);
  981. }
  982. void GuiControl::setFloatVariable(F32 value)
  983. {
  984. if (mConsoleVariable[0])
  985. Con::setFloatVariable(mConsoleVariable, value);
  986. }
  987. const char * GuiControl::getVariable()
  988. {
  989. if (mConsoleVariable[0])
  990. return Con::getVariable(mConsoleVariable);
  991. else return NULL;
  992. }
  993. S32 GuiControl::getIntVariable()
  994. {
  995. if (mConsoleVariable[0])
  996. return Con::getIntVariable(mConsoleVariable);
  997. else return 0;
  998. }
  999. F32 GuiControl::getFloatVariable()
  1000. {
  1001. if (mConsoleVariable[0])
  1002. return Con::getFloatVariable(mConsoleVariable);
  1003. else return 0.0f;
  1004. }
  1005. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  1006. bool GuiControl::cursorInControl()
  1007. {
  1008. GuiCanvas *root = getRoot();
  1009. if (! root) return false;
  1010. Point2I pt = root->getCursorPos();
  1011. Point2I offset = localToGlobalCoord(Point2I(0, 0));
  1012. if (pt.x >= offset.x && pt.y >= offset.y &&
  1013. pt.x < offset.x + mBounds.extent.x && pt.y < offset.y + mBounds.extent.y)
  1014. {
  1015. return true;
  1016. }
  1017. else
  1018. {
  1019. return false;
  1020. }
  1021. }
  1022. bool GuiControl::pointInControl(const Point2I& parentCoordPoint)
  1023. {
  1024. S32 xt = parentCoordPoint.x - mBounds.point.x;
  1025. S32 yt = parentCoordPoint.y - mBounds.point.y;
  1026. return xt >= 0 && yt >= 0 && xt < mBounds.extent.x && yt < mBounds.extent.y;
  1027. }
  1028. ConsoleMethod( GuiControl, findHitControl, S32, 4, 4, "(int x, int y) Searches for the control at the given point\n"
  1029. "@return Returns the Id of the control at the point")
  1030. {
  1031. Point2I pos(dAtoi(argv[2]), dAtoi(argv[3]));
  1032. GuiControl *hit = object->findHitControl(pos);
  1033. return hit ? hit->getId() : 0;
  1034. }
  1035. GuiControl* GuiControl::findHitControl(const Point2I &pt, S32 initialLayer)
  1036. {
  1037. iterator i = end(); // find in z order (last to first)
  1038. while (i != begin())
  1039. {
  1040. i--;
  1041. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1042. if (initialLayer >= 0 && ctrl->mLayer > initialLayer)
  1043. {
  1044. continue;
  1045. }
  1046. else if (ctrl->mVisible && ctrl->pointInControl(pt))
  1047. {
  1048. Point2I ptemp = pt - ctrl->mBounds.point;
  1049. GuiControl *hitCtrl = ctrl->findHitControl(ptemp);
  1050. if(hitCtrl->mProfile->mModal)
  1051. return hitCtrl;
  1052. }
  1053. }
  1054. return this;
  1055. }
  1056. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  1057. bool GuiControl::isMouseLocked()
  1058. {
  1059. GuiCanvas *root = getRoot();
  1060. return root ? root->getMouseLockedControl() == this : false;
  1061. }
  1062. void GuiControl::mouseLock(GuiControl *lockingControl)
  1063. {
  1064. GuiCanvas *root = getRoot();
  1065. if (root)
  1066. root->mouseLock(lockingControl);
  1067. }
  1068. void GuiControl::mouseLock()
  1069. {
  1070. GuiCanvas *root = getRoot();
  1071. if (root)
  1072. root->mouseLock(this);
  1073. }
  1074. void GuiControl::mouseUnlock()
  1075. {
  1076. GuiCanvas *root = getRoot();
  1077. if (root)
  1078. root->mouseUnlock(this);
  1079. }
  1080. bool GuiControl::onInputEvent(const InputEvent &event)
  1081. {
  1082. // Do nothing by default...
  1083. return( false );
  1084. }
  1085. void GuiControl::onMouseUp(const GuiEvent &event)
  1086. {
  1087. }
  1088. void GuiControl::onMouseDown(const GuiEvent &event)
  1089. {
  1090. }
  1091. void GuiControl::onMouseMove(const GuiEvent &event)
  1092. {
  1093. //if this control is a dead end, make sure the event stops here
  1094. if ( !mVisible || !mAwake )
  1095. return;
  1096. //pass the event to the parent
  1097. GuiControl *parent = getParent();
  1098. if ( parent )
  1099. parent->onMouseMove( event );
  1100. }
  1101. void GuiControl::onMouseDragged(const GuiEvent &event)
  1102. {
  1103. }
  1104. void GuiControl::onMouseEnter(const GuiEvent &)
  1105. {
  1106. }
  1107. void GuiControl::onMouseLeave(const GuiEvent &)
  1108. {
  1109. }
  1110. bool GuiControl::onMouseWheelUp( const GuiEvent &event )
  1111. {
  1112. //if this control is a dead end, make sure the event stops here
  1113. if ( !mVisible || !mAwake )
  1114. return true;
  1115. //pass the event to the parent
  1116. GuiControl *parent = getParent();
  1117. if ( parent )
  1118. return parent->onMouseWheelUp( event );
  1119. else
  1120. return false;
  1121. }
  1122. bool GuiControl::onMouseWheelDown( const GuiEvent &event )
  1123. {
  1124. //if this control is a dead end, make sure the event stops here
  1125. if ( !mVisible || !mAwake )
  1126. return true;
  1127. //pass the event to the parent
  1128. GuiControl *parent = getParent();
  1129. if ( parent )
  1130. return parent->onMouseWheelDown( event );
  1131. else
  1132. return false;
  1133. }
  1134. void GuiControl::onRightMouseDown(const GuiEvent &)
  1135. {
  1136. }
  1137. void GuiControl::onRightMouseUp(const GuiEvent &)
  1138. {
  1139. }
  1140. void GuiControl::onRightMouseDragged(const GuiEvent &)
  1141. {
  1142. }
  1143. void GuiControl::onMiddleMouseDown(const GuiEvent &)
  1144. {
  1145. }
  1146. void GuiControl::onMiddleMouseUp(const GuiEvent &)
  1147. {
  1148. }
  1149. void GuiControl::onMiddleMouseDragged(const GuiEvent &)
  1150. {
  1151. }
  1152. GuiControl* GuiControl::findFirstTabable()
  1153. {
  1154. GuiControl *tabCtrl = NULL;
  1155. iterator i;
  1156. for (i = begin(); i != end(); i++)
  1157. {
  1158. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1159. tabCtrl = ctrl->findFirstTabable();
  1160. if (tabCtrl)
  1161. {
  1162. mFirstResponder = tabCtrl;
  1163. return tabCtrl;
  1164. }
  1165. }
  1166. //nothing was found, therefore, see if this ctrl is tabable
  1167. return ( mProfile != NULL ) ? ( ( mProfile->mTabable && mAwake && mVisible ) ? this : NULL ) : NULL;
  1168. }
  1169. GuiControl* GuiControl::findLastTabable(bool firstCall)
  1170. {
  1171. //if this is the first call, clear the global
  1172. if (firstCall)
  1173. smPrevResponder = NULL;
  1174. //if this control is tabable, set the global
  1175. if (mProfile->mTabable)
  1176. smPrevResponder = this;
  1177. iterator i;
  1178. for (i = begin(); i != end(); i++)
  1179. {
  1180. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1181. ctrl->findLastTabable(false);
  1182. }
  1183. //after the entire tree has been traversed, return the last responder found
  1184. mFirstResponder = smPrevResponder;
  1185. return smPrevResponder;
  1186. }
  1187. GuiControl *GuiControl::findNextTabable(GuiControl *curResponder, bool firstCall)
  1188. {
  1189. //if this is the first call, clear the global
  1190. if (firstCall)
  1191. smCurResponder = NULL;
  1192. //first find the current responder
  1193. if (curResponder == this)
  1194. smCurResponder = this;
  1195. //if the first responder has been found, return the very next *tabable* control
  1196. else if ( smCurResponder && mProfile->mTabable && mAwake && mVisible && mActive )
  1197. return( this );
  1198. //loop through, checking each child to see if it is the one that follows the firstResponder
  1199. GuiControl *tabCtrl = NULL;
  1200. iterator i;
  1201. for (i = begin(); i != end(); i++)
  1202. {
  1203. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1204. tabCtrl = ctrl->findNextTabable(curResponder, false);
  1205. if (tabCtrl) break;
  1206. }
  1207. mFirstResponder = tabCtrl;
  1208. return tabCtrl;
  1209. }
  1210. GuiControl *GuiControl::findPrevTabable(GuiControl *curResponder, bool firstCall)
  1211. {
  1212. if (firstCall)
  1213. smPrevResponder = NULL;
  1214. //if this is the current reponder, return the previous one
  1215. if (curResponder == this)
  1216. return smPrevResponder;
  1217. //else if this is a responder, store it in case the next found is the current responder
  1218. else if ( mProfile->mTabable && mAwake && mVisible && mActive )
  1219. smPrevResponder = this;
  1220. //loop through, checking each child to see if it is the one that follows the firstResponder
  1221. GuiControl *tabCtrl = NULL;
  1222. iterator i;
  1223. for (i = begin(); i != end(); i++)
  1224. {
  1225. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1226. tabCtrl = ctrl->findPrevTabable(curResponder, false);
  1227. if (tabCtrl) break;
  1228. }
  1229. mFirstResponder = tabCtrl;
  1230. return tabCtrl;
  1231. }
  1232. void GuiControl::onLoseFirstResponder()
  1233. {
  1234. // Since many controls have visual cues when they are the firstResponder...
  1235. setUpdate();
  1236. }
  1237. bool GuiControl::ControlIsChild(GuiControl *child)
  1238. {
  1239. //function returns true if this control, or one of it's children is the child control
  1240. if (child == this)
  1241. return true;
  1242. //loop through, checking each child to see if it is ,or contains, the firstResponder
  1243. iterator i;
  1244. for (i = begin(); i != end(); i++)
  1245. {
  1246. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1247. if (ctrl->ControlIsChild(child)) return true;
  1248. }
  1249. //not found, therefore false
  1250. return false;
  1251. }
  1252. bool GuiControl::isFirstResponder()
  1253. {
  1254. GuiCanvas *root = getRoot();
  1255. return root && root->getFirstResponder() == this;
  1256. }
  1257. void GuiControl::setFirstResponder( GuiControl* firstResponder )
  1258. {
  1259. if ( firstResponder && firstResponder->mProfile->mCanKeyFocus )
  1260. mFirstResponder = firstResponder;
  1261. GuiControl *parent = getParent();
  1262. if ( parent )
  1263. parent->setFirstResponder( firstResponder );
  1264. }
  1265. void GuiControl::setFirstResponder()
  1266. {
  1267. if ( mAwake && mVisible )
  1268. {
  1269. GuiControl *parent = getParent();
  1270. if (mProfile->mCanKeyFocus == true && parent != NULL )
  1271. {
  1272. parent->setFirstResponder(this);
  1273. // Since many controls have visual cues when they are the firstResponder...
  1274. this->setUpdate();
  1275. }
  1276. }
  1277. }
  1278. ConsoleMethod(GuiControl, setFirstResponder, void , 2, 2, "Sets this control as the first responder")
  1279. {
  1280. object->setFirstResponder();
  1281. }
  1282. void GuiControl::clearFirstResponder()
  1283. {
  1284. GuiControl *parent = this;
  1285. while((parent = parent->getParent()) != NULL)
  1286. {
  1287. if(parent->mFirstResponder == this)
  1288. parent->mFirstResponder = NULL;
  1289. else
  1290. break;
  1291. }
  1292. }
  1293. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  1294. void GuiControl::buildAcceleratorMap()
  1295. {
  1296. //add my own accel key
  1297. addAcceleratorKey();
  1298. //add all my childrens keys
  1299. iterator i;
  1300. for(i = begin(); i != end(); i++)
  1301. {
  1302. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1303. ctrl->buildAcceleratorMap();
  1304. }
  1305. }
  1306. void GuiControl::addAcceleratorKey()
  1307. {
  1308. //see if we have an accelerator
  1309. if (mAcceleratorKey == StringTable->EmptyString)
  1310. return;
  1311. EventDescriptor accelEvent;
  1312. ActionMap::createEventDescriptor(mAcceleratorKey, &accelEvent);
  1313. //now we have a modifier, and a key, add them to the canvas
  1314. GuiCanvas *root = getRoot();
  1315. if (root)
  1316. root->addAcceleratorKey(this, 0, accelEvent.eventCode, accelEvent.flags);
  1317. }
  1318. void GuiControl::acceleratorKeyPress(U32 index)
  1319. {
  1320. onAction();
  1321. }
  1322. void GuiControl::acceleratorKeyRelease(U32 index)
  1323. {
  1324. //do nothing
  1325. }
  1326. bool GuiControl::onKeyDown(const GuiEvent &event)
  1327. {
  1328. //pass the event to the parent
  1329. GuiControl *parent = getParent();
  1330. if (parent)
  1331. return parent->onKeyDown(event);
  1332. else
  1333. return false;
  1334. }
  1335. bool GuiControl::onKeyRepeat(const GuiEvent &event)
  1336. {
  1337. // default to just another key down.
  1338. return onKeyDown(event);
  1339. }
  1340. bool GuiControl::onKeyUp(const GuiEvent &event)
  1341. {
  1342. //pass the event to the parent
  1343. GuiControl *parent = getParent();
  1344. if (parent)
  1345. return parent->onKeyUp(event);
  1346. else
  1347. return false;
  1348. }
  1349. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  1350. void GuiControl::onAction()
  1351. {
  1352. if (! mActive)
  1353. return;
  1354. //execute the console command
  1355. if (mConsoleCommand && mConsoleCommand[0])
  1356. {
  1357. execConsoleCallback();
  1358. }
  1359. else
  1360. Con::executef(this, 1, "onAction");
  1361. }
  1362. void GuiControl::onMessage(GuiControl *sender, S32 msg)
  1363. {
  1364. }
  1365. void GuiControl::messageSiblings(S32 message)
  1366. {
  1367. GuiControl *parent = getParent();
  1368. if (! parent) return;
  1369. GuiControl::iterator i;
  1370. for(i = parent->begin(); i != parent->end(); i++)
  1371. {
  1372. GuiControl *ctrl = dynamic_cast<GuiControl *>(*i);
  1373. if (ctrl != this)
  1374. ctrl->onMessage(this, message);
  1375. }
  1376. }
  1377. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  1378. void GuiControl::onDialogPush()
  1379. {
  1380. // Notify Script.
  1381. if( isMethod("onDialogPush") )
  1382. Con::executef(this, 1, "onDialogPush");
  1383. }
  1384. void GuiControl::onDialogPop()
  1385. {
  1386. // Notify Script.
  1387. if( isMethod("onDialogPop") )
  1388. Con::executef(this, 1, "onDialogPop");
  1389. }
  1390. //------------------------------------------------------------------------------
  1391. void GuiControl::setVisible(bool value)
  1392. {
  1393. mVisible = value;
  1394. iterator i;
  1395. setUpdate();
  1396. for(i = begin(); i != end(); i++)
  1397. {
  1398. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1399. ctrl->clearFirstResponder();
  1400. }
  1401. GuiControl *parent = getParent();
  1402. if (parent)
  1403. parent->childResized(this);
  1404. }
  1405. void GuiControl::makeFirstResponder(bool value)
  1406. {
  1407. if ( value )
  1408. //setFirstResponder(this);
  1409. setFirstResponder();
  1410. else
  1411. clearFirstResponder();
  1412. }
  1413. void GuiControl::setActive( bool value )
  1414. {
  1415. mActive = value;
  1416. if ( !mActive )
  1417. clearFirstResponder();
  1418. if ( mVisible && mAwake )
  1419. setUpdate();
  1420. }
  1421. void GuiControl::getScrollLineSizes(U32 *rowHeight, U32 *columnWidth)
  1422. {
  1423. // default to 10 pixels in y, 30 pixels in x
  1424. *columnWidth = 30;
  1425. *rowHeight = 30;
  1426. }
  1427. void GuiControl::renderJustifiedText(Point2I offset, Point2I extent, const char *text)
  1428. {
  1429. GFont *font = mProfile->mFont;
  1430. S32 textWidth = font->getStrWidth((const UTF8*)text);
  1431. Point2I start;
  1432. // align the horizontal
  1433. switch( mProfile->mAlignment )
  1434. {
  1435. case GuiControlProfile::RightJustify:
  1436. start.set( extent.x - textWidth, 0 );
  1437. break;
  1438. case GuiControlProfile::CenterJustify:
  1439. start.set( ( extent.x - textWidth) / 2, 0 );
  1440. break;
  1441. default:
  1442. // GuiControlProfile::LeftJustify
  1443. start.set( 0, 0 );
  1444. break;
  1445. }
  1446. // If the text is longer then the box size, (it'll get clipped) so
  1447. // force Left Justify
  1448. if( textWidth > extent.x )
  1449. start.set( 0, 0 );
  1450. // center the vertical
  1451. if(font->getHeight() > (U32)extent.y)
  1452. start.y = 0 - ((font->getHeight() - extent.y) / 2) ;
  1453. else
  1454. start.y = ( extent.y - font->getHeight() ) / 2;
  1455. dglDrawText( font, start + offset, text, mProfile->mFontColors );
  1456. }
  1457. void GuiControl::getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent)
  1458. {
  1459. if(GuiControl::smCursorChanged != -1 && !isMouseLocked())
  1460. {
  1461. // We've already changed the cursor,
  1462. // so set it back before we change it again.
  1463. Input::popCursor();
  1464. // We haven't changed it
  1465. GuiControl::smCursorChanged = -1;
  1466. }
  1467. }
  1468. const char* GuiControl::execConsoleCallback()
  1469. {
  1470. if (mConsoleCommand && mConsoleCommand[0])
  1471. {
  1472. Con::setVariable("$ThisControl", avar("%d",getId()));
  1473. return Con::evaluate(mConsoleCommand, false);
  1474. }
  1475. return "";
  1476. }
  1477. const char* GuiControl::execAltConsoleCallback()
  1478. {
  1479. if(mAltConsoleCommand && mAltConsoleCommand[0])
  1480. {
  1481. Con::setVariable("$ThisControl", avar("%d",getId()));
  1482. return Con::evaluate(mAltConsoleCommand, false);
  1483. }
  1484. return "";
  1485. }