guiControl.cc 66 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241
  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. #include "2d/core/Utility.h"
  37. #include <sstream>
  38. #include <iostream>
  39. #include <vector>
  40. #include <string>
  41. #include "guiControl_ScriptBinding.h"
  42. #ifndef _FRAMEALLOCATOR_H_
  43. #include "memory/frameAllocator.h"
  44. #endif
  45. //------------------------------------------------------------------------------
  46. IMPLEMENT_CONOBJECT_CHILDREN(GuiControl);
  47. static EnumTable::Enums alignCtrlEnums[] =
  48. {
  49. { AlignmentType::LeftAlign, "left" },
  50. { AlignmentType::CenterAlign, "center" },
  51. { AlignmentType::RightAlign, "right" },
  52. { AlignmentType::DefaultAlign, "default" }
  53. };
  54. static EnumTable gAlignCtrlTable(3, &alignCtrlEnums[0]);
  55. static EnumTable::Enums vAlignCtrlEnums[] =
  56. {
  57. { VertAlignmentType::TopVAlign, "top" },
  58. { VertAlignmentType::MiddleVAlign, "middle" },
  59. { VertAlignmentType::BottomVAlign, "bottom" },
  60. { VertAlignmentType::DefaultVAlign, "default" }
  61. };
  62. static EnumTable gVAlignCtrlTable(3, &vAlignCtrlEnums[0]);
  63. //used to locate the next/prev responder when tab is pressed
  64. S32 GuiControl::smCursorChanged = -1;
  65. GuiControl *GuiControl::smPrevResponder = NULL;
  66. GuiControl *GuiControl::smCurResponder = NULL;
  67. GuiEditCtrl *GuiControl::smEditorHandle = NULL;
  68. bool GuiControl::smDesignTime = false;
  69. GuiControl::GuiControl()
  70. {
  71. mLayer = 0;
  72. mBounds.set(0, 0, 64, 64);
  73. mStoredExtent.set(0, 0);
  74. mRenderInsetLT.set(0, 0);
  75. mRenderInsetRB.set(0, 0);
  76. mMinExtent.set(0, 0);
  77. mStoredRelativePosH.set(0, 0);
  78. mStoredRelativePosV.set(0, 0);
  79. mUseRelPosH = false;
  80. mUseRelPosV = false;
  81. mProfile = NULL;
  82. mConsoleVariable = StringTable->EmptyString;
  83. mConsoleCommand = StringTable->EmptyString;
  84. mAltConsoleCommand = StringTable->EmptyString;
  85. mAcceleratorKey = StringTable->EmptyString;
  86. mLangTableName = StringTable->EmptyString;
  87. mText = StringTable->EmptyString;
  88. mTextID = StringTable->EmptyString;
  89. mAlignment = AlignmentType::DefaultAlign;
  90. mVAlignment = VertAlignmentType::DefaultVAlign;
  91. mFontSizeAdjust = 1;
  92. mFontColor.set(0, 0, 0, 255);
  93. mOverrideFontColor = false;
  94. mLangTable = NULL;
  95. mFirstResponder = NULL;
  96. mCanSaveFieldDictionary = false;
  97. mVisible = true;
  98. mActive = false;
  99. mAwake = false;
  100. mCanSave = true;
  101. mHorizSizing = horizResizeRight;
  102. mVertSizing = vertResizeBottom;
  103. mTooltipProfile = NULL;
  104. mTooltip = StringTable->EmptyString;
  105. mTipHoverTime = 1000;
  106. mTooltipWidth = 250;
  107. mIsContainer = false;
  108. mTextWrap = false;
  109. mTextExtend = false;
  110. mUseInput = true;
  111. }
  112. GuiControl::~GuiControl()
  113. {
  114. }
  115. bool GuiControl::onAdd()
  116. {
  117. // Let Parent Do Work.
  118. if(!Parent::onAdd())
  119. return false;
  120. // Grab the classname of this object
  121. const char *cName = getClassName();
  122. // if we're a pure GuiControl, then we're a container by default.
  123. if(dStrcmp("GuiControl", cName) == 0)
  124. mIsContainer = true;
  125. // Clamp to minExtent
  126. mBounds.extent.x = getMax( mMinExtent.x, mBounds.extent.x );
  127. mBounds.extent.y = getMax( mMinExtent.y, mBounds.extent.y );
  128. // Add to root group.
  129. Sim::getGuiGroup()->addObject(this);
  130. // Return Success.
  131. return true;
  132. }
  133. void GuiControl::onChildAdded( GuiControl *child )
  134. {
  135. if(mProfile)
  136. {
  137. //This will cause the child control to be centered if it needs to be.
  138. RectI innerRect = this->getInnerRect(mBounds.point, mBounds.extent, GuiControlState::NormalState, mProfile);
  139. child->parentResized(innerRect.extent, innerRect.extent);
  140. if (isMethod("onChildAdded"))
  141. {
  142. Con::executef(this, 3, "onChildAdded", child->getIdString());
  143. }
  144. }
  145. }
  146. void GuiControl::onChildRemoved(GuiControl* child)
  147. {
  148. if (mProfile && isMethod("onChildRemoved"))
  149. {
  150. Con::executef(this, 3, "onChildRemoved", child->getIdString());
  151. }
  152. }
  153. static EnumTable::Enums horzEnums[] =
  154. {
  155. { GuiControl::horizResizeRight, "right" },
  156. { GuiControl::horizResizeWidth, "width" },
  157. { GuiControl::horizResizeLeft, "left" },
  158. { GuiControl::horizResizeCenter, "center" },
  159. { GuiControl::horizResizeRelative, "relative" }
  160. };
  161. static EnumTable gHorizSizingTable(5, &horzEnums[0]);
  162. static EnumTable::Enums vertEnums[] =
  163. {
  164. { GuiControl::vertResizeBottom, "bottom" },
  165. { GuiControl::vertResizeHeight, "height" },
  166. { GuiControl::vertResizeTop, "top" },
  167. { GuiControl::vertResizeCenter, "center" },
  168. { GuiControl::vertResizeRelative, "relative" }
  169. };
  170. static EnumTable gVertSizingTable(5, &vertEnums[0]);
  171. void GuiControl::initPersistFields()
  172. {
  173. Parent::initPersistFields();
  174. // Things relevant only to the editor.
  175. addGroup("Gui Editing");
  176. addField("isContainer", TypeBool, Offset(mIsContainer, GuiControl));
  177. endGroup("Gui Editing");
  178. // Parent Group.
  179. addGroup("GuiControl");
  180. addField("Profile", TypeGuiProfile, Offset(mProfile, GuiControl));
  181. addField("HorizSizing", TypeEnum, Offset(mHorizSizing, GuiControl), 1, &gHorizSizingTable);
  182. addField("VertSizing", TypeEnum, Offset(mVertSizing, GuiControl), 1, &gVertSizingTable);
  183. addProtectedField("Position", TypePoint2I, Offset(mBounds.point, GuiControl), &setPositionFn, &defaultProtectedGetFn, "The location of the control in relation to its parent's content area.");
  184. addProtectedField("Extent", TypePoint2I, Offset(mBounds.extent, GuiControl), &setExtentFn, &defaultProtectedGetFn, "The size of the control writen as width and height.");
  185. addProtectedField("MinExtent", TypePoint2I, Offset(mMinExtent, GuiControl), &setMinExtentFn, &defaultProtectedGetFn, &writeMinExtentFn, "The extent will not shrink below this size.");
  186. addField("canSave", TypeBool, Offset(mCanSave, GuiControl));
  187. addField("Visible", TypeBool, Offset(mVisible, GuiControl));
  188. addField("useInput", TypeBool, Offset(mUseInput, GuiControl));
  189. addDepricatedField("Modal");
  190. addField("SetFirstResponder", TypeBool, Offset(mFirstResponder, GuiControl));
  191. addField("Variable", TypeString, Offset(mConsoleVariable, GuiControl));
  192. addField("Command", TypeString, Offset(mConsoleCommand, GuiControl));
  193. addField("AltCommand", TypeString, Offset(mAltConsoleCommand, GuiControl));
  194. addField("Accelerator", TypeString, Offset(mAcceleratorKey, GuiControl));
  195. addField("Active", TypeBool, Offset(mActive, GuiControl));
  196. endGroup("GuiControl");
  197. addGroup("ToolTip");
  198. addField("tooltipprofile", TypeGuiProfile, Offset(mTooltipProfile, GuiControl));
  199. addField("tooltip", TypeString, Offset(mTooltip, GuiControl));
  200. addField("tooltipWidth", TypeS32, Offset(mTooltipWidth, GuiControl));
  201. addField("hovertime", TypeS32, Offset(mTipHoverTime, GuiControl));
  202. endGroup("ToolTip");
  203. addGroup("Localization");
  204. addField("langTableMod", TypeString, Offset(mLangTableName, GuiControl));
  205. endGroup("Localization");
  206. addGroup("Text");
  207. addProtectedField("text", TypeCaseString, Offset(mText, GuiControl), setTextProperty, getTextProperty, "");
  208. addField("textID", TypeString, Offset(mTextID, GuiControl));
  209. addField("textWrap", TypeBool, Offset(mTextWrap, GuiControl), &writeTextWrapFn, "If true, text will wrap to additional lines.");
  210. addField("textExtend", TypeBool, Offset(mTextExtend, GuiControl), &writeTextExtendFn, "If true, extent will change based on the size of the control's text when possible.");
  211. addField("align", TypeEnum, Offset(mAlignment, GuiControl), 1, &gAlignCtrlTable);
  212. addField("vAlign", TypeEnum, Offset(mVAlignment, GuiControl), 1, &gVAlignCtrlTable);
  213. addField("fontSizeAdjust", TypeF32, Offset(mFontSizeAdjust, GuiControl), "A decimal value that is multiplied with the profile's fontSize to determine the control's actual font size.");
  214. addField("fontColor", TypeColorI, Offset(mFontColor, GuiControl), "A color to override the font color of the control's profile. OverrideFontColor must be set to true for this to work.");
  215. addField("overrideFontColor", TypeBool, Offset(mOverrideFontColor, GuiControl), "If true, the control's fontColor will override the profile's font color.");
  216. endGroup("Text");
  217. }
  218. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  219. LangTable * GuiControl::getGUILangTable()
  220. {
  221. if(mLangTable)
  222. return mLangTable;
  223. if(mLangTableName && *mLangTableName)
  224. {
  225. mLangTable = (LangTable *)getModLangTable((const UTF8*)mLangTableName);
  226. return mLangTable;
  227. }
  228. GuiControl *parent = getParent();
  229. if(parent)
  230. return parent->getGUILangTable();
  231. return NULL;
  232. }
  233. const UTF8 * GuiControl::getGUIString(S32 id)
  234. {
  235. LangTable *lt = getGUILangTable();
  236. if(lt)
  237. return lt->getString(id);
  238. return NULL;
  239. }
  240. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  241. void GuiControl::addObject(SimObject *object)
  242. {
  243. GuiControl *ctrl = dynamic_cast<GuiControl *>(object);
  244. if(!ctrl)
  245. {
  246. AssertWarn(0, "GuiControl::addObject: attempted to add NON GuiControl to set");
  247. return;
  248. }
  249. if(object->getGroup() == this)
  250. return;
  251. Parent::addObject(object);
  252. AssertFatal(!ctrl->isAwake(), "GuiControl::addObject: object is already awake before add");
  253. if(mAwake)
  254. ctrl->awaken();
  255. // If we are a child, notify our parent that we've been added
  256. GuiControl *parent = ctrl->getParent();
  257. if( parent )
  258. parent->onChildAdded( ctrl );
  259. }
  260. void GuiControl::removeObject(SimObject *object)
  261. {
  262. GuiControl *ctrl = dynamic_cast<GuiControl *>(object);
  263. if (!ctrl)
  264. {
  265. AssertWarn(0, "GuiControl::removeObject: attempted to remove NON GuiControl from set");
  266. return;
  267. }
  268. GuiControl *parent = ctrl->getParent();
  269. AssertFatal(mAwake == static_cast<GuiControl*>(object)->isAwake(), "GuiControl::removeObject: child control wake state is bad");
  270. if (mAwake)
  271. static_cast<GuiControl*>(object)->sleep();
  272. Parent::removeObject(object);
  273. // If we are a child, notify our parent that we've been removed
  274. if (parent)
  275. parent->onChildRemoved(ctrl);
  276. }
  277. GuiControl *GuiControl::getParent()
  278. {
  279. SimObject *obj = getGroup();
  280. if (GuiControl* gui = dynamic_cast<GuiControl*>(obj))
  281. return gui;
  282. return 0;
  283. }
  284. GuiCanvas *GuiControl::getRoot()
  285. {
  286. GuiControl *root = NULL;
  287. GuiControl *parent = getParent();
  288. while (parent)
  289. {
  290. root = parent;
  291. parent = parent->getParent();
  292. }
  293. if (root)
  294. return dynamic_cast<GuiCanvas*>(root);
  295. else
  296. return NULL;
  297. }
  298. void GuiControl::inspectPreApply()
  299. {
  300. if(smDesignTime && smEditorHandle)
  301. smEditorHandle->controlInspectPreApply(this);
  302. // The canvas never sleeps
  303. if(mAwake && dynamic_cast<GuiCanvas*>(this) == NULL )
  304. {
  305. onSleep(); // release all our resources.
  306. mAwake = true;
  307. }
  308. }
  309. void GuiControl::inspectPostApply()
  310. {
  311. // Shhhhhhh, you don't want to wake the canvas!
  312. if(mAwake && dynamic_cast<GuiCanvas*>(this) == NULL )
  313. {
  314. mAwake = false;
  315. onWake();
  316. }
  317. if(smDesignTime && smEditorHandle)
  318. smEditorHandle->controlInspectPostApply(this);
  319. }
  320. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  321. Point2I GuiControl::localToGlobalCoord(const Point2I &src)
  322. {
  323. Point2I ret = src;
  324. ret += (mBounds.point + mRenderInsetLT);
  325. GuiControl *walk = getParent();
  326. while(walk)
  327. {
  328. ret += (walk->getPosition() + walk->mRenderInsetLT);
  329. walk = walk->getParent();
  330. }
  331. return ret;
  332. }
  333. Point2I GuiControl::globalToLocalCoord(const Point2I &src)
  334. {
  335. Point2I ret = src;
  336. ret -= (mBounds.point + mRenderInsetLT);
  337. GuiControl *walk = getParent();
  338. while(walk)
  339. {
  340. ret -= (walk->getPosition() + walk->mRenderInsetLT);
  341. walk = walk->getParent();
  342. }
  343. return ret;
  344. }
  345. //----------------------------------------------------------------
  346. void GuiControl::resize(const Point2I &newPosition, const Point2I &newExtent)
  347. {
  348. Point2I actualNewExtent = Point2I(getMax(mMinExtent.x, newExtent.x),
  349. getMax(mMinExtent.y, newExtent.y));
  350. Point2I oldExtent = mBounds.extent;
  351. //force center if using center positioning
  352. Point2I actualNewPosition = Point2I(newPosition);
  353. GuiControl* parent = getParent();
  354. if (parent)
  355. {
  356. if (mHorizSizing == horizResizeCenter)
  357. {
  358. actualNewPosition.x = (parent->mBounds.extent.x - actualNewExtent.x) / 2;
  359. }
  360. if (mVertSizing == vertResizeCenter)
  361. {
  362. actualNewPosition.y = (parent->mBounds.extent.y - actualNewExtent.y) / 2;
  363. }
  364. }
  365. // only do the child control resizing stuff if you really need to.
  366. bool extentChanged = (actualNewExtent != oldExtent);
  367. if (extentChanged) {
  368. //call set update both before and after
  369. setUpdate();
  370. mBounds.set(actualNewPosition, actualNewExtent);
  371. iterator i;
  372. for(i = begin(); i != end(); i++)
  373. {
  374. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  375. ctrl->parentResized(oldExtent - (ctrl->mRenderInsetLT + ctrl->mRenderInsetRB), actualNewExtent - (ctrl->mRenderInsetLT + ctrl->mRenderInsetRB));
  376. }
  377. if (parent)
  378. parent->childResized(this);
  379. setUpdate();
  380. if (isMethod("onResize"))
  381. {
  382. Con::executef(this, 2, "onResize");
  383. }
  384. }
  385. else {
  386. mBounds.point = actualNewPosition;
  387. }
  388. }
  389. void GuiControl::setPosition( const Point2I &newPosition )
  390. {
  391. resize( newPosition, mBounds.extent );
  392. }
  393. void GuiControl::setExtent( const Point2I &newExtent )
  394. {
  395. resize( mBounds.point, newExtent );
  396. }
  397. void GuiControl::setBounds( const RectI &newBounds )
  398. {
  399. resize( newBounds.point, newBounds.extent );
  400. }
  401. void GuiControl::setLeft( S32 newLeft )
  402. {
  403. resize( Point2I( newLeft, mBounds.point.y), mBounds.extent );
  404. }
  405. void GuiControl::setTop( S32 newTop )
  406. {
  407. resize( Point2I( mBounds.point.x, newTop ), mBounds.extent );
  408. }
  409. void GuiControl::setWidth( S32 newWidth )
  410. {
  411. resize( mBounds.point, Point2I( newWidth, mBounds.extent.y ) );
  412. }
  413. void GuiControl::setHeight( S32 newHeight )
  414. {
  415. resize( mBounds.point, Point2I( mBounds.extent.x, newHeight ) );
  416. }
  417. void GuiControl::childResized(GuiControl *child)
  418. {
  419. // Default to do nothing. Do not call resize from here as it will create an infinite loop.
  420. if (isMethod("onChildResized"))
  421. {
  422. Con::executef(this, 3, "onChildResized", child->getIdString());
  423. }
  424. }
  425. void GuiControl::parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent)
  426. {
  427. Point2I newPosition = getPosition();
  428. Point2I newExtent = getExtent();
  429. S32 deltaX = newParentExtent.x - oldParentExtent.x;
  430. S32 deltaY = newParentExtent.y - oldParentExtent.y;
  431. //In the case of centering, we want to make doubly sure we are using the inner rect.
  432. GuiControl* parent = getParent();
  433. Point2I parentInnerExt = Point2I(newParentExtent);
  434. if(mHorizSizing == horizResizeCenter || mVertSizing == vertResizeCenter)
  435. {
  436. //This is based on the "new" outer extent of the parent.
  437. Point2I origin = Point2I(0, 0);
  438. parentInnerExt = getInnerRect(origin, parent->mBounds.extent, NormalState, parent->mProfile).extent;
  439. }
  440. if (mHorizSizing == horizResizeCenter)
  441. newPosition.x = (parentInnerExt.x - mBounds.extent.x) >> 1;
  442. else if (mHorizSizing == horizResizeWidth)
  443. newExtent.x += deltaX;
  444. else if (mHorizSizing == horizResizeLeft)
  445. newPosition.x += deltaX;
  446. else if (mHorizSizing == horizResizeRelative && oldParentExtent.x != 0)
  447. {
  448. Point2F percent = relPosBatteryH(newPosition.x, newExtent.x, oldParentExtent.x);
  449. S32 newLeft = mRound(percent.x * newParentExtent.x);
  450. S32 newRight = mRound(percent.y * newParentExtent.x);
  451. newPosition.x = newLeft;
  452. newExtent.x = newRight - newLeft;
  453. }
  454. if (mVertSizing == vertResizeCenter)
  455. newPosition.y = (parentInnerExt.y - mBounds.extent.y) >> 1;
  456. else if (mVertSizing == vertResizeHeight)
  457. newExtent.y += deltaY;
  458. else if (mVertSizing == vertResizeTop)
  459. newPosition.y += deltaY;
  460. else if(mVertSizing == vertResizeRelative && oldParentExtent.y != 0)
  461. {
  462. Point2F percent = relPosBatteryV(newPosition.y, newExtent.y, oldParentExtent.y);
  463. S32 newTop = mRound(percent.x * newParentExtent.y);
  464. S32 newBottom = mRound(percent.y * newParentExtent.y);
  465. newPosition.y = newTop;
  466. newExtent.y = newBottom - newTop;
  467. }
  468. newExtent = extentBattery(newExtent);
  469. resize(newPosition, newExtent);
  470. }
  471. Point2I GuiControl::extentBattery(Point2I &newExtent)
  472. {
  473. if (mMinExtent.x == 0 && mMinExtent.y == 0)
  474. {
  475. return newExtent;
  476. }
  477. Point2I result = Point2I(newExtent);
  478. if (mHorizSizing != horizResizeRelative)
  479. {
  480. if (newExtent.x < mBounds.extent.x && newExtent.x < mMinExtent.x)
  481. {
  482. mStoredExtent.x += mBounds.extent.x > mMinExtent.x ? (mMinExtent.x - newExtent.x) : (mBounds.extent.x - newExtent.x);
  483. result.x = mMinExtent.x;
  484. }
  485. else if (newExtent.x > mBounds.extent.x && mStoredExtent.x > 0)
  486. {
  487. S32 charge = getMin(newExtent.x - mBounds.extent.x, mStoredExtent.x);
  488. mStoredExtent.x -= charge;
  489. result.x = newExtent.x - charge;
  490. }
  491. }
  492. if (mVertSizing != vertResizeRelative)
  493. {
  494. if (newExtent.y < mBounds.extent.y && newExtent.y < mMinExtent.y)
  495. {
  496. mStoredExtent.y += mBounds.extent.y > mMinExtent.y ? (mMinExtent.y - newExtent.y) : (mBounds.extent.y - newExtent.y);
  497. result.y = mMinExtent.y;
  498. }
  499. else if (newExtent.y > mBounds.extent.y && mStoredExtent.y > 0)
  500. {
  501. S32 charge = getMin(newExtent.y - mBounds.extent.y, mStoredExtent.y);
  502. mStoredExtent.y -= charge;
  503. result.y = newExtent.y - charge;
  504. }
  505. }
  506. return result;
  507. }
  508. Point2F GuiControl::relPosBatteryH(S32 pos, S32 ext, S32 parentExt)
  509. {
  510. if (!mUseRelPosH)
  511. {
  512. relPosBattery(mStoredRelativePosH, pos, ext, parentExt);
  513. mUseRelPosH = true;
  514. }
  515. return mStoredRelativePosH;
  516. }
  517. Point2F GuiControl::relPosBatteryV(S32 pos, S32 ext, S32 parentExt)
  518. {
  519. if (!mUseRelPosV)
  520. {
  521. relPosBattery(mStoredRelativePosV, pos, ext, parentExt);
  522. mUseRelPosV = true;
  523. }
  524. return mStoredRelativePosV;
  525. }
  526. void GuiControl::relPosBattery(Point2F& battery, S32 pos, S32 ext, S32 parentExt)
  527. {
  528. battery.x = static_cast<F32>(pos) / parentExt;
  529. battery.y = static_cast<F32>(pos + ext) / parentExt;
  530. }
  531. //----------------------------------------------------------------
  532. void GuiControl::onRender(Point2I offset, const RectI &updateRect)
  533. {
  534. RectI ctrlRect = applyMargins(offset, mBounds.extent, NormalState, mProfile);
  535. if (!ctrlRect.isValidRect())
  536. {
  537. return;
  538. }
  539. renderUniversalRect(ctrlRect, mProfile, NormalState);
  540. //Render Text
  541. dglSetBitmapModulation(getFontColor(mProfile));
  542. RectI fillRect = applyBorders(ctrlRect.point, ctrlRect.extent, NormalState, mProfile);
  543. RectI contentRect = applyPadding(fillRect.point, fillRect.extent, NormalState, mProfile);
  544. if(contentRect.isValidRect())
  545. {
  546. renderText(contentRect.point, contentRect.extent, mText, mProfile);
  547. //Render the childen
  548. renderChildControls(offset, contentRect, updateRect);
  549. }
  550. }
  551. RectI GuiControl::applyMargins(Point2I &offset, Point2I &extent, GuiControlState currentState, GuiControlProfile *profile)
  552. {
  553. //Get the border profiles
  554. GuiBorderProfile *leftProfile = profile->getLeftBorder();
  555. GuiBorderProfile *rightProfile = profile->getRightBorder();
  556. GuiBorderProfile *topProfile = profile->getTopBorder();
  557. GuiBorderProfile *bottomProfile = profile->getBottomBorder();
  558. S32 leftSize = (leftProfile) ? leftProfile->getMargin(currentState) : 0;
  559. S32 rightSize = (rightProfile) ? rightProfile->getMargin(currentState) : 0;
  560. S32 topSize = (topProfile) ? topProfile->getMargin(currentState) : 0;
  561. S32 bottomSize = (bottomProfile) ? bottomProfile->getMargin(currentState) : 0;
  562. return RectI(offset.x + leftSize, offset.y + topSize, (extent.x - leftSize) - rightSize, (extent.y - topSize) - bottomSize);
  563. }
  564. RectI GuiControl::applyBorders(Point2I &offset, Point2I &extent, GuiControlState currentState, GuiControlProfile *profile)
  565. {
  566. //Get the border profiles
  567. GuiBorderProfile *leftProfile = profile->getLeftBorder();
  568. GuiBorderProfile *rightProfile = profile->getRightBorder();
  569. GuiBorderProfile *topProfile = profile->getTopBorder();
  570. GuiBorderProfile *bottomProfile = profile->getBottomBorder();
  571. S32 leftSize = (leftProfile) ? leftProfile->getBorder(currentState) : 0;
  572. S32 rightSize = (rightProfile) ? rightProfile->getBorder(currentState) : 0;
  573. S32 topSize = (topProfile) ? topProfile->getBorder(currentState) : 0;
  574. S32 bottomSize = (bottomProfile) ? bottomProfile->getBorder(currentState) : 0;
  575. return RectI(offset.x + leftSize, offset.y + topSize, (extent.x - leftSize) - rightSize, (extent.y - topSize) - bottomSize);
  576. }
  577. RectI GuiControl::applyPadding(Point2I &offset, Point2I &extent, GuiControlState currentState, GuiControlProfile *profile)
  578. {
  579. //Get the border profiles
  580. GuiBorderProfile *leftProfile = profile->getLeftBorder();
  581. GuiBorderProfile *rightProfile = profile->getRightBorder();
  582. GuiBorderProfile *topProfile = profile->getTopBorder();
  583. GuiBorderProfile *bottomProfile = profile->getBottomBorder();
  584. S32 leftSize = (leftProfile) ? leftProfile->getPadding(currentState) : 0;
  585. S32 rightSize = (rightProfile) ? rightProfile->getPadding(currentState) : 0;
  586. S32 topSize = (topProfile) ? topProfile->getPadding(currentState) : 0;
  587. S32 bottomSize = (bottomProfile) ? bottomProfile->getPadding(currentState) : 0;
  588. return RectI(offset.x + leftSize, offset.y + topSize, (extent.x - leftSize) - rightSize, (extent.y - topSize) - bottomSize);
  589. }
  590. RectI GuiControl::getInnerRect(Point2I &offset, Point2I &extent, GuiControlState currentState, GuiControlProfile *profile)
  591. {
  592. //Get the border profiles
  593. GuiBorderProfile *leftProfile = profile->getLeftBorder();
  594. GuiBorderProfile *rightProfile = profile->getRightBorder();
  595. GuiBorderProfile *topProfile = profile->getTopBorder();
  596. GuiBorderProfile *bottomProfile = profile->getBottomBorder();
  597. S32 leftSize = (leftProfile) ? leftProfile->getMargin(currentState) + leftProfile->getBorder(currentState) + leftProfile->getPadding(currentState) : 0;
  598. S32 rightSize = (rightProfile) ? rightProfile->getMargin(currentState) + rightProfile->getBorder(currentState) + rightProfile->getPadding(currentState) : 0;
  599. S32 topSize = (topProfile) ? topProfile->getMargin(currentState) + topProfile->getBorder(currentState) + topProfile->getPadding(currentState) : 0;
  600. S32 bottomSize = (bottomProfile) ? bottomProfile->getMargin(currentState) + bottomProfile->getBorder(currentState) + bottomProfile->getPadding(currentState) : 0;
  601. return RectI(offset.x + leftSize, offset.y + topSize, (extent.x - leftSize) - rightSize, (extent.y - topSize) - bottomSize);
  602. }
  603. Point2I GuiControl::getOuterExtent(Point2I &innerExtent, GuiControlState currentState, GuiControlProfile *profile)
  604. {
  605. return Point2I(getOuterWidth(innerExtent.x, currentState, profile), getOuterHeight(innerExtent.y, currentState, profile));
  606. }
  607. S32 GuiControl::getOuterWidth(S32 innerWidth, GuiControlState currentState, GuiControlProfile* profile)
  608. {
  609. //Get the border profiles
  610. GuiBorderProfile* leftProfile = profile->getLeftBorder();
  611. GuiBorderProfile* rightProfile = profile->getRightBorder();
  612. S32 leftSize = (leftProfile) ? leftProfile->getMargin(currentState) + leftProfile->getBorder(currentState) + leftProfile->getPadding(currentState) : 0;
  613. S32 rightSize = (rightProfile) ? rightProfile->getMargin(currentState) + rightProfile->getBorder(currentState) + rightProfile->getPadding(currentState) : 0;
  614. return innerWidth + leftSize + rightSize;
  615. }
  616. S32 GuiControl::getOuterHeight(S32 innerHeight, GuiControlState currentState, GuiControlProfile* profile)
  617. {
  618. //Get the border profiles
  619. GuiBorderProfile* topProfile = profile->getTopBorder();
  620. GuiBorderProfile* bottomProfile = profile->getBottomBorder();
  621. S32 topSize = (topProfile) ? topProfile->getMargin(currentState) + topProfile->getBorder(currentState) + topProfile->getPadding(currentState) : 0;
  622. S32 bottomSize = (bottomProfile) ? bottomProfile->getMargin(currentState) + bottomProfile->getBorder(currentState) + bottomProfile->getPadding(currentState) : 0;
  623. return innerHeight + topSize + bottomSize;
  624. }
  625. bool GuiControl::renderTooltip(Point2I &cursorPos, const char* tipText )
  626. {
  627. #if !defined(TORQUE_OS_IOS) && !defined(TORQUE_OS_ANDROID) && !defined(TORQUE_OS_EMSCRIPTEN)
  628. // Short Circuit.
  629. if (!mAwake)
  630. return false;
  631. if ( dStrlen( mTooltip ) == 0 && ( tipText == NULL || dStrlen( tipText ) == 0 ) )
  632. return false;
  633. const char* renderTip = mTooltip;
  634. if( tipText != NULL )
  635. renderTip = tipText;
  636. // Finish if no root.
  637. GuiCanvas *root = getRoot();
  638. if ( !root )
  639. return false;
  640. if (!mTooltipProfile)
  641. setField("TooltipProfile", "GuiTooltipProfile");
  642. GFont *font = mTooltipProfile->getFont();
  643. // Set text bounds.
  644. Point2I textBounds( 0, 0 );
  645. // Fetch the width of a space.
  646. const S32 spaceWidth = (S32)font->getStrWidth(" ");
  647. // Fetch the maximum allowed tooltip extent.
  648. const S32 maxTooltipWidth = mTooltipWidth;
  649. // Fetch word count.
  650. const S32 wordCount = StringUnit::getUnitCount( renderTip, " " );
  651. // Reset line storage.
  652. const S32 tooltipLineStride = (S32)font->getHeight() + 4;
  653. const S32 maxTooltipLines = 20;
  654. S32 tooltipLineCount = 0;
  655. S32 tooltipLineWidth = 0;
  656. FrameTemp<StringBuffer> tooltipLines( maxTooltipLines );
  657. // Reset word indexing.
  658. S32 wordStartIndex = 0;
  659. S32 wordEndIndex = 0;
  660. // Search for end word.
  661. while( true )
  662. {
  663. // Do we have any words left?
  664. if ( wordEndIndex < wordCount )
  665. {
  666. // Yes, so fetch the word.
  667. const char* pWord = StringUnit::getUnit( renderTip, wordEndIndex, " " );
  668. // Add word length.
  669. const S32 wordLength = (S32)font->getStrWidth( pWord ) + spaceWidth;
  670. // Do we still have room?
  671. if ( (tooltipLineWidth + wordLength) < maxTooltipWidth )
  672. {
  673. // Yes, so add word length.
  674. tooltipLineWidth += wordLength;
  675. // Next word.
  676. wordEndIndex++;
  677. continue;
  678. }
  679. // Do we have any lines left?
  680. if ( tooltipLineCount < maxTooltipLines )
  681. {
  682. // Yes, so insert line.
  683. tooltipLines[tooltipLineCount++] = StringUnit::getUnits( renderTip, wordStartIndex, wordEndIndex-1, " " );
  684. // Update horizontal text bounds.
  685. if ( tooltipLineWidth > textBounds.x )
  686. textBounds.x = tooltipLineWidth;
  687. }
  688. // Set new line length.
  689. tooltipLineWidth = wordLength;
  690. // Set word start.
  691. wordStartIndex = wordEndIndex;
  692. // Next word.
  693. wordEndIndex++;
  694. continue;
  695. }
  696. // Do we have any words left?
  697. if ( wordStartIndex < wordCount )
  698. {
  699. // Yes, so do we have any lines left?
  700. if ( tooltipLineCount < maxTooltipLines )
  701. {
  702. // Yes, so insert line.
  703. tooltipLines[tooltipLineCount++] = StringUnit::getUnits( renderTip, wordStartIndex, wordCount-1, " " );
  704. // Update horizontal text bounds.
  705. if ( tooltipLineWidth > textBounds.x )
  706. textBounds.x = tooltipLineWidth;
  707. }
  708. }
  709. break;
  710. }
  711. // Controls the size of the inside (gutter) tooltip region.
  712. const S32 tooltipGutterSize = 5;
  713. // Adjust text bounds.
  714. textBounds.x += tooltipGutterSize * 2;
  715. textBounds.y = (((S32)font->getHeight() + 4) * tooltipLineCount - 4) + (tooltipGutterSize * 2);
  716. // Adjust to tooltip is always on-screen.
  717. Point2I screensize = Platform::getWindowSize();
  718. Point2I offset = cursorPos;
  719. offset.y += 22;
  720. if (screensize.x < (offset.x + textBounds.x))
  721. offset.x = screensize.x - textBounds.x;
  722. if(screensize.y < (offset.y + textBounds.y) )
  723. offset.y = screensize.y - textBounds.y;
  724. // Fetch the old clip.
  725. RectI oldClip = dglGetClipRect();
  726. // Set rectangle for the box, and set the clip rectangle.
  727. RectI rect(offset, textBounds);
  728. dglSetClipRect(rect);
  729. // Draw body and border of the tool tip
  730. renderUniversalRect(rect, mTooltipProfile, NormalState);
  731. // Draw the text centered in the tool tip box
  732. dglSetBitmapModulation( mTooltipProfile->mFontColor );
  733. Point2I start( tooltipGutterSize, tooltipGutterSize );
  734. for ( S32 lineIndex = 0; lineIndex < tooltipLineCount; lineIndex++ )
  735. {
  736. dglDrawText( font, start + offset, tooltipLines[lineIndex].getPtr8(), mProfile->mFontColors );
  737. offset.y += tooltipLineStride;
  738. }
  739. dglSetClipRect( oldClip );
  740. #endif
  741. return true;
  742. }
  743. void GuiControl::renderChildControls(Point2I offset, RectI content, const RectI &updateRect)
  744. {
  745. // offset is the upper-left corner of this control in screen coordinates. It should almost always be the same offset passed into the onRender method.
  746. // updateRect is the area that this control was allowed to draw in. It should almost always be the same as the value in onRender.
  747. // content is the area that child controls are allowed to draw in.
  748. RectI clipRect = content;
  749. if(clipRect.intersect(dglGetClipRect()))
  750. {
  751. S32 size = objectList.size();
  752. S32 size_cpy = size;
  753. //-Mat look through our vector all normal-like, trying to use an iterator sometimes gives us
  754. //bad cast on good objects
  755. for( S32 count = 0; count < objectList.size(); count++ )
  756. {
  757. GuiControl *ctrl = (GuiControl *)objectList[count];
  758. if( ctrl == NULL ) {
  759. Con::errorf( "GuiControl::renderChildControls() object %i is NULL", count );
  760. continue;
  761. }
  762. if (ctrl->mVisible)
  763. {
  764. ctrl->mRenderInsetLT = content.point - offset;
  765. ctrl->mRenderInsetRB = mBounds.extent - (ctrl->mRenderInsetLT + content.extent);
  766. Point2I childPosition = content.point + ctrl->getPosition();
  767. RectI childClip(childPosition, ctrl->getExtent());
  768. if (childClip.intersect(clipRect))
  769. {
  770. RectI old = dglGetClipRect();
  771. dglSetClipRect(clipRect);
  772. glDisable(GL_CULL_FACE);
  773. ctrl->onRender(childPosition, RectI(childPosition, ctrl->getExtent()));
  774. dglSetClipRect(old);
  775. }
  776. }
  777. size_cpy = objectList.size(); // CHRIS: i know its wierd but the size of the list changes sometimes during execution of this loop
  778. if(size != size_cpy)
  779. {
  780. size = size_cpy;
  781. count--; // CHRIS: just to make sure one wasnt skipped.
  782. }
  783. }
  784. }
  785. }
  786. void GuiControl::setUpdateRegion(Point2I pos, Point2I ext)
  787. {
  788. Point2I upos = localToGlobalCoord(pos);
  789. GuiCanvas *root = getRoot();
  790. if (root)
  791. {
  792. root->addUpdateRegion(upos, ext);
  793. }
  794. }
  795. void GuiControl::setUpdate()
  796. {
  797. setUpdateRegion(Point2I(0,0), mBounds.extent);
  798. }
  799. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  800. void GuiControl::awaken()
  801. {
  802. AssertFatal(!mAwake, "GuiControl::awaken: control is already awake");
  803. if(mAwake)
  804. return;
  805. iterator i;
  806. for(i = begin(); i != end(); i++)
  807. {
  808. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  809. AssertFatal(!ctrl->isAwake(), "GuiControl::awaken: child control is already awake");
  810. if(!ctrl->isAwake())
  811. ctrl->awaken();
  812. }
  813. AssertFatal(!mAwake, "GuiControl::awaken: should not be awake here");
  814. if(!mAwake)
  815. {
  816. if(!onWake())
  817. {
  818. Con::errorf(ConsoleLogEntry::General, "GuiControl::awaken: failed onWake for obj: %s", getName());
  819. AssertFatal(0, "GuiControl::awaken: failed onWake");
  820. deleteObject();
  821. }
  822. else
  823. {
  824. if (mTextID && *mTextID != 0)
  825. setTextID(mTextID);
  826. }
  827. }
  828. }
  829. void GuiControl::sleep()
  830. {
  831. AssertFatal(mAwake, "GuiControl::sleep: control is not awake");
  832. if(!mAwake)
  833. return;
  834. iterator i;
  835. for(i = begin(); i != end(); i++)
  836. {
  837. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  838. AssertFatal(ctrl->isAwake(), "GuiControl::sleep: child control is already asleep");
  839. if(ctrl->isAwake())
  840. ctrl->sleep();
  841. }
  842. AssertFatal(mAwake, "GuiControl::sleep: should not be asleep here");
  843. if(mAwake)
  844. onSleep();
  845. }
  846. void GuiControl::preRender()
  847. {
  848. AssertFatal(mAwake, "GuiControl::preRender: control is not awake");
  849. if(!mAwake)
  850. return;
  851. iterator i;
  852. for(i = begin(); i != end(); i++)
  853. {
  854. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  855. if (ctrl->isVisible())
  856. {
  857. ctrl->preRender();
  858. }
  859. }
  860. onPreRender();
  861. }
  862. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  863. bool GuiControl::onWake()
  864. {
  865. AssertFatal( !mAwake, "GuiControl::onWake: control is already awake" );
  866. if( mAwake )
  867. return false;
  868. // [tom, 4/18/2005] Cause mLangTable to be refreshed in case it was changed
  869. mLangTable = NULL;
  870. // Grab the classname of this object
  871. const char *cName = getClassName();
  872. //make sure we have a profile
  873. if( !mProfile )
  874. {
  875. // Ensure the classname is a valid name...
  876. if( cName && cName[0] )
  877. {
  878. S32 pos = 0;
  879. for( pos = 0; pos <= (S32)dStrlen( cName ); pos++ )
  880. if( !dStrncmp( cName + pos, "Ctrl", 4 ) )
  881. break;
  882. if( pos != 0 ) {
  883. char buff[255];
  884. dStrncpy( buff, cName, pos );
  885. buff[pos] = '\0';
  886. dStrcat( buff, "Profile\0" );
  887. SimObject *obj = Sim::findObject( buff );
  888. if( obj )
  889. mProfile = dynamic_cast<GuiControlProfile*>( obj );
  890. }
  891. }
  892. // Ok lets check to see if that worked
  893. if( !mProfile ) {
  894. SimObject *obj = Sim::findObject( "GuiDefaultProfile" );
  895. if( obj )
  896. mProfile = dynamic_cast<GuiControlProfile*>(obj);
  897. }
  898. AssertFatal( mProfile, avar( "GuiControl: %s created with no profile.", getName() ) );
  899. }
  900. //set the flag
  901. mAwake = true;
  902. //set the layer
  903. GuiCanvas *root = getRoot();
  904. AssertFatal(root, "Unable to get the root Canvas.");
  905. GuiControl *parent = getParent();
  906. if (parent && parent != root)
  907. mLayer = parent->mLayer;
  908. //make sure the first responder exists
  909. if (! mFirstResponder)
  910. mFirstResponder = findFirstTabable();
  911. //see if we should force this control to be the first responder
  912. //if (mProfile->mTabable && mProfile->mCanKeyFocus)
  913. // setFirstResponder();
  914. //increment the profile
  915. mProfile->incRefCount();
  916. // Only invoke script callbacks if we have a namespace in which to do so
  917. // This will suppress warnings
  918. if( isMethod("onWake") )
  919. Con::executef(this, 1, "onWake");
  920. if (mTooltipProfile != NULL)
  921. mTooltipProfile->incRefCount();
  922. return true;
  923. }
  924. void GuiControl::onSleep()
  925. {
  926. AssertFatal(mAwake, "GuiControl::onSleep: control is not awake");
  927. if(!mAwake)
  928. return;
  929. //decrement the profile referrence
  930. if( mProfile != NULL )
  931. mProfile->decRefCount();
  932. clearFirstResponder();
  933. mouseUnlock();
  934. // Only invoke script callbacks if we have a namespace in which to do so
  935. // This will suppress warnings
  936. if( isMethod("onSleep") )
  937. Con::executef(this, 1, "onSleep");
  938. if (mTooltipProfile != NULL)
  939. mTooltipProfile->decRefCount();
  940. // Set Flag
  941. mAwake = false;
  942. }
  943. void GuiControl::setControlProfile(GuiControlProfile *prof)
  944. {
  945. AssertFatal(prof, "GuiControl::setControlProfile: invalid profile");
  946. if(prof == mProfile)
  947. return;
  948. if(mAwake)
  949. mProfile->decRefCount();
  950. mProfile = prof;
  951. if(mAwake)
  952. mProfile->incRefCount();
  953. }
  954. void GuiControl::onPreRender()
  955. {
  956. // do nothing.
  957. }
  958. //-----------------------------------------------------------------------------
  959. // checks up the parent hierarchy - if anyone above us is not savable returns false
  960. // otherwise, returns true.
  961. //-----------------------------------------------------------------------------
  962. bool GuiControl::getCanSaveParent()
  963. {
  964. GuiControl *walk = this;
  965. while(walk)
  966. {
  967. if(!walk->getCanSave())
  968. return false;
  969. walk = walk->getParent();
  970. }
  971. return true;
  972. }
  973. //-----------------------------------------------------------------------------
  974. // Can we Save to a TorqueScript file?
  975. //-----------------------------------------------------------------------------
  976. bool GuiControl::getCanSave()
  977. {
  978. return mCanSave;
  979. }
  980. //-----------------------------------------------------------------------------
  981. // Sets whether we can save out to a file (TorqueScript)
  982. //-----------------------------------------------------------------------------
  983. void GuiControl::setCanSave(bool bCanSave)
  984. {
  985. mCanSave = bCanSave;
  986. }
  987. ////////////////////////////////////////////////////////////////////////////////////////////////////
  988. // checks out mCanSave flag, if true just passes along to our parent,
  989. // if false, then we return without writing. Note, also, that
  990. // if our parent is not writeable, then we should not be writable...
  991. ////////////////////////////////////////////////////////////////////////////////////////////////////
  992. void GuiControl::write(Stream &stream, U32 tabStop, U32 flags)
  993. {
  994. //note: this will return false if either we, or any of our parents, are non-save controls
  995. bool bCanSave = getCanSaveParent();
  996. if(bCanSave)
  997. {
  998. Parent::write(stream, tabStop, flags);
  999. }
  1000. }
  1001. //This is only called if the control is deleted, not when the control is removed from its parent.
  1002. void GuiControl::onRemove()
  1003. {
  1004. Parent::onRemove();
  1005. }
  1006. //For GuiControls, this will always just before it is actually removed.
  1007. void GuiControl::onGroupRemove()
  1008. {
  1009. clearFirstResponder();
  1010. }
  1011. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  1012. const char *GuiControl::getScriptValue()
  1013. {
  1014. return NULL;
  1015. }
  1016. void GuiControl::setScriptValue(const char *value)
  1017. {
  1018. }
  1019. void GuiControl::setConsoleVariable(const char *variable)
  1020. {
  1021. if (variable)
  1022. {
  1023. mConsoleVariable = StringTable->insert(variable);
  1024. }
  1025. else
  1026. {
  1027. mConsoleVariable = StringTable->EmptyString;
  1028. }
  1029. }
  1030. //-----------------------------------------------------------------------------
  1031. // finds and returns the first immediate child of ours whose
  1032. // internal name matches the passed String. returns Null if not found.
  1033. //-----------------------------------------------------------------------------
  1034. void GuiControl::setConsoleCommand(const char *newCmd)
  1035. {
  1036. if (newCmd)
  1037. mConsoleCommand = StringTable->insert(newCmd);
  1038. else
  1039. mConsoleCommand = StringTable->EmptyString;
  1040. }
  1041. const char * GuiControl::getConsoleCommand()
  1042. {
  1043. return mConsoleCommand;
  1044. }
  1045. void GuiControl::setSizing(S32 horz, S32 vert)
  1046. {
  1047. mHorizSizing = horz;
  1048. mVertSizing = vert;
  1049. }
  1050. void GuiControl::setVariable(const char *value)
  1051. {
  1052. if (mConsoleVariable[0])
  1053. Con::setVariable(mConsoleVariable, value);
  1054. }
  1055. void GuiControl::setIntVariable(S32 value)
  1056. {
  1057. if (mConsoleVariable[0])
  1058. Con::setIntVariable(mConsoleVariable, value);
  1059. }
  1060. void GuiControl::setFloatVariable(F32 value)
  1061. {
  1062. if (mConsoleVariable[0])
  1063. Con::setFloatVariable(mConsoleVariable, value);
  1064. }
  1065. const char * GuiControl::getVariable()
  1066. {
  1067. if (mConsoleVariable[0])
  1068. return Con::getVariable(mConsoleVariable);
  1069. else return NULL;
  1070. }
  1071. S32 GuiControl::getIntVariable()
  1072. {
  1073. if (mConsoleVariable[0])
  1074. return Con::getIntVariable(mConsoleVariable);
  1075. else return 0;
  1076. }
  1077. F32 GuiControl::getFloatVariable()
  1078. {
  1079. if (mConsoleVariable[0])
  1080. return Con::getFloatVariable(mConsoleVariable);
  1081. else return 0.0f;
  1082. }
  1083. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  1084. bool GuiControl::cursorInControl()
  1085. {
  1086. GuiCanvas *root = getRoot();
  1087. if (! root) return false;
  1088. Point2I pt = root->getCursorPos();
  1089. Point2I offset = localToGlobalCoord(Point2I(0, 0));
  1090. if (pt.x >= offset.x && pt.y >= offset.y &&
  1091. pt.x < offset.x + mBounds.extent.x && pt.y < offset.y + mBounds.extent.y)
  1092. {
  1093. return true;
  1094. }
  1095. else
  1096. {
  1097. return false;
  1098. }
  1099. }
  1100. bool GuiControl::pointInControl(const Point2I& parentCoordPoint)
  1101. {
  1102. S32 xt = parentCoordPoint.x - mBounds.point.x;
  1103. S32 yt = parentCoordPoint.y - mBounds.point.y;
  1104. return xt >= 0 && yt >= 0 && xt < mBounds.extent.x && yt < mBounds.extent.y;
  1105. }
  1106. GuiControl* GuiControl::findHitControl(const Point2I &pt, S32 initialLayer)
  1107. {
  1108. iterator i = end(); // find in z order (last to first)
  1109. while (i != begin())
  1110. {
  1111. i--;
  1112. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1113. if (initialLayer >= 0 && ctrl->mLayer > initialLayer)
  1114. {
  1115. continue;
  1116. }
  1117. else if (ctrl->mVisible && ctrl->pointInControl(pt - ctrl->mRenderInsetLT) && ctrl->mUseInput)
  1118. {
  1119. Point2I ptemp = pt - (ctrl->mBounds.point + ctrl->mRenderInsetLT);
  1120. GuiControl *hitCtrl = ctrl->findHitControl(ptemp);
  1121. if(hitCtrl->mUseInput)
  1122. return hitCtrl;
  1123. }
  1124. }
  1125. return this;
  1126. }
  1127. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  1128. bool GuiControl::isMouseLocked()
  1129. {
  1130. GuiCanvas *root = getRoot();
  1131. return root ? root->getMouseLockedControl() == this : false;
  1132. }
  1133. void GuiControl::mouseLock(GuiControl *lockingControl)
  1134. {
  1135. GuiCanvas *root = getRoot();
  1136. if (root)
  1137. root->mouseLock(lockingControl);
  1138. }
  1139. void GuiControl::mouseLock()
  1140. {
  1141. GuiCanvas *root = getRoot();
  1142. if (root)
  1143. root->mouseLock(this);
  1144. }
  1145. void GuiControl::mouseUnlock()
  1146. {
  1147. GuiCanvas *root = getRoot();
  1148. if (root)
  1149. root->mouseUnlock(this);
  1150. }
  1151. bool GuiControl::sendScriptMouseEvent(const char* name, const GuiEvent& event)
  1152. {
  1153. bool consumed = false;
  1154. if (isMethod(name))
  1155. {
  1156. char buf[3][32];
  1157. dSprintf(buf[0], 32, "%d", event.modifier);
  1158. dSprintf(buf[1], 32, "%d %d", event.mousePoint.x, event.mousePoint.y);
  1159. dSprintf(buf[2], 32, "%d", event.mouseClickCount);
  1160. consumed = dAtob(Con::executef(this, 4, name, buf[0], buf[1], buf[2]));
  1161. }
  1162. return consumed;
  1163. }
  1164. bool GuiControl::sendScriptKeyEvent(const char* name, const InputEvent& event)
  1165. {
  1166. bool consumed = false;
  1167. if (isMethod(name))
  1168. {
  1169. char buf[2][32];
  1170. dSprintf(buf[0], 32, "%d", event.modifier);
  1171. if (!ActionMap::getKeyString(event.objInst, buf[1]))
  1172. return(false);
  1173. consumed = dAtob(Con::executef(this, 3, name, buf[0], buf[1]));
  1174. }
  1175. return consumed;
  1176. }
  1177. bool GuiControl::onInputEvent(const InputEvent &event)
  1178. {
  1179. if (event.objType == SI_KEY)
  1180. {
  1181. if (event.action == SI_MAKE)
  1182. {
  1183. return sendScriptKeyEvent("onKeyDown", event);
  1184. }
  1185. else if (event.action == SI_BREAK)
  1186. {
  1187. return sendScriptKeyEvent("onKeyUp", event);
  1188. }
  1189. else if (event.action == SI_REPEAT)
  1190. {
  1191. return sendScriptKeyEvent("onKeyRepeat", event);
  1192. }
  1193. }
  1194. return false;
  1195. }
  1196. void GuiControl::onTouchUp(const GuiEvent &event)
  1197. {
  1198. if (!mVisible || !mAwake)
  1199. return;
  1200. bool consumed1 = sendScriptMouseEvent("onTouchUp", event);
  1201. bool consumed2 = sendScriptMouseEvent("onMouseUp", event);
  1202. GuiControl* parent = getParent();
  1203. if (parent && !consumed1 && !consumed2)
  1204. parent->onTouchUp(event);
  1205. }
  1206. void GuiControl::onTouchDown(const GuiEvent &event)
  1207. {
  1208. if (!mVisible || !mAwake)
  1209. return;
  1210. bool consumed1 = sendScriptMouseEvent("onTouchDown", event);
  1211. bool consumed2 = sendScriptMouseEvent("onMouseDown", event);
  1212. GuiControl* parent = getParent();
  1213. if (parent && !consumed1 && !consumed2)
  1214. parent->onTouchDown(event);
  1215. }
  1216. void GuiControl::onTouchMove(const GuiEvent &event)
  1217. {
  1218. if ( !mVisible || !mAwake )
  1219. return;
  1220. bool consumed1 = sendScriptMouseEvent("onTouchMove", event);
  1221. bool consumed2 = sendScriptMouseEvent("onMouseMove", event);
  1222. GuiControl *parent = getParent();
  1223. if (parent && !consumed1 && !consumed2)
  1224. parent->onTouchMove( event );
  1225. }
  1226. void GuiControl::onTouchDragged(const GuiEvent &event)
  1227. {
  1228. if (!mVisible || !mAwake)
  1229. return;
  1230. bool consumed1 = sendScriptMouseEvent("onTouchDragged", event);
  1231. bool consumed2 = sendScriptMouseEvent("onMouseDragged", event);
  1232. GuiControl* parent = getParent();
  1233. if (parent && !consumed1 && !consumed2)
  1234. parent->onTouchDragged(event);
  1235. }
  1236. void GuiControl::onTouchEnter(const GuiEvent &event)
  1237. {
  1238. if (!mVisible || !mAwake)
  1239. return;
  1240. sendScriptMouseEvent("onTouchEnter", event);
  1241. sendScriptMouseEvent("onMouseEnter", event);
  1242. //Entering a child means nothing to a parent
  1243. }
  1244. void GuiControl::onTouchLeave(const GuiEvent &event)
  1245. {
  1246. if (!mVisible || !mAwake)
  1247. return;
  1248. sendScriptMouseEvent("onTouchLeave", event);
  1249. sendScriptMouseEvent("onMouseLeave", event);
  1250. //Leaving a child means nothing to a parent
  1251. }
  1252. void GuiControl::onMouseWheelUp( const GuiEvent &event )
  1253. {
  1254. if ( !mVisible || !mAwake )
  1255. return;
  1256. bool consumed = sendScriptMouseEvent("onMouseWheelUp", event);
  1257. GuiControl *parent = getParent();
  1258. if (parent && !consumed)
  1259. return parent->onMouseWheelUp(event);
  1260. }
  1261. void GuiControl::onMouseWheelDown( const GuiEvent &event )
  1262. {
  1263. if ( !mVisible || !mAwake )
  1264. return;
  1265. bool consumed = sendScriptMouseEvent("onMouseWheelDown", event);
  1266. GuiControl *parent = getParent();
  1267. if (parent && !consumed)
  1268. return parent->onMouseWheelDown(event);
  1269. }
  1270. void GuiControl::onRightMouseDown(const GuiEvent &event)
  1271. {
  1272. if (!mVisible || !mAwake)
  1273. return;
  1274. bool consumed = sendScriptMouseEvent("onRightMouseDown", event);
  1275. GuiControl* parent = getParent();
  1276. if (parent && !consumed)
  1277. parent->onRightMouseDown(event);
  1278. }
  1279. void GuiControl::onRightMouseUp(const GuiEvent &event)
  1280. {
  1281. if (!mVisible || !mAwake)
  1282. return;
  1283. bool consumed = sendScriptMouseEvent("onRightMouseUp", event);
  1284. GuiControl* parent = getParent();
  1285. if (parent && !consumed)
  1286. parent->onRightMouseUp(event);
  1287. }
  1288. void GuiControl::onRightMouseDragged(const GuiEvent &event)
  1289. {
  1290. if (!mVisible || !mAwake)
  1291. return;
  1292. bool consumed = sendScriptMouseEvent("onRightMouseDragged", event);
  1293. GuiControl* parent = getParent();
  1294. if (parent && !consumed)
  1295. parent->onRightMouseDragged(event);
  1296. }
  1297. void GuiControl::onMiddleMouseDown(const GuiEvent &event)
  1298. {
  1299. if (!mVisible || !mAwake)
  1300. return;
  1301. bool consumed = sendScriptMouseEvent("onMiddleMouseDown", event);
  1302. GuiControl* parent = getParent();
  1303. if (parent && !consumed)
  1304. parent->onMiddleMouseDown(event);
  1305. }
  1306. void GuiControl::onMiddleMouseUp(const GuiEvent &event)
  1307. {
  1308. if (!mVisible || !mAwake)
  1309. return;
  1310. bool consumed = sendScriptMouseEvent("onMiddleMouseUp", event);
  1311. GuiControl* parent = getParent();
  1312. if (parent && !consumed)
  1313. parent->onMiddleMouseUp(event);
  1314. }
  1315. void GuiControl::onMiddleMouseDragged(const GuiEvent &event)
  1316. {
  1317. if (!mVisible || !mAwake)
  1318. return;
  1319. bool consumed = sendScriptMouseEvent("onMiddleMouseDragged", event);
  1320. GuiControl* parent = getParent();
  1321. if (parent && !consumed)
  1322. parent->onMiddleMouseDragged(event);
  1323. }
  1324. GuiControl* GuiControl::findFirstTabable()
  1325. {
  1326. GuiControl *tabCtrl = NULL;
  1327. iterator i;
  1328. for (i = begin(); i != end(); i++)
  1329. {
  1330. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1331. tabCtrl = ctrl->findFirstTabable();
  1332. if (tabCtrl)
  1333. {
  1334. mFirstResponder = tabCtrl;
  1335. return tabCtrl;
  1336. }
  1337. }
  1338. //nothing was found, therefore, see if this ctrl is tabable
  1339. return ( mProfile != NULL ) ? ( ( mProfile->mTabable && mAwake && mVisible ) ? this : NULL ) : NULL;
  1340. }
  1341. GuiControl* GuiControl::findLastTabable(bool firstCall)
  1342. {
  1343. //if this is the first call, clear the global
  1344. if (firstCall)
  1345. smPrevResponder = NULL;
  1346. //if this control is tabable, set the global
  1347. if (mProfile->mTabable)
  1348. smPrevResponder = this;
  1349. iterator i;
  1350. for (i = begin(); i != end(); i++)
  1351. {
  1352. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1353. ctrl->findLastTabable(false);
  1354. }
  1355. //after the entire tree has been traversed, return the last responder found
  1356. mFirstResponder = smPrevResponder;
  1357. return smPrevResponder;
  1358. }
  1359. GuiControl *GuiControl::findNextTabable(GuiControl *curResponder, bool firstCall)
  1360. {
  1361. //if this is the first call, clear the global
  1362. if (firstCall)
  1363. smCurResponder = NULL;
  1364. //first find the current responder
  1365. if (curResponder == this)
  1366. smCurResponder = this;
  1367. //if the first responder has been found, return the very next *tabable* control
  1368. else if ( smCurResponder && mProfile->mTabable && mAwake && mVisible && mActive )
  1369. return( this );
  1370. //loop through, checking each child to see if it is the one that follows the firstResponder
  1371. GuiControl *tabCtrl = NULL;
  1372. iterator i;
  1373. for (i = begin(); i != end(); i++)
  1374. {
  1375. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1376. tabCtrl = ctrl->findNextTabable(curResponder, false);
  1377. if (tabCtrl) break;
  1378. }
  1379. mFirstResponder = tabCtrl;
  1380. return tabCtrl;
  1381. }
  1382. GuiControl *GuiControl::findPrevTabable(GuiControl *curResponder, bool firstCall)
  1383. {
  1384. if (firstCall)
  1385. smPrevResponder = NULL;
  1386. //if this is the current reponder, return the previous one
  1387. if (curResponder == this)
  1388. return smPrevResponder;
  1389. //else if this is a responder, store it in case the next found is the current responder
  1390. else if ( mProfile->mTabable && mAwake && mVisible && mActive )
  1391. smPrevResponder = this;
  1392. //loop through, checking each child to see if it is the one that follows the firstResponder
  1393. GuiControl *tabCtrl = NULL;
  1394. iterator i;
  1395. for (i = begin(); i != end(); i++)
  1396. {
  1397. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1398. tabCtrl = ctrl->findPrevTabable(curResponder, false);
  1399. if (tabCtrl) break;
  1400. }
  1401. mFirstResponder = tabCtrl;
  1402. return tabCtrl;
  1403. }
  1404. void GuiControl::onLoseFirstResponder()
  1405. {
  1406. // Since many controls have visual cues when they are the firstResponder...
  1407. setUpdate();
  1408. if (isMethod("onLoseFirstResponder"))
  1409. {
  1410. Con::executef(this, 2, "onLoseFirstResponder");
  1411. }
  1412. else if (isMethod("onBlur"))
  1413. {
  1414. Con::executef(this, 2, "onBlur");
  1415. }
  1416. }
  1417. bool GuiControl::ControlIsChild(GuiControl *child)
  1418. {
  1419. //function returns true if this control, or one of it's children is the child control
  1420. if (child == this)
  1421. return true;
  1422. //loop through, checking each child to see if it is ,or contains, the firstResponder
  1423. iterator i;
  1424. for (i = begin(); i != end(); i++)
  1425. {
  1426. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1427. if (ctrl->ControlIsChild(child)) return true;
  1428. }
  1429. //not found, therefore false
  1430. return false;
  1431. }
  1432. void GuiControl::onFocus()
  1433. {
  1434. //bubble the focus up
  1435. GuiControl *parent = getParent();
  1436. if (parent)
  1437. parent->onFocus();
  1438. }
  1439. bool GuiControl::isFirstResponder()
  1440. {
  1441. GuiCanvas *root = getRoot();
  1442. return root && root->getFirstResponder() == this;
  1443. }
  1444. void GuiControl::setFirstResponder( GuiControl* firstResponder )
  1445. {
  1446. if ( firstResponder && firstResponder->mProfile->mCanKeyFocus )
  1447. mFirstResponder = firstResponder;
  1448. GuiControl *parent = getParent();
  1449. if ( parent )
  1450. parent->setFirstResponder( firstResponder );
  1451. }
  1452. void GuiControl::setFirstResponder()
  1453. {
  1454. if ( mAwake && mVisible )
  1455. {
  1456. GuiControl *parent = getParent();
  1457. if (mProfile->mCanKeyFocus == true && parent != NULL )
  1458. {
  1459. parent->setFirstResponder(this);
  1460. // Since many controls have visual cues when they are the firstResponder...
  1461. this->setUpdate();
  1462. if (isMethod("onGainFirstResponder"))
  1463. {
  1464. Con::executef(this, 2, "onGainFirstResponder");
  1465. }
  1466. else if (isMethod("onFocus"))
  1467. {
  1468. Con::executef(this, 2, "onFocus");
  1469. }
  1470. }
  1471. }
  1472. }
  1473. void GuiControl::clearFirstResponder()
  1474. {
  1475. GuiControl *parent = this;
  1476. while((parent = parent->getParent()) != NULL)
  1477. {
  1478. if(parent->mFirstResponder == this)
  1479. parent->mFirstResponder = NULL;
  1480. else
  1481. break;
  1482. }
  1483. }
  1484. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  1485. void GuiControl::buildAcceleratorMap()
  1486. {
  1487. //add my own accel key
  1488. addAcceleratorKey();
  1489. //add all my childrens keys
  1490. iterator i;
  1491. for(i = begin(); i != end(); i++)
  1492. {
  1493. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1494. ctrl->buildAcceleratorMap();
  1495. }
  1496. }
  1497. void GuiControl::addAcceleratorKey()
  1498. {
  1499. //see if we have an accelerator
  1500. if (mAcceleratorKey == StringTable->EmptyString)
  1501. return;
  1502. EventDescriptor accelEvent;
  1503. ActionMap::createEventDescriptor(mAcceleratorKey, &accelEvent);
  1504. //now we have a modifier, and a key, add them to the canvas
  1505. GuiCanvas *root = getRoot();
  1506. if (root)
  1507. root->addAcceleratorKey(this, 0, accelEvent.eventCode, accelEvent.flags);
  1508. }
  1509. void GuiControl::acceleratorKeyPress(U32 index)
  1510. {
  1511. onAction();
  1512. }
  1513. void GuiControl::acceleratorKeyRelease(U32 index)
  1514. {
  1515. //do nothing
  1516. }
  1517. bool GuiControl::onKeyDown(const GuiEvent &event)
  1518. {
  1519. //pass the event to the parent
  1520. GuiControl *parent = getParent();
  1521. if (parent)
  1522. return parent->onKeyDown(event);
  1523. else
  1524. return false;
  1525. }
  1526. bool GuiControl::onKeyRepeat(const GuiEvent &event)
  1527. {
  1528. // default to just another key down.
  1529. return onKeyDown(event);
  1530. }
  1531. bool GuiControl::onKeyUp(const GuiEvent &event)
  1532. {
  1533. //pass the event to the parent
  1534. GuiControl *parent = getParent();
  1535. if (parent)
  1536. return parent->onKeyUp(event);
  1537. else
  1538. return false;
  1539. }
  1540. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  1541. void GuiControl::onAction()
  1542. {
  1543. if (! mActive)
  1544. return;
  1545. //execute the console command
  1546. if (mConsoleCommand && mConsoleCommand[0])
  1547. {
  1548. execConsoleCallback();
  1549. }
  1550. else
  1551. Con::executef(this, 1, "onAction");
  1552. }
  1553. void GuiControl::onMessage(GuiControl *sender, S32 msg)
  1554. {
  1555. }
  1556. void GuiControl::messageSiblings(S32 message)
  1557. {
  1558. GuiControl *parent = getParent();
  1559. if (! parent) return;
  1560. GuiControl::iterator i;
  1561. for(i = parent->begin(); i != parent->end(); i++)
  1562. {
  1563. GuiControl *ctrl = dynamic_cast<GuiControl *>(*i);
  1564. if (ctrl != this)
  1565. ctrl->onMessage(this, message);
  1566. }
  1567. }
  1568. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
  1569. void GuiControl::onDialogPush()
  1570. {
  1571. // Notify Script.
  1572. if( isMethod("onDialogPush") )
  1573. Con::executef(this, 1, "onDialogPush");
  1574. }
  1575. void GuiControl::onDialogPop()
  1576. {
  1577. // Notify Script.
  1578. if( isMethod("onDialogPop") )
  1579. Con::executef(this, 1, "onDialogPop");
  1580. }
  1581. //------------------------------------------------------------------------------
  1582. void GuiControl::setVisible(bool value)
  1583. {
  1584. mVisible = value;
  1585. iterator i;
  1586. setUpdate();
  1587. for(i = begin(); i != end(); i++)
  1588. {
  1589. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1590. ctrl->clearFirstResponder();
  1591. }
  1592. GuiControl *parent = getParent();
  1593. if (parent)
  1594. parent->childResized(this);
  1595. }
  1596. void GuiControl::makeFirstResponder(bool value)
  1597. {
  1598. if ( value )
  1599. //setFirstResponder(this);
  1600. setFirstResponder();
  1601. else
  1602. clearFirstResponder();
  1603. }
  1604. void GuiControl::setActive( bool value )
  1605. {
  1606. mActive = value;
  1607. if (value && isMethod("onActive"))
  1608. Con::executef(this, 1, "onActive");
  1609. else if (!value && isMethod("onInactive"))
  1610. Con::executef(this, 1, "onInactive");
  1611. if ( !mActive )
  1612. clearFirstResponder();
  1613. if ( mVisible && mAwake )
  1614. setUpdate();
  1615. }
  1616. void GuiControl::getScrollLineSizes(U32 *rowHeight, U32 *columnWidth)
  1617. {
  1618. // default to 10 pixels in y, 30 pixels in x
  1619. *columnWidth = 30;
  1620. *rowHeight = 30;
  1621. }
  1622. void GuiControl::renderText(const Point2I& offset, const Point2I& extent, const char* text, GuiControlProfile* profile, TextRotationOptions rot)
  1623. {
  1624. RectI old = dglGetClipRect();
  1625. RectI clipRect = RectI(offset, extent);
  1626. if (clipRect.intersect(old))
  1627. {
  1628. dglSetClipRect(clipRect);
  1629. const S32 textHeight = profile->getFont(mFontSizeAdjust)->getHeight();
  1630. S32 totalWidth = (rot == tRotateNone) ? extent.x : extent.y;
  1631. S32 totalHeight = (rot == tRotateNone) ? extent.y : extent.x;
  1632. S32 startOffsetY = 0;
  1633. vector<string> lineList = getLineList(text, profile, totalWidth);
  1634. //first align vertical
  1635. S32 blockHeight = textHeight * lineList.size();
  1636. if (mTextExtend)
  1637. {
  1638. Point2I extent = getExtent();
  1639. if (mTextWrap)
  1640. {
  1641. extent.y = getOuterHeight(blockHeight, NormalState, profile);
  1642. }
  1643. else
  1644. {
  1645. extent.x = getOuterWidth(profile->getFont(mFontSizeAdjust)->getStrWidth(text), NormalState, profile);
  1646. }
  1647. setExtent(extent);
  1648. }
  1649. if (blockHeight < totalHeight)
  1650. {
  1651. startOffsetY = getTextVerticalOffset(blockHeight, totalHeight, getVertAlignmentType(profile));
  1652. }
  1653. else if (!mTextWrap)
  1654. {
  1655. startOffsetY = getTextVerticalOffset(blockHeight, totalHeight, VertAlignmentType::MiddleVAlign);
  1656. }
  1657. else
  1658. {
  1659. startOffsetY = getTextVerticalOffset(blockHeight, totalHeight, VertAlignmentType::TopVAlign);
  1660. }
  1661. renderLineList(offset, extent, startOffsetY, lineList, profile, rot);
  1662. dglSetClipRect(old);
  1663. }
  1664. }
  1665. void GuiControl::renderLineList(const Point2I& offset, const Point2I& extent, const S32 startOffsetY, const vector<string> lineList, GuiControlProfile* profile, const TextRotationOptions rot)
  1666. {
  1667. const S32 textHeight = profile->getFont(mFontSizeAdjust)->getHeight();
  1668. S32 totalWidth = (rot == tRotateNone) ? extent.x : extent.y;
  1669. //Now print each line
  1670. U32 ibeamPos = 0;
  1671. U32 lineNumber = 0;
  1672. S32 offsetX = 0;
  1673. S32 offsetY = startOffsetY;
  1674. for(string line : lineList)
  1675. {
  1676. // align the horizontal
  1677. string trimmedLine = Utility::trim_copy(line);
  1678. U32 textWidth = profile->getFont(mFontSizeAdjust)->getStrWidth(trimmedLine.c_str());
  1679. if(textWidth < totalWidth)
  1680. {
  1681. offsetX = getTextHorizontalOffset(textWidth, totalWidth, getAlignmentType(profile));
  1682. }
  1683. Point2I start = Point2I(0, 0);
  1684. F32 rotation;
  1685. if (rot == tRotateNone)
  1686. {
  1687. start.x += offsetX;
  1688. start.y += offsetY;
  1689. rotation = 0.0f;
  1690. }
  1691. else if (rot == tRotateLeft)
  1692. {
  1693. start.x = offsetY;
  1694. start.y = extent.y + offsetX;
  1695. rotation = 90.0f;
  1696. }
  1697. else if (rot == tRotateRight)
  1698. {
  1699. start.x = extent.x - offsetY;
  1700. start.y = offsetX;
  1701. rotation = -90.0f;
  1702. }
  1703. renderTextLine(start + offset + profile->mTextOffset, trimmedLine, profile, rotation, ibeamPos, lineNumber);
  1704. offsetY += textHeight;
  1705. ibeamPos += line.length();
  1706. lineNumber++;
  1707. }
  1708. }
  1709. vector<string> GuiControl::getLineList(const char* text, GuiControlProfile* profile, S32 totalWidth)
  1710. {
  1711. GFont* font = profile->getFont(mFontSizeAdjust);
  1712. vector<string> lineList = vector<string>();
  1713. if (!mTextWrap)
  1714. {
  1715. lineList.push_back(text);
  1716. }
  1717. else
  1718. {
  1719. vector<string> paragraphList = vector<string>();
  1720. istringstream f(text);
  1721. string s;
  1722. while (getline(f, s)) {
  1723. paragraphList.push_back(s);
  1724. }
  1725. for (string& paragraph : paragraphList)
  1726. {
  1727. vector<string> wordList = vector<string>();
  1728. istringstream f2(paragraph);
  1729. string s2;
  1730. while (getline(f2, s2, ' ')) {
  1731. wordList.push_back(s2);
  1732. }
  1733. //now process the word list
  1734. string line;
  1735. bool newLine = true;
  1736. line.clear();
  1737. for (string& word : wordList)
  1738. {
  1739. if (font->getStrWidth(word.c_str()) >= totalWidth)
  1740. {
  1741. if (line.size() > 0)
  1742. {
  1743. lineList.push_back(string(line + " "));
  1744. line.clear();
  1745. }
  1746. lineList.push_back(word + " ");
  1747. newLine = true;
  1748. continue;
  1749. }
  1750. string prevLine = string(line);
  1751. line += (!newLine) ? " " + word : word;
  1752. newLine = false;
  1753. if (font->getStrWidth(line.c_str()) >= totalWidth && word.length() != 0)
  1754. {
  1755. lineList.push_back(prevLine + " ");
  1756. line = word;
  1757. }
  1758. }
  1759. if (paragraph.back() == ' ')
  1760. {
  1761. line += " ";
  1762. }
  1763. lineList.push_back(string(line));
  1764. }
  1765. }
  1766. return lineList;
  1767. }
  1768. void GuiControl::renderTextLine(const Point2I& startPoint, const string line, GuiControlProfile* profile, F32 rotationInDegrees, U32, U32)
  1769. {
  1770. dglDrawText(profile->getFont(mFontSizeAdjust), startPoint, line.c_str(), profile->mFontColors, 9, rotationInDegrees);
  1771. }
  1772. S32 GuiControl::getTextHorizontalOffset(S32 textWidth, S32 totalWidth, AlignmentType align)
  1773. {
  1774. if (align == RightAlign)
  1775. {
  1776. return totalWidth - textWidth;
  1777. }
  1778. else if (align == CenterAlign)
  1779. {
  1780. return (totalWidth - textWidth) / 2;
  1781. }
  1782. return 0;//left aligned
  1783. }
  1784. S32 GuiControl::getTextVerticalOffset(S32 textHeight, S32 totalHeight, VertAlignmentType align)
  1785. {
  1786. if (align == MiddleVAlign)
  1787. {
  1788. return (totalHeight - textHeight) / 2;
  1789. }
  1790. else if (align == BottomVAlign)
  1791. {
  1792. return totalHeight - textHeight;
  1793. }
  1794. return 0;
  1795. }
  1796. void GuiControl::getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent)
  1797. {
  1798. lastGuiEvent;
  1799. if(GuiControl::smCursorChanged != -1 && !isMouseLocked())
  1800. {
  1801. // We've already changed the cursor,
  1802. // so set it back before we change it again.
  1803. Input::popCursor();
  1804. // We haven't changed it
  1805. GuiControl::smCursorChanged = -1;
  1806. }
  1807. }
  1808. const char* GuiControl::execConsoleCallback()
  1809. {
  1810. if (mConsoleCommand && mConsoleCommand[0])
  1811. {
  1812. Con::setVariable("$ThisControl", avar("%d",getId()));
  1813. return Con::evaluate(mConsoleCommand, false);
  1814. }
  1815. return "";
  1816. }
  1817. const char* GuiControl::execAltConsoleCallback()
  1818. {
  1819. if(mAltConsoleCommand && mAltConsoleCommand[0])
  1820. {
  1821. Con::setVariable("$ThisControl", avar("%d",getId()));
  1822. return Con::evaluate(mAltConsoleCommand, false);
  1823. }
  1824. return "";
  1825. }
  1826. void GuiControl::setText(const char *text)
  1827. {
  1828. mText = StringTable->insert(text, true);
  1829. }
  1830. void GuiControl::setTextID(const char *id)
  1831. {
  1832. S32 n = Con::getIntVariable(id, -1);
  1833. if (n != -1)
  1834. {
  1835. mTextID = StringTable->insert(id);
  1836. setTextID(n);
  1837. }
  1838. }
  1839. void GuiControl::setTextID(S32 id)
  1840. {
  1841. const UTF8 *str = getGUIString(id);
  1842. if (str)
  1843. setText((const char*)str);
  1844. }
  1845. const char *GuiControl::getText()
  1846. {
  1847. return mText;
  1848. }
  1849. AlignmentType GuiControl::getAlignmentType()
  1850. {
  1851. return getAlignmentType(mProfile);
  1852. }
  1853. AlignmentType GuiControl::getAlignmentType(GuiControlProfile* profile)
  1854. {
  1855. return mAlignment == AlignmentType::DefaultAlign ? profile->mAlignment : mAlignment;
  1856. }
  1857. VertAlignmentType GuiControl::getVertAlignmentType()
  1858. {
  1859. return getVertAlignmentType(mProfile);
  1860. }
  1861. VertAlignmentType GuiControl::getVertAlignmentType(GuiControlProfile* profile)
  1862. {
  1863. return mVAlignment == VertAlignmentType::DefaultVAlign ? profile->mVAlignment : mVAlignment;
  1864. }
  1865. const ColorI& GuiControl::getFontColor(GuiControlProfile* profile, const GuiControlState state)
  1866. {
  1867. return mOverrideFontColor ? mFontColor : profile->getFontColor(state);
  1868. }