guiControl.cpp 91 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 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. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  23. // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
  24. // Copyright (C) 2015 Faust Logic, Inc.
  25. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  26. #include "platform/platform.h"
  27. #include "gui/core/guiControl.h"
  28. #include "console/consoleTypes.h"
  29. #include "console/console.h"
  30. #include "console/consoleInternal.h"
  31. #include "console/engineAPI.h"
  32. #include "console/codeBlock.h"
  33. #include "gfx/bitmap/gBitmap.h"
  34. #include "sim/actionMap.h"
  35. #include "gui/core/guiCanvas.h"
  36. #include "gui/core/guiDefaultControlRender.h"
  37. #include "gui/editor/guiEditCtrl.h"
  38. #include "gfx/gfxDrawUtil.h"
  39. //#define DEBUG_SPEW
  40. IMPLEMENT_CONOBJECT_CHILDREN( GuiControl );
  41. ConsoleDocClass( GuiControl,
  42. "@brief Base class for all Gui control objects.\n\n"
  43. "GuiControl is the basis for the Gui system. It represents an individual control that can be placed on the canvas and with which "
  44. "the mouse and keyboard can potentially interact with.\n\n"
  45. "@section GuiControl_Hierarchy Control Hierarchies\n"
  46. "GuiControls are arranged in a hierarchy. All children of a control are placed in their parent's coordinate space, i.e. their "
  47. "coordinates are relative to the upper left corner of their immediate parent. When a control is moved, all its child controls "
  48. "are moved along with it.\n\n"
  49. "Since GuiControl's are SimGroups, hierarchy also implies ownership. This means that if a control is destroyed, all its children "
  50. "are destroyed along with it. It also means that a given control can only be part of a single GuiControl hierarchy. When adding a "
  51. "control to another control, it will automatically be reparented from another control it may have previously been parented to.\n\n"
  52. "@section GuiControl_Layout Layout System\n"
  53. "GuiControls have a two-dimensional position and are rectangular in shape.\n\n"
  54. "@section GuiControl_Events Event System\n"
  55. "@section GuiControl_Profiles Control Profiles\n"
  56. "Common data accessed by GuiControls is stored in so-called \"Control Profiles.\" This includes font, color, and texture information. "
  57. "By pooling this data in shared objects, the appearance of any number of controls can be changed quickly and easily by modifying "
  58. "only the shared profile object.\n\n"
  59. "If not explicitly assigned a profile, a control will by default look for a profile object that matches its class name. This means "
  60. "that the class GuiMyCtrl, for example, will look for a profile called 'GuiMyProfile'. If this profile cannot be found, the control "
  61. "will fall back to GuiDefaultProfile which must be defined in any case for the Gui system to work.\n\n"
  62. "In addition to its primary profile, a control may be assigned a second profile called 'tooltipProfile' that will be used to render "
  63. "tooltip popups for the control.\n\n"
  64. "@section GuiControl_Actions Triggered Actions\n"
  65. "@section GuiControl_FirstResponders First Responders\n"
  66. "At any time, a single control can be what is called the \"first responder\" on the GuiCanvas is placed on. This control "
  67. "will be the first control to receive keyboard events not bound in the global ActionMap. If the first responder choses to "
  68. "handle a particular keyboard event, \n\n"
  69. "@section GuiControl_Waking Waking and Sleeping\n"
  70. "@section GuiControl_VisibleActive Visibility and Activeness\n"
  71. "By default, a GuiControl is active which means that it\n\n"
  72. "@see GuiCanvas\n"
  73. "@see GuiControlProfile\n"
  74. "@ingroup GuiCore\n"
  75. );
  76. IMPLEMENT_CALLBACK( GuiControl, onAdd, void, (), (),
  77. "Called when the control object is registered with the system after the control has been created." );
  78. IMPLEMENT_CALLBACK( GuiControl, onRemove, void, (), (),
  79. "Called when the control object is removed from the system before it is deleted." );
  80. IMPLEMENT_CALLBACK( GuiControl, onWake, void, (), (),
  81. "Called when the control is woken up.\n"
  82. "@ref GuiControl_Waking" );
  83. IMPLEMENT_CALLBACK( GuiControl, onSleep, void, (), (),
  84. "Called when the control is put to sleep.\n"
  85. "@ref GuiControl_Waking" );
  86. IMPLEMENT_CALLBACK( GuiControl, onGainFirstResponder, void, (), (),
  87. "Called when the control gains first responder status on the GuiCanvas.\n"
  88. "@see setFirstResponder\n"
  89. "@see makeFirstResponder\n"
  90. "@see isFirstResponder\n"
  91. "@ref GuiControl_FirstResponders" );
  92. IMPLEMENT_CALLBACK( GuiControl, onLoseFirstResponder, void, (), (),
  93. "Called when the control loses first responder status on the GuiCanvas.\n"
  94. "@see setFirstResponder\n"
  95. "@see makeFirstResponder\n"
  96. "@see isFirstResponder\n"
  97. "@ref GuiControl_FirstResponders" );
  98. IMPLEMENT_CALLBACK( GuiControl, onAction, void, (), (),
  99. "Called when the control's associated action is triggered and no 'command' is defined for the control.\n"
  100. "@ref GuiControl_Actions" );
  101. IMPLEMENT_CALLBACK( GuiControl, onVisible, void, ( bool state ), ( state ),
  102. "Called when the control changes its visibility state, i.e. when going from visible to invisible or vice versa.\n"
  103. "@param state The new visibility state.\n"
  104. "@see isVisible\n"
  105. "@see setVisible\n"
  106. "@ref GuiControl_VisibleActive" );
  107. IMPLEMENT_CALLBACK( GuiControl, onActive, void, ( bool state ), ( state ),
  108. "Called when the control changes its activeness state, i.e. when going from active to inactive or vice versa.\n"
  109. "@param stat The new activeness state.\n"
  110. "@see isActive\n"
  111. "@see setActive\n"
  112. "@ref GuiControl_VisibleActive" );
  113. IMPLEMENT_CALLBACK( GuiControl, onDialogPush, void, (), (),
  114. "Called when the control is pushed as a dialog onto the canvas.\n"
  115. "@see GuiCanvas::pushDialog" );
  116. IMPLEMENT_CALLBACK( GuiControl, onDialogPop, void, (), (),
  117. "Called when the control is removed as a dialog from the canvas.\n"
  118. "@see GuiCanvas::popDialog" );
  119. IMPLEMENT_CALLBACK( GuiControl, onControlDragEnter, void, ( GuiControl* control, const Point2I& dropPoint ), ( control, dropPoint ),
  120. "Called when a drag&drop operation through GuiDragAndDropControl has entered the control. This is only called for "
  121. "topmost visible controls as the GuiDragAndDropControl moves over them.\n\n"
  122. "@param control The payload of the drag operation.\n"
  123. "@param dropPoint The point at which the payload would be dropped if it were released now. Relative to the canvas." );
  124. IMPLEMENT_CALLBACK( GuiControl, onControlDragExit, void, ( GuiControl* control, const Point2I& dropPoint ), ( control, dropPoint ),
  125. "Called when a drag&drop operation through GuiDragAndDropControl has exited the control and moved over a different control. This is only called for "
  126. "topmost visible controls as the GuiDragAndDropControl moves off of them.\n\n"
  127. "@param control The payload of the drag operation.\n"
  128. "@param dropPoint The point at which the payload would be dropped if it were released now. Relative to the canvas." );
  129. IMPLEMENT_CALLBACK( GuiControl, onControlDragged, void, ( GuiControl* control, const Point2I& dropPoint ), ( control, dropPoint ),
  130. "Called when a drag&drop operation through GuiDragAndDropControl is moving across the control after it has entered it. This is only called for "
  131. "topmost visible controls as the GuiDragAndDropControl moves across them.\n\n"
  132. "@param control The payload of the drag operation.\n"
  133. "@param dropPoint The point at which the payload would be dropped if it were released now. Relative to the canvas." );
  134. IMPLEMENT_CALLBACK( GuiControl, onControlDropped, void, ( GuiControl* control, const Point2I& dropPoint ), ( control, dropPoint ),
  135. "Called when a drag&drop operation through GuiDragAndDropControl has completed and is dropping its payload onto the control. "
  136. "This is only called for topmost visible controls as the GuiDragAndDropControl drops its payload on them.\n\n"
  137. "@param control The control that is being dropped onto this control.\n"
  138. "@param dropPoint The point at which the control is being dropped. Relative to the canvas." );
  139. GuiControl *GuiControl::smPrevResponder = NULL;
  140. GuiControl *GuiControl::smCurResponder = NULL;
  141. GuiEditCtrl*GuiControl::smEditorHandle = NULL;
  142. bool GuiControl::smDesignTime = false;
  143. GuiControl* GuiControl::smThisControl;
  144. IMPLEMENT_SCOPE( GuiAPI, Gui,, "" );
  145. ImplementEnumType( GuiHorizontalSizing,
  146. "Horizontal sizing behavior of a GuiControl.\n\n"
  147. "@ingroup GuiCore" )
  148. { GuiControl::horizResizeRight, "right" },
  149. { GuiControl::horizResizeWidth, "width" },
  150. { GuiControl::horizResizeLeft, "left" },
  151. { GuiControl::horizResizeCenter, "center" },
  152. { GuiControl::horizResizeRelative, "relative" },
  153. { GuiControl::horizResizeAspectLeft, "aspectLeft" },
  154. { GuiControl::horizResizeAspectRight, "aspectRight" },
  155. { GuiControl::horizResizeAspectCenter, "aspectCenter" },
  156. { GuiControl::horizResizeWindowRelative, "windowRelative" }
  157. EndImplementEnumType;
  158. ImplementEnumType( GuiVerticalSizing,
  159. "Vertical sizing behavior of a GuiControl.\n\n"
  160. "@ingroup GuiCore" )
  161. { GuiControl::vertResizeBottom, "bottom" },
  162. { GuiControl::vertResizeHeight, "height" },
  163. { GuiControl::vertResizeTop, "top" },
  164. { GuiControl::vertResizeCenter, "center" },
  165. { GuiControl::vertResizeRelative, "relative" },
  166. { GuiControl::vertResizeAspectTop, "aspectTop" },
  167. { GuiControl::vertResizeAspectBottom, "aspectBottom" },
  168. { GuiControl::vertResizeAspectCenter, "aspectCenter" },
  169. { GuiControl::vertResizeWindowRelative, "windowRelative" }
  170. EndImplementEnumType;
  171. //-----------------------------------------------------------------------------
  172. GuiControl::GuiControl() : mAddGroup( NULL ),
  173. mBounds(0,0,64,64),
  174. mProfile(NULL),
  175. mTooltipProfile(NULL),
  176. mTipHoverTime(1000),
  177. mVisible(true),
  178. mActive(true),
  179. mAwake(false),
  180. mIsContainer(false),
  181. mCanResize(true),
  182. mCanHit( true ),
  183. mLayer(0),
  184. mMinExtent(8,2),
  185. mLangTable(NULL),
  186. mFirstResponder(NULL),
  187. mHorizSizing(horizResizeRight),
  188. mVertSizing(vertResizeBottom)
  189. {
  190. mConsoleVariable = StringTable->EmptyString();
  191. mAcceleratorKey = StringTable->EmptyString();
  192. mLangTableName = StringTable->EmptyString();
  193. mTooltip = StringTable->EmptyString();
  194. mRenderTooltipDelegate.bind( this, &GuiControl::defaultTooltipRender );
  195. mCanSaveFieldDictionary = false;
  196. mNotifyChildrenResized = true;
  197. fade_amt = 1.0f;
  198. }
  199. //-----------------------------------------------------------------------------
  200. GuiControl::~GuiControl()
  201. {
  202. }
  203. //-----------------------------------------------------------------------------
  204. void GuiControl::consoleInit()
  205. {
  206. Con::addVariable( "$ThisControl", TYPEID< GuiControl >(), &smThisControl,
  207. "The control for which a command is currently being evaluated. Only set during 'command' "
  208. "and altCommand callbacks to the control for which the command or altCommand is invoked.\n"
  209. "@ingroup GuiCore");
  210. }
  211. //-----------------------------------------------------------------------------
  212. void GuiControl::initPersistFields()
  213. {
  214. addGroup( "Layout" );
  215. addField("position", TypePoint2I, Offset(mBounds.point, GuiControl),
  216. "The position relative to the parent control." );
  217. addField("extent", TypePoint2I, Offset(mBounds.extent, GuiControl),
  218. "The width and height of the control." );
  219. addField("minExtent", TypePoint2I, Offset(mMinExtent, GuiControl),
  220. "The minimum width and height of the control. The control will not be resized smaller than this." );
  221. addField("horizSizing", TYPEID< horizSizingOptions >(), Offset(mHorizSizing, GuiControl),
  222. "The horizontal resizing behavior." );
  223. addField("vertSizing", TYPEID< vertSizingOptions >(), Offset(mVertSizing, GuiControl),
  224. "The vertical resizing behavior." );
  225. endGroup( "Layout" );
  226. addGroup( "Control");
  227. addProtectedField("profile", TYPEID< GuiControlProfile >(), Offset(mProfile, GuiControl), &setProfileProt, &defaultProtectedGetFn,
  228. "The control profile that determines fill styles, font settings, etc." );
  229. addProtectedField( "visible", TypeBool, Offset(mVisible, GuiControl), &_setVisible, &defaultProtectedGetFn,
  230. "Whether the control is visible or hidden." );
  231. addProtectedField( "active", TypeBool, Offset( mActive, GuiControl ), &_setActive, &defaultProtectedGetFn,
  232. "Whether the control is enabled for user interaction." );
  233. addDeprecatedField("modal");
  234. addDeprecatedField("setFirstResponder");
  235. addField("variable", TypeString, Offset(mConsoleVariable, GuiControl),
  236. "Name of the variable to which the value of this control will be synchronized." );
  237. addField("command", TypeCommand, Offset(mConsoleCommand, GuiControl),
  238. "Command to execute on the primary action of the control.\n\n"
  239. "@note Within this script snippet, the control on which the #command is being executed is bound to "
  240. "the global variable $ThisControl." );
  241. addField("altCommand", TypeCommand, Offset(mAltConsoleCommand, GuiControl),
  242. "Command to execute on the secondary action of the control.\n\n"
  243. "@note Within this script snippet, the control on which the #altCommand is being executed is bound to "
  244. "the global variable $ThisControl." );
  245. addField("accelerator", TypeString, Offset(mAcceleratorKey, GuiControl),
  246. "Key combination that triggers the control's primary action when the control is on the canvas." );
  247. endGroup( "Control" );
  248. addGroup( "ToolTip" );
  249. addProtectedField("tooltipProfile", TYPEID< GuiControlProfile >(), Offset(mTooltipProfile, GuiControl), &setTooltipProfileProt, &defaultProtectedGetFn,
  250. "Control profile to use when rendering tooltips for this control." );
  251. addField("tooltip", TypeRealString, Offset(mTooltip, GuiControl),
  252. "String to show in tooltip for this control." );
  253. addField("hovertime", TypeS32, Offset(mTipHoverTime, GuiControl),
  254. "Time for mouse to hover over control until tooltip is shown (in milliseconds)." );
  255. endGroup( "ToolTip" );
  256. addGroup( "Editing" );
  257. addField("isContainer", TypeBool, Offset(mIsContainer, GuiControl),
  258. "If true, the control may contain child controls." );
  259. endGroup( "Editing" );
  260. addGroup( "Localization" );
  261. addField("langTableMod", TypeString, Offset(mLangTableName, GuiControl),
  262. "Name of string table to use for lookup of internationalized text." );
  263. endGroup( "Localization" );
  264. Parent::initPersistFields();
  265. }
  266. //-----------------------------------------------------------------------------
  267. bool GuiControl::processArguments(S32 argc, ConsoleValue *argv)
  268. {
  269. // argv[0] - The GuiGroup to add this control to when it's created.
  270. // this is an optional parameter that may be specified at
  271. // object creation time to organize a gui control into a
  272. // subgroup of GuiControls and is useful in helping the
  273. // gui editor group and sort the existent gui's in the Sim.
  274. // Specified group?
  275. if( argc == 1 )
  276. {
  277. StringTableEntry steIntName = StringTable->insert(argv[0]);
  278. mAddGroup = dynamic_cast<SimGroup*>(Sim::getGuiGroup()->findObjectByInternalName( steIntName ));
  279. if( mAddGroup == NULL )
  280. {
  281. mAddGroup = new SimGroup();
  282. if( mAddGroup->registerObject() )
  283. {
  284. mAddGroup->setInternalName( steIntName );
  285. Sim::getGuiGroup()->addObject( mAddGroup );
  286. }
  287. else
  288. {
  289. SAFE_DELETE( mAddGroup );
  290. return false;
  291. }
  292. }
  293. mAddGroup->addObject(this);
  294. }
  295. return true;
  296. }
  297. //-----------------------------------------------------------------------------
  298. void GuiControl::awaken()
  299. {
  300. PROFILE_SCOPE( GuiControl_awaken );
  301. #ifdef DEBUG_SPEW
  302. Platform::outputDebugString( "[GuiControl] Waking up %i:%s (%s:%s) awake=%s",
  303. getId(), getClassName(), getName(), getInternalName(),
  304. mAwake ? "true" : "false" );
  305. #endif
  306. if( mAwake )
  307. return;
  308. // Wake up visible children.
  309. for( GuiControl::iterator iter = begin(); iter != end(); ++ iter )
  310. {
  311. GuiControl* ctrl = static_cast< GuiControl* >( *iter );
  312. if( ctrl->isVisible() && !ctrl->isAwake() )
  313. ctrl->awaken();
  314. }
  315. if( !mAwake && !onWake() )
  316. {
  317. Con::errorf( ConsoleLogEntry::General, "GuiControl::awaken: failed onWake for obj: %i:%s (%s)",
  318. getId(), getClassName(), getName() );
  319. mAwake = false;
  320. }
  321. }
  322. //-----------------------------------------------------------------------------
  323. void GuiControl::sleep()
  324. {
  325. #ifdef DEBUG_SPEW
  326. Platform::outputDebugString( "[GuiControl] Putting to sleep %i:%s (%s:%s) awake=%s",
  327. getId(), getClassName(), getName(), getInternalName(),
  328. mAwake ? "true" : "false" );
  329. #endif
  330. if( !mAwake )
  331. return;
  332. iterator i;
  333. for(i = begin(); i != end(); i++)
  334. {
  335. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  336. if( ctrl->isAwake() )
  337. ctrl->sleep();
  338. }
  339. if( mAwake )
  340. onSleep();
  341. }
  342. //=============================================================================
  343. // Rendering.
  344. //=============================================================================
  345. // MARK: ---- Rendering ----
  346. //-----------------------------------------------------------------------------
  347. void GuiControl::preRender()
  348. {
  349. if( !mAwake )
  350. return;
  351. iterator i;
  352. for(i = begin(); i != end(); i++)
  353. {
  354. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  355. ctrl->preRender();
  356. }
  357. onPreRender();
  358. }
  359. //-----------------------------------------------------------------------------
  360. void GuiControl::onPreRender()
  361. {
  362. // do nothing.
  363. }
  364. //-----------------------------------------------------------------------------
  365. void GuiControl::onRender(Point2I offset, const RectI &updateRect)
  366. {
  367. RectI ctrlRect(offset, getExtent());
  368. //if opaque, fill the update rect with the fill color
  369. if ( mProfile->mOpaque )
  370. GFX->getDrawUtil()->drawRectFill(ctrlRect, mProfile->mFillColor);
  371. //if there's a border, draw the border
  372. if ( mProfile->mBorder )
  373. renderBorder(ctrlRect, mProfile);
  374. // Render Children
  375. renderChildControls(offset, updateRect);
  376. }
  377. //-----------------------------------------------------------------------------
  378. bool GuiControl::defaultTooltipRender( const Point2I &hoverPos, const Point2I &cursorPos, const char* tipText )
  379. {
  380. // Short Circuit.
  381. if (!mAwake)
  382. return false;
  383. if ( dStrlen( mTooltip ) == 0 && ( tipText == NULL || dStrlen( tipText ) == 0 ) )
  384. return false;
  385. String renderTip( mTooltip );
  386. if ( tipText != NULL )
  387. renderTip = tipText;
  388. // Need to have root.
  389. GuiCanvas *root = getRoot();
  390. if ( !root )
  391. return false;
  392. GFont *font = mTooltipProfile->mFont;
  393. GFXDrawUtil* drawUtil = GFX->getDrawUtil();
  394. // Support for multi-line tooltip text...
  395. Vector<U32> startLineOffsets, lineLengths;
  396. font->wrapString( renderTip, U32_MAX, startLineOffsets, lineLengths );
  397. // The width is the longest line.
  398. U32 tipWidth = 0;
  399. for ( U32 i = 0; i < lineLengths.size(); i++ )
  400. {
  401. U32 width = font->getStrNWidth( renderTip.c_str() + startLineOffsets[i], lineLengths[i] );
  402. if ( width > tipWidth )
  403. tipWidth = width;
  404. }
  405. // The height is the number of lines times the height of the font.
  406. U32 tipHeight = lineLengths.size() * font->getHeight();
  407. // Vars used:
  408. // Screensize (for position check)
  409. // Offset to get position of cursor
  410. // textBounds for text extent.
  411. Point2I screensize = getRoot()->getWindowSize();
  412. Point2I offset = hoverPos;
  413. Point2I textBounds;
  414. // Offset below cursor image
  415. offset.y += 20; // TODO: Attempt to fix?: root->getCursorExtent().y;
  416. // Create text bounds...
  417. // Pixels above/below the text
  418. const U32 vMargin = 2;
  419. // Pixels left/right of the text
  420. const U32 hMargin = 4;
  421. textBounds.x = tipWidth + hMargin * 2;
  422. textBounds.y = tipHeight + vMargin * 2;
  423. // Check position/width to make sure all of the tooltip will be rendered
  424. // 5 is given as a buffer against the edge
  425. if ( screensize.x < offset.x + textBounds.x + 5 )
  426. offset.x = screensize.x - textBounds.x - 5;
  427. // And ditto for the height
  428. if ( screensize.y < offset.y + textBounds.y + 5 )
  429. offset.y = hoverPos.y - textBounds.y - 5;
  430. RectI oldClip = GFX->getClipRect();
  431. // Set rectangle for the box, and set the clip rectangle.
  432. RectI rect( offset, textBounds );
  433. GFX->setClipRect( rect );
  434. // Draw Filler bit, then border on top of that
  435. drawUtil->drawRectFill( rect, mTooltipProfile->mFillColor );
  436. drawUtil->drawRect( rect, mTooltipProfile->mBorderColor );
  437. // Draw the text centered in the tool tip box...
  438. drawUtil->setBitmapModulation( mTooltipProfile->mFontColor );
  439. for ( U32 i = 0; i < lineLengths.size(); i++ )
  440. {
  441. Point2I start( hMargin, vMargin + i * font->getHeight() );
  442. const UTF8 *line = renderTip.c_str() + startLineOffsets[i];
  443. U32 lineLen = lineLengths[i];
  444. drawUtil->drawTextN( font, start + offset, line, lineLen, mProfile->mFontColors );
  445. }
  446. GFX->setClipRect( oldClip );
  447. return true;
  448. }
  449. //-----------------------------------------------------------------------------
  450. void GuiControl::renderChildControls(Point2I offset, const RectI &updateRect)
  451. {
  452. // Save the current clip rect
  453. // so we can restore it at the end of this method.
  454. RectI savedClipRect = GFX->getClipRect();
  455. // offset is the upper-left corner of this control in screen coordinates
  456. // updateRect is the intersection rectangle in screen coords of the control
  457. // hierarchy. This can be set as the clip rectangle in most cases.
  458. RectI clipRect = updateRect;
  459. iterator i;
  460. for(i = begin(); i != end(); i++)
  461. {
  462. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  463. if (ctrl->mVisible)
  464. {
  465. Point2I childPosition = offset + ctrl->getPosition();
  466. RectI childClip(childPosition, ctrl->getExtent() + Point2I(1,1));
  467. if (childClip.intersect(clipRect))
  468. {
  469. GFX->setClipRect( childClip );
  470. GFX->setStateBlock(mDefaultGuiSB);
  471. ctrl->onRender(childPosition, childClip);
  472. }
  473. }
  474. }
  475. // Restore the clip rect to what it was at the start
  476. // of this method.
  477. GFX->setClipRect( savedClipRect );
  478. }
  479. //-----------------------------------------------------------------------------
  480. void GuiControl::setUpdateRegion(Point2I pos, Point2I ext)
  481. {
  482. Point2I upos = localToGlobalCoord(pos);
  483. GuiCanvas *root = getRoot();
  484. if (root)
  485. {
  486. root->addUpdateRegion(upos, ext);
  487. }
  488. }
  489. //-----------------------------------------------------------------------------
  490. void GuiControl::setUpdate()
  491. {
  492. setUpdateRegion(Point2I(0,0), getExtent());
  493. }
  494. //-----------------------------------------------------------------------------
  495. void GuiControl::renderJustifiedText(Point2I offset, Point2I extent, const char *text)
  496. {
  497. GFont *font = mProfile->mFont;
  498. if(!font)
  499. return;
  500. S32 textWidth = font->getStrWidthPrecise((const UTF8*)text);
  501. U32 textHeight = font->getHeight();
  502. Point2I start( 0, 0 );
  503. // Align horizontal.
  504. if( textWidth > extent.x )
  505. {
  506. // If the text is longer then the box size, (it'll get clipped) so
  507. // force Left Justify
  508. start.x = 0;
  509. }
  510. else
  511. switch( mProfile->mAlignment )
  512. {
  513. case GuiControlProfile::RightJustify:
  514. start.x = extent.x - textWidth;
  515. break;
  516. case GuiControlProfile::TopJustify:
  517. case GuiControlProfile::BottomJustify:
  518. case GuiControlProfile::CenterJustify:
  519. start.x = ( extent.x - textWidth) / 2;
  520. break;
  521. case GuiControlProfile::LeftJustify:
  522. start.x = 0;
  523. break;
  524. }
  525. // Align vertical.
  526. if( textHeight > extent.y )
  527. {
  528. start.y = 0 - ( textHeight - extent.y ) / 2;
  529. }
  530. else
  531. switch( mProfile->mAlignment )
  532. {
  533. case GuiControlProfile::TopJustify:
  534. start.y = 0;
  535. break;
  536. case GuiControlProfile::BottomJustify:
  537. start.y = extent.y - textHeight - 1;
  538. break;
  539. default:
  540. // Center vertical.
  541. start.y = ( extent.y - font->getHeight() ) / 2;
  542. break;
  543. }
  544. GFX->getDrawUtil()->drawText( font, start + offset, text, mProfile->mFontColors );
  545. }
  546. //=============================================================================
  547. // Events.
  548. //=============================================================================
  549. // MARK: ---- Events ----
  550. //-----------------------------------------------------------------------------
  551. bool GuiControl::onAdd()
  552. {
  553. // Let Parent Do Work.
  554. if ( !Parent::onAdd() )
  555. return false;
  556. // Grab the classname of this object
  557. const char *cName = getClassName();
  558. // if we're a pure GuiControl, then we're a container by default.
  559. if ( String::compare( "GuiControl", cName ) == 0 )
  560. mIsContainer = true;
  561. // Add to root group.
  562. if ( mAddGroup == NULL )
  563. mAddGroup = Sim::getGuiGroup();
  564. mAddGroup->addObject(this);
  565. // If we don't have a profile we must assign one now.
  566. // Try assigning one based on the control's class name...
  567. if ( !mProfile )
  568. {
  569. String name = getClassName();
  570. if ( name.isNotEmpty() )
  571. {
  572. U32 pos = name.find( "Ctrl" );
  573. if ( pos != -1 )
  574. name.replace( pos, 4, "Profile" );
  575. else
  576. name += "Profile";
  577. GuiControlProfile *profile = NULL;
  578. if ( Sim::findObject( name, profile ) )
  579. setControlProfile( profile );
  580. }
  581. }
  582. // Try assigning the default profile...
  583. if ( !mProfile )
  584. {
  585. GuiControlProfile *profile = NULL;
  586. Sim::findObject( "GuiDefaultProfile", profile );
  587. AssertISV( profile != NULL, avar("GuiControl::onAdd() unable to find specified profile and GuiDefaultProfile does not exist!") );
  588. setControlProfile( profile );
  589. }
  590. // We must also assign a valid TooltipProfile...
  591. if ( !mTooltipProfile )
  592. {
  593. GuiControlProfile *profile = NULL;
  594. Sim::findObject( "GuiTooltipProfile", profile );
  595. AssertISV( profile != NULL, avar("GuiControl::onAdd() unable to find specified tooltip profile and GuiTooltipProfile does not exist!") );
  596. setTooltipProfile( profile );
  597. }
  598. // Notify Script.
  599. onAdd_callback();
  600. GFXStateBlockDesc d;
  601. d.cullDefined = true;
  602. d.cullMode = GFXCullNone;
  603. d.zDefined = true;
  604. d.zEnable = false;
  605. mDefaultGuiSB = GFX->createStateBlock( d );
  606. // Return Success.
  607. return true;
  608. }
  609. //-----------------------------------------------------------------------------
  610. void GuiControl::onRemove()
  611. {
  612. // If control is still awake, put it to sleep first. Otherwise, we'll see an
  613. // onSleep() call triggered when we are removed from our parent.
  614. if( mAwake )
  615. sleep();
  616. // Only invoke script callbacks if they can be received
  617. onRemove_callback();
  618. if ( mProfile )
  619. {
  620. mProfile->decUseCount();
  621. mProfile = NULL;
  622. }
  623. if ( mTooltipProfile )
  624. {
  625. mTooltipProfile->decUseCount();
  626. mTooltipProfile = NULL;
  627. }
  628. clearFirstResponder();
  629. Parent::onRemove();
  630. }
  631. //-----------------------------------------------------------------------------
  632. void GuiControl::onDeleteNotify(SimObject *object)
  633. {
  634. if( object == mProfile )
  635. {
  636. GuiControlProfile* profile;
  637. Sim::findObject( "GuiDefaultProfile", profile );
  638. if ( profile == mProfile )
  639. mProfile = NULL;
  640. else
  641. setControlProfile( profile );
  642. }
  643. if (object == mTooltipProfile)
  644. {
  645. GuiControlProfile* profile;
  646. Sim::findObject( "GuiDefaultProfile", profile );
  647. if ( profile == mTooltipProfile )
  648. mTooltipProfile = NULL;
  649. else
  650. setTooltipProfile( profile );
  651. }
  652. }
  653. //-----------------------------------------------------------------------------
  654. bool GuiControl::onWake()
  655. {
  656. PROFILE_SCOPE( GuiControl_onWake );
  657. AssertFatal( !mAwake, "GuiControl::onWake() - control is already awake" );
  658. if( mAwake )
  659. return true;
  660. // [tom, 4/18/2005] Cause mLangTable to be refreshed in case it was changed
  661. mLangTable = NULL;
  662. //set the flag
  663. mAwake = true;
  664. //set the layer
  665. GuiCanvas *root = getRoot();
  666. GuiControl *parent = getParent();
  667. if (parent && parent != root)
  668. mLayer = parent->mLayer;
  669. //make sure the first responder exists
  670. if (! mFirstResponder)
  671. mFirstResponder = findFirstTabable();
  672. //increment the profile
  673. mProfile->incLoadCount();
  674. if (mTooltipProfile)
  675. {
  676. mTooltipProfile->incLoadCount();
  677. }
  678. // Only invoke script callbacks if we have a namespace in which to do so
  679. // This will suppress warnings
  680. onWake_callback();
  681. return true;
  682. }
  683. //-----------------------------------------------------------------------------
  684. void GuiControl::onSleep()
  685. {
  686. AssertFatal( mAwake, "GuiControl::onSleep() - control is already asleep" );
  687. if( !mAwake )
  688. return;
  689. clearFirstResponder();
  690. mouseUnlock();
  691. // Only invoke script callbacks if we have a namespace in which to do so
  692. // This will suppress warnings
  693. onSleep_callback();
  694. //decrement the profile reference
  695. mProfile->decLoadCount();
  696. if (mTooltipProfile)
  697. {
  698. mTooltipProfile->decLoadCount();
  699. }
  700. // Set Flag
  701. mAwake = false;
  702. }
  703. //-----------------------------------------------------------------------------
  704. void GuiControl::onChildAdded( GuiControl *child )
  705. {
  706. // Base class does not make use of this
  707. }
  708. //-----------------------------------------------------------------------------
  709. void GuiControl::onChildRemoved( GuiControl *child )
  710. {
  711. // Base does nothing with this
  712. }
  713. //-----------------------------------------------------------------------------
  714. void GuiControl::onGroupRemove()
  715. {
  716. // If we have a first responder in our hierarchy,
  717. // make sure to kill it off.
  718. if( mFirstResponder )
  719. mFirstResponder->clearFirstResponder();
  720. else
  721. {
  722. GuiCanvas* root = getRoot();
  723. if( root )
  724. {
  725. GuiControl* firstResponder = root->getFirstResponder();
  726. if( firstResponder && firstResponder->isChildOfGroup( this ) )
  727. firstResponder->clearFirstResponder();
  728. }
  729. }
  730. // If we are awake, put us to sleep.
  731. if( isAwake() )
  732. sleep();
  733. }
  734. //-----------------------------------------------------------------------------
  735. bool GuiControl::onInputEvent(const InputEventInfo &event)
  736. {
  737. // Do nothing by default...
  738. return( false );
  739. }
  740. //-----------------------------------------------------------------------------
  741. bool GuiControl::onKeyDown(const GuiEvent &event)
  742. {
  743. //pass the event to the parent
  744. GuiControl *parent = getParent();
  745. if (parent)
  746. return parent->onKeyDown(event);
  747. else
  748. return false;
  749. }
  750. //-----------------------------------------------------------------------------
  751. bool GuiControl::onKeyRepeat(const GuiEvent &event)
  752. {
  753. // default to just another key down.
  754. return onKeyDown(event);
  755. }
  756. //-----------------------------------------------------------------------------
  757. bool GuiControl::onKeyUp(const GuiEvent &event)
  758. {
  759. //pass the event to the parent
  760. GuiControl *parent = getParent();
  761. if (parent)
  762. return parent->onKeyUp(event);
  763. else
  764. return false;
  765. }
  766. //-----------------------------------------------------------------------------
  767. void GuiControl::onMouseUp(const GuiEvent &event)
  768. {
  769. }
  770. //-----------------------------------------------------------------------------
  771. void GuiControl::onMouseDown(const GuiEvent &event)
  772. {
  773. if ( !mVisible || !mAwake )
  774. return;
  775. execConsoleCallback();
  776. }
  777. //-----------------------------------------------------------------------------
  778. void GuiControl::onMouseMove(const GuiEvent &event)
  779. {
  780. //if this control is a dead end, make sure the event stops here
  781. if ( !mVisible || !mAwake )
  782. return;
  783. //pass the event to the parent
  784. GuiControl *parent = getParent();
  785. if ( parent )
  786. parent->onMouseMove( event );
  787. }
  788. //-----------------------------------------------------------------------------
  789. void GuiControl::onMouseDragged(const GuiEvent &event)
  790. {
  791. }
  792. //-----------------------------------------------------------------------------
  793. void GuiControl::onMouseEnter(const GuiEvent &event)
  794. {
  795. }
  796. //-----------------------------------------------------------------------------
  797. void GuiControl::onMouseLeave(const GuiEvent &event)
  798. {
  799. }
  800. //-----------------------------------------------------------------------------
  801. bool GuiControl::onMouseWheelUp( const GuiEvent &event )
  802. {
  803. //if this control is a dead end, make sure the event stops here
  804. if ( !mVisible || !mAwake )
  805. return true;
  806. //pass the event to the parent
  807. GuiControl *parent = getParent();
  808. if ( parent )
  809. return parent->onMouseWheelUp( event );
  810. else
  811. return false;
  812. }
  813. //-----------------------------------------------------------------------------
  814. bool GuiControl::onMouseWheelDown( const GuiEvent &event )
  815. {
  816. //if this control is a dead end, make sure the event stops here
  817. if ( !mVisible || !mAwake )
  818. return true;
  819. //pass the event to the parent
  820. GuiControl *parent = getParent();
  821. if ( parent )
  822. return parent->onMouseWheelDown( event );
  823. else
  824. return false;
  825. }
  826. //-----------------------------------------------------------------------------
  827. void GuiControl::onRightMouseDown(const GuiEvent &)
  828. {
  829. }
  830. //-----------------------------------------------------------------------------
  831. void GuiControl::onRightMouseUp(const GuiEvent &)
  832. {
  833. }
  834. //-----------------------------------------------------------------------------
  835. void GuiControl::onRightMouseDragged(const GuiEvent &)
  836. {
  837. }
  838. //-----------------------------------------------------------------------------
  839. void GuiControl::onMiddleMouseDown(const GuiEvent &)
  840. {
  841. }
  842. //-----------------------------------------------------------------------------
  843. void GuiControl::onMiddleMouseUp(const GuiEvent &)
  844. {
  845. }
  846. //-----------------------------------------------------------------------------
  847. void GuiControl::onMiddleMouseDragged(const GuiEvent &)
  848. {
  849. }
  850. //-----------------------------------------------------------------------------
  851. bool GuiControl::onGamepadButtonDown(const GuiEvent &event)
  852. {
  853. return onKeyDown(event);
  854. }
  855. //-----------------------------------------------------------------------------
  856. bool GuiControl::onGamepadButtonUp(const GuiEvent &event)
  857. {
  858. return onKeyUp(event);
  859. }
  860. //-----------------------------------------------------------------------------
  861. bool GuiControl::onGamepadAxisUp(const GuiEvent &event)
  862. {
  863. //pass the event to the parent
  864. GuiControl *parent = getParent();
  865. if (parent)
  866. {
  867. return parent->onGamepadAxisUp(event);
  868. }
  869. else
  870. {
  871. return false;
  872. }
  873. }
  874. //-----------------------------------------------------------------------------
  875. bool GuiControl::onGamepadAxisDown(const GuiEvent &event)
  876. {
  877. //pass the event to the parent
  878. GuiControl *parent = getParent();
  879. if (parent)
  880. {
  881. return parent->onGamepadAxisDown(event);
  882. }
  883. else
  884. {
  885. return false;
  886. }
  887. }
  888. //-----------------------------------------------------------------------------
  889. bool GuiControl::onGamepadAxisLeft(const GuiEvent &event)
  890. {
  891. //pass the event to the parent
  892. GuiControl *parent = getParent();
  893. if (parent)
  894. {
  895. return parent->onGamepadAxisLeft(event);
  896. }
  897. else
  898. {
  899. return false;
  900. }
  901. }
  902. //-----------------------------------------------------------------------------
  903. bool GuiControl::onGamepadAxisRight(const GuiEvent &event)
  904. {
  905. //pass the event to the parent
  906. GuiControl *parent = getParent();
  907. if (parent)
  908. {
  909. return parent->onGamepadAxisRight(event);
  910. }
  911. else
  912. {
  913. return false;
  914. }
  915. }
  916. //-----------------------------------------------------------------------------
  917. bool GuiControl::onGamepadTrigger(const GuiEvent &event)
  918. {
  919. //pass the event to the parent
  920. GuiControl *parent = getParent();
  921. if (parent)
  922. {
  923. return parent->onGamepadTrigger(event);
  924. }
  925. else
  926. {
  927. return false;
  928. }
  929. }
  930. //-----------------------------------------------------------------------------
  931. void GuiControl::onAction()
  932. {
  933. if (! mActive)
  934. return;
  935. //execute the console command
  936. if( mConsoleCommand.isNotEmpty() )
  937. {
  938. execConsoleCallback();
  939. }
  940. else
  941. onAction_callback();
  942. }
  943. //-----------------------------------------------------------------------------
  944. void GuiControl::onMessage( GuiControl* , S32 )
  945. {
  946. }
  947. //-----------------------------------------------------------------------------
  948. void GuiControl::onDialogPush()
  949. {
  950. // Notify Script.
  951. onDialogPush_callback();
  952. }
  953. //-----------------------------------------------------------------------------
  954. void GuiControl::onDialogPop()
  955. {
  956. // Notify Script.
  957. onDialogPop_callback();
  958. }
  959. //-----------------------------------------------------------------------------
  960. void GuiControl::inspectPreApply()
  961. {
  962. }
  963. //-----------------------------------------------------------------------------
  964. void GuiControl::inspectPostApply()
  965. {
  966. // To not require every control to hook onto inspectPostApply to make
  967. // all changed properties take effect, just put controls through a fake
  968. // sleep&wake sequence. This should generally get most property changes
  969. // to show.
  970. //
  971. // Don't do this with the canvas.
  972. if( mAwake && !dynamic_cast< GuiCanvas* >( this ) )
  973. {
  974. bool isContainer = mIsContainer;
  975. onSleep();
  976. onWake();
  977. mIsContainer = isContainer;
  978. }
  979. }
  980. //=============================================================================
  981. // Layout.
  982. //=============================================================================
  983. // MARK: ---- Layout ----
  984. //-----------------------------------------------------------------------------
  985. void GuiControl::setSizing(S32 horz, S32 vert)
  986. {
  987. mHorizSizing = horz;
  988. mVertSizing = vert;
  989. }
  990. //-----------------------------------------------------------------------------
  991. bool GuiControl::resize(const Point2I &newPosition, const Point2I &newExtent)
  992. {
  993. const Point2I minExtent = getMinExtent();
  994. Point2I actualNewExtent = Point2I(getMax(minExtent.x, newExtent.x),
  995. getMax(minExtent.y, newExtent.y));
  996. // only do the child control resizing stuff if you really need to.
  997. const RectI bounds = getBounds();
  998. // If we didn't size anything, return false to indicate such
  999. bool extentChanged = (actualNewExtent != bounds.extent);
  1000. bool positionChanged = (newPosition != bounds.point);
  1001. if (!extentChanged && !positionChanged )
  1002. return false;
  1003. // Update Position
  1004. if ( positionChanged )
  1005. mBounds.point = newPosition;
  1006. // Update Extent
  1007. if( extentChanged )
  1008. {
  1009. //call set update both before and after
  1010. setUpdate();
  1011. mBounds.extent = actualNewExtent;
  1012. // Obey the flag!
  1013. // Could be set if we are resizing in response to a child resizing!
  1014. if ( mNotifyChildrenResized )
  1015. {
  1016. iterator i;
  1017. for(i = begin(); i != end(); i++)
  1018. {
  1019. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1020. ctrl->parentResized(RectI(bounds.point, bounds.extent), RectI(newPosition,actualNewExtent));
  1021. }
  1022. }
  1023. GuiControl *parent = getParent();
  1024. if (parent)
  1025. parent->childResized(this);
  1026. setUpdate();
  1027. }
  1028. // We sized something
  1029. if( extentChanged )
  1030. return true;
  1031. // Note : We treat a repositioning as no sizing happening
  1032. // because parent's should really not need to know when they
  1033. // have moved, as it should not affect any child sizing since
  1034. // all child bounds are relative to the parent's 0,0
  1035. return false;
  1036. }
  1037. //-----------------------------------------------------------------------------
  1038. bool GuiControl::setPosition( const Point2I &newPosition )
  1039. {
  1040. return resize( newPosition, mBounds.extent );
  1041. }
  1042. //-----------------------------------------------------------------------------
  1043. bool GuiControl::setExtent( const Point2I &newExtent )
  1044. {
  1045. return resize( mBounds.point, newExtent );
  1046. }
  1047. //-----------------------------------------------------------------------------
  1048. bool GuiControl::setBounds( const RectI &newBounds )
  1049. {
  1050. return resize( newBounds.point, newBounds.extent );
  1051. }
  1052. //-----------------------------------------------------------------------------
  1053. void GuiControl::setLeft( S32 newLeft )
  1054. {
  1055. resize( Point2I( newLeft, mBounds.point.y), mBounds.extent );
  1056. }
  1057. //-----------------------------------------------------------------------------
  1058. void GuiControl::setTop( S32 newTop )
  1059. {
  1060. resize( Point2I( mBounds.point.x, newTop ), mBounds.extent );
  1061. }
  1062. //-----------------------------------------------------------------------------
  1063. void GuiControl::setWidth( S32 newWidth )
  1064. {
  1065. resize( mBounds.point, Point2I( newWidth, mBounds.extent.y ) );
  1066. }
  1067. //-----------------------------------------------------------------------------
  1068. void GuiControl::setHeight( S32 newHeight )
  1069. {
  1070. resize( mBounds.point, Point2I( mBounds.extent.x, newHeight ) );
  1071. }
  1072. //-----------------------------------------------------------------------------
  1073. void GuiControl::childResized( GuiControl* )
  1074. {
  1075. }
  1076. //-----------------------------------------------------------------------------
  1077. void GuiControl::parentResized(const RectI &oldParentRect, const RectI &newParentRect)
  1078. {
  1079. Point2I newPosition = getPosition();
  1080. Point2I newExtent = getExtent();
  1081. S32 deltaX = newParentRect.extent.x - oldParentRect.extent.x;
  1082. S32 deltaY = newParentRect.extent.y - oldParentRect.extent.y;
  1083. if (mHorizSizing == horizResizeCenter)
  1084. newPosition.x = (newParentRect.extent.x - getWidth()) >> 1;
  1085. else if (mHorizSizing == horizResizeWidth)
  1086. newExtent.x += deltaX;
  1087. else if (mHorizSizing == horizResizeLeft)
  1088. newPosition.x += deltaX;
  1089. else if (mHorizSizing == horizResizeRelative && oldParentRect.extent.x != 0)
  1090. {
  1091. S32 newLeft = mRoundToNearest( ( F32( newPosition.x ) / F32( oldParentRect.extent.x ) ) * F32( newParentRect.extent.x ) );
  1092. S32 newWidth = mRoundToNearest( ( F32( newExtent.x ) / F32( oldParentRect.extent.x ) ) * F32( newParentRect.extent.x ) );
  1093. newPosition.x = newLeft;
  1094. newExtent.x = newWidth;
  1095. }
  1096. else if (mHorizSizing == horizResizeAspectLeft && oldParentRect.extent.x != 0)
  1097. {
  1098. S32 newLeft = mRoundToNearest((F32(newPosition.x) / F32(oldParentRect.extent.x)) * F32(newParentRect.extent.x));
  1099. S32 newWidth = mRoundToNearest((F32(newExtent.x) / F32(oldParentRect.extent.y)) * F32(newParentRect.extent.y));
  1100. newPosition.x = newLeft;
  1101. newExtent.x = newWidth;
  1102. }
  1103. else if (mHorizSizing == horizResizeAspectRight && oldParentRect.extent.x != 0)
  1104. {
  1105. S32 newLeft = mRoundToNearest((F32(newPosition.x) / F32(oldParentRect.extent.x)) * F32(newParentRect.extent.x));
  1106. S32 newWidth = mRoundToNearest((F32(newExtent.x) / F32(oldParentRect.extent.y)) * F32(newParentRect.extent.y)); //origional aspect ratio corrected width
  1107. S32 rWidth = mRoundToNearest((F32(newExtent.x) / F32(oldParentRect.extent.x)) * F32(newParentRect.extent.x)); //parent aspect ratio relative width
  1108. S32 offset = rWidth - newWidth; // account for change in relative width
  1109. newLeft += offset;
  1110. newPosition.x = newLeft;
  1111. newExtent.x = newWidth;
  1112. }
  1113. else if (mHorizSizing == horizResizeAspectCenter && oldParentRect.extent.x != 0)
  1114. {
  1115. S32 newLeft = mRoundToNearest((F32(newPosition.x) / F32(oldParentRect.extent.x)) * F32(newParentRect.extent.x));
  1116. S32 newWidth = mRoundToNearest((F32(newExtent.x) / F32(oldParentRect.extent.y)) * F32(newParentRect.extent.y)); //origional aspect ratio corrected width
  1117. S32 rWidth = mRoundToNearest((F32(newExtent.x) / F32(oldParentRect.extent.x)) * F32(newParentRect.extent.x)); //parent aspect ratio relative width
  1118. S32 offset = rWidth - newWidth; // account for change in relative width
  1119. newLeft += offset/2;
  1120. newPosition.x = newLeft;
  1121. newExtent.x = newWidth;
  1122. }
  1123. if (mVertSizing == vertResizeCenter)
  1124. newPosition.y = (newParentRect.extent.y - getHeight()) >> 1;
  1125. else if (mVertSizing == vertResizeHeight)
  1126. newExtent.y += deltaY;
  1127. else if (mVertSizing == vertResizeTop)
  1128. newPosition.y += deltaY;
  1129. else if(mVertSizing == vertResizeRelative && oldParentRect.extent.y != 0)
  1130. {
  1131. S32 newTop = mRoundToNearest( ( F32( newPosition.y ) / F32( oldParentRect.extent.y ) ) * F32( newParentRect.extent.y ) );
  1132. S32 newHeight = mRoundToNearest( ( F32( newExtent.y ) / F32( oldParentRect.extent.y ) ) * F32( newParentRect.extent.y ) );
  1133. newPosition.y = newTop;
  1134. newExtent.y = newHeight;
  1135. }
  1136. else if (mVertSizing == vertResizeAspectTop && oldParentRect.extent.y != 0)
  1137. {
  1138. S32 newTop = mRoundToNearest((F32(newPosition.y) / F32(oldParentRect.extent.y)) * F32(newParentRect.extent.y));
  1139. S32 newHeight = mRoundToNearest((F32(newExtent.y) / F32(oldParentRect.extent.x)) * F32(newParentRect.extent.x));
  1140. newPosition.y = newTop;
  1141. newExtent.y = newHeight;
  1142. }
  1143. else if (mVertSizing == vertResizeAspectBottom && oldParentRect.extent.y != 0)
  1144. {
  1145. S32 newTop = mRoundToNearest((F32(newPosition.y) / F32(oldParentRect.extent.y)) * F32(newParentRect.extent.y));
  1146. S32 newHeight = mRoundToNearest((F32(newExtent.y) / F32(oldParentRect.extent.x)) * F32(newParentRect.extent.x)); //origional aspect ratio corrected hieght
  1147. S32 rHeight = mRoundToNearest((F32(newExtent.y) / F32(oldParentRect.extent.y)) * F32(newParentRect.extent.y)); //parent aspect ratio relative hieght
  1148. S32 offset = rHeight - newHeight; // account for change in relative hieght
  1149. newTop += offset;
  1150. newPosition.y = newTop;
  1151. newExtent.y = newHeight;
  1152. }
  1153. else if (mVertSizing == vertResizeAspectCenter && oldParentRect.extent.y != 0)
  1154. {
  1155. S32 newTop = mRoundToNearest((F32(newPosition.y) / F32(oldParentRect.extent.y)) * F32(newParentRect.extent.y));
  1156. S32 newHeight = mRoundToNearest((F32(newExtent.y) / F32(oldParentRect.extent.x)) * F32(newParentRect.extent.x)); //origional aspect ratio corrected hieght
  1157. S32 rHeight = mRoundToNearest((F32(newExtent.y) / F32(oldParentRect.extent.y)) * F32(newParentRect.extent.y)); //parent aspect ratio relative hieght
  1158. S32 offset = rHeight - newHeight; // account for change in relative hieght
  1159. newTop += offset / 2;
  1160. newPosition.y = newTop;
  1161. newExtent.y = newHeight;
  1162. }
  1163. // Resizing Re factor [9/18/2006]
  1164. // Only resize if our minExtent is satisfied with it.
  1165. Point2I minExtent = getMinExtent();
  1166. if( newExtent.x >= minExtent.x && newExtent.y >= minExtent.y )
  1167. resize(newPosition, newExtent);
  1168. }
  1169. //-----------------------------------------------------------------------------
  1170. Point2I GuiControl::localToGlobalCoord(const Point2I &src)
  1171. {
  1172. Point2I ret = src;
  1173. ret += getPosition();
  1174. GuiControl *walk = getParent();
  1175. while(walk)
  1176. {
  1177. ret += walk->getPosition();
  1178. walk = walk->getParent();
  1179. }
  1180. return ret;
  1181. }
  1182. //-----------------------------------------------------------------------------
  1183. Point2I GuiControl::globalToLocalCoord(const Point2I &src)
  1184. {
  1185. Point2I ret = src;
  1186. ret -= getPosition();
  1187. GuiControl *walk = getParent();
  1188. while(walk)
  1189. {
  1190. ret -= walk->getPosition();
  1191. walk = walk->getParent();
  1192. }
  1193. return ret;
  1194. }
  1195. //-----------------------------------------------------------------------------
  1196. bool GuiControl::cursorInControl()
  1197. {
  1198. GuiCanvas *root = getRoot();
  1199. if (! root) return false;
  1200. Point2I pt = root->getCursorPos();
  1201. pt = root->getPlatformWindow() ? root->getPlatformWindow()->screenToClient(pt) : pt;
  1202. Point2I extent = getExtent();
  1203. Point2I offset = localToGlobalCoord(Point2I(0, 0));
  1204. if (pt.x >= offset.x && pt.y >= offset.y &&
  1205. pt.x < offset.x + extent.x && pt.y < offset.y + extent.y)
  1206. {
  1207. return true;
  1208. }
  1209. else
  1210. {
  1211. return false;
  1212. }
  1213. }
  1214. //-----------------------------------------------------------------------------
  1215. bool GuiControl::pointInControl(const Point2I& parentCoordPoint)
  1216. {
  1217. const RectI &bounds = getBounds();
  1218. S32 xt = parentCoordPoint.x - bounds.point.x;
  1219. S32 yt = parentCoordPoint.y - bounds.point.y;
  1220. return xt >= 0 && yt >= 0 && xt < bounds.extent.x && yt < bounds.extent.y;
  1221. }
  1222. //=============================================================================
  1223. // Properties.
  1224. //=============================================================================
  1225. // MARK: ---- Properties ----
  1226. //-----------------------------------------------------------------------------
  1227. void GuiControl::setTooltipProfile( GuiControlProfile *prof )
  1228. {
  1229. AssertFatal( prof, "GuiControl::setTooltipProfile: invalid profile" );
  1230. if ( prof == mTooltipProfile )
  1231. return;
  1232. bool skipAwaken = false;
  1233. if ( mTooltipProfile == NULL )
  1234. skipAwaken = true;
  1235. if( mTooltipProfile )
  1236. mTooltipProfile->decUseCount();
  1237. if ( mAwake && mTooltipProfile )
  1238. mTooltipProfile->decLoadCount();
  1239. // Clear the delete notification we previously set up
  1240. if ( mTooltipProfile )
  1241. clearNotify( mTooltipProfile );
  1242. mTooltipProfile = prof;
  1243. mTooltipProfile->incUseCount();
  1244. if ( mAwake )
  1245. mTooltipProfile->incLoadCount();
  1246. // Make sure that the new profile will notify us when it is deleted
  1247. if ( mTooltipProfile )
  1248. deleteNotify( mTooltipProfile );
  1249. // force an update when the profile is changed
  1250. if ( mAwake && !skipAwaken )
  1251. {
  1252. sleep();
  1253. if( !Sim::isShuttingDown() )
  1254. awaken();
  1255. }
  1256. }
  1257. //-----------------------------------------------------------------------------
  1258. void GuiControl::setControlProfile( GuiControlProfile *prof )
  1259. {
  1260. AssertFatal( prof, "GuiControl::setControlProfile: invalid profile" );
  1261. if ( prof == mProfile )
  1262. return;
  1263. bool skipAwaken = false;
  1264. if ( mProfile == NULL )
  1265. skipAwaken = true;
  1266. if( mProfile )
  1267. mProfile->decUseCount();
  1268. if ( mAwake && mProfile )
  1269. mProfile->decLoadCount();
  1270. // Clear the delete notification we previously set up
  1271. if ( mProfile )
  1272. clearNotify( mProfile );
  1273. mProfile = prof;
  1274. mProfile->incUseCount();
  1275. if ( mAwake )
  1276. mProfile->incLoadCount();
  1277. // Make sure that the new profile will notify us when it is deleted
  1278. if ( mProfile )
  1279. deleteNotify( mProfile );
  1280. // force an update when the profile is changed
  1281. if ( mAwake && !skipAwaken )
  1282. {
  1283. sleep();
  1284. if( !Sim::isShuttingDown() )
  1285. awaken();
  1286. }
  1287. }
  1288. //-----------------------------------------------------------------------------
  1289. bool GuiControl::setProfileProt( void *object, const char *index, const char *data )
  1290. {
  1291. GuiControl* ctrl = static_cast<GuiControl*>( object );
  1292. GuiControlProfile *prof = dynamic_cast<GuiControlProfile*>( Sim::findObject( data ) );
  1293. if ( prof == NULL )
  1294. return false;
  1295. // filter through our setter, for consistency
  1296. ctrl->setControlProfile( prof );
  1297. // ask the console not to set the data, because we've already set it
  1298. return false;
  1299. }
  1300. //-----------------------------------------------------------------------------
  1301. bool GuiControl::setTooltipProfileProt( void *object, const char *index, const char *data )
  1302. {
  1303. GuiControl* ctrl = static_cast<GuiControl*>( object );
  1304. GuiControlProfile *prof = dynamic_cast<GuiControlProfile*>( Sim::findObject( data ) );
  1305. if ( prof == NULL )
  1306. return false;
  1307. // filter through our setter, for consistency
  1308. ctrl->setTooltipProfile( prof );
  1309. // ask the console not to set the data, because we've already set it
  1310. return false;
  1311. }
  1312. //-----------------------------------------------------------------------------
  1313. const char *GuiControl::getScriptValue()
  1314. {
  1315. return NULL;
  1316. }
  1317. //-----------------------------------------------------------------------------
  1318. void GuiControl::setScriptValue( const char* )
  1319. {
  1320. }
  1321. //-----------------------------------------------------------------------------
  1322. void GuiControl::setConsoleVariable(const char *variable)
  1323. {
  1324. if (variable)
  1325. {
  1326. mConsoleVariable = StringTable->insert(variable);
  1327. }
  1328. else
  1329. {
  1330. mConsoleVariable = StringTable->EmptyString();
  1331. }
  1332. }
  1333. //-----------------------------------------------------------------------------
  1334. void GuiControl::setConsoleCommand( const String& newCmd )
  1335. {
  1336. mConsoleCommand = newCmd;
  1337. }
  1338. //-----------------------------------------------------------------------------
  1339. const char * GuiControl::getConsoleCommand()
  1340. {
  1341. return mConsoleCommand;
  1342. }
  1343. //-----------------------------------------------------------------------------
  1344. void GuiControl::setVariable(const char *value)
  1345. {
  1346. if (mConsoleVariable[0])
  1347. Con::setVariable(mConsoleVariable, value);
  1348. }
  1349. //-----------------------------------------------------------------------------
  1350. void GuiControl::setIntVariable(S32 value)
  1351. {
  1352. if (mConsoleVariable[0])
  1353. Con::setIntVariable(mConsoleVariable, value);
  1354. }
  1355. //-----------------------------------------------------------------------------
  1356. void GuiControl::setFloatVariable(F32 value)
  1357. {
  1358. if (mConsoleVariable[0])
  1359. Con::setFloatVariable(mConsoleVariable, value);
  1360. }
  1361. //-----------------------------------------------------------------------------
  1362. const char * GuiControl::getVariable()
  1363. {
  1364. if (mConsoleVariable[0])
  1365. return Con::getVariable(mConsoleVariable);
  1366. else return NULL;
  1367. }
  1368. //-----------------------------------------------------------------------------
  1369. S32 GuiControl::getIntVariable()
  1370. {
  1371. if (mConsoleVariable[0])
  1372. return Con::getIntVariable(mConsoleVariable);
  1373. else return 0;
  1374. }
  1375. //-----------------------------------------------------------------------------
  1376. F32 GuiControl::getFloatVariable()
  1377. {
  1378. if (mConsoleVariable[0])
  1379. return Con::getFloatVariable(mConsoleVariable);
  1380. else return 0.0f;
  1381. }
  1382. //-----------------------------------------------------------------------------
  1383. void GuiControl::setVisible(bool value)
  1384. {
  1385. mVisible = value;
  1386. setUpdate();
  1387. for( iterator i = begin(); i != end(); i++)
  1388. {
  1389. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1390. ctrl->clearFirstResponder();
  1391. }
  1392. GuiControl *parent = getParent();
  1393. if( parent )
  1394. {
  1395. parent->childResized( this );
  1396. // If parent is visible and awake and this control has just
  1397. // become visible but was sleeping, wake it up now.
  1398. if( parent->isVisible() && parent->isAwake()
  1399. && this->isVisible() && !this->isAwake() )
  1400. awaken();
  1401. }
  1402. if( getNamespace() ) // May be called during construction.
  1403. onVisible_callback( value );
  1404. }
  1405. //-----------------------------------------------------------------------------
  1406. void GuiControl::setActive( bool value )
  1407. {
  1408. if( mActive == value )
  1409. return;
  1410. mActive = value;
  1411. if ( !mActive )
  1412. clearFirstResponder();
  1413. if ( mVisible && mAwake )
  1414. setUpdate();
  1415. if( getNamespace() ) // May be called during construction.
  1416. onActive_callback( value );
  1417. // Pass activation on to children.
  1418. for( iterator iter = begin(); iter != end(); ++ iter )
  1419. {
  1420. GuiControl* child = dynamic_cast< GuiControl* >( *iter );
  1421. if( child )
  1422. child->setActive( value );
  1423. }
  1424. }
  1425. //=============================================================================
  1426. // Persistence.
  1427. //=============================================================================
  1428. // MARK: ---- Persistence ----
  1429. //-----------------------------------------------------------------------------
  1430. bool GuiControl::getCanSaveParent()
  1431. {
  1432. GuiControl *walk = this;
  1433. while(walk)
  1434. {
  1435. if(!walk->getCanSave())
  1436. return false;
  1437. walk = walk->getParent();
  1438. }
  1439. return true;
  1440. }
  1441. //-----------------------------------------------------------------------------
  1442. void GuiControl::write(Stream &stream, U32 tabStop, U32 flags)
  1443. {
  1444. //note: this will return false if either we, or any of our parents, are non-save controls
  1445. bool bCanSave = ( flags & IgnoreCanSave ) || ( flags & NoCheckParentCanSave && getCanSave() ) || getCanSaveParent();
  1446. if (bCanSave && mAddGroup)
  1447. {
  1448. StringTableEntry steName = mAddGroup->getInternalName();
  1449. if ((steName != NULL) && (steName != StringTable->insert("null")) && getName())
  1450. {
  1451. MutexHandle handle;
  1452. handle.lock(mMutex);
  1453. // export selected only?
  1454. if ((flags & SelectedOnly) && !isSelected())
  1455. {
  1456. for (U32 i = 0; i < size(); i++)
  1457. (*this)[i]->write(stream, tabStop, flags);
  1458. return;
  1459. }
  1460. stream.writeTabs(tabStop);
  1461. char buffer[1024];
  1462. dSprintf(buffer, sizeof(buffer), "new %s(%s,%s) {\r\n", getClassName(), getName() ? getName() : "", mAddGroup->getInternalName());
  1463. stream.write(dStrlen(buffer), buffer);
  1464. writeFields(stream, tabStop + 1);
  1465. if (size())
  1466. {
  1467. stream.write(2, "\r\n");
  1468. for (U32 i = 0; i < size(); i++)
  1469. (*this)[i]->write(stream, tabStop + 1, flags);
  1470. }
  1471. stream.writeTabs(tabStop);
  1472. stream.write(4, "};\r\n");
  1473. return;
  1474. }
  1475. }
  1476. if (bCanSave)
  1477. Parent::write( stream, tabStop, flags );
  1478. }
  1479. //=============================================================================
  1480. // Hierarchies.
  1481. //=============================================================================
  1482. // MARK: ---- Hierarchies ----
  1483. //-----------------------------------------------------------------------------
  1484. void GuiControl::addObject(SimObject *object)
  1485. {
  1486. GuiControl *ctrl = dynamic_cast<GuiControl *>(object);
  1487. if(object->getGroup() == this)
  1488. return;
  1489. AssertFatal( ctrl, "GuiControl::addObject() - cannot add non-GuiControl as child of GuiControl" );
  1490. Parent::addObject(object);
  1491. AssertFatal(!ctrl->isAwake(), "GuiControl::addObject: object is already awake before add");
  1492. if( mAwake )
  1493. ctrl->awaken();
  1494. // If we are a child, notify our parent that we've been removed
  1495. GuiControl *parent = ctrl->getParent();
  1496. if( parent )
  1497. parent->onChildAdded( ctrl );
  1498. }
  1499. //-----------------------------------------------------------------------------
  1500. void GuiControl::removeObject(SimObject *object)
  1501. {
  1502. GuiControl* ctrl = static_cast< GuiControl* >( object );
  1503. if( mAwake && ctrl->isAwake() )
  1504. ctrl->sleep();
  1505. onChildRemoved( ctrl );
  1506. Parent::removeObject(object);
  1507. }
  1508. //-----------------------------------------------------------------------------
  1509. GuiControl *GuiControl::getParent()
  1510. {
  1511. SimObject *obj = getGroup();
  1512. if (GuiControl* gui = dynamic_cast<GuiControl*>(obj))
  1513. return gui;
  1514. return 0;
  1515. }
  1516. //-----------------------------------------------------------------------------
  1517. GuiCanvas *GuiControl::getRoot()
  1518. {
  1519. GuiControl *root = NULL;
  1520. GuiControl *parent = getParent();
  1521. while (parent)
  1522. {
  1523. root = parent;
  1524. parent = parent->getParent();
  1525. }
  1526. if (root)
  1527. return dynamic_cast<GuiCanvas*>(root);
  1528. else
  1529. return NULL;
  1530. }
  1531. //-----------------------------------------------------------------------------
  1532. bool GuiControl::acceptsAsChild( SimObject* object ) const
  1533. {
  1534. return ( dynamic_cast< GuiControl* >( object ) != NULL );
  1535. }
  1536. //-----------------------------------------------------------------------------
  1537. GuiControl* GuiControl::findHitControl(const Point2I &pt, S32 initialLayer)
  1538. {
  1539. iterator i = end(); // find in z order (last to first)
  1540. while (i != begin())
  1541. {
  1542. i--;
  1543. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1544. if (initialLayer >= 0 && ctrl->mLayer > initialLayer)
  1545. {
  1546. continue;
  1547. }
  1548. else if (ctrl->mVisible && ctrl->mCanHit && ctrl->pointInControl(pt))
  1549. {
  1550. Point2I ptemp = pt - ctrl->getPosition();
  1551. GuiControl *hitCtrl = ctrl->findHitControl(ptemp);
  1552. if ( hitCtrl->mProfile->mModal )
  1553. return hitCtrl;
  1554. }
  1555. }
  1556. if( mCanHit )
  1557. return this;
  1558. return NULL;
  1559. }
  1560. //-----------------------------------------------------------------------------
  1561. bool GuiControl::findHitControls( const RectI& rect, Vector< GuiControl* >& outResult, U32 flags, S32 initialLayer, U32 depth )
  1562. {
  1563. if( !mVisible )
  1564. return false;
  1565. else if( !mCanHit && flags & HIT_NoCanHitNoRecurse )
  1566. return false;
  1567. // Check for hit. If not full-box, always counts.
  1568. bool isHit = mVisible;
  1569. if( flags & HIT_FullBoxOnly )
  1570. {
  1571. RectI rectInParentSpace = rect;
  1572. rectInParentSpace.point += getPosition();
  1573. isHit &= rectInParentSpace.contains( getBounds() );
  1574. }
  1575. else
  1576. isHit &= mCanHit;
  1577. // If we have a hit and should not recurse into children,
  1578. // return us.
  1579. if( isHit && flags & HIT_ParentPreventsChildHit && depth > 0 )
  1580. {
  1581. outResult.push_back( this );
  1582. return true;
  1583. }
  1584. // Check child controls.
  1585. bool haveFoundChild = false;
  1586. iterator i = end();
  1587. while( i != begin() )
  1588. {
  1589. i --;
  1590. GuiControl* ctrl = static_cast< GuiControl* >( *i );
  1591. if( initialLayer >= 0 && ctrl->mLayer > initialLayer )
  1592. continue;
  1593. if( ctrl->getBounds().overlaps( rect ) )
  1594. {
  1595. RectI transposedRect = rect;
  1596. transposedRect.point -= ctrl->getPosition();
  1597. if( ctrl->findHitControls( transposedRect, outResult, flags, -1, depth + 1 ) )
  1598. haveFoundChild = true;
  1599. }
  1600. }
  1601. if( ( !haveFoundChild || flags & HIT_AddParentHits ) && isHit )
  1602. {
  1603. outResult.push_back( this );
  1604. return true;
  1605. }
  1606. return haveFoundChild;
  1607. }
  1608. //-----------------------------------------------------------------------------
  1609. GuiControl* GuiControl::findFirstTabable()
  1610. {
  1611. // No tabbing if the control is disabled or hidden.
  1612. if ( !mAwake || !mVisible )
  1613. return NULL;
  1614. GuiControl *tabCtrl = NULL;
  1615. iterator i;
  1616. for (i = begin(); i != end(); i++)
  1617. {
  1618. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1619. tabCtrl = ctrl->findFirstTabable();
  1620. if (tabCtrl)
  1621. {
  1622. mFirstResponder = tabCtrl;
  1623. return tabCtrl;
  1624. }
  1625. }
  1626. //nothing was found, therefore, see if this ctrl is tabable
  1627. return ( mProfile != NULL ) ? ( ( mProfile->mTabable && mAwake && mVisible ) ? this : NULL ) : NULL;
  1628. }
  1629. //-----------------------------------------------------------------------------
  1630. GuiControl* GuiControl::findLastTabable(bool firstCall)
  1631. {
  1632. // No tabbing if the control is disabled or hidden.
  1633. if ( !mAwake || !mVisible )
  1634. return NULL;
  1635. //if this is the first call, clear the global
  1636. if (firstCall)
  1637. smPrevResponder = NULL;
  1638. //if this control is tabable, set the global
  1639. if (mProfile->mTabable)
  1640. smPrevResponder = this;
  1641. iterator i;
  1642. for (i = begin(); i != end(); i++)
  1643. {
  1644. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1645. ctrl->findLastTabable(false);
  1646. }
  1647. //after the entire tree has been traversed, return the last responder found
  1648. mFirstResponder = smPrevResponder;
  1649. return smPrevResponder;
  1650. }
  1651. //-----------------------------------------------------------------------------
  1652. GuiControl *GuiControl::findNextTabable(GuiControl *curResponder, bool firstCall)
  1653. {
  1654. // No tabbing if the control is disabled or hidden.
  1655. if ( !mAwake || !mVisible )
  1656. return NULL;
  1657. //if this is the first call, clear the global
  1658. if (firstCall)
  1659. smCurResponder = NULL;
  1660. //first find the current responder
  1661. if (curResponder == this)
  1662. smCurResponder = this;
  1663. //if the first responder has been found, return the very next *tabable* control
  1664. else if ( smCurResponder && mProfile->mTabable && mAwake && mVisible && mActive )
  1665. return( this );
  1666. //loop through, checking each child to see if it is the one that follows the firstResponder
  1667. GuiControl *tabCtrl = NULL;
  1668. iterator i;
  1669. for (i = begin(); i != end(); i++)
  1670. {
  1671. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1672. tabCtrl = ctrl->findNextTabable(curResponder, false);
  1673. if (tabCtrl) break;
  1674. }
  1675. mFirstResponder = tabCtrl;
  1676. return tabCtrl;
  1677. }
  1678. //-----------------------------------------------------------------------------
  1679. GuiControl *GuiControl::findPrevTabable(GuiControl *curResponder, bool firstCall)
  1680. {
  1681. // No tabbing if the control is disabled or hidden.
  1682. if ( !mAwake || !mVisible )
  1683. return NULL;
  1684. if (firstCall)
  1685. smPrevResponder = NULL;
  1686. //if this is the current reponder, return the previous one
  1687. if (curResponder == this)
  1688. return smPrevResponder;
  1689. //else if this is a responder, store it in case the next found is the current responder
  1690. else if ( mProfile->mTabable && mAwake && mVisible && mActive )
  1691. smPrevResponder = this;
  1692. //loop through, checking each child to see if it is the one that follows the firstResponder
  1693. GuiControl *tabCtrl = NULL;
  1694. iterator i;
  1695. for (i = begin(); i != end(); i++)
  1696. {
  1697. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1698. tabCtrl = ctrl->findPrevTabable(curResponder, false);
  1699. if (tabCtrl) break;
  1700. }
  1701. mFirstResponder = tabCtrl;
  1702. return tabCtrl;
  1703. }
  1704. //-----------------------------------------------------------------------------
  1705. bool GuiControl::controlIsChild( GuiControl* child )
  1706. {
  1707. for( iterator i = begin(); i != end(); ++ i )
  1708. {
  1709. GuiControl* ctrl = static_cast< GuiControl* >( *i );
  1710. if( ctrl == child || ctrl->controlIsChild( child ) )
  1711. return true;
  1712. }
  1713. return false;
  1714. }
  1715. //=============================================================================
  1716. // Event Handling.
  1717. //=============================================================================
  1718. // MARK: ---- Event Handling ----
  1719. //-----------------------------------------------------------------------------
  1720. bool GuiControl::isFirstResponder()
  1721. {
  1722. GuiCanvas *root = getRoot();
  1723. return root && root->getFirstResponder() == this;
  1724. }
  1725. //-----------------------------------------------------------------------------
  1726. void GuiControl::makeFirstResponder(bool value)
  1727. {
  1728. if ( value )
  1729. //setFirstResponder(this);
  1730. setFirstResponder();
  1731. else
  1732. clearFirstResponder();
  1733. }
  1734. //-----------------------------------------------------------------------------
  1735. void GuiControl::setFirstResponder( GuiControl* firstResponder )
  1736. {
  1737. // If the control cannot have keyboard focus, refuse
  1738. // to make it first responder.
  1739. if( firstResponder && !firstResponder->mProfile->mCanKeyFocus )
  1740. return;
  1741. mFirstResponder = firstResponder;
  1742. if( getParent() )
  1743. getParent()->setFirstResponder( firstResponder );
  1744. }
  1745. //-----------------------------------------------------------------------------
  1746. void GuiControl::setFirstResponder()
  1747. {
  1748. if( mAwake && mVisible )
  1749. {
  1750. GuiControl *parent = getParent();
  1751. if ( mProfile->mCanKeyFocus == true && parent != NULL )
  1752. parent->setFirstResponder( this );
  1753. }
  1754. }
  1755. //-----------------------------------------------------------------------------
  1756. void GuiControl::clearFirstResponder()
  1757. {
  1758. if( !getParent() )
  1759. return;
  1760. if( isFirstResponder() )
  1761. getParent()->setFirstResponder( NULL );
  1762. else
  1763. for( GuiControl* parent = this; parent != NULL; parent = parent->getParent() )
  1764. if( parent->mFirstResponder == this )
  1765. parent->mFirstResponder = NULL;
  1766. }
  1767. //-----------------------------------------------------------------------------
  1768. void GuiControl::onLoseFirstResponder()
  1769. {
  1770. // Since many controls have visual cues when they are the firstResponder...
  1771. setUpdate();
  1772. onLoseFirstResponder_callback();
  1773. }
  1774. //-----------------------------------------------------------------------------
  1775. void GuiControl::onGainFirstResponder()
  1776. {
  1777. // Since many controls have visual cues when they are the firstResponder...
  1778. this->setUpdate();
  1779. onGainFirstResponder_callback();
  1780. }
  1781. //-----------------------------------------------------------------------------
  1782. void GuiControl::buildAcceleratorMap()
  1783. {
  1784. //add my own accel key
  1785. addAcceleratorKey();
  1786. //add all my childrens keys
  1787. iterator i;
  1788. for(i = begin(); i != end(); i++)
  1789. {
  1790. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1791. ctrl->buildAcceleratorMap();
  1792. }
  1793. }
  1794. //-----------------------------------------------------------------------------
  1795. void GuiControl::addAcceleratorKey()
  1796. {
  1797. //see if we have an accelerator
  1798. if( mAcceleratorKey == StringTable->EmptyString() )
  1799. return;
  1800. EventDescriptor accelEvent;
  1801. ActionMap::createEventDescriptor(mAcceleratorKey, &accelEvent);
  1802. //now we have a modifier, and a key, add them to the canvas
  1803. GuiCanvas *root = getRoot();
  1804. if (root)
  1805. root->addAcceleratorKey(this, 0, accelEvent.eventCode, accelEvent.flags);
  1806. }
  1807. //-----------------------------------------------------------------------------
  1808. void GuiControl::acceleratorKeyPress( U32 )
  1809. {
  1810. onAction();
  1811. }
  1812. //-----------------------------------------------------------------------------
  1813. void GuiControl::acceleratorKeyRelease( U32 )
  1814. {
  1815. //do nothing
  1816. }
  1817. //-----------------------------------------------------------------------------
  1818. bool GuiControl::isMouseLocked()
  1819. {
  1820. GuiCanvas *root = getRoot();
  1821. return root ? root->getMouseLockedControl() == this : false;
  1822. }
  1823. //-----------------------------------------------------------------------------
  1824. void GuiControl::mouseLock(GuiControl *lockingControl)
  1825. {
  1826. GuiCanvas *root = getRoot();
  1827. if (root)
  1828. root->mouseLock(lockingControl);
  1829. }
  1830. //-----------------------------------------------------------------------------
  1831. void GuiControl::mouseLock()
  1832. {
  1833. GuiCanvas *root = getRoot();
  1834. if (root)
  1835. root->mouseLock(this);
  1836. }
  1837. //-----------------------------------------------------------------------------
  1838. void GuiControl::mouseUnlock()
  1839. {
  1840. GuiCanvas *root = getRoot();
  1841. if (root)
  1842. root->mouseUnlock(this);
  1843. }
  1844. //=============================================================================
  1845. // Misc.
  1846. //=============================================================================
  1847. // MARK: ---- Misc ----
  1848. //-----------------------------------------------------------------------------
  1849. LangTable * GuiControl::getGUILangTable()
  1850. {
  1851. if(mLangTable)
  1852. return mLangTable;
  1853. if(mLangTableName && *mLangTableName)
  1854. {
  1855. mLangTable = (LangTable *)getModLangTable((const UTF8*)mLangTableName);
  1856. return mLangTable;
  1857. }
  1858. GuiControl *parent = getParent();
  1859. if(parent)
  1860. return parent->getGUILangTable();
  1861. return NULL;
  1862. }
  1863. //-----------------------------------------------------------------------------
  1864. const UTF8 * GuiControl::getGUIString(S32 id)
  1865. {
  1866. LangTable *lt = getGUILangTable();
  1867. if(lt)
  1868. return lt->getString(id);
  1869. return NULL;
  1870. }
  1871. //-----------------------------------------------------------------------------
  1872. void GuiControl::messageSiblings(S32 message)
  1873. {
  1874. GuiControl *parent = getParent();
  1875. if (! parent) return;
  1876. GuiControl::iterator i;
  1877. for(i = parent->begin(); i != parent->end(); i++)
  1878. {
  1879. GuiControl *ctrl = dynamic_cast<GuiControl *>(*i);
  1880. if (ctrl != this)
  1881. ctrl->onMessage(this, message);
  1882. }
  1883. }
  1884. //-----------------------------------------------------------------------------
  1885. void GuiControl::getScrollLineSizes(U32 *rowHeight, U32 *columnWidth)
  1886. {
  1887. // default to 10 pixels in y, 30 pixels in x
  1888. *columnWidth = 30;
  1889. *rowHeight = 30;
  1890. }
  1891. //-----------------------------------------------------------------------------
  1892. U32 GuiControl::clipText( String &text, U32 clipWidth ) const
  1893. {
  1894. PROFILE_SCOPE( GuiControl_clipText );
  1895. U32 textWidth = mProfile->mFont->getStrWidthPrecise( text );
  1896. if ( textWidth <= clipWidth )
  1897. return textWidth;
  1898. // Start removing characters from the end of the string
  1899. // until the string width plus the elipsesWidth is less
  1900. // than clipWidth...
  1901. // Note this would be more efficient without calling
  1902. // getStrWidthPrecise each loop iteration. eg. get the
  1903. // length of each char, store in a temporary U32 array,
  1904. // and then remove the number we need from the end all at once.
  1905. String temp;
  1906. while ( text.isNotEmpty() )
  1907. {
  1908. text.erase( text.length() - 1, 1 );
  1909. temp = text;
  1910. temp += "...";
  1911. textWidth = mProfile->mFont->getStrWidthPrecise( temp );
  1912. if ( textWidth <= clipWidth )
  1913. {
  1914. text = temp;
  1915. return textWidth;
  1916. }
  1917. }
  1918. // Uh, not even the ellipses will fit in the passed width.
  1919. // Text should be an ellipses string now,
  1920. // which is the right thing to do in this case.
  1921. return 0;
  1922. }
  1923. //-----------------------------------------------------------------------------
  1924. void GuiControl::getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent)
  1925. {
  1926. #ifdef _XBOX
  1927. return;
  1928. #endif
  1929. TORQUE_UNUSED(lastGuiEvent);
  1930. if( !getRoot() )
  1931. return;
  1932. if(getRoot()->mCursorChanged != -1 && !isMouseLocked())
  1933. {
  1934. // We've already changed the cursor,
  1935. // so set it back before we change it again.
  1936. PlatformWindow *pWindow = static_cast<GuiCanvas*>(getRoot())->getPlatformWindow();
  1937. if (!pWindow)
  1938. return;
  1939. PlatformCursorController *pController = pWindow->getCursorController();
  1940. AssertFatal(pController != NULL,"PlatformWindow without an owned CursorController!");
  1941. pController->popCursor();
  1942. // We haven't changed it
  1943. getRoot()->mCursorChanged = -1;
  1944. }
  1945. }
  1946. //-----------------------------------------------------------------------------
  1947. const char* GuiControl::evaluate( const char* str )
  1948. {
  1949. smThisControl = this;
  1950. const char* result = Con::evaluate(str, false);
  1951. smThisControl = NULL;
  1952. return result;
  1953. }
  1954. //-----------------------------------------------------------------------------
  1955. const char* GuiControl::execConsoleCallback()
  1956. {
  1957. if( mConsoleCommand.isNotEmpty() )
  1958. return evaluate( mConsoleCommand );
  1959. return "";
  1960. }
  1961. //-----------------------------------------------------------------------------
  1962. const char* GuiControl::execAltConsoleCallback()
  1963. {
  1964. if( mAltConsoleCommand.isNotEmpty() )
  1965. return evaluate( mAltConsoleCommand );
  1966. return "";
  1967. }
  1968. //=============================================================================
  1969. // Console Methods.
  1970. //=============================================================================
  1971. // MARK: ---- Console Methods ----
  1972. //-----------------------------------------------------------------------------
  1973. DefineEngineMethod( GuiControl, findHitControl, GuiControl*, ( S32 x, S32 y ),,
  1974. "Find the topmost child control located at the given coordinates.\n"
  1975. "@note Only children that are both visible and have the 'modal' flag set in their profile will be considered in the search."
  1976. "@param x The X coordinate in the control's own coordinate space.\n"
  1977. "@param y The Y coordinate in the control's own coordinate space.\n"
  1978. "@return The topmost child control at the given coordintes or the control on which the method was called if no matching child could be found.\n"
  1979. "@see GuiControlProfile::modal\n"
  1980. "@see findHitControls" )
  1981. {
  1982. return object->findHitControl( Point2I( x, y ) );
  1983. }
  1984. //-----------------------------------------------------------------------------
  1985. DefineEngineMethod( GuiControl, findHitControls, const char*, ( S32 x, S32 y, S32 width, S32 height ),,
  1986. "Find all visible child controls that intersect with the given rectangle.\n"
  1987. "@note Invisible child controls will not be included in the search.\n"
  1988. "@param x The X coordinate of the rectangle's upper left corner in the control's own coordinate space.\n"
  1989. "@param y The Y coordinate of the rectangle's upper left corner in the control's own coordinate space.\n"
  1990. "@param width The width of the search rectangle in pixels.\n"
  1991. "@param height The height of the search rectangle in pixels.\n"
  1992. "@return A space-separated list of the IDs of all visible control objects intersecting the given rectangle.\n\n"
  1993. "@tsexample\n"
  1994. "// Lock all controls in the rectangle at x=10 and y=10 and the extent width=100 and height=100.\n"
  1995. "foreach$( %ctrl in %this.findHitControls( 10, 10, 100, 100 ) )\n"
  1996. " %ctrl.setLocked( true );\n"
  1997. "@endtsexample\n"
  1998. "@see findHitControl" )
  1999. {
  2000. // Find hit controls.
  2001. RectI bounds( x, y, width, height );
  2002. Vector< GuiControl* > controls;
  2003. if( !object->findHitControls( bounds, controls ) )
  2004. return "";
  2005. // Create vector string.
  2006. bool isFirst = true;
  2007. StringBuilder str;
  2008. for( U32 i = 0, num = controls.size(); i < num; ++ i )
  2009. {
  2010. if( !isFirst )
  2011. str.append( ' ' );
  2012. str.append( controls[ i ]->getIdString() );
  2013. isFirst = false;
  2014. }
  2015. String s = str.end();
  2016. // Return result.
  2017. if ( s.compare( object->getIdString() ) == 0 )
  2018. return "";
  2019. char* buffer = Con::getReturnBuffer( s.size() );
  2020. dStrcpy( buffer, s.c_str(), s.size() );
  2021. return buffer;
  2022. }
  2023. //-----------------------------------------------------------------------------
  2024. DefineEngineMethod( GuiControl, controlIsChild, bool, ( GuiControl* control ),,
  2025. "Test whether the given control is a direct or indirect child to this control.\n"
  2026. "@param control The potential child control.\n"
  2027. "@return True if the given control is a direct or indirect child to this control." )
  2028. {
  2029. if( !control )
  2030. return false;
  2031. return object->controlIsChild( control );
  2032. }
  2033. //-----------------------------------------------------------------------------
  2034. DefineEngineMethod( GuiControl, isFirstResponder, bool, (),,
  2035. "Test whether the control is the current first responder.\n"
  2036. "@return True if the control is the current first responder.\n"
  2037. "@see makeFirstResponder\n"
  2038. "@see setFirstResponder\n"
  2039. "@ref GuiControl_FirstResponders" )
  2040. {
  2041. return object->isFirstResponder();
  2042. }
  2043. //-----------------------------------------------------------------------------
  2044. DefineEngineMethod( GuiControl, setFirstResponder, void, (),,
  2045. "Make this control the current first responder.\n"
  2046. "@note Only controls with a profile that has canKeyFocus enabled are able to become first responders.\n"
  2047. "@see GuiControlProfile::canKeyFocus\n"
  2048. "@see isFirstResponder\n"
  2049. "@ref GuiControl_FirstResponders" )
  2050. {
  2051. object->setFirstResponder();
  2052. }
  2053. //-----------------------------------------------------------------------------
  2054. DefineEngineMethod( GuiControl, getFirstResponder, GuiControl*, (),,
  2055. "Get the first responder set on this GuiControl tree.\n"
  2056. "@return The first responder set on the control's subtree.\n"
  2057. "@see isFirstResponder\n"
  2058. "@see makeFirstResponder\n"
  2059. "@see setFirstResponder\n"
  2060. "@ref GuiControl_FirstResponders" )
  2061. {
  2062. return object->getFirstResponder();
  2063. }
  2064. //-----------------------------------------------------------------------------
  2065. DefineEngineMethod( GuiControl, clearFirstResponder, void, ( bool ignored ), ( false ),
  2066. "Clear this control from being the first responder in its hierarchy chain.\n"
  2067. "@param ignored Ignored. Supported for backwards-compatibility.\n" )
  2068. {
  2069. object->clearFirstResponder();
  2070. }
  2071. //-----------------------------------------------------------------------------
  2072. DefineEngineMethod( GuiControl, pointInControl, bool, ( S32 x, S32 y ),,
  2073. "Test whether the given point lies within the rectangle of the control.\n"
  2074. "@param x X coordinate of the point in parent-relative coordinates.\n"
  2075. "@param y Y coordinate of the point in parent-relative coordinates.\n"
  2076. "@return True if the point is within the control, false if not.\n"
  2077. "@see getExtent\n"
  2078. "@see getPosition\n" )
  2079. {
  2080. return object->pointInControl( Point2I( x, y ) );
  2081. }
  2082. //-----------------------------------------------------------------------------
  2083. DefineEngineMethod( GuiControl, addGuiControl, void, ( GuiControl* control ),,
  2084. "Add the given control as a child to this control.\n"
  2085. "This is synonymous to calling SimGroup::addObject.\n"
  2086. "@param control The control to add as a child.\n"
  2087. "@note The control will retain its current position and size.\n"
  2088. "@see SimGroup::addObject\n"
  2089. "@ref GuiControl_Hierarchy\n" )
  2090. {
  2091. if( control )
  2092. object->addObject( control );
  2093. }
  2094. //-----------------------------------------------------------------------------
  2095. DefineEngineMethod( GuiControl, getRoot, GuiCanvas*, (),,
  2096. "Get the canvas on which the control is placed.\n"
  2097. "@return The canvas on which the control's hierarchy is currently placed or 0 if the control is not currently placed on a GuiCanvas.\n"
  2098. "@see GuiControl_Hierarchy\n" )
  2099. {
  2100. return object->getRoot();
  2101. }
  2102. //-----------------------------------------------------------------------------
  2103. DefineEngineMethod( GuiControl, getParent, GuiControl*, (),,
  2104. "Get the immediate parent control of the control.\n"
  2105. "@return The immediate parent GuiControl or 0 if the control is not parented to a GuiControl.\n" )
  2106. {
  2107. return object->getParent();
  2108. }
  2109. //-----------------------------------------------------------------------------
  2110. DefineEngineMethod( GuiControl, isMouseLocked, bool, (),,
  2111. "Indicates if the mouse is locked in this control.\n"
  2112. "@return True if the mouse is currently locked.\n" )
  2113. {
  2114. return object->isMouseLocked();
  2115. }
  2116. //-----------------------------------------------------------------------------
  2117. DefineEngineMethod( GuiControl, setValue, void, ( const char* value ),,
  2118. "Set the value associated with the control.\n"
  2119. "@param value The new value for the control.\n" )
  2120. {
  2121. object->setScriptValue( value );
  2122. }
  2123. DefineEngineMethod( GuiControl, getValue, const char*, (),,
  2124. "Get the value associated with the control.\n"
  2125. "@return value for the control.\n" )
  2126. {
  2127. return object->getScriptValue();
  2128. }
  2129. DefineEngineMethod( GuiControl, makeFirstResponder, void, ( bool isFirst ),,
  2130. "Make this control the first responder.\n"
  2131. "@param isFirst True to make first responder, false to not.\n" )
  2132. {
  2133. //object->makeFirstResponder(dAtob(argv[2]));
  2134. object->makeFirstResponder(isFirst);
  2135. }
  2136. DefineEngineMethod( GuiControl, isActive, bool, (),,
  2137. "Check if this control is active or not.\n"
  2138. "@return True if it's active, false if not.\n" )
  2139. {
  2140. return object->isActive();
  2141. }
  2142. //-----------------------------------------------------------------------------
  2143. DefineEngineMethod( GuiControl, setActive, void, ( bool state ), ( true ),
  2144. "Set the control as active or inactive."
  2145. "@param state True to set the control as active, false to set it as inactive.")
  2146. {
  2147. object->setActive( state );
  2148. }
  2149. //-----------------------------------------------------------------------------
  2150. DefineEngineMethod( GuiControl, isVisible, bool, (),,
  2151. "Test whether the control is currently set to be visible.\n"
  2152. "@return True if the control is currently set to be visible."
  2153. "@note This method does not tell anything about whether the control is actually visible to "
  2154. "the user at the moment.\n\n"
  2155. "@ref GuiControl_VisibleActive" )
  2156. {
  2157. return object->isVisible();
  2158. }
  2159. //-----------------------------------------------------------------------------
  2160. DefineEngineMethod( GuiControl, setVisible, void, ( bool state ), ( true ),
  2161. "Set whether the control is visible or not.\n"
  2162. "@param state The new visiblity flag state for the control.\n"
  2163. "@ref GuiControl_VisibleActive" )
  2164. {
  2165. object->setVisible( state );
  2166. }
  2167. //-----------------------------------------------------------------------------
  2168. DefineEngineMethod( GuiControl, isAwake, bool, (),,
  2169. "Test whether the control is currently awake.\n"
  2170. "If a control is awake it means that it is part of the GuiControl hierarchy of a GuiCanvas.\n"
  2171. "@return True if the control is awake."
  2172. "@ref GuiControl_Waking" )
  2173. {
  2174. return object->isAwake();
  2175. }
  2176. //-----------------------------------------------------------------------------
  2177. DefineEngineMethod( GuiControl, setProfile, void, ( GuiControlProfile* profile ),,
  2178. "Set the control profile for the control to use.\n"
  2179. "The profile used by a control determines a great part of its behavior and appearance.\n"
  2180. "@param profile The new profile the control should use.\n"
  2181. "@ref GuiControl_Profiles" )
  2182. {
  2183. if( !profile )
  2184. return;
  2185. object->setControlProfile( profile );
  2186. }
  2187. //-----------------------------------------------------------------------------
  2188. DefineEngineMethod( GuiControl, resize, void, ( S32 x, S32 y, S32 width, S32 height ),,
  2189. "Resize and reposition the control using the give coordinates and dimensions. Child controls "
  2190. "will resize according to their layout behaviors.\n"
  2191. "@param x The new X coordinate of the control in its parent's coordinate space.\n"
  2192. "@param y The new Y coordinate of the control in its parent's coordinate space.\n"
  2193. "@param width The new width to which the control should be resized.\n"
  2194. "@param height The new height to which the control should be resized." )
  2195. {
  2196. Point2I newPos( x, y );
  2197. Point2I newExt( width, height );
  2198. object->resize(newPos, newExt);
  2199. }
  2200. //-----------------------------------------------------------------------------
  2201. DefineEngineMethod( GuiControl, getPosition, Point2I, (),,
  2202. "Get the control's current position relative to its parent.\n"
  2203. "@return The coordinate of the control in its parent's coordinate space." )
  2204. {
  2205. return object->getPosition();
  2206. }
  2207. //-----------------------------------------------------------------------------
  2208. DefineEngineMethod( GuiControl, getCenter, Point2I, (),,
  2209. "Get the coordinate of the control's center point relative to its parent.\n"
  2210. "@return The coordinate of the control's center point in parent-relative coordinates." )
  2211. {
  2212. const Point2I pos = object->getPosition();
  2213. const Point2I ext = object->getExtent();
  2214. Point2I center( pos.x + ext.x / 2, pos.y + ext.y / 2 );
  2215. return center;
  2216. }
  2217. //-----------------------------------------------------------------------------
  2218. DefineEngineMethod( GuiControl, setCenter, void, ( S32 x, S32 y ),,
  2219. "Set the control's position by its center point.\n"
  2220. "@param x The X coordinate of the new center point of the control relative to the control's parent.\n"
  2221. "@param y The Y coordinate of the new center point of the control relative to the control's parent." )
  2222. {
  2223. const Point2I ext = object->getExtent();
  2224. Point2I newpos( x - ext.x / 2, y - ext.y / 2 );
  2225. object->setPosition( newpos );
  2226. }
  2227. //-----------------------------------------------------------------------------
  2228. DefineEngineMethod( GuiControl, getGlobalCenter, Point2I, (),,
  2229. "Get the coordinate of the control's center point in coordinates relative to the root control in its control hierarchy.\n"
  2230. "@Return the center coordinate of the control in root-relative coordinates.\n" )
  2231. {
  2232. const Point2I tl( 0, 0 );
  2233. Point2I pos = object->localToGlobalCoord( tl );
  2234. const Point2I ext = object->getExtent();
  2235. Point2I center( pos.x + ext.x / 2, pos.y + ext.y / 2 );
  2236. return center;
  2237. }
  2238. //-----------------------------------------------------------------------------
  2239. DefineEngineMethod( GuiControl, getGlobalPosition, Point2I, (),,
  2240. "Get the position of the control relative to the root of the GuiControl hierarchy it is contained in.\n"
  2241. "@return The control's current position in root-relative coordinates." )
  2242. {
  2243. const Point2I pos(0,0);
  2244. return object->localToGlobalCoord(pos);
  2245. }
  2246. //-----------------------------------------------------------------------------
  2247. DefineEngineMethod( GuiControl, setPositionGlobal, void, ( S32 x, S32 y ),,
  2248. "Set position of the control relative to the root of the GuiControl hierarchy it is contained in.\n"
  2249. "@param x The new X coordinate of the control relative to the root's upper left corner.\n"
  2250. "@param y The new Y coordinate of the control relative to the root's upper left corner." )
  2251. {
  2252. //see if we can turn the x/y into ints directly,
  2253. Point2I lPosOffset = object->globalToLocalCoord( Point2I( x, y ) );
  2254. lPosOffset += object->getPosition();
  2255. object->setPosition( lPosOffset );
  2256. }
  2257. //-----------------------------------------------------------------------------
  2258. DefineEngineMethod( GuiControl, setPosition, void, ( S32 x, S32 y ),,
  2259. "Position the control in the local space of the parent control.\n"
  2260. "@param x The new X coordinate of the control relative to its parent's upper left corner.\n"
  2261. "@param y The new Y coordinate of the control relative to its parent's upper left corner." )
  2262. {
  2263. object->setPosition( Point2I( x, y ) );
  2264. }
  2265. //-----------------------------------------------------------------------------
  2266. DefineEngineMethod( GuiControl, getExtent, Point2I, (),,
  2267. "Get the width and height of the control.\n"
  2268. "@return A point structure containing the width of the control in x and the height in y." )
  2269. {
  2270. return object->getExtent();
  2271. }
  2272. //-----------------------------------------------------------------------------
  2273. static ConsoleDocFragment _sGuiControlSetExtent1(
  2274. "@brief Resize the control to the given dimensions.\n\n"
  2275. "Child controls will resize according to their layout settings.\n"
  2276. "@param width The new width of the control in pixels.\n"
  2277. "@param height The new height of the control in pixels.",
  2278. "GuiControl", // The class to place the method in; use NULL for functions.
  2279. "void setExtent( S32 width, S32 height );" ); // The definition string.
  2280. static ConsoleDocFragment _sGuiControlSetExtent2(
  2281. "@brief Resize the control to the given dimensions.\n\n"
  2282. "Child controls with resize according to their layout settings.\n"
  2283. "@param p The new ( width, height ) extents of the control.",
  2284. "GuiControl", // The class to place the method in; use NULL for functions.
  2285. "void setExtent( Point2I p );" ); // The definition string.
  2286. DefineEngineMethod( GuiControl, setExtent, void, ( const char* extOrX, const char* y ), ("", nullAsType<const char*>()),
  2287. "( Point2I p | int x, int y ) Set the width and height of the control.\n\n"
  2288. "@hide" )
  2289. {
  2290. Point2I extent;
  2291. if(!String::isEmpty(extOrX) && String::isEmpty(y))
  2292. dSscanf(extOrX, "%d %d", &extent.x, &extent.y);
  2293. else if(!String::isEmpty(extOrX) && !String::isEmpty(y))
  2294. {
  2295. extent.x = dAtoi(extOrX);
  2296. extent.y = dAtoi(y);
  2297. }
  2298. object->setExtent( extent );
  2299. }
  2300. //-----------------------------------------------------------------------------
  2301. DefineEngineMethod( GuiControl, getMinExtent, Point2I, (),,
  2302. "Get the minimum allowed size of the control.\n"
  2303. "@return The minimum size to which the control can be shrunk.\n"
  2304. "@see minExtent" )
  2305. {
  2306. return object->getMinExtent();
  2307. }
  2308. //-----------------------------------------------------------------------------
  2309. DefineEngineMethod( GuiControl, getAspect, F32, (),,
  2310. "Get the aspect ratio of the control's extents.\n"
  2311. "@return The width of the control divided by its height.\n"
  2312. "@see getExtent" )
  2313. {
  2314. const Point2I &ext = object->getExtent();
  2315. return (F32)ext.x / (F32)ext.y;
  2316. }