guiCanvas.cpp 89 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  23. // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
  24. // Copyright (C) 2015 Faust Logic, Inc.
  25. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  26. #include "platform/platform.h"
  27. #include "gui/core/guiCanvas.h"
  28. #include "console/console.h"
  29. #include "console/engineAPI.h"
  30. #include "platform/profiler.h"
  31. #include "gfx/gfxDevice.h"
  32. #include "gfx/gfxDrawUtil.h"
  33. #include "gui/core/guiTypes.h"
  34. #include "gui/core/guiControl.h"
  35. #include "gui/editor/guiMenuBar.h"
  36. #include "console/consoleTypes.h"
  37. #include "gfx/screenshot.h"
  38. #include "gfx/video/videoCapture.h"
  39. #include "lighting/lightManager.h"
  40. #include "core/strings/stringUnit.h"
  41. #include "gui/core/guiOffscreenCanvas.h"
  42. #ifndef TORQUE_TGB_ONLY
  43. #include "scene/sceneObject.h"
  44. #endif
  45. #include "gfx/gfxInit.h"
  46. #include "core/util/journal/process.h"
  47. #ifdef TORQUE_GFX_STATE_DEBUG
  48. #include "gfx/gfxDebugStateTracker.h"
  49. #endif
  50. IMPLEMENT_CONOBJECT(GuiCanvas);
  51. ConsoleDocClass( GuiCanvas,
  52. "@brief A canvas on which rendering occurs.\n\n"
  53. "@section GuiCanvas_contents What a GUICanvas Can Contain...\n\n"
  54. "@subsection GuiCanvas_content_contentcontrol Content Control\n"
  55. "A content control is the top level GuiControl for a screen. This GuiControl "
  56. "will be the parent control for all other GuiControls on that particular "
  57. "screen.\n\n"
  58. "@subsection GuiCanvas_content_dialogs Dialogs\n\n"
  59. "A dialog is essentially another screen, only it gets overlaid on top of the "
  60. "current content control, and all input goes to the dialog. This is most akin "
  61. "to the \"Open File\" dialog box found in most operating systems. When you "
  62. "choose to open a file, and the \"Open File\" dialog pops up, you can no longer "
  63. "send input to the application, and must complete or cancel the open file "
  64. "request. Torque keeps track of layers of dialogs. The dialog with the highest "
  65. "layer is on top and will get all the input, unless the dialog is "
  66. "modeless, which is a profile option.\n\n"
  67. "@see GuiControlProfile\n\n"
  68. "@section GuiCanvas_dirty Dirty Rectangles\n\n"
  69. "The GuiCanvas is based on dirty regions. "
  70. "Every frame the canvas paints only the areas of the canvas that are 'dirty' "
  71. "or need updating. In most cases, this only is the area under the mouse cursor. "
  72. "This is why if you look in guiCanvas.cc the call to glClear is commented out. "
  73. "What you will see is a black screen, except in the dirty regions, where the "
  74. "screen will be painted normally. If you are making an animated GuiControl "
  75. "you need to add your control to the dirty areas of the canvas.\n\n"
  76. "@see GuiControl\n\n"
  77. "@ingroup GuiCore\n");
  78. ImplementEnumType(KeyboardTranslationMode,
  79. "Modes for handling keyboard translation or native accelerator requests.\n\n")
  80. { GuiCanvas::TranslationMode_Platform, "Platform",
  81. "Requests will be passed to the platform window for handling." },
  82. { GuiCanvas::TranslationMode_Callback, "Callback",
  83. "Script callbacks will be issued to notify and allow override of these events." },
  84. { GuiCanvas::TranslationMode_Ignore, "Ignore",
  85. "Requsts to enable/disable keyboard translations or native accelerators will be ignored "
  86. "with no callback triggered." },
  87. EndImplementEnumType;
  88. IMPLEMENT_CALLBACK(GuiCanvas, onSetKeyboardTranslationEnabled, bool, (bool enable), (enable),
  89. "Called when the canvas receives an enableKeyboardTranslation request. This is usually the "
  90. "result of a GuitTextInputCtrl gaining or losing focus. Return true to allow the request "
  91. "to be passed to the platform window. Return false to override the request and handle it in script.\n\n"
  92. "@note This callback is only issued if keyTranslationMode is set to \"Callback\" for this canvas.\n"
  93. "@param enable Requested keyboard translation state.\n"
  94. "@see KeyboardTranslationMode\n");
  95. IMPLEMENT_CALLBACK(GuiCanvas, onSetNativeAcceleratorsEnabled, bool, (bool enable), (enable),
  96. "Called when the canvas receives a setNativeAcceleratorsEnabled request. This is usually the "
  97. "result of a GuitTextInputCtrl gaining or losing focus. Return true to allow the request to "
  98. "be passed to the platform window. Return false to override the request and handle it in script.\n\n"
  99. "@note This callback is only issued if nativeAcceleratorMode is set to \"Callback\" for this canvas.\n"
  100. "@param enable Requested accelerator state.\n"
  101. "@see KeyboardTranslationMode\n");
  102. ColorI gCanvasClearColor( 255, 0, 255 ); ///< For GFX->clear
  103. extern InputModifiers convertModifierBits(const U32 in);
  104. //-----------------------------------------------------------------------------
  105. GuiCanvas::GuiCanvas(): GuiControl(),
  106. mCurUpdateRect(0, 0, 0, 0),
  107. mCursorEnabled(true),
  108. mForceMouseToGUI(false),
  109. mAlwaysHandleMouseButtons(false),
  110. mShowCursor(true),
  111. mClampTorqueCursor(true),
  112. mCursorChanged(0),
  113. mLastCursorEnabled(false),
  114. mMouseCapturedControl(NULL),
  115. mMouseControl(NULL),
  116. mMouseControlClicked(false),
  117. mMouseButtonDown(false),
  118. mMouseRightButtonDown(false),
  119. mDefaultCursor(NULL),
  120. mMouseMiddleButtonDown(false),
  121. mCursorPt(0,0),
  122. mLastCursorPt(0,0),
  123. mLastCursor(NULL),
  124. mLastMouseClickCount(0),
  125. mRenderFront(false),
  126. mPrevMouseTime(0),
  127. mLastMouseDownTime(0),
  128. mHoverControl(NULL),
  129. mHoverPositionSet(false),
  130. mLeftMouseLast(false),
  131. mHoverLeftControlTime(0),
  132. mKeyTranslationMode(TranslationMode_Platform),
  133. mNativeAcceleratorMode(TranslationMode_Platform),
  134. mMiddleMouseLast(false),
  135. mRightMouseLast(false),
  136. mMouseDownPoint(0.0f,0.0f),
  137. mLastRenderMs(0),
  138. mPlatformWindow(NULL),
  139. mDisplayWindow(true),
  140. mMenuBarCtrl(nullptr),
  141. mMenuBackground(nullptr)
  142. {
  143. setBounds(0, 0, 640, 480);
  144. mAwake = true;
  145. mHoverControlStart = Platform::getRealMilliseconds();
  146. mHoverPosition = getCursorPos();
  147. mFences = NULL;
  148. mNextFenceIdx = -1;
  149. #ifndef _XBOX
  150. mNumFences = Con::getIntVariable( "$pref::Video::defaultFenceCount", 0 );
  151. #else
  152. mNumFences = 0;
  153. #endif
  154. mConsumeLastInputEvent = false;
  155. }
  156. GuiCanvas::~GuiCanvas()
  157. {
  158. SAFE_DELETE(mPlatformWindow);
  159. SAFE_DELETE_ARRAY( mFences );
  160. }
  161. //------------------------------------------------------------------------------
  162. bool GuiCanvas::setProtectedNumFences( void *object, const char *index, const char *data)
  163. {
  164. GuiCanvas *canvas = reinterpret_cast<GuiCanvas *>( object );
  165. canvas->mNumFences = dAtoi( data );
  166. canvas->setupFences();
  167. return false;
  168. }
  169. void GuiCanvas::initPersistFields()
  170. {
  171. docsURL;
  172. addGroup("Mouse Handling");
  173. addField("alwaysHandleMouseButtons", TypeBool, Offset(mAlwaysHandleMouseButtons, GuiCanvas),
  174. "Deal with mouse buttons, even if the cursor is hidden." );
  175. endGroup("Mouse Handling");
  176. addGroup("Canvas Rendering");
  177. addProtectedField( "numFences", TypeS32, Offset( mNumFences, GuiCanvas ), &setProtectedNumFences, &defaultProtectedGetFn, "The number of GFX fences to use." );
  178. addField("displayWindow", TypeBool, Offset(mDisplayWindow, GuiCanvas), "Controls if the canvas window is rendered or not." );
  179. endGroup("Canvas Rendering");
  180. addGroup("KeyboardMode Callbacks");
  181. addField("keyTranslationMode", TYPEID< KeyTranslationMode >(), Offset(mKeyTranslationMode, GuiCanvas),
  182. "How to handle enable/disable keyboard translation requests. \"Platform\", \"Callback\" or \"Ignore\".\n");
  183. addField("nativeAcceleratorMode", TYPEID< KeyTranslationMode >(), Offset(mNativeAcceleratorMode, GuiCanvas),
  184. "How to handle enable/disable native accelerator requests. \"Platform\", \"Callback\" or \"Ignore\".\n");
  185. endGroup("KeyboardMode Callbacks");
  186. Parent::initPersistFields();
  187. }
  188. //------------------------------------------------------------------------------
  189. bool GuiCanvas::onAdd()
  190. {
  191. // ensure that we have a cursor
  192. setCursor(dynamic_cast<GuiCursor*>(Sim::findObject("DefaultCursor")));
  193. // Enumerate things for GFX before we have an active device.
  194. GFXInit::enumerateAdapters();
  195. // Create a device.
  196. GFXAdapter *a = GFXInit::getBestAdapterChoice();
  197. // Do we have a global device already? (This is the site if you want
  198. // to start rendering to multiple devices simultaneously)
  199. GFXDevice *newDevice = GFX;
  200. if(newDevice == NULL)
  201. newDevice = GFXInit::createDevice(a);
  202. newDevice->setAllowRender( false );
  203. // Disable starting a new journal recording or playback from here on
  204. Journal::Disable();
  205. // Initialize the window...
  206. GFXVideoMode vm = GFXInit::getInitialVideoMode();
  207. //If we're recording, store the intial video resolution
  208. if (Journal::IsRecording())
  209. {
  210. Journal::Write(vm.resolution.x);
  211. Journal::Write(vm.resolution.y);
  212. Journal::Write(vm.fullScreen);
  213. }
  214. //If we're playing, read the intial video resolution from the journal
  215. if (Journal::IsPlaying())
  216. {
  217. Journal::Read(&vm.resolution.x);
  218. Journal::Read(&vm.resolution.y);
  219. Journal::Read(&vm.fullScreen);
  220. }
  221. if (a && a->mType != NullDevice)
  222. {
  223. mPlatformWindow = WindowManager->createWindow(newDevice, vm);
  224. //Disable window resizing if recording ir playing a journal
  225. if (Journal::IsRecording() || Journal::IsPlaying())
  226. mPlatformWindow->lockSize(true);
  227. // Set a minimum on the window size so people can't break us by resizing tiny.
  228. mPlatformWindow->setMinimumWindowSize(Point2I(Con::getIntVariable("$Video::minimumXResolution", 1024),
  229. Con::getIntVariable("$Video::minimumYResolution", 720)));
  230. // Now, we have to hook in our event callbacks so we'll get
  231. // appropriate events from the window.
  232. mPlatformWindow->resizeEvent .notify(this, &GuiCanvas::handleResize);
  233. mPlatformWindow->appEvent .notify(this, &GuiCanvas::handleAppEvent);
  234. mPlatformWindow->displayEvent.notify(this, &GuiCanvas::handlePaintEvent);
  235. mPlatformWindow->setInputController( dynamic_cast<IProcessInput*>(this) );
  236. }
  237. // Need to get painted, too! :)
  238. Process::notify(this, &GuiCanvas::paint, PROCESS_RENDER_ORDER);
  239. // Set up the fences
  240. setupFences();
  241. // Make sure we're able to render.
  242. newDevice->setAllowRender( true );
  243. // NULL device returns a nullptr for getPlatformWindow
  244. PlatformWindow* window = getPlatformWindow();
  245. if (mDisplayWindow && window)
  246. {
  247. window->show();
  248. WindowManager->setDisplayWindow(true);
  249. window->setDisplayWindow(true);
  250. }
  251. else if (window)
  252. {
  253. window->hide();
  254. WindowManager->setDisplayWindow(false);
  255. window->setDisplayWindow(false);
  256. }
  257. // Propagate add to parents.
  258. // CodeReview - if GuiCanvas fails to add for whatever reason, what happens to
  259. // all the event registration above?
  260. bool parentRet = Parent::onAdd();
  261. // Define the menu bar for this canvas (if any)
  262. Con::executef(this, "onCreateMenu");
  263. return parentRet;
  264. }
  265. void GuiCanvas::onRemove()
  266. {
  267. // And the process list
  268. Process::remove(this, &GuiCanvas::paint);
  269. // Destroy the menu bar for this canvas (if any)
  270. Con::executef(this, "onDestroyMenu");
  271. Parent::onRemove();
  272. }
  273. #ifdef TORQUE_TOOLS
  274. void GuiCanvas::setMenuBar(SimObject *obj)
  275. {
  276. GuiControl *oldMenuBar = mMenuBarCtrl;
  277. mMenuBarCtrl = dynamic_cast<GuiControl*>(obj);
  278. //remove old menubar
  279. if (oldMenuBar)
  280. {
  281. Parent::removeObject(oldMenuBar);
  282. Parent::removeObject(mMenuBackground); //also remove the modeless wrapper
  283. }
  284. // set new menubar
  285. if (mMenuBarCtrl)
  286. {
  287. //Add a wrapper control so that the menubar sizes correctly
  288. GuiControlProfile* profile;
  289. Sim::findObject("GuiModelessDialogProfile", profile);
  290. if (!profile)
  291. {
  292. Con::errorf("GuiCanvas::setMenuBar: Unable to find the GuiModelessDialogProfile profile!");
  293. return;
  294. }
  295. if (mMenuBackground == nullptr)
  296. {
  297. mMenuBackground = new GuiControl();
  298. mMenuBackground->registerObject();
  299. mMenuBackground->setControlProfile(profile);
  300. }
  301. mMenuBackground->addObject(mMenuBarCtrl);
  302. Parent::addObject(mMenuBackground);
  303. }
  304. // update window accelerator keys
  305. if( oldMenuBar != mMenuBarCtrl )
  306. {
  307. GuiMenuBar* oldMenu = dynamic_cast<GuiMenuBar*>(oldMenuBar);
  308. GuiMenuBar* newMenu = dynamic_cast<GuiMenuBar*>(mMenuBarCtrl);
  309. if(oldMenu)
  310. oldMenu->removeWindowAcceleratorMap(*getPlatformWindow()->getInputGenerator());
  311. if(newMenu)
  312. newMenu->buildWindowAcceleratorMap(*getPlatformWindow()->getInputGenerator());
  313. }
  314. }
  315. #endif
  316. void GuiCanvas::setWindowTitle(const char *newTitle)
  317. {
  318. if (mPlatformWindow)
  319. mPlatformWindow->setCaption(newTitle);
  320. }
  321. CanvasSizeChangeSignal GuiCanvas::smCanvasSizeChangeSignal;
  322. void GuiCanvas::handleResize( WindowId did, S32 width, S32 height )
  323. {
  324. getCanvasSizeChangeSignal().trigger(this);
  325. if (Journal::IsPlaying() && mPlatformWindow)
  326. {
  327. mPlatformWindow->lockSize(false);
  328. mPlatformWindow->setSize(Point2I(width, height));
  329. mPlatformWindow->lockSize(true);
  330. }
  331. // Notify the scripts
  332. if ( isMethod( "onResize" ) )
  333. Con::executef( this, "onResize", Con::getIntArg( width ), Con::getIntArg( height ) );
  334. }
  335. void GuiCanvas::handlePaintEvent(WindowId did)
  336. {
  337. bool canRender = mPlatformWindow->isVisible() && GFX->allowRender() && !GFX->canCurrentlyRender();
  338. // Do the screenshot first.
  339. if ( gScreenShot != NULL && gScreenShot->isPending() && canRender )
  340. gScreenShot->capture( this );
  341. // If the video capture is waiting for a canvas, start the capture
  342. if ( VIDCAP->isWaitingForCanvas() && canRender )
  343. VIDCAP->begin( this );
  344. // Now capture the video
  345. if ( VIDCAP->isRecording() && canRender )
  346. VIDCAP->capture();
  347. renderFrame(false);
  348. }
  349. void GuiCanvas::handleAppEvent( WindowId did, S32 event )
  350. {
  351. // Notify script if we gain or lose focus.
  352. if(event == LoseFocus)
  353. {
  354. if(isMethod("onLoseFocus"))
  355. Con::executef(this, "onLoseFocus");
  356. }
  357. if(event == GainFocus)
  358. {
  359. if(isMethod("onGainFocus"))
  360. Con::executef(this, "onGainFocus");
  361. }
  362. if(event == WindowClose || event == WindowDestroy)
  363. {
  364. if(isMethod("onWindowClose"))
  365. {
  366. // First see if there is a method on this window to handle
  367. // it's closure
  368. Con::executef(this,"onWindowClose");
  369. }
  370. else if(Con::isFunction("onWindowClose"))
  371. {
  372. // otherwise check to see if there is a global function handling it
  373. Con::executef("onWindowClose", getIdString());
  374. }
  375. else
  376. {
  377. // Else just shutdown
  378. Process::requestShutdown();
  379. }
  380. }
  381. }
  382. Point2I GuiCanvas::getWindowSize()
  383. {
  384. // CodeReview Asserting on this breaks previous logic
  385. // and code assumptions. It seems logical that we would
  386. // handle this and return an error value rather than implementing
  387. // if(!mPlatformWindow) whenever we need to call getWindowSize.
  388. // This should help keep our API error free and easy to use, while
  389. // cutting down on code duplication for sanity checking. [5/5/2007 justind]
  390. if( !mPlatformWindow )
  391. return Point2I(-1,-1);
  392. return mPlatformWindow->getClientExtent();
  393. }
  394. void GuiCanvas::enableKeyboardTranslation()
  395. {
  396. if ((mKeyTranslationMode == TranslationMode_Platform) ||
  397. ((mKeyTranslationMode == TranslationMode_Callback) && onSetKeyboardTranslationEnabled_callback(true)))
  398. {
  399. AssertISV(mPlatformWindow, "GuiCanvas::enableKeyboardTranslation - no window present!");
  400. mPlatformWindow->setKeyboardTranslation(true);
  401. }
  402. }
  403. void GuiCanvas::disableKeyboardTranslation()
  404. {
  405. if ((mKeyTranslationMode == TranslationMode_Platform) ||
  406. ((mKeyTranslationMode == TranslationMode_Callback) && onSetKeyboardTranslationEnabled_callback(false)))
  407. {
  408. AssertISV(mPlatformWindow, "GuiCanvas::disableKeyboardTranslation - no window present!");
  409. mPlatformWindow->setKeyboardTranslation(false);
  410. }
  411. }
  412. void GuiCanvas::setNativeAcceleratorsEnabled( bool enabled )
  413. {
  414. if ((mNativeAcceleratorMode == TranslationMode_Platform) ||
  415. ((mNativeAcceleratorMode == TranslationMode_Callback) && onSetNativeAcceleratorsEnabled_callback(enabled)))
  416. {
  417. AssertISV(mPlatformWindow, "GuiCanvas::setNativeAcceleratorsEnabled - no window present!");
  418. mPlatformWindow->setAcceleratorsEnabled(enabled);
  419. }
  420. }
  421. void GuiCanvas::setForceMouseToGUI(bool onOff)
  422. {
  423. mForceMouseToGUI = onOff;
  424. }
  425. void GuiCanvas::setClampTorqueCursor(bool onOff)
  426. {
  427. mClampTorqueCursor = onOff;
  428. }
  429. void GuiCanvas::setCursor(GuiCursor *curs)
  430. {
  431. mDefaultCursor = curs;
  432. }
  433. void GuiCanvas::setCursorON(bool onOff)
  434. {
  435. mCursorEnabled = onOff;
  436. if(!mCursorEnabled)
  437. mMouseControl = NULL;
  438. }
  439. Point2I GuiCanvas::getCursorPos()
  440. {
  441. Point2I p( 0, 0 );
  442. if( mPlatformWindow )
  443. mPlatformWindow->getCursorPosition( p );
  444. return p;
  445. }
  446. void GuiCanvas::setCursorPos(const Point2I &pt)
  447. {
  448. AssertISV(mPlatformWindow, "GuiCanvas::setCursorPos - no window present!");
  449. if ( mPlatformWindow->isMouseLocked() )
  450. {
  451. mCursorPt.x = F32( pt.x );
  452. mCursorPt.y = F32( pt.y );
  453. }
  454. else
  455. {
  456. mPlatformWindow->setCursorPosition(pt.x, pt.y);
  457. }
  458. }
  459. void GuiCanvas::showCursor(bool state)
  460. {
  461. mShowCursor = state;
  462. mPlatformWindow->setCursorVisible( state );
  463. }
  464. bool GuiCanvas::isCursorShown()
  465. {
  466. if ( !mPlatformWindow->getCursorController() )
  467. {
  468. return mShowCursor;
  469. }
  470. return mPlatformWindow->isCursorVisible();
  471. }
  472. void GuiCanvas::cursorClick(S32 buttonId, bool isDown)
  473. {
  474. InputEventInfo inputEvent;
  475. inputEvent.deviceType = MouseDeviceType;
  476. inputEvent.deviceInst = 0;
  477. inputEvent.objType = SI_BUTTON;
  478. inputEvent.objInst = (InputObjectInstances)(KEY_BUTTON0 + buttonId);
  479. inputEvent.modifier = (InputModifiers)0;
  480. inputEvent.ascii = 0;
  481. inputEvent.action = isDown ? SI_MAKE : SI_BREAK;
  482. inputEvent.fValue = isDown ? 1.0 : 0.0;
  483. processMouseEvent(inputEvent);
  484. }
  485. void GuiCanvas::cursorNudge(F32 x, F32 y)
  486. {
  487. // Generate a base Movement along and Axis event
  488. InputEventInfo inputEvent;
  489. inputEvent.deviceType = MouseDeviceType;
  490. inputEvent.deviceInst = 0;
  491. inputEvent.objType = SI_AXIS;
  492. inputEvent.modifier = (InputModifiers)0;
  493. inputEvent.ascii = 0;
  494. // Generate delta movement along each axis
  495. Point2F cursDelta(x, y);
  496. // If X axis changed, generate a relative event
  497. if(mFabs(cursDelta.x) > 0.1)
  498. {
  499. inputEvent.objInst = SI_XAXIS;
  500. inputEvent.action = SI_MOVE;
  501. inputEvent.fValue = cursDelta.x;
  502. processMouseEvent(inputEvent);
  503. }
  504. // If Y axis changed, generate a relative event
  505. if(mFabs(cursDelta.y) > 0.1)
  506. {
  507. inputEvent.objInst = SI_YAXIS;
  508. inputEvent.action = SI_MOVE;
  509. inputEvent.fValue = cursDelta.y;
  510. processMouseEvent(inputEvent);
  511. }
  512. processMouseEvent(inputEvent);
  513. }
  514. void GuiCanvas::addAcceleratorKey(GuiControl *ctrl, U32 index, U32 keyCode, U32 modifier)
  515. {
  516. if (keyCode > 0 && ctrl)
  517. {
  518. AccKeyMap newMap;
  519. newMap.ctrl = ctrl;
  520. newMap.index = index;
  521. newMap.keyCode = keyCode;
  522. newMap.modifier = modifier;
  523. mAcceleratorMap.push_back(newMap);
  524. }
  525. }
  526. bool GuiCanvas::tabNext(void)
  527. {
  528. GuiControl *ctrl = static_cast<GuiControl *>(last());
  529. if (ctrl)
  530. {
  531. //save the old
  532. GuiControl *oldResponder = mFirstResponder;
  533. GuiControl* newResponder = ctrl->findNextTabable(mFirstResponder);
  534. if ( !newResponder )
  535. newResponder = ctrl->findFirstTabable();
  536. if ( newResponder && newResponder != oldResponder )
  537. {
  538. newResponder->setFirstResponder();
  539. // CodeReview Can this get killed? Note tabPrev code. BJG - 3/25/07
  540. // if ( oldResponder )
  541. // oldResponder->onLoseFirstResponder();
  542. return true;
  543. }
  544. }
  545. return false;
  546. }
  547. bool GuiCanvas::tabPrev(void)
  548. {
  549. GuiControl *ctrl = static_cast<GuiControl *>(last());
  550. if (ctrl)
  551. {
  552. //save the old
  553. GuiControl *oldResponder = mFirstResponder;
  554. GuiControl* newResponder = ctrl->findPrevTabable(mFirstResponder);
  555. if ( !newResponder )
  556. newResponder = ctrl->findLastTabable();
  557. if ( newResponder && newResponder != oldResponder )
  558. {
  559. newResponder->setFirstResponder();
  560. // CodeReview As with tabNext() above, looks like this can now go. DAW - 7/05/09
  561. //if ( oldResponder )
  562. // oldResponder->onLoseFirstResponder();
  563. return true;
  564. }
  565. }
  566. return false;
  567. }
  568. bool GuiCanvas::processInputEvent(InputEventInfo &inputEvent)
  569. {
  570. mConsumeLastInputEvent = true;
  571. // First call the general input handler (on the extremely off-chance that it will be handled):
  572. if (mFirstResponder && mFirstResponder->onInputEvent(inputEvent))
  573. {
  574. return mConsumeLastInputEvent;
  575. }
  576. switch (inputEvent.deviceType)
  577. {
  578. case KeyboardDeviceType:
  579. return processKeyboardEvent(inputEvent);
  580. break;
  581. case GamepadDeviceType:
  582. return processGamepadEvent(inputEvent);
  583. break;
  584. case MouseDeviceType:
  585. if (mCursorEnabled || mForceMouseToGUI ||
  586. (mAlwaysHandleMouseButtons && inputEvent.objType == SI_BUTTON) )
  587. {
  588. return processMouseEvent(inputEvent);
  589. }
  590. break;
  591. default:
  592. break;
  593. }
  594. return false;
  595. }
  596. bool GuiCanvas::processKeyboardEvent(InputEventInfo &inputEvent)
  597. {
  598. mLastEvent.ascii = inputEvent.ascii;
  599. mLastEvent.modifier = inputEvent.modifier;
  600. mLastEvent.keyCode = inputEvent.objInst;
  601. // Combine left/right shift bits - if one shift modifier key
  602. // bit is set, then set the other one. This way we can simplify
  603. // our processing logic by treating the keys identically.
  604. U32 eventModifier = inputEvent.modifier;
  605. if(eventModifier & SI_SHIFT)
  606. {
  607. eventModifier |= SI_SHIFT;
  608. }
  609. if(eventModifier & SI_CTRL)
  610. {
  611. eventModifier |= SI_CTRL;
  612. }
  613. if(eventModifier & SI_ALT)
  614. {
  615. eventModifier |= SI_ALT;
  616. }
  617. if (inputEvent.action == SI_MAKE)
  618. {
  619. //see if we should now pass the event to the first responder
  620. if (mFirstResponder)
  621. {
  622. if(mFirstResponder->onKeyDown(mLastEvent))
  623. return mConsumeLastInputEvent;
  624. }
  625. //see if we should tab next/prev
  626. if ( isCursorON() && ( inputEvent.objInst == KEY_TAB ) )
  627. {
  628. if (size() > 0)
  629. {
  630. if (inputEvent.modifier & SI_SHIFT)
  631. {
  632. if(tabPrev())
  633. return mConsumeLastInputEvent;
  634. }
  635. else if (inputEvent.modifier == 0)
  636. {
  637. if(tabNext())
  638. return mConsumeLastInputEvent;
  639. }
  640. }
  641. }
  642. //if not handled, search for an accelerator
  643. for (U32 i = 0; i < mAcceleratorMap.size(); i++)
  644. {
  645. if ((U32)mAcceleratorMap[i].keyCode == (U32)inputEvent.objInst && (U32)mAcceleratorMap[i].modifier == eventModifier)
  646. {
  647. mAcceleratorMap[i].ctrl->acceleratorKeyPress(mAcceleratorMap[i].index);
  648. return mConsumeLastInputEvent;
  649. }
  650. }
  651. }
  652. else if(inputEvent.action == SI_BREAK)
  653. {
  654. if(mFirstResponder && mFirstResponder->onKeyUp(mLastEvent))
  655. return mConsumeLastInputEvent;
  656. //see if there's an accelerator
  657. for (U32 i = 0; i < mAcceleratorMap.size(); i++)
  658. {
  659. if ((U32)mAcceleratorMap[i].keyCode == (U32)inputEvent.objInst && (U32)mAcceleratorMap[i].modifier == eventModifier)
  660. {
  661. mAcceleratorMap[i].ctrl->acceleratorKeyRelease(mAcceleratorMap[i].index);
  662. return mConsumeLastInputEvent;
  663. }
  664. }
  665. }
  666. else if(inputEvent.action == SI_REPEAT)
  667. {
  668. //if not handled, search for an accelerator
  669. for (U32 i = 0; i < mAcceleratorMap.size(); i++)
  670. {
  671. if ((U32)mAcceleratorMap[i].keyCode == (U32)inputEvent.objInst && (U32)mAcceleratorMap[i].modifier == eventModifier)
  672. {
  673. mAcceleratorMap[i].ctrl->acceleratorKeyPress(mAcceleratorMap[i].index);
  674. return mConsumeLastInputEvent;
  675. }
  676. }
  677. if(mFirstResponder)
  678. {
  679. bool ret = mFirstResponder->onKeyRepeat(mLastEvent);
  680. return ret && mConsumeLastInputEvent;
  681. }
  682. }
  683. return false;
  684. }
  685. bool GuiCanvas::processMouseEvent(InputEventInfo &inputEvent)
  686. {
  687. // [rene 09/09/10] This custom mouse cursor tracking that is happening here is bad. It will frequently
  688. // get ouf of step with where the cursor actually is. We really should *not* track the cursor; it's
  689. // just another thing that can/will go wrong. Let the input system pass us absolute screen coordinates
  690. // for every mouse event instead and work off that.
  691. //
  692. // 'mCursorPt' basically is an accumulation of errors and the number of bugs that have cropped up with
  693. // the GUI clicking stuff where it is not supposed to are probably all to blame on this.
  694. S32 mouseDoubleClickWidth = 12;
  695. S32 mouseDoubleClickHeight = 12;
  696. U32 mouseDoubleClickTime = 500;
  697. // Query platform for mouse info if its available
  698. PlatformCursorController *pController = mPlatformWindow ? mPlatformWindow->getCursorController() : NULL;
  699. if (pController)
  700. {
  701. mouseDoubleClickWidth = pController->getDoubleClickWidth();
  702. mouseDoubleClickHeight = pController->getDoubleClickHeight();
  703. mouseDoubleClickTime = pController->getDoubleClickTime();
  704. }
  705. //copy the modifier into the new event
  706. mLastEvent.modifier = inputEvent.modifier;
  707. if(inputEvent.objType == SI_AXIS &&
  708. (inputEvent.objInst == SI_XAXIS || inputEvent.objInst == SI_YAXIS))
  709. {
  710. // Set the absolute position if we get an SI_MAKE on an axis
  711. if( inputEvent.objInst == SI_XAXIS )
  712. {
  713. if( inputEvent.action == SI_MAKE )
  714. mCursorPt.x = (S32)inputEvent.fValue;
  715. else if( inputEvent.action == SI_MOVE )
  716. mCursorPt.x += (S32)inputEvent.fValue;
  717. mCursorPt.x = getMax(0, getMin((S32)mCursorPt.x, getBounds().extent.x - 1));
  718. }
  719. else if( inputEvent.objInst == SI_YAXIS )
  720. {
  721. if( inputEvent.action == SI_MAKE )
  722. mCursorPt.y = (S32)inputEvent.fValue;
  723. else if( inputEvent.action == SI_MOVE )
  724. mCursorPt.y += (S32)inputEvent.fValue;
  725. mCursorPt.y = getMax(0, getMin((S32)mCursorPt.y, getBounds().extent.y - 1));
  726. }
  727. // Store new cursor position.
  728. mLastEvent.mousePoint.x = S32(mCursorPt.x);
  729. mLastEvent.mousePoint.y = S32(mCursorPt.y);
  730. // See if we need to invalidate a possible dbl click due to the cursor
  731. // moving too much.
  732. Point2F movement = mMouseDownPoint - mCursorPt;
  733. if ((mAbs((S32)movement.x) > mouseDoubleClickWidth) || (mAbs((S32)movement.y) > mouseDoubleClickHeight ) )
  734. {
  735. mLeftMouseLast = false;
  736. mMiddleMouseLast = false;
  737. mRightMouseLast = false;
  738. }
  739. if (mMouseButtonDown)
  740. rootMouseDragged(mLastEvent);
  741. else if (mMouseRightButtonDown)
  742. rootRightMouseDragged(mLastEvent);
  743. else if(mMouseMiddleButtonDown)
  744. rootMiddleMouseDragged(mLastEvent);
  745. else
  746. rootMouseMove(mLastEvent);
  747. return mConsumeLastInputEvent;
  748. }
  749. else if ( inputEvent.objInst == SI_ZAXIS
  750. || inputEvent.objInst == SI_RZAXIS )
  751. {
  752. mLastEvent.mousePoint.x = S32( mCursorPt.x );
  753. mLastEvent.mousePoint.y = S32( mCursorPt.y );
  754. mLastEvent.fval = inputEvent.fValue;
  755. if( inputEvent.objInst == SI_ZAXIS )
  756. mLastEvent.mouseAxis = 1;
  757. else
  758. mLastEvent.mouseAxis = 0;
  759. if ( inputEvent.fValue < 0.0f )
  760. return rootMouseWheelDown( mLastEvent );
  761. else
  762. return rootMouseWheelUp( mLastEvent );
  763. }
  764. else if(inputEvent.objType == SI_BUTTON)
  765. {
  766. //copy the cursor point into the event
  767. mLastEvent.mousePoint.x = S32(mCursorPt.x);
  768. mLastEvent.mousePoint.y = S32(mCursorPt.y);
  769. mMouseDownPoint = mCursorPt;
  770. if(inputEvent.objInst == KEY_BUTTON0) // left button
  771. {
  772. //see if button was pressed
  773. if (inputEvent.action == SI_MAKE)
  774. {
  775. U32 curTime = Platform::getVirtualMilliseconds();
  776. //if the last button pressed was the left...
  777. if (mLeftMouseLast)
  778. {
  779. //if it was within the double click time count the clicks
  780. if (curTime - mLastMouseDownTime <= mouseDoubleClickTime)
  781. mLastMouseClickCount++;
  782. else
  783. mLastMouseClickCount = 1;
  784. }
  785. else
  786. {
  787. mLeftMouseLast = true;
  788. mLastMouseClickCount = 1;
  789. }
  790. mLastMouseDownTime = curTime;
  791. mLastEvent.mouseClickCount = mLastMouseClickCount;
  792. rootMouseDown(mLastEvent);
  793. }
  794. //else button was released
  795. else
  796. {
  797. rootMouseUp(mLastEvent);
  798. }
  799. return mConsumeLastInputEvent;
  800. }
  801. else if(inputEvent.objInst == KEY_BUTTON1) // right button
  802. {
  803. if(inputEvent.action == SI_MAKE)
  804. {
  805. U32 curTime = Platform::getVirtualMilliseconds();
  806. //if the last button pressed was the right...
  807. if (mRightMouseLast)
  808. {
  809. //if it was within the double click time count the clicks
  810. if (curTime - mLastMouseDownTime <= mouseDoubleClickTime)
  811. mLastMouseClickCount++;
  812. else
  813. mLastMouseClickCount = 1;
  814. }
  815. else
  816. {
  817. mRightMouseLast = true;
  818. mLastMouseClickCount = 1;
  819. }
  820. mLastMouseDownTime = curTime;
  821. mLastEvent.mouseClickCount = mLastMouseClickCount;
  822. rootRightMouseDown(mLastEvent);
  823. }
  824. else // it was a mouse up
  825. rootRightMouseUp(mLastEvent);
  826. return mConsumeLastInputEvent;
  827. }
  828. else if(inputEvent.objInst == KEY_BUTTON2) // middle button
  829. {
  830. if(inputEvent.action == SI_MAKE)
  831. {
  832. U32 curTime = Platform::getVirtualMilliseconds();
  833. //if the last button pressed was the right...
  834. if (mMiddleMouseLast)
  835. {
  836. //if it was within the double click time count the clicks
  837. if (curTime - mLastMouseDownTime <= mouseDoubleClickTime)
  838. mLastMouseClickCount++;
  839. else
  840. mLastMouseClickCount = 1;
  841. }
  842. else
  843. {
  844. mMiddleMouseLast = true;
  845. mLastMouseClickCount = 1;
  846. }
  847. mLastMouseDownTime = curTime;
  848. mLastEvent.mouseClickCount = mLastMouseClickCount;
  849. rootMiddleMouseDown(mLastEvent);
  850. }
  851. else // it was a mouse up
  852. rootMiddleMouseUp(mLastEvent);
  853. return mConsumeLastInputEvent;
  854. }
  855. }
  856. return false;
  857. }
  858. bool GuiCanvas::processGamepadEvent(InputEventInfo &inputEvent)
  859. {
  860. if (! mFirstResponder)
  861. {
  862. // early out, no first responder to receive gamepad input
  863. return false;
  864. }
  865. if (inputEvent.deviceInst >= MAX_GAMEPADS)
  866. {
  867. // early out, we only support the first MAX_GAMEPADS gamepads
  868. return false;
  869. }
  870. mLastEvent.keyCode = inputEvent.objInst;
  871. if (inputEvent.objType == SI_BUTTON)
  872. {
  873. switch (inputEvent.action)
  874. {
  875. case SI_MAKE:
  876. switch (inputEvent.objInst)
  877. {
  878. case SI_UPOV:
  879. return mFirstResponder->onGamepadAxisUp(mLastEvent);
  880. case SI_DPOV:
  881. return mFirstResponder->onGamepadAxisDown(mLastEvent);
  882. case SI_LPOV:
  883. return mFirstResponder->onGamepadAxisLeft(mLastEvent);
  884. case SI_RPOV:
  885. return mFirstResponder->onGamepadAxisRight(mLastEvent);
  886. default:
  887. return mFirstResponder->onGamepadButtonDown(mLastEvent);
  888. }
  889. break;
  890. case SI_BREAK:
  891. return mFirstResponder->onGamepadButtonUp(mLastEvent);
  892. default:
  893. return false;
  894. }
  895. }
  896. else if (inputEvent.objType == SI_AXIS)
  897. {
  898. F32 incomingValue = mFabs(inputEvent.fValue);
  899. static const F32 DEAD_ZONE = 0.5f;
  900. static const F32 MIN_CLICK_TIME = 500.0f;
  901. static const F32 MAX_CLICK_TIME = 1000.0f;
  902. static F32 xDecay [] = {1.0f, 1.0f, 1.0f, 1.0f};
  903. static F32 yDecay [] = {1.0f, 1.0f, 1.0f, 1.0f};
  904. static F32 zDecay [] = {1.0f, 1.0f, 1.0f, 1.0f};
  905. static U32 xLastClickTime [] = {0, 0, 0, 0};
  906. static U32 yLastClickTime [] = {0, 0, 0, 0};
  907. static U32 zLastClickTime [] = {0, 0, 0, 0};
  908. U32 curTime = Platform::getRealMilliseconds();
  909. F32 *decay;
  910. U32 *lastClickTime;
  911. switch (inputEvent.objInst)
  912. {
  913. case SI_ZAXIS:
  914. case XI_LEFT_TRIGGER:
  915. case XI_RIGHT_TRIGGER:
  916. decay = &zDecay[inputEvent.deviceInst];
  917. lastClickTime = &zLastClickTime[inputEvent.deviceInst];
  918. break;
  919. case SI_YAXIS:
  920. case XI_THUMBLY:
  921. case XI_THUMBRY:
  922. decay = &yDecay[inputEvent.deviceInst];
  923. lastClickTime = &yLastClickTime[inputEvent.deviceInst];
  924. break;
  925. case SI_XAXIS:
  926. case XI_THUMBLX:
  927. case XI_THUMBRX:
  928. default:
  929. decay = &xDecay[inputEvent.deviceInst];
  930. lastClickTime = &xLastClickTime[inputEvent.deviceInst];
  931. break;
  932. }
  933. if (incomingValue < DEAD_ZONE)
  934. {
  935. // early out, control movement is within the deadzone
  936. *decay = 1.0f;
  937. *lastClickTime = 0;
  938. return false;
  939. }
  940. // Rescales the input between 0.0 and 1.0
  941. incomingValue = (incomingValue - DEAD_ZONE) * (1.0f / (1.0f - DEAD_ZONE));
  942. F32 clickTime = MIN_CLICK_TIME + (MAX_CLICK_TIME - MIN_CLICK_TIME) * (1.0f - incomingValue);
  943. clickTime *= *decay;
  944. if (clickTime < (curTime - *lastClickTime))
  945. {
  946. *decay *= 0.9f;
  947. if (*decay < 0.2f)
  948. {
  949. *decay = 0.2f;
  950. }
  951. *lastClickTime = curTime;
  952. bool negative = (inputEvent.fValue < 0.0f);
  953. switch (inputEvent.objInst)
  954. {
  955. case SI_ZAXIS:
  956. case SI_RZAXIS:
  957. return mFirstResponder->onGamepadTrigger(mLastEvent);
  958. case SI_YAXIS:
  959. case SI_RYAXIS:
  960. if (!negative)
  961. {
  962. return mFirstResponder->onGamepadAxisDown(mLastEvent);
  963. }
  964. else
  965. {
  966. return mFirstResponder->onGamepadAxisUp(mLastEvent);
  967. }
  968. case SI_XAXIS:
  969. case SI_RXAXIS:
  970. default:
  971. if (negative)
  972. {
  973. return mFirstResponder->onGamepadAxisLeft(mLastEvent);
  974. }
  975. else
  976. {
  977. return mFirstResponder->onGamepadAxisRight(mLastEvent);
  978. }
  979. }
  980. }
  981. }
  982. return false;
  983. }
  984. void GuiCanvas::rootMouseDown(const GuiEvent &event)
  985. {
  986. mPrevMouseTime = Platform::getVirtualMilliseconds();
  987. mMouseButtonDown = true;
  988. //pass the event to the mouse locked control
  989. if (bool(mMouseCapturedControl))
  990. mMouseCapturedControl->onMouseDown(event);
  991. else
  992. {
  993. //else pass it to whoever is underneath the cursor
  994. iterator i;
  995. i = end();
  996. while (i != begin())
  997. {
  998. i--;
  999. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1000. GuiControl *controlHit = ctrl->findHitControl( event.mousePoint - ctrl->getPosition() );
  1001. //see if the controlHit is a modeless dialog...
  1002. if( !controlHit->getControlProfile()->mModal )
  1003. continue;
  1004. else
  1005. {
  1006. controlHit->onMouseDown(event);
  1007. break;
  1008. }
  1009. }
  1010. }
  1011. if (bool(mMouseControl))
  1012. mMouseControlClicked = true;
  1013. }
  1014. void GuiCanvas::findMouseControl(const GuiEvent &event)
  1015. {
  1016. // Any children at all?
  1017. if(size() == 0)
  1018. {
  1019. mMouseControl = NULL;
  1020. return;
  1021. }
  1022. // Otherwise, check the point and find the overlapped control.
  1023. GuiControl *controlHit = findHitControl(event.mousePoint);
  1024. if(controlHit != static_cast<GuiControl*>(mMouseControl))
  1025. {
  1026. if(bool(mMouseControl))
  1027. mMouseControl->onMouseLeave(event);
  1028. mMouseControl = controlHit;
  1029. mMouseControl->onMouseEnter(event);
  1030. }
  1031. }
  1032. void GuiCanvas::refreshMouseControl()
  1033. {
  1034. GuiEvent evt;
  1035. evt.mousePoint.x = S32(mCursorPt.x);
  1036. evt.mousePoint.y = S32(mCursorPt.y);
  1037. findMouseControl(evt);
  1038. }
  1039. void GuiCanvas::checkLockMouseMove( const GuiEvent& event )
  1040. {
  1041. GuiControl* controlHit = findHitControl( event.mousePoint );
  1042. if( controlHit != mMouseControl )
  1043. {
  1044. if( mMouseControl == mMouseCapturedControl )
  1045. mMouseCapturedControl->onMouseLeave( event );
  1046. else if( controlHit == mMouseCapturedControl )
  1047. mMouseCapturedControl->onMouseEnter( event );
  1048. mMouseControl = controlHit;
  1049. }
  1050. }
  1051. void GuiCanvas::rootMouseUp(const GuiEvent &event)
  1052. {
  1053. mPrevMouseTime = Platform::getVirtualMilliseconds();
  1054. mMouseButtonDown = false;
  1055. // pass the event to the mouse locked control
  1056. if (bool(mMouseCapturedControl))
  1057. {
  1058. checkLockMouseMove( event );
  1059. mMouseCapturedControl->onMouseUp(event);
  1060. }
  1061. else
  1062. {
  1063. findMouseControl(event);
  1064. if(bool(mMouseControl))
  1065. mMouseControl->onMouseUp(event);
  1066. }
  1067. }
  1068. void GuiCanvas::rootMouseDragged(const GuiEvent &event)
  1069. {
  1070. //pass the event to the mouse locked control
  1071. if (bool(mMouseCapturedControl))
  1072. {
  1073. checkLockMouseMove( event );
  1074. mMouseCapturedControl->onMouseDragged(event);
  1075. }
  1076. else
  1077. {
  1078. findMouseControl(event);
  1079. if(bool(mMouseControl))
  1080. mMouseControl->onMouseDragged(event);
  1081. }
  1082. }
  1083. void GuiCanvas::rootMouseMove(const GuiEvent &event)
  1084. {
  1085. if (bool(mMouseCapturedControl))
  1086. {
  1087. mMouseCapturedControl->onMouseMove(event);
  1088. }
  1089. else
  1090. {
  1091. findMouseControl(event);
  1092. if(bool(mMouseControl))
  1093. mMouseControl->onMouseMove(event);
  1094. }
  1095. }
  1096. void GuiCanvas::rootRightMouseDown(const GuiEvent &event)
  1097. {
  1098. mPrevMouseTime = Platform::getVirtualMilliseconds();
  1099. mMouseRightButtonDown = true;
  1100. if (bool(mMouseCapturedControl))
  1101. {
  1102. checkLockMouseMove( event );
  1103. mMouseCapturedControl->onRightMouseDown(event);
  1104. }
  1105. else
  1106. {
  1107. findMouseControl(event);
  1108. if(bool(mMouseControl))
  1109. {
  1110. mMouseControl->onRightMouseDown(event);
  1111. }
  1112. }
  1113. }
  1114. void GuiCanvas::rootRightMouseUp(const GuiEvent &event)
  1115. {
  1116. mPrevMouseTime = Platform::getVirtualMilliseconds();
  1117. mMouseRightButtonDown = false;
  1118. if (bool(mMouseCapturedControl))
  1119. mMouseCapturedControl->onRightMouseUp(event);
  1120. else
  1121. {
  1122. findMouseControl(event);
  1123. if(bool(mMouseControl))
  1124. mMouseControl->onRightMouseUp(event);
  1125. }
  1126. }
  1127. void GuiCanvas::rootRightMouseDragged(const GuiEvent &event)
  1128. {
  1129. mPrevMouseTime = Platform::getVirtualMilliseconds();
  1130. if (bool(mMouseCapturedControl))
  1131. {
  1132. mMouseCapturedControl->onRightMouseDragged(event);
  1133. }
  1134. else
  1135. {
  1136. findMouseControl(event);
  1137. if(bool(mMouseControl))
  1138. mMouseControl->onRightMouseDragged(event);
  1139. }
  1140. }
  1141. void GuiCanvas::rootMiddleMouseDown(const GuiEvent &event)
  1142. {
  1143. mPrevMouseTime = Platform::getVirtualMilliseconds();
  1144. mMouseMiddleButtonDown = true;
  1145. if (bool(mMouseCapturedControl))
  1146. mMouseCapturedControl->onMiddleMouseDown(event);
  1147. else
  1148. {
  1149. findMouseControl(event);
  1150. if(bool(mMouseControl))
  1151. {
  1152. mMouseControl->onMiddleMouseDown(event);
  1153. }
  1154. }
  1155. }
  1156. void GuiCanvas::rootMiddleMouseUp(const GuiEvent &event)
  1157. {
  1158. mPrevMouseTime = Platform::getVirtualMilliseconds();
  1159. mMouseMiddleButtonDown = false;
  1160. if (bool(mMouseCapturedControl))
  1161. mMouseCapturedControl->onMiddleMouseUp(event);
  1162. else
  1163. {
  1164. findMouseControl(event);
  1165. if(bool(mMouseControl))
  1166. mMouseControl->onMiddleMouseUp(event);
  1167. }
  1168. }
  1169. void GuiCanvas::rootMiddleMouseDragged(const GuiEvent &event)
  1170. {
  1171. mPrevMouseTime = Platform::getVirtualMilliseconds();
  1172. if (bool(mMouseCapturedControl))
  1173. {
  1174. checkLockMouseMove( event );
  1175. mMouseCapturedControl->onMiddleMouseDragged(event);
  1176. }
  1177. else
  1178. {
  1179. findMouseControl(event);
  1180. if(bool(mMouseControl))
  1181. mMouseControl->onMiddleMouseDragged(event);
  1182. }
  1183. }
  1184. bool GuiCanvas::rootMouseWheelUp(const GuiEvent &event)
  1185. {
  1186. if (bool(mMouseCapturedControl))
  1187. return mMouseCapturedControl->onMouseWheelUp(event);
  1188. else
  1189. {
  1190. findMouseControl(event);
  1191. if (bool(mMouseControl))
  1192. return mMouseControl->onMouseWheelUp(event);
  1193. }
  1194. return false;
  1195. }
  1196. bool GuiCanvas::rootMouseWheelDown(const GuiEvent &event)
  1197. {
  1198. if (bool(mMouseCapturedControl))
  1199. return mMouseCapturedControl->onMouseWheelDown(event);
  1200. else
  1201. {
  1202. findMouseControl(event);
  1203. if (bool(mMouseControl))
  1204. return mMouseControl->onMouseWheelDown(event);
  1205. }
  1206. return false;
  1207. }
  1208. void GuiCanvas::setContentControl(GuiControl *gui)
  1209. {
  1210. // Skip out if we got passed NULL (why would that happen?)
  1211. if(!gui)
  1212. return;
  1213. GuiControl *oldContent = getContentControl();
  1214. if(oldContent)
  1215. Con::executef(oldContent, "onUnsetContent", Con::getIntArg(gui->getId()));
  1216. //remove all dialogs on layer 0
  1217. U32 index = 0;
  1218. while (size() > index)
  1219. {
  1220. GuiControl *ctrl = static_cast<GuiControl*>((*this)[index]);
  1221. if (ctrl == gui || ctrl->mLayer != 0)
  1222. index++;
  1223. Sim::getGuiGroup()->addObject( ctrl );
  1224. }
  1225. #ifdef TORQUE_TOOLS
  1226. // set current menu bar
  1227. setMenuBar( mMenuBarCtrl );
  1228. #endif
  1229. // lose the first responder from the old GUI
  1230. GuiControl* responder = gui->findFirstTabable();
  1231. if(responder)
  1232. responder->setFirstResponder();
  1233. //add the gui to the front
  1234. if(!size() || gui != (*this)[0])
  1235. {
  1236. // automatically wakes objects in GuiControl::onWake
  1237. addObject(gui);
  1238. if (size() >= 2)
  1239. reOrder(gui, *begin());
  1240. }
  1241. //refresh the entire gui
  1242. resetUpdateRegions();
  1243. //rebuild the accelerator map
  1244. mAcceleratorMap.clear();
  1245. for(iterator i = end(); i != begin() ; )
  1246. {
  1247. i--;
  1248. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  1249. ctrl->buildAcceleratorMap();
  1250. if (ctrl->getControlProfile()->mModal)
  1251. break;
  1252. }
  1253. refreshMouseControl();
  1254. // Force the canvas to update the sizing of the new content control
  1255. maintainSizing();
  1256. // Do this last so onWake gets called first
  1257. Con::executef(gui, "onSetContent", Con::getIntArg(oldContent ? oldContent->getId() : 0));
  1258. }
  1259. GuiControl *GuiCanvas::getContentControl()
  1260. {
  1261. if(size() > 0)
  1262. return (GuiControl *) first();
  1263. return NULL;
  1264. }
  1265. void GuiCanvas::pushDialogControl(GuiControl *gui, S32 layer, bool center)
  1266. {
  1267. if( center )
  1268. gui->setPosition( getExtent().x / 2 - gui->getExtent().x / 2,
  1269. getExtent().y / 2 - gui->getExtent().y / 2 );
  1270. //add the gui
  1271. gui->mLayer = layer;
  1272. // GuiControl::addObject wakes the object
  1273. addObject(gui);
  1274. //reorder it to the correct layer
  1275. iterator i;
  1276. for (i = begin(); i != end(); i++)
  1277. {
  1278. GuiControl *ctrl = static_cast<GuiControl*>(*i);
  1279. if (ctrl->mLayer > gui->mLayer)
  1280. {
  1281. reOrder(gui, ctrl);
  1282. break;
  1283. }
  1284. }
  1285. //call the dialog push method
  1286. gui->onDialogPush();
  1287. //find the first responder
  1288. GuiControl* responder = gui->findFirstTabable();
  1289. if(responder)
  1290. responder->setFirstResponder();
  1291. // call the 'onWake' method?
  1292. //if(wakedGui)
  1293. // Con::executef(gui, 1, "onWake");
  1294. //refresh the entire gui
  1295. resetUpdateRegions();
  1296. //rebuild the accelerator map
  1297. mAcceleratorMap.clear();
  1298. if (size() > 0)
  1299. {
  1300. GuiControl *ctrl = static_cast<GuiControl*>(last());
  1301. ctrl->buildAcceleratorMap();
  1302. }
  1303. refreshMouseControl();
  1304. // I don't see the purpose of this, and it's causing issues when showing, for instance the
  1305. // metrics dialog while in a 3d scene, causing the cursor to be shown even when the mouse
  1306. // is locked [4/25/2007 justind]
  1307. //if(gui->mProfile && gui->mProfile->mModal)
  1308. // mPlatformWindow->getCursorController()->pushCursor(PlatformCursorController::curArrow);
  1309. }
  1310. void GuiCanvas::popDialogControl(GuiControl *gui)
  1311. {
  1312. if (size() < 1)
  1313. return;
  1314. //first, find the dialog, and call the "onDialogPop()" method
  1315. GuiControl *ctrl = NULL;
  1316. if (gui)
  1317. {
  1318. //make sure the gui really exists on the stack
  1319. iterator i;
  1320. bool found = false;
  1321. for(i = begin(); i != end(); i++)
  1322. {
  1323. GuiControl *check = static_cast<GuiControl *>(*i);
  1324. if (check == gui)
  1325. {
  1326. ctrl = check;
  1327. found = true;
  1328. }
  1329. }
  1330. if (!found)
  1331. return;
  1332. }
  1333. else
  1334. ctrl = static_cast<GuiControl*>(last());
  1335. //call the "on pop" function
  1336. ctrl->onDialogPop();
  1337. //now pop the last child (will sleep if awake)
  1338. Sim::getGuiGroup()->addObject(ctrl);
  1339. if (size() > 0)
  1340. {
  1341. GuiControl *lastCtrl = static_cast<GuiControl *>(last());
  1342. if(lastCtrl->getFirstResponder() )
  1343. lastCtrl->getFirstResponder()->setFirstResponder();
  1344. }
  1345. else
  1346. {
  1347. setFirstResponder(NULL);
  1348. }
  1349. //refresh the entire gui
  1350. resetUpdateRegions();
  1351. //rebuild the accelerator map
  1352. mAcceleratorMap.clear();
  1353. if (size() > 0)
  1354. {
  1355. GuiControl *lastCtrl = static_cast<GuiControl*>(last());
  1356. lastCtrl->buildAcceleratorMap();
  1357. }
  1358. refreshMouseControl();
  1359. }
  1360. void GuiCanvas::popDialogControl(S32 layer)
  1361. {
  1362. if (size() < 1)
  1363. return;
  1364. GuiControl *ctrl = NULL;
  1365. iterator i = end(); // find in z order (last to first)
  1366. while (i != begin())
  1367. {
  1368. i--;
  1369. ctrl = static_cast<GuiControl*>(*i);
  1370. if (ctrl->mLayer == layer)
  1371. break;
  1372. }
  1373. if (ctrl)
  1374. popDialogControl(ctrl);
  1375. }
  1376. void GuiCanvas::mouseLock(GuiControl *lockingControl)
  1377. {
  1378. if (bool(mMouseCapturedControl))
  1379. return;
  1380. mMouseCapturedControl = lockingControl;
  1381. if(mMouseControl && mMouseControl != mMouseCapturedControl)
  1382. {
  1383. GuiEvent evt;
  1384. evt.mousePoint.x = S32(mCursorPt.x);
  1385. evt.mousePoint.y = S32(mCursorPt.y);
  1386. mMouseControl->onMouseLeave(evt);
  1387. }
  1388. }
  1389. void GuiCanvas::mouseUnlock(GuiControl *lockingControl)
  1390. {
  1391. if (static_cast<GuiControl*>(mMouseCapturedControl) != lockingControl)
  1392. return;
  1393. GuiEvent evt;
  1394. evt.mousePoint.x = S32(mCursorPt.x);
  1395. evt.mousePoint.y = S32(mCursorPt.y);
  1396. GuiControl * controlHit = findHitControl(evt.mousePoint);
  1397. if(controlHit != mMouseCapturedControl)
  1398. {
  1399. mMouseControl = controlHit;
  1400. mMouseControlClicked = false;
  1401. if(bool(mMouseControl))
  1402. mMouseControl->onMouseEnter(evt);
  1403. }
  1404. mMouseCapturedControl = NULL;
  1405. }
  1406. void GuiCanvas::paint()
  1407. {
  1408. resetUpdateRegions();
  1409. // inhibit explicit refreshes in the case we're swapped out
  1410. if( mPlatformWindow && mPlatformWindow->isVisible() && GFX->allowRender())
  1411. mPlatformWindow->displayEvent.trigger(mPlatformWindow->getWindowId());
  1412. }
  1413. void GuiCanvas::repaint(U32 elapsedMS)
  1414. {
  1415. // Make sure we have a window.
  1416. if ( !mPlatformWindow )
  1417. return;
  1418. // Has enough time elapsed?
  1419. U32 elapsed = Platform::getRealMilliseconds() - mLastRenderMs;
  1420. if (elapsed < elapsedMS)
  1421. return;
  1422. // Do the render.
  1423. resetUpdateRegions();
  1424. handlePaintEvent(mPlatformWindow->getWindowId());
  1425. }
  1426. void GuiCanvas::maintainSizing()
  1427. {
  1428. Point2I size = getWindowSize();
  1429. if(size.x == -1 || size.y == -1)
  1430. return;
  1431. RectI screenRect(0, 0, size.x, size.y);
  1432. setBounds(screenRect);
  1433. // all bottom level controls should be the same dimensions as the canvas
  1434. // this is necessary for passing mouse events accurately
  1435. iterator i;
  1436. for (i = begin(); i != end(); i++)
  1437. {
  1438. AssertFatal(static_cast<GuiControl*>((*i))->isAwake(), "GuiCanvas::maintainSizing - ctrl is not awake");
  1439. GuiControl *ctrl = static_cast<GuiControl*>(*i);
  1440. Point2I ext = ctrl->getExtent();
  1441. Point2I pos = ctrl->getPosition();
  1442. Point2I newExt = screenRect.extent;
  1443. Point2I newPos = screenRect.point;
  1444. // if menubar is active displace content gui control
  1445. if (mMenuBarCtrl && (ctrl == getContentControl()))
  1446. {
  1447. /*const SimObject *menu = mMenuBarCtrl->findObjectByInternalName( StringTable->insert("menubar"), true);
  1448. if( !menu )
  1449. continue;
  1450. AssertFatal( dynamic_cast<const GuiControl*>(menu), "");*/
  1451. const U32 yOffset = static_cast<const GuiMenuBar*>(mMenuBarCtrl)->mMenubarHeight;
  1452. newPos.y += yOffset;
  1453. newExt.y -= yOffset;
  1454. }
  1455. if (pos != newPos || ext != newExt)
  1456. {
  1457. ctrl->resize(newPos, newExt);
  1458. resetUpdateRegions();
  1459. }
  1460. }
  1461. }
  1462. void GuiCanvas::setupFences()
  1463. {
  1464. // Destroy old fences
  1465. SAFE_DELETE_ARRAY( mFences );
  1466. // Now create the new ones
  1467. if( mNumFences > 0 )
  1468. {
  1469. mFences = new GFXFence*[mNumFences];
  1470. // Allocate the new fences
  1471. for( S32 i = 0; i < mNumFences; i++ )
  1472. mFences[i] = GFX->createFence();
  1473. }
  1474. // Reset state
  1475. mNextFenceIdx = 0;
  1476. }
  1477. void GuiCanvas::renderFrame(bool preRenderOnly, bool bufferSwap /* = true */)
  1478. {
  1479. AssertISV(mPlatformWindow, "GuiCanvas::renderFrame - no window present!");
  1480. if(!mPlatformWindow->isVisible() || !GFX->allowRender() || GFX->canCurrentlyRender())
  1481. return;
  1482. PROFILE_START(CanvasPreRender);
  1483. // Set our window as the current render target so we can see outputs.
  1484. GFX->setActiveRenderTarget(mPlatformWindow->getGFXTarget());
  1485. if (!GFX->getActiveRenderTarget())
  1486. {
  1487. PROFILE_END();
  1488. return;
  1489. }
  1490. #ifdef TORQUE_GFX_STATE_DEBUG
  1491. GFX->getDebugStateManager()->startFrame();
  1492. #endif
  1493. GFXTarget* renderTarget = GFX->getActiveRenderTarget();
  1494. if (renderTarget == NULL)
  1495. {
  1496. PROFILE_END();
  1497. return;
  1498. }
  1499. // Make sure the root control is the size of the canvas.
  1500. Point2I size = renderTarget->getSize();
  1501. if(size.x == 0 || size.y == 0)
  1502. {
  1503. PROFILE_END();
  1504. return;
  1505. }
  1506. RectI screenRect(0, 0, size.x, size.y);
  1507. maintainSizing();
  1508. //preRender (recursive) all controls
  1509. preRender();
  1510. PROFILE_END();
  1511. // Are we just doing pre-render?
  1512. if(preRenderOnly)
  1513. return;
  1514. // Signal the interested parties.
  1515. GuiCanvas::getGuiCanvasFrameSignal().trigger(true);
  1516. // Gross hack to make sure we don't end up with advanced lighting and msaa
  1517. // at the same time, which causes artifacts. At the same time we don't
  1518. // want to just throw the settings the user has chosen if the light manager
  1519. // changes at a later time.
  1520. GFXVideoMode mode = mPlatformWindow->getVideoMode();
  1521. if ( dStricmp( LIGHTMGR->getId(), "ADVLM" ) == 0 && mode.antialiasLevel > 0 )
  1522. {
  1523. const char *pref = Con::getVariable( "$pref::Video::mode" );
  1524. mode.parseFromString( pref );
  1525. mode.antialiasLevel = 0;
  1526. Point2I winPos = mPlatformWindow->getPosition(); // Save position so we can put window back.
  1527. mPlatformWindow->setVideoMode(mode);
  1528. // setVideoMode (above) will center the window on the display device. If the window had been positioned
  1529. // by the user or from script, put it back where it was before the light manager change.
  1530. mPlatformWindow->setPosition(winPos);
  1531. Con::printf( "AntiAliasing has been disabled; it is not compatible with AdvancedLighting." );
  1532. }
  1533. else if ( dStricmp( LIGHTMGR->getId(), "BLM" ) == 0)
  1534. {
  1535. const char *pref = Con::getVariable( "$pref::Video::mode" );
  1536. U32 prefAA = dAtoi( StringUnit::getUnit(pref, 5, " ") );
  1537. if ( prefAA != mode.antialiasLevel )
  1538. {
  1539. mode.parseFromString( pref );
  1540. Point2I winPos = mPlatformWindow->getPosition(); // Save position so we can put window back.
  1541. mPlatformWindow->setVideoMode(mode);
  1542. // setVideoMode (above) will center the window on the display device. If the window had been positioned
  1543. // by the user or from script, put it back where it was before the light manager change.
  1544. mPlatformWindow->setPosition(winPos);
  1545. Con::printf( "AntiAliasing has been enabled while running BasicLighting." );
  1546. }
  1547. }
  1548. // for now, just always reset the update regions - this is a
  1549. // fix for FSAA on ATI cards
  1550. resetUpdateRegions();
  1551. PROFILE_START(CanvasRenderControls);
  1552. // Draw the mouse
  1553. GuiCursor *mouseCursor = NULL;
  1554. bool cursorVisible = true;
  1555. if(bool(mMouseCapturedControl))
  1556. mMouseCapturedControl->getCursor(mouseCursor, cursorVisible, mLastEvent);
  1557. else if(bool(mMouseControl))
  1558. mMouseControl->getCursor(mouseCursor, cursorVisible, mLastEvent);
  1559. Point2I cursorPos((S32)mCursorPt.x, (S32)mCursorPt.y);
  1560. if(!mouseCursor)
  1561. mouseCursor = mDefaultCursor;
  1562. if(mLastCursorEnabled && mLastCursor)
  1563. {
  1564. Point2I spot = mLastCursor->getHotSpot();
  1565. Point2I cext = mLastCursor->getExtent();
  1566. Point2I pos = mLastCursorPt - spot;
  1567. addUpdateRegion(pos - Point2I(2, 2), Point2I(cext.x + 4, cext.y + 4));
  1568. }
  1569. if(cursorVisible && mouseCursor)
  1570. {
  1571. Point2I spot = mouseCursor->getHotSpot();
  1572. Point2I cext = mouseCursor->getExtent();
  1573. Point2I pos = cursorPos - spot;
  1574. addUpdateRegion(pos - Point2I(2, 2), Point2I(cext.x + 4, cext.y + 4));
  1575. }
  1576. mLastCursorEnabled = cursorVisible;
  1577. mLastCursor = mouseCursor;
  1578. mLastCursorPt = cursorPos;
  1579. // Begin GFX
  1580. PROFILE_START(GFXBeginScene);
  1581. bool beginSceneRes = GFX->beginScene();
  1582. PROFILE_END();
  1583. // Render all offscreen canvas objects here since we may need them in the render loop
  1584. if (GuiOffscreenCanvas::sList.size() != 0)
  1585. {
  1586. // Reset the entire state since oculus shit will have barfed it.
  1587. GFX->updateStates(true);
  1588. for (Vector<GuiOffscreenCanvas*>::iterator itr = GuiOffscreenCanvas::sList.begin(); itr != GuiOffscreenCanvas::sList.end(); itr++)
  1589. {
  1590. (*itr)->renderFrame(false, false);
  1591. }
  1592. GFX->setActiveRenderTarget(renderTarget);
  1593. }
  1594. // Can't render if waiting for device to reset.
  1595. if ( !beginSceneRes )
  1596. {
  1597. PROFILE_END(); // CanvasRenderControls
  1598. // Since we already triggered the signal once for begin-of-frame,
  1599. // we should be consistent and trigger it again for end-of-frame.
  1600. GuiCanvas::getGuiCanvasFrameSignal().trigger(false);
  1601. return;
  1602. }
  1603. // Clear the current viewport area
  1604. GFX->setViewport( screenRect );
  1605. GFX->clear( GFXClearZBuffer | GFXClearStencil | GFXClearTarget, gCanvasClearColor, 1.0f, 0 );
  1606. resetUpdateRegions();
  1607. // Make sure we have a clean matrix state
  1608. // before we start rendering anything!
  1609. GFX->setWorldMatrix( MatrixF::Identity );
  1610. GFX->setViewMatrix( MatrixF::Identity );
  1611. GFX->setProjectionMatrix( MatrixF::Identity );
  1612. // If we're taking a screenshot then let it have
  1613. // a chance at altering the view matrix.
  1614. if ( gScreenShot && gScreenShot->isPending() )
  1615. gScreenShot->tileGui( size );
  1616. RectI updateUnion;
  1617. buildUpdateUnion(&updateUnion);
  1618. if (updateUnion.intersect(screenRect))
  1619. {
  1620. // Render active GUI Dialogs
  1621. for(iterator i = begin(); i != end(); i++)
  1622. {
  1623. // Get the control
  1624. GuiControl *contentCtrl = static_cast<GuiControl*>(*i);
  1625. GFX->setClipRect( updateUnion );
  1626. GFX->setStateBlock(mDefaultGuiSB);
  1627. contentCtrl->onRender(contentCtrl->getPosition(), updateUnion);
  1628. }
  1629. // Fill Black if no Dialogs
  1630. if(this->size() == 0)
  1631. GFX->clear( GFXClearTarget, ColorI(0,0,0,0), 1.0f, 0 );
  1632. // Tooltip resource
  1633. if(bool(mMouseControl))
  1634. {
  1635. U32 curTime = Platform::getRealMilliseconds();
  1636. if(mHoverControl == mMouseControl)
  1637. {
  1638. if(mHoverPositionSet || (curTime - mHoverControlStart) >= mHoverControl->mTipHoverTime || (curTime - mHoverLeftControlTime) <= mHoverControl->mTipHoverTime)
  1639. {
  1640. if(!mHoverPositionSet)
  1641. {
  1642. mHoverPosition = cursorPos;
  1643. }
  1644. mHoverPositionSet = mMouseControl->mRenderTooltipDelegate( mHoverPosition, cursorPos, NULL );
  1645. }
  1646. }
  1647. else
  1648. {
  1649. if(mHoverPositionSet)
  1650. {
  1651. mHoverLeftControlTime = curTime;
  1652. mHoverPositionSet = false;
  1653. }
  1654. mHoverControl = mMouseControl;
  1655. mHoverControlStart = curTime;
  1656. }
  1657. }
  1658. GFX->setClipRect( updateUnion );
  1659. // Draw an ugly box if we don't have a cursor available...
  1660. //if (mCursorEnabled && mShowCursor && !mouseCursor)
  1661. //{
  1662. // GFX->drawRectFill( RectI( mCursorPt.x, mCursorPt.y, mCursorPt.x + 2, mCursorPt.y + 2 ), ColorI( 255, 0, 0 ) );
  1663. //}
  1664. // CodeReview - Make sure our bitmap modulation is clear or else there's a black modulation
  1665. // that ruins rendering of textures at startup.. This was done in mouseCursor
  1666. // onRender and so at startup when it wasn't called the modulation was black, ruining
  1667. // the loading screen display. This fixes the issue, but is it only masking a deeper issue
  1668. // in GFX with regard to gui rendering? [5/3/2007 justind]
  1669. GFX->getDrawUtil()->clearBitmapModulation();
  1670. // Really draw the cursor. :)
  1671. // Only if the platform cursor controller is missing or the platform cursor
  1672. // isn't visible.
  1673. if (!mPlatformWindow->getCursorController() || (mCursorEnabled && mouseCursor && mShowCursor &&
  1674. !mPlatformWindow->getCursorController()->isCursorVisible()))
  1675. {
  1676. Point2I pos((S32)mCursorPt.x, (S32)mCursorPt.y);
  1677. Point2I spot = mouseCursor->getHotSpot();
  1678. pos -= spot;
  1679. mouseCursor->render(pos);
  1680. }
  1681. }
  1682. // Render all RTT end of frame updates HERE
  1683. //DynamicTexture::updateScreenTextures();
  1684. //DynamicTexture::updateEndOfFrameTextures();
  1685. // mPending is set when the console function "screenShot()" is called
  1686. // this situation is necessary because it needs to take the screenshot
  1687. // before the buffers swap
  1688. PROFILE_END();
  1689. // Fence logic here, because this is where endScene is called.
  1690. if( mNumFences > 0 )
  1691. {
  1692. // Issue next fence
  1693. mFences[mNextFenceIdx]->issue();
  1694. mNextFenceIdx++;
  1695. // Wrap the next fence around to first if we're maxxed
  1696. if( mNextFenceIdx >= mNumFences )
  1697. mNextFenceIdx = 0;
  1698. // Block on previous fence
  1699. mFences[mNextFenceIdx]->block();
  1700. }
  1701. PROFILE_START(GFXEndScene);
  1702. GFX->endScene();
  1703. PROFILE_END();
  1704. GFX->getDeviceEventSignal().trigger( GFXDevice::dePostFrame );
  1705. swapBuffers();
  1706. GuiCanvas::getGuiCanvasFrameSignal().trigger(false);
  1707. #ifdef TORQUE_GFX_STATE_DEBUG
  1708. GFX->getDebugStateManager()->endFrame();
  1709. #endif
  1710. // Keep track of the last time we rendered.
  1711. mLastRenderMs = Platform::getRealMilliseconds();
  1712. }
  1713. GuiCanvas::GuiCanvasFrameSignal& GuiCanvas::getGuiCanvasFrameSignal()
  1714. {
  1715. static GuiCanvasFrameSignal theSignal;
  1716. return theSignal;
  1717. }
  1718. void GuiCanvas::swapBuffers()
  1719. {
  1720. AssertISV(mPlatformWindow, "GuiCanvas::swapBuffers - no window present!");
  1721. if(!mPlatformWindow->isVisible())
  1722. return;
  1723. PROFILE_START(SwapBuffers);
  1724. mPlatformWindow->getGFXTarget()->present();
  1725. PROFILE_END();
  1726. }
  1727. void GuiCanvas::buildUpdateUnion(RectI *updateUnion)
  1728. {
  1729. *updateUnion = mOldUpdateRects[0];
  1730. //the update region should encompass the oldUpdateRects, and the curUpdateRect
  1731. Point2I upperL;
  1732. Point2I lowerR;
  1733. upperL.x = getMin(mOldUpdateRects[0].point.x, mOldUpdateRects[1].point.x);
  1734. upperL.x = getMin(upperL.x, mCurUpdateRect.point.x);
  1735. upperL.y = getMin(mOldUpdateRects[0].point.y, mOldUpdateRects[1].point.y);
  1736. upperL.y = getMin(upperL.y, mCurUpdateRect.point.y);
  1737. lowerR.x = getMax(mOldUpdateRects[0].point.x + mOldUpdateRects[0].extent.x, mOldUpdateRects[1].point.x + mOldUpdateRects[1].extent.x);
  1738. lowerR.x = getMax(lowerR.x, mCurUpdateRect.point.x + mCurUpdateRect.extent.x);
  1739. lowerR.y = getMax(mOldUpdateRects[0].point.y + mOldUpdateRects[0].extent.y, mOldUpdateRects[1].point.y + mOldUpdateRects[1].extent.y);
  1740. lowerR.y = getMax(lowerR.y, mCurUpdateRect.point.y + mCurUpdateRect.extent.y);
  1741. updateUnion->point = upperL;
  1742. updateUnion->extent = lowerR - upperL;
  1743. //shift the oldUpdateRects
  1744. mOldUpdateRects[0] = mOldUpdateRects[1];
  1745. mOldUpdateRects[1] = mCurUpdateRect;
  1746. mCurUpdateRect.point.set(0,0);
  1747. mCurUpdateRect.extent.set(0,0);
  1748. }
  1749. void GuiCanvas::addUpdateRegion(Point2I pos, Point2I ext)
  1750. {
  1751. if(mCurUpdateRect.extent.x == 0)
  1752. {
  1753. mCurUpdateRect.point = pos;
  1754. mCurUpdateRect.extent = ext;
  1755. }
  1756. else
  1757. {
  1758. Point2I upperL;
  1759. upperL.x = getMin(mCurUpdateRect.point.x, pos.x);
  1760. upperL.y = getMin(mCurUpdateRect.point.y, pos.y);
  1761. Point2I lowerR;
  1762. lowerR.x = getMax(mCurUpdateRect.point.x + mCurUpdateRect.extent.x, pos.x + ext.x);
  1763. lowerR.y = getMax(mCurUpdateRect.point.y + mCurUpdateRect.extent.y, pos.y + ext.y);
  1764. mCurUpdateRect.point = upperL;
  1765. mCurUpdateRect.extent = lowerR - upperL;
  1766. }
  1767. }
  1768. void GuiCanvas::resetUpdateRegions()
  1769. {
  1770. //DEBUG - get surface width and height
  1771. mOldUpdateRects[0] = getBounds();
  1772. mOldUpdateRects[1] = mOldUpdateRects[0];
  1773. mCurUpdateRect = mOldUpdateRects[0];
  1774. }
  1775. void GuiCanvas::setFirstResponder( GuiControl* newResponder )
  1776. {
  1777. GuiControl* oldResponder = mFirstResponder;
  1778. Parent::setFirstResponder( newResponder );
  1779. if( oldResponder == mFirstResponder )
  1780. return;
  1781. if( oldResponder && ( oldResponder != newResponder ) )
  1782. oldResponder->onLoseFirstResponder();
  1783. if( newResponder && ( newResponder != oldResponder ) )
  1784. newResponder->onGainFirstResponder();
  1785. }
  1786. DefineEngineMethod( GuiCanvas, getContent, S32, (),,
  1787. "@brief Get the GuiControl which is being used as the content.\n\n"
  1788. "@tsexample\n"
  1789. "Canvas.getContent();\n"
  1790. "@endtsexample\n\n"
  1791. "@return ID of current content control")
  1792. {
  1793. GuiControl *ctrl = object->getContentControl();
  1794. if(ctrl)
  1795. return ctrl->getId();
  1796. return -1;
  1797. }
  1798. DefineEngineMethod( GuiCanvas, setContent, void, (GuiControl* ctrl),,
  1799. "@brief Set the content of the canvas to a specified control.\n\n"
  1800. "@param ctrl ID or name of GuiControl to set content to\n\n"
  1801. "@tsexample\n"
  1802. "Canvas.setContent(PlayGui);\n"
  1803. "@endtsexample\n\n")
  1804. {
  1805. // Not using old error reporting until we modify the engineAPI - mperry
  1806. //GuiControl *gui = NULL;
  1807. // if(argv[2][0])
  1808. // {
  1809. // if (!Sim::findObject(argv[2], gui))
  1810. // {
  1811. // Con::printf("%s(): Invalid control: %s", argv[0], argv[2]);
  1812. // return;
  1813. // }
  1814. // }
  1815. if(!ctrl)
  1816. {
  1817. Con::errorf("GuiCanvas::setContent - Invalid control specified')");
  1818. return;
  1819. }
  1820. //set the new content control
  1821. object->setContentControl(ctrl);
  1822. }
  1823. ConsoleDocFragment _pushDialog(
  1824. "@brief Adds a dialog control onto the stack of dialogs\n\n"
  1825. "@param ctrl Dialog to add\n"
  1826. "@param layer Layer to put dialog on (optional)\n"
  1827. "@param center True to center dialog on canvas (optional)\n\n"
  1828. "@tsexample\n"
  1829. "Canvas.pushDialog(RecordingsDlg);\n"
  1830. "@endtsexample\n\n",
  1831. "GuiCanvas",
  1832. "void pushDialog( GuiControl ctrl, int layer=0, bool center=false);"
  1833. );
  1834. DefineEngineMethod( GuiCanvas, pushDialog, void, (const char * ctrlName, S32 layer, bool center), ( 0, false), "(GuiControl ctrl, int layer=0, bool center=false)"
  1835. "@hide")
  1836. {
  1837. GuiControl *gui;
  1838. if (! Sim::findObject(ctrlName, gui))
  1839. {
  1840. Con::printf("pushDialog(): Invalid control: %s", ctrlName);
  1841. return;
  1842. }
  1843. //find the layer
  1844. //set the new content control
  1845. object->pushDialogControl(gui, layer, center);
  1846. }
  1847. ConsoleDocFragment _popDialog1(
  1848. "@brief Removes a specific dialog control\n\n"
  1849. "@param ctrl Dialog to pop\n"
  1850. "@tsexample\n"
  1851. "Canvas.popDialog(RecordingsDlg);\n"
  1852. "@endtsexample\n\n",
  1853. "GuiCanvas",
  1854. "void popDialog( GuiControl ctrl);"
  1855. );
  1856. ConsoleDocFragment _popDialog2(
  1857. "@brief Removes a dialog at the front most layer\n\n"
  1858. "@tsexample\n"
  1859. "// Pops whatever is on layer 0\n"
  1860. "Canvas.popDialog();\n"
  1861. "@endtsexample\n\n",
  1862. "GuiCanvas",
  1863. "void popDialog();"
  1864. );
  1865. DefineEngineMethod( GuiCanvas, popDialog, void, (GuiControl * gui), (nullAsType<GuiControl*>()), "(GuiControl ctrl=NULL)"
  1866. "@hide")
  1867. {
  1868. if (gui)
  1869. object->popDialogControl(gui);
  1870. else
  1871. object->popDialogControl();
  1872. }
  1873. ConsoleDocFragment _popLayer1(
  1874. "@brief Removes the top most layer of dialogs\n\n"
  1875. "@tsexample\n"
  1876. "Canvas.popLayer();\n"
  1877. "@endtsexample\n\n",
  1878. "GuiCanvas",
  1879. "void popLayer();"
  1880. );
  1881. ConsoleDocFragment _popLayer2(
  1882. "@brief Removes a specified layer of dialogs\n\n"
  1883. "@param layer Number of the layer to pop\n\n"
  1884. "@tsexample\n"
  1885. "Canvas.popLayer(1);\n"
  1886. "@endtsexample\n\n",
  1887. "GuiCanvas",
  1888. "void popLayer(S32 layer);"
  1889. );
  1890. DefineEngineMethod( GuiCanvas, popLayer, void, (S32 layer), (0), "(int layer)"
  1891. "@hide")
  1892. {
  1893. object->popDialogControl(layer);
  1894. }
  1895. DefineEngineMethod( GuiCanvas, cursorOn, void, (),,
  1896. "@brief Turns on the mouse cursor.\n\n"
  1897. "@tsexample\n"
  1898. "Canvas.cursorOn();\n"
  1899. "@endtsexample\n\n")
  1900. {
  1901. object->setCursorON(true);
  1902. }
  1903. DefineEngineMethod( GuiCanvas, cursorOff, void, (),,
  1904. "@brief Turns on the mouse off.\n\n"
  1905. "@tsexample\n"
  1906. "Canvas.cursorOff();\n"
  1907. "@endtsexample\n\n")
  1908. {
  1909. object->setCursorON(false);
  1910. }
  1911. DefineEngineMethod( GuiCanvas, setCursor, void, (GuiCursor* cursor),,
  1912. "@brief Sets the cursor for the canvas.\n\n"
  1913. "@param cursor Name of the GuiCursor to use\n\n"
  1914. "@tsexample\n"
  1915. "Canvas.setCursor(\"DefaultCursor\");\n"
  1916. "@endtsexample\n\n")
  1917. {
  1918. if(!cursor)
  1919. {
  1920. Con::errorf("GuiCanvas::setCursor - Invalid GuiCursor name or ID");
  1921. return;
  1922. }
  1923. object->setCursor(cursor);
  1924. }
  1925. DefineEngineMethod( GuiCanvas, renderFront, void, ( bool enable ),,
  1926. "@brief This turns on/off front-buffer rendering.\n\n"
  1927. "@param enable True if all rendering should be done to the front buffer\n\n"
  1928. "@tsexample\n"
  1929. "Canvas.renderFront(false);\n"
  1930. "@endtsexample\n\n")
  1931. {
  1932. object->setRenderFront(enable);
  1933. }
  1934. DefineEngineMethod( GuiCanvas, showCursor, void, (),,
  1935. "@brief Enable rendering of the cursor.\n\n"
  1936. "@tsexample\n"
  1937. "Canvas.showCursor();\n"
  1938. "@endtsexample\n\n")
  1939. {
  1940. object->showCursor(true);
  1941. }
  1942. DefineEngineMethod( GuiCanvas, hideCursor, void, (),,
  1943. "@brief Disable rendering of the cursor.\n\n"
  1944. "@tsexample\n"
  1945. "Canvas.hideCursor();\n"
  1946. "@endtsexample\n\n")
  1947. {
  1948. object->showCursor(false);
  1949. }
  1950. DefineEngineMethod( GuiCanvas, isCursorOn, bool, (),,
  1951. "@brief Determines if mouse cursor is enabled.\n\n"
  1952. "@tsexample\n"
  1953. "// Is cursor on?\n"
  1954. "if(Canvas.isCursorOn())\n"
  1955. " echo(\"Canvas cursor is on\");\n"
  1956. "@endtsexample\n\n"
  1957. "@return Returns true if the cursor is on.\n\n")
  1958. {
  1959. return object->isCursorON();
  1960. }
  1961. DefineEngineMethod( GuiCanvas, isCursorShown, bool, (),,
  1962. "@brief Determines if mouse cursor is rendering.\n\n"
  1963. "@tsexample\n"
  1964. "// Is cursor rendering?\n"
  1965. "if(Canvas.isCursorShown())\n"
  1966. " echo(\"Canvas cursor is rendering\");\n"
  1967. "@endtsexample\n\n"
  1968. "@return Returns true if the cursor is rendering.\n\n")
  1969. {
  1970. return object->isCursorShown();
  1971. }
  1972. DefineEngineMethod( GuiCanvas, repaint, void, ( S32 elapsedMS ), (0),
  1973. "@brief Force canvas to redraw.\n"
  1974. "If the elapsed time is greater than the time since the last paint "
  1975. "then the repaint will be skipped.\n"
  1976. "@param elapsedMS The optional elapsed time in milliseconds.\n\n"
  1977. "@tsexample\n"
  1978. "Canvas.repaint();\n"
  1979. "@endtsexample\n\n")
  1980. {
  1981. object->repaint(elapsedMS < 0 ? 0 : elapsedMS);
  1982. }
  1983. DefineEngineMethod( GuiCanvas, reset, void, (),,
  1984. "@brief Reset the update regions for the canvas.\n\n"
  1985. "@tsexample\n"
  1986. "Canvas.reset();\n"
  1987. "@endtsexample\n\n")
  1988. {
  1989. object->resetUpdateRegions();
  1990. }
  1991. DefineEngineMethod( GuiCanvas, getCursorPos, Point2I, (),,
  1992. "@brief Get the current position of the cursor in screen-space. Note that this position"
  1993. " might be outside the Torque window. If you want to get the position within the Canvas,"
  1994. " call screenToClient on the result.\n\n"
  1995. "@see Canvas::screenToClient()\n\n"
  1996. "@param param Description\n\n"
  1997. "@tsexample\n"
  1998. "%cursorPos = Canvas.getCursorPos();\n"
  1999. "@endtsexample\n\n"
  2000. "@return Screen coordinates of mouse cursor, in format \"X Y\"")
  2001. {
  2002. return object->getCursorPos();
  2003. }
  2004. ConsoleDocFragment _setCursorPos1(
  2005. "@brief Sets the position of the cursor\n\n"
  2006. "@param pos Point, in screenspace for the cursor. Formatted as (\"x y\")\n\n"
  2007. "@tsexample\n"
  2008. "Canvas.setCursorPos(\"0 0\");\n"
  2009. "@endtsexample\n\n",
  2010. "GuiCanvas",
  2011. "bool setCursorPos( Point2I pos );"
  2012. );
  2013. ConsoleDocFragment _setCursorPos2(
  2014. "@brief Sets the position of the cursor\n\n"
  2015. "@param posX X-coordinate, in screenspace for the cursor.\n"
  2016. "@param posY Y-coordinate, in screenspace for the cursor.\n\n"
  2017. "@tsexample\n"
  2018. "Canvas.setCursorPos(0,0);\n"
  2019. "@endtsexample\n\n",
  2020. "GuiCanvas",
  2021. "bool setCursorPos( F32 posX, F32 posY);"
  2022. );
  2023. DefineEngineMethod( GuiCanvas, setCursorPos, void, (Point2I pos), , "(Point2I pos)"
  2024. "@hide")
  2025. {
  2026. object->setCursorPos(pos);
  2027. }
  2028. DefineEngineMethod( GuiCanvas, getMouseControl, S32, (),,
  2029. "@brief Gets the gui control under the mouse.\n\n"
  2030. "@tsexample\n"
  2031. "%underMouse = Canvas.getMouseControl();\n"
  2032. "@endtsexample\n\n"
  2033. "@return ID of the gui control, if one was found. NULL otherwise")
  2034. {
  2035. GuiControl* control = object->getMouseControl();
  2036. if (control)
  2037. return control->getId();
  2038. return 0;
  2039. }
  2040. DefineEngineFunction(excludeOtherInstance, bool, (const char* appIdentifer),,
  2041. "@brief Used to exclude/prevent all other instances using the same identifier specified\n\n"
  2042. "@note Not used on OSX, Xbox, or in Win debug builds\n\n"
  2043. "@param appIdentifier Name of the app set up for exclusive use.\n"
  2044. "@return False if another app is running that specified the same appIdentifier\n\n"
  2045. "@ingroup Platform\n"
  2046. "@ingroup GuiCore")
  2047. {
  2048. // mac can only run one instance in general.
  2049. #if !defined(TORQUE_OS_MAC) && !defined(TORQUE_DEBUG) && !defined(TORQUE_OS_LINUX)
  2050. return Platform::excludeOtherInstances(appIdentifer);
  2051. #else
  2052. // We can just return true if we get here.
  2053. return true;
  2054. #endif
  2055. }
  2056. DefineEngineMethod( GuiCanvas, getExtent, Point2I, (),,
  2057. "@brief Returns the dimensions of the canvas\n\n"
  2058. "@tsexample\n"
  2059. "%extent = Canvas.getExtent();\n"
  2060. "@endtsexample\n\n"
  2061. "@return Width and height of canvas. Formatted as numerical values in a single string \"# #\"")
  2062. {
  2063. return object->getExtent();
  2064. }
  2065. DefineEngineMethod( GuiCanvas, setWindowTitle, void, ( const char* newTitle),,
  2066. "@brief Change the title of the OS window.\n\n"
  2067. "@param newTitle String containing the new name\n\n"
  2068. "@tsexample\n"
  2069. "Canvas.setWindowTitle(\"Documentation Rocks!\");\n"
  2070. "@endtsexample\n\n")
  2071. {
  2072. object->setWindowTitle(newTitle);
  2073. }
  2074. DefineEngineMethod( GuiCanvas, findFirstMatchingMonitor, S32, (const char* name),,
  2075. "@brief Find the first monitor index that matches the given name.\n\n"
  2076. "The actual match algorithm depends on the implementation.\n"
  2077. "@param name The name to search for.\n\n"
  2078. "@return The number of monitors attached to the system, including the default monoitor.")
  2079. {
  2080. return PlatformWindowManager::get()->findFirstMatchingMonitor(name);
  2081. }
  2082. DefineEngineMethod( GuiCanvas, getMonitorCount, S32, (),,
  2083. "@brief Gets the number of monitors attached to the system.\n\n"
  2084. "@return The number of monitors attached to the system, including the default monoitor.")
  2085. {
  2086. return PlatformWindowManager::get()->getMonitorCount();
  2087. }
  2088. DefineEngineMethod( GuiCanvas, getMonitorName, const char*, (S32 index),,
  2089. "@brief Gets the name of the requested monitor.\n\n"
  2090. "@param index The monitor index.\n\n"
  2091. "@return The name of the requested monitor.")
  2092. {
  2093. return PlatformWindowManager::get()->getMonitorName(index);
  2094. }
  2095. DefineEngineMethod( GuiCanvas, getMonitorRect, RectI, (S32 index),,
  2096. "@brief Gets the region of the requested monitor.\n\n"
  2097. "@param index The monitor index.\n\n"
  2098. "@return The rectangular region of the requested monitor.")
  2099. {
  2100. return PlatformWindowManager::get()->getMonitorRect(index);
  2101. }
  2102. DefineEngineMethod( GuiCanvas, getMonitorUsableRect, RectI, (S32 index),,
  2103. "@brief Use this function to get the usable desktop area represented by a display, with the primary display located at 0,0.\n\n"
  2104. "This is the same area as Canvas.getMonitorRect() reports, but with portions reserved by the system removed. "
  2105. "For example, on Apple Mac OS X, this subtracts the area occupied by the menu bar and dock.\n"
  2106. "Setting a window to be fullscreen generally bypasses these unusable areas, so these are good guidelines for "
  2107. "the maximum space available to a non - fullscreen window."
  2108. "@param index The monitor index.\n\n"
  2109. "@return The rectangular region of the requested monitor.")
  2110. {
  2111. return PlatformWindowManager::get()->getMonitorUsableRect(index);
  2112. }
  2113. DefineEngineMethod(GuiCanvas, getMonitorModeCount, S32, (S32 monitorIndex), (0),
  2114. "Gets the number of video modes available on the selected monitor.\n\n")
  2115. {
  2116. return PlatformWindowManager::get()->getMonitorModeCount(monitorIndex);
  2117. }
  2118. DefineEngineMethod(GuiCanvas, getMonitorMode, const char*, (S32 monitorIndex, S32 modeIndex), (0),
  2119. "Gets a video mode string from the selected monitor.\n\n")
  2120. {
  2121. char* buf = Con::getReturnBuffer(PlatformWindowManager::get()->getMonitorMode(monitorIndex, modeIndex));
  2122. return buf;
  2123. }
  2124. DefineEngineMethod(GuiCanvas, getMonitorDesktopMode, const char*, (S32 monitorIndex), (0),
  2125. "Gets the current desktop mode for the selected monitor.\n\n")
  2126. {
  2127. char* buf = Con::getReturnBuffer(PlatformWindowManager::get()->getMonitorDesktopMode(monitorIndex));
  2128. return buf;
  2129. }
  2130. DefineEngineMethod( GuiCanvas, getVideoMode, const char*, (),,
  2131. "@brief Gets the current screen mode as a string.\n\n"
  2132. "The return string will contain 5 values (width, height, fullscreen, bitdepth, refreshRate). "
  2133. "You will need to parse out each one for individual use.\n\n"
  2134. "@tsexample\n"
  2135. "%screenWidth = getWord(Canvas.getVideoMode(), 0);\n"
  2136. "%screenHeight = getWord(Canvas.getVideoMode(), 1);\n"
  2137. "%isFullscreen = getWord(Canvas.getVideoMode(), 2);\n"
  2138. "%bitdepth = getWord(Canvas.getVideoMode(), 3);\n"
  2139. "%refreshRate = getWord(Canvas.getVideoMode(), 4);\n"
  2140. "@endtsexample\n\n"
  2141. "@return String formatted with screen width, screen height, screen mode, bit depth, and refresh rate.")
  2142. {
  2143. // Grab the video mode.
  2144. if (!object->getPlatformWindow())
  2145. return "";
  2146. GFXVideoMode vm = object->getPlatformWindow()->getVideoMode();
  2147. char* buf = Con::getReturnBuffer(vm.toString());
  2148. return buf;
  2149. }
  2150. DefineEngineMethod( GuiCanvas, getModeCount, S32, (),,
  2151. "@brief Gets the number of modes available on this device.\n\n"
  2152. "@param param Description\n\n"
  2153. "@tsexample\n"
  2154. "%modeCount = Canvas.getModeCount()\n"
  2155. "@endtsexample\n\n"
  2156. "@return The number of video modes supported by the device")
  2157. {
  2158. if (!object->getPlatformWindow())
  2159. return 0;
  2160. // Grab the available mode list from the device.
  2161. const Vector<GFXVideoMode>* const modeList =
  2162. object->getPlatformWindow()->getGFXDevice()->getVideoModeList();
  2163. // Return the number of resolutions.
  2164. return modeList->size();
  2165. }
  2166. DefineEngineMethod( GuiCanvas, getMode, const char*, (S32 modeId),,
  2167. "@brief Gets information on the specified mode of this device.\n\n"
  2168. "@param modeId Index of the mode to get data from.\n"
  2169. "@return A video mode string given an adapter and mode index.\n\n"
  2170. "@see GuiCanvas::getVideoMode()")
  2171. {
  2172. if (!object->getPlatformWindow())
  2173. return 0;
  2174. // Grab the available mode list from the device.
  2175. const Vector<GFXVideoMode>* const modeList =
  2176. object->getPlatformWindow()->getGFXDevice()->getVideoModeList();
  2177. // Get the desired index and confirm it's valid.
  2178. S32 idx = modeId;
  2179. if((idx < 0) || (idx >= modeList->size()))
  2180. {
  2181. Con::errorf("GuiCanvas::getResolution - You requested an out of range index of %d. Please specify an index in the range [0, %d).", idx, modeList->size());
  2182. return "";
  2183. }
  2184. // Great - we got something valid, so convert the videomode into a
  2185. // string and return to the user.
  2186. GFXVideoMode vm = (*modeList)[idx];
  2187. char *retString = Con::getReturnBuffer(vm.toString());
  2188. return retString;
  2189. }
  2190. DefineEngineMethod( GuiCanvas, toggleFullscreen, void, (),,
  2191. "@brief toggle canvas from fullscreen to windowed mode or back.\n\n"
  2192. "@tsexample\n"
  2193. "// If we are in windowed mode, the following will put is in fullscreen\n"
  2194. "Canvas.toggleFullscreen();"
  2195. "@endtsexample\n\n")
  2196. {
  2197. if (Platform::getWebDeployment())
  2198. return;
  2199. if (!object->getPlatformWindow())
  2200. return;
  2201. if (Journal::IsRecording() || Journal::IsPlaying())
  2202. return;
  2203. // Get the window's video mode.
  2204. GFXVideoMode origMode = object->getPlatformWindow()->getVideoMode();
  2205. // And grab the device its using.
  2206. GFXDevice *device = object->getPlatformWindow()->getGFXDevice();
  2207. // Toggle the fullscreen bit.
  2208. GFXVideoMode newMode = origMode;
  2209. newMode.fullScreen = !origMode.fullScreen;
  2210. // CodeReview Toggling might be better served by reading the fullscreen
  2211. // or windowed video mode pref and setting that instead [bjg 5/2/07]
  2212. if(newMode.fullScreen == true)
  2213. {
  2214. // Are we going to fullscreen? If so find the first matching resolution that
  2215. // is equal to or bigger in size, and has same BPP - windows
  2216. // are often strangely sized and will need to be adjusted to a viable
  2217. // fullscreen res.
  2218. for(S32 i=0; i<device->getVideoModeList()->size(); i++)
  2219. {
  2220. const GFXVideoMode &newVm = (*(device->getVideoModeList()))[i];
  2221. if(newMode.resolution.x > newVm.resolution.x)
  2222. continue;
  2223. if(newMode.resolution.y > newVm.resolution.y)
  2224. continue;
  2225. if(newMode.bitDepth != newVm.bitDepth)
  2226. continue;
  2227. // Great - got a match.
  2228. newMode = newVm;
  2229. newMode.fullScreen = true;
  2230. break;
  2231. }
  2232. }
  2233. // Ok, we have new video mode. Set it!
  2234. object->getPlatformWindow()->setVideoMode(newMode);
  2235. }
  2236. DefineEngineMethod( GuiCanvas, clientToScreen, Point2I, ( Point2I coordinate ),,
  2237. "Translate a coordinate from canvas window-space to screen-space.\n"
  2238. "@param coordinate The coordinate in window-space.\n"
  2239. "@return The given coordinate translated to screen-space." )
  2240. {
  2241. if( !object->getPlatformWindow() )
  2242. return coordinate;
  2243. return object->getPlatformWindow()->clientToScreen( coordinate );
  2244. }
  2245. DefineEngineMethod( GuiCanvas, screenToClient, Point2I, ( Point2I coordinate ),,
  2246. "Translate a coordinate from screen-space to canvas window-space.\n"
  2247. "@param coordinate The coordinate in screen-space.\n"
  2248. "@return The given coordinate translated to window-space." )
  2249. {
  2250. if( !object->getPlatformWindow() )
  2251. return coordinate;
  2252. return object->getPlatformWindow()->screenToClient( coordinate );
  2253. }
  2254. DefineEngineMethod( GuiCanvas, getWindowPosition, Point2I, (),,
  2255. "Get the current position of the platform window associated with the canvas.\n"
  2256. "@return The window position of the canvas in screen-space." )
  2257. {
  2258. if( !object->getPlatformWindow() )
  2259. return Point2I( 0, 0 );
  2260. return object->getPlatformWindow()->getPosition();
  2261. }
  2262. DefineEngineMethod( GuiCanvas, setWindowPosition, void, ( Point2I position ),,
  2263. "Set the position of the platform window associated with the canvas.\n"
  2264. "@param position The new position of the window in screen-space." )
  2265. {
  2266. if( !object->getPlatformWindow() )
  2267. return;
  2268. object->getPlatformWindow()->setPosition( position );
  2269. }
  2270. DefineEngineMethod( GuiCanvas, isFullscreen, bool, (), , "() - Is this canvas currently fullscreen?" )
  2271. {
  2272. if (Platform::getWebDeployment())
  2273. return false;
  2274. if (!object->getPlatformWindow())
  2275. return false;
  2276. return object->getPlatformWindow()->getVideoMode().fullScreen;
  2277. }
  2278. DefineEngineMethod( GuiCanvas, minimizeWindow, void, (), , "() - minimize this canvas' window." )
  2279. {
  2280. PlatformWindow* window = object->getPlatformWindow();
  2281. if ( window )
  2282. window->minimize();
  2283. }
  2284. DefineEngineMethod( GuiCanvas, isMinimized, bool, (), , "()" )
  2285. {
  2286. PlatformWindow* window = object->getPlatformWindow();
  2287. if ( window )
  2288. return window->isMinimized();
  2289. return false;
  2290. }
  2291. DefineEngineMethod( GuiCanvas, isMaximized, bool, (), , "()" )
  2292. {
  2293. PlatformWindow* window = object->getPlatformWindow();
  2294. if ( window )
  2295. return window->isMaximized();
  2296. return false;
  2297. }
  2298. DefineEngineMethod( GuiCanvas, maximizeWindow, void, (), , "() - maximize this canvas' window." )
  2299. {
  2300. PlatformWindow* window = object->getPlatformWindow();
  2301. if ( window )
  2302. window->maximize();
  2303. }
  2304. DefineEngineMethod( GuiCanvas, restoreWindow, void, (), , "() - restore this canvas' window." )
  2305. {
  2306. PlatformWindow* window = object->getPlatformWindow();
  2307. if( window )
  2308. window->restore();
  2309. }
  2310. DefineEngineMethod( GuiCanvas, setFocus, void, (), , "() - Claim OS input focus for this canvas' window.")
  2311. {
  2312. PlatformWindow* window = object->getPlatformWindow();
  2313. if (window)
  2314. {
  2315. window->setFocus();
  2316. window->appEvent.trigger(window->getWindowId(), GainFocus);
  2317. }
  2318. }
  2319. #ifdef TORQUE_TOOLS
  2320. DefineEngineMethod( GuiCanvas, setMenuBar, void, ( GuiControl* menu ),,
  2321. "Translate a coordinate from canvas window-space to screen-space.\n"
  2322. "@param coordinate The coordinate in window-space.\n"
  2323. "@return The given coordinate translated to screen-space." )
  2324. {
  2325. return object->setMenuBar( menu );
  2326. }
  2327. #endif
  2328. DefineEngineMethod( GuiCanvas, setVideoMode, void,
  2329. (U32 width, U32 height, bool fullscreen, U32 bitDepth, U32 refreshRate, U32 antialiasLevel),
  2330. ( false, 0, 0, 0),
  2331. "(int width, int height, bool fullscreen, [int bitDepth], [int refreshRate], [int antialiasLevel] )\n"
  2332. "Change the video mode of this canvas. This method has the side effect of setting the $pref::Video::mode to the new values.\n\n"
  2333. "\\param width The screen width to set.\n"
  2334. "\\param height The screen height to set.\n"
  2335. "\\param fullscreen Specify true to run fullscreen or false to run in a window\n"
  2336. "\\param bitDepth [optional] The desired bit-depth. Defaults to the current setting. This parameter is ignored if you are running in a window.\n"
  2337. "\\param refreshRate [optional] The desired refresh rate. Defaults to the current setting. This parameter is ignored if you are running in a window"
  2338. "\\param antialiasLevel [optional] The level of anti-aliasing to apply 0 = none" )
  2339. {
  2340. if (!object->getPlatformWindow())
  2341. return;
  2342. if (Journal::IsRecording() || Journal::IsPlaying())
  2343. return;
  2344. // Update the video mode and tell the window to reset.
  2345. GFXVideoMode vm = object->getPlatformWindow()->getVideoMode();
  2346. bool changed = false;
  2347. if (width == 0 && height > 0)
  2348. {
  2349. // Our width is 0 but our height isn't...
  2350. // Try to find a matching width
  2351. for(S32 i=0; i<object->getPlatformWindow()->getGFXDevice()->getVideoModeList()->size(); i++)
  2352. {
  2353. const GFXVideoMode &newVm = (*(object->getPlatformWindow()->getGFXDevice()->getVideoModeList()))[i];
  2354. if(newVm.resolution.y == height)
  2355. {
  2356. width = newVm.resolution.x;
  2357. changed = true;
  2358. break;
  2359. }
  2360. }
  2361. }
  2362. else if (height == 0 && width > 0)
  2363. {
  2364. // Our height is 0 but our width isn't...
  2365. // Try to find a matching height
  2366. for(S32 i=0; i<object->getPlatformWindow()->getGFXDevice()->getVideoModeList()->size(); i++)
  2367. {
  2368. const GFXVideoMode &newVm = (*(object->getPlatformWindow()->getGFXDevice()->getVideoModeList()))[i];
  2369. if(newVm.resolution.x == width)
  2370. {
  2371. height = newVm.resolution.y;
  2372. changed = true;
  2373. break;
  2374. }
  2375. }
  2376. }
  2377. if (width == 0 || height == 0)
  2378. {
  2379. // Got a bad size for both of our dimensions or one of our dimensions and
  2380. // didn't get a match for the other default back to our current resolution
  2381. width = vm.resolution.x;
  2382. height = vm.resolution.y;
  2383. changed = true;
  2384. }
  2385. if (changed)
  2386. {
  2387. Con::errorf("GuiCanvas::setVideoMode(): Error - Invalid resolution of (%d, %d) - attempting (%d, %d)", width, height, width, height);
  2388. }
  2389. vm.resolution = Point2I(width, height);
  2390. vm.fullScreen = fullscreen;
  2391. if (Platform::getWebDeployment())
  2392. vm.fullScreen = false;
  2393. // These optional params are set to default at construction of vm. If they
  2394. // aren't specified, just leave them at whatever they were set to.
  2395. if (bitDepth > 0)
  2396. {
  2397. vm.bitDepth = bitDepth;
  2398. }
  2399. if (refreshRate > 0)
  2400. {
  2401. vm.refreshRate = refreshRate;
  2402. }
  2403. if (antialiasLevel > 0)
  2404. {
  2405. vm.antialiasLevel = antialiasLevel;
  2406. }
  2407. object->getPlatformWindow()->setVideoMode(vm);
  2408. // Store the new mode into a pref.
  2409. Con::setVariable( "$pref::Video::mode", vm.toString() );
  2410. }
  2411. DefineEngineMethod(GuiCanvas, showWindow, void, (),, "")
  2412. {
  2413. if (!object->getPlatformWindow())
  2414. return;
  2415. object->getPlatformWindow()->show();
  2416. WindowManager->setDisplayWindow(true);
  2417. object->getPlatformWindow()->setDisplayWindow(true);
  2418. }
  2419. DefineEngineMethod(GuiCanvas, hideWindow, void, (),, "")
  2420. {
  2421. if (!object->getPlatformWindow())
  2422. return;
  2423. object->getPlatformWindow()->hide();
  2424. WindowManager->setDisplayWindow(false);
  2425. object->getPlatformWindow()->setDisplayWindow(false);
  2426. }
  2427. DefineEngineMethod(GuiCanvas, cursorClick, void, (S32 buttonId, bool isDown), , "")
  2428. {
  2429. object->cursorClick(buttonId, isDown);
  2430. }
  2431. DefineEngineMethod(GuiCanvas, cursorNudge, void, (F32 x, F32 y), , "")
  2432. {
  2433. object->cursorNudge(x, y);
  2434. }
  2435. // This function allows resetting of the video-mode from script. It was motivated by
  2436. // the need to temporarily disable vsync during datablock cache load to avoid a
  2437. // significant slowdown.
  2438. bool AFX_forceVideoReset = false;
  2439. DefineEngineMethod(GuiCanvas, resetVideoMode, void, (), , "")
  2440. {
  2441. PlatformWindow* window = object->getPlatformWindow();
  2442. if (window)
  2443. {
  2444. GFXWindowTarget* gfx_target = window->getGFXTarget();
  2445. if (gfx_target)
  2446. {
  2447. AFX_forceVideoReset = true;
  2448. gfx_target->resetMode();
  2449. AFX_forceVideoReset = false;
  2450. }
  2451. }
  2452. }