guiControl.cpp 86 KB

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