guiCanvas.cc 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "torqueConfig.h"
  23. #include "console/consoleInternal.h"
  24. #include "debug/profiler.h"
  25. #include "graphics/dgl.h"
  26. #include "platform/event.h"
  27. #include "platform/platform.h"
  28. #include "platform/platformInput.h"
  29. #include "platform/platformVideo.h"
  30. #include "gui/guiTypes.h"
  31. #include "gui/guiControl.h"
  32. #include "gui/guiCanvas.h"
  33. #include "game/gameInterface.h"
  34. #include "guiCanvas_ScriptBinding.h"
  35. extern int _AndroidGetScreenWidth();
  36. extern int _AndroidGetScreenHeight();
  37. IMPLEMENT_CONOBJECT(GuiCanvas);
  38. GuiCanvas *Canvas = NULL;
  39. GuiCanvas::GuiCanvas()
  40. {
  41. #ifdef TORQUE_OS_IOS
  42. mBounds.set(0, 0, IOS_DEFAULT_RESOLUTION_X, IOS_DEFAULT_RESOLUTION_Y);
  43. #elif TORQUE_OS_ANDROID
  44. mBounds.set(0, 0, _AndroidGetScreenWidth(), _AndroidGetScreenHeight());
  45. #else
  46. mBounds.set(0, 0, MIN_RESOLUTION_X, MIN_RESOLUTION_Y);
  47. #endif
  48. mAwake = true;
  49. mPixelsPerMickey = 1.0f;
  50. cursorON = true;
  51. mShowCursor = false;
  52. mUseNativeCursor = true;
  53. lastCursorON = false;
  54. rLastFrameTime = 0.0f;
  55. mMouseCapturedControl = NULL;
  56. mMouseControl = NULL;
  57. mMouseControlClicked = false;
  58. mMouseButtonDown = false;
  59. mMouseRightButtonDown = false;
  60. mMouseMiddleButtonDown = false;
  61. lastCursor = NULL;
  62. lastCursorPt.set(0,0);
  63. cursorPt.set(0,0);
  64. mLastMouseClickCount = 0;
  65. mLastMouseDownTime = 0;
  66. mPrevMouseTime = 0;
  67. defaultCursor = NULL;
  68. mRenderFront = false;
  69. hoverControlStart = Platform::getRealMilliseconds();
  70. hoverControl = NULL;
  71. hoverPosition = getCursorPos();
  72. hoverPositionSet = false;
  73. hoverLeftControlTime = 0;
  74. mLeftMouseLast = false;
  75. mMiddleMouseLast = false;
  76. mRightMouseLast = false;
  77. mDoubleClickWidth = Input::getDoubleClickWidth();
  78. mDoubleClickHeight = Input::getDoubleClickHeight();
  79. mDoubleClickTime = Input::getDoubleClickTime();
  80. mTouchDetectionSize = 100;
  81. mPotentialTouchEvent = false;
  82. mHideCursorBecauseOfTouch = false;
  83. /// Background color.
  84. mBackgroundColor.set( 0.0f, 0.0f, 0.0f, 0.0f );
  85. mUseBackgroundColor = true;
  86. }
  87. GuiCanvas::~GuiCanvas()
  88. {
  89. if(Canvas == this)
  90. Canvas = 0;
  91. }
  92. //-----------------------------------------------------------------------------
  93. void GuiCanvas::initPersistFields()
  94. {
  95. // Call Parent.
  96. Parent::initPersistFields();
  97. // Physics.
  98. addField("UseBackgroundColor", TypeBool, Offset(mUseBackgroundColor, GuiCanvas), "" );
  99. addField("BackgroundColor", TypeColorF, Offset(mBackgroundColor, GuiCanvas), "" );
  100. }
  101. //------------------------------------------------------------------------------
  102. void GuiCanvas::setCursor(GuiCursor *curs)
  103. {
  104. defaultCursor = curs;
  105. if(mShowCursor)
  106. {
  107. mUseNativeCursor = false;
  108. Input::setCursorState(false);
  109. }
  110. }
  111. void GuiCanvas::setCursorON(bool onOff)
  112. {
  113. cursorON = onOff;
  114. if(!cursorON)
  115. mMouseControl = NULL;
  116. }
  117. bool GuiCanvas::getUseNativeCursor(void)
  118. {
  119. return mUseNativeCursor;
  120. }
  121. void GuiCanvas::useNativeCursor(bool useNative)
  122. {
  123. if(!mUseNativeCursor && useNative)
  124. {
  125. //We are turning on the native cursor
  126. Input::setCursorState(true);
  127. }
  128. else if(mUseNativeCursor && !useNative)
  129. {
  130. //We are turning off the native cursor
  131. Input::setCursorState(false);
  132. }
  133. mUseNativeCursor = useNative;
  134. }
  135. void GuiCanvas::setCursorPos(const Point2I &pt)
  136. {
  137. cursorPt.x = F32(pt.x);
  138. cursorPt.y = F32(pt.y);
  139. Input::setCursorPos( pt.x, pt.y );
  140. }
  141. void GuiCanvas::addAcceleratorKey(GuiControl *ctrl, U32 index, U32 keyCode, U32 modifier)
  142. {
  143. if (keyCode > 0 && ctrl)
  144. {
  145. AccKeyMap newMap;
  146. newMap.ctrl = ctrl;
  147. newMap.index = index;
  148. newMap.keyCode = keyCode;
  149. newMap.modifier = modifier;
  150. mAcceleratorMap.push_back(newMap);
  151. }
  152. }
  153. bool GuiCanvas::tabNext(void)
  154. {
  155. GuiControl *ctrl = static_cast<GuiControl *>(last());
  156. if (ctrl)
  157. {
  158. //save the old
  159. GuiControl *oldResponder = mFirstResponder;
  160. GuiControl* newResponder = ctrl->findNextTabable(mFirstResponder);
  161. if ( !newResponder )
  162. newResponder = ctrl->findFirstTabable();
  163. if ( newResponder && newResponder != oldResponder )
  164. {
  165. newResponder->setFirstResponder();
  166. if ( oldResponder )
  167. oldResponder->onLoseFirstResponder();
  168. return true;
  169. }
  170. }
  171. return false;
  172. }
  173. bool GuiCanvas::tabPrev(void)
  174. {
  175. GuiControl *ctrl = static_cast<GuiControl *>(last());
  176. if (ctrl)
  177. {
  178. //save the old
  179. GuiControl *oldResponder = mFirstResponder;
  180. GuiControl* newResponder = ctrl->findPrevTabable(mFirstResponder);
  181. if ( !newResponder )
  182. newResponder = ctrl->findLastTabable();
  183. if ( newResponder && newResponder != oldResponder )
  184. {
  185. newResponder->setFirstResponder();
  186. if ( oldResponder )
  187. oldResponder->onLoseFirstResponder();
  188. return true;
  189. }
  190. }
  191. return false;
  192. }
  193. void GuiCanvas::processScreenTouchEvent(const ScreenTouchEvent *event)
  194. {
  195. //copy the cursor point into the event
  196. mLastEvent.mousePoint.x = S32(event->xPos);
  197. mLastEvent.mousePoint.y = S32(event->yPos);
  198. mLastEvent.eventID = event->touchID;
  199. mLastEvent.mouseClickCount = event->numTouches;
  200. //see if button was pressed
  201. if (event->action == SI_MAKE)
  202. {
  203. U32 curTime = Platform::getVirtualMilliseconds();
  204. mNextMouseTime = curTime + mInitialMouseDelay;
  205. mLastMouseDownTime = curTime;
  206. // mLastEvent.mouseClickCount = mLastMouseClickCount;
  207. rootScreenTouchDown(mLastEvent);
  208. }
  209. else if(event->action == SI_MOVE)
  210. {
  211. rootScreenTouchMove(mLastEvent);
  212. }
  213. //else button was released
  214. else if(event->action == SI_BREAK)
  215. {
  216. mNextMouseTime = 0xFFFFFFFF;
  217. rootScreenTouchUp(mLastEvent);
  218. }
  219. }
  220. void GuiCanvas::processMouseMoveEvent(const MouseMoveEvent *event)
  221. {
  222. if( cursorON )
  223. {
  224. //copy the modifier into the new event
  225. mLastEvent.modifier = event->modifier;
  226. cursorPt.x += ( F32(event->xPos - cursorPt.x) * mPixelsPerMickey);
  227. cursorPt.y += ( F32(event->yPos - cursorPt.y) * mPixelsPerMickey);
  228. // clamp the cursor to the window, or not
  229. if( ! Con::getBoolVariable( "$pref::Gui::noClampTorqueCursorToWindow", true ))
  230. {
  231. cursorPt.x =(F32) getMax(0, getMin((S32)cursorPt.x, mBounds.extent.x - 1));
  232. cursorPt.y = (F32)getMax(0, getMin((S32)cursorPt.y, mBounds.extent.y - 1));
  233. }
  234. mLastEvent.mousePoint.x = S32(cursorPt.x);
  235. mLastEvent.mousePoint.y = S32(cursorPt.y);
  236. mLastEvent.eventID = 0;
  237. Point2F movement = mMouseDownPoint - cursorPt;
  238. if ((mAbs((S32)movement.x) > mDoubleClickWidth) || (mAbs((S32)movement.y) > mDoubleClickHeight))
  239. {
  240. mLeftMouseLast = false;
  241. mMiddleMouseLast = false;
  242. mRightMouseLast = false;
  243. }
  244. //should we try to detect a touch event pretending to be a mouse event?
  245. if( Con::getBoolVariable( "$pref::Gui::hideCursorWhenTouchEventDetected", false ))
  246. {
  247. mPotentialTouchEvent = false;
  248. Point2F jump = mPrevMouseMovePosition - cursorPt;
  249. if ((mAbs((S32)jump.x) > mTouchDetectionSize) || (mAbs((S32)jump.y) > mTouchDetectionSize))
  250. {
  251. mPotentialTouchEvent = true;
  252. mPotentialMouseEventCount = 0;
  253. }
  254. else if(mHideCursorBecauseOfTouch && !mMouseButtonDown)
  255. {
  256. if(mPotentialMouseEventCount > 20)
  257. {
  258. //This is our 20th small movement with no click or drag so it must be a mouse!
  259. mHideCursorBecauseOfTouch = false;
  260. mPotentialMouseEventCount = 0;
  261. }
  262. else
  263. {
  264. mPotentialMouseEventCount++;
  265. }
  266. }
  267. mPrevMouseMovePosition.set(cursorPt.x, cursorPt.y);
  268. }
  269. if (mMouseButtonDown)
  270. rootMouseDragged(mLastEvent);
  271. else if (mMouseRightButtonDown)
  272. rootRightMouseDragged(mLastEvent);
  273. else if(mMouseMiddleButtonDown)
  274. rootMiddleMouseDragged(mLastEvent);
  275. else
  276. rootMouseMove(mLastEvent);
  277. }
  278. }
  279. bool GuiCanvas::processInputEvent(const InputEvent *event)
  280. {
  281. // First call the general input handler (on the extremely off-chance that it will be handled):
  282. if ( mFirstResponder )
  283. {
  284. if ( mFirstResponder->onInputEvent( *event ) )
  285. return( true );
  286. }
  287. if(event->deviceType == KeyboardDeviceType)
  288. {
  289. mLastEvent.ascii = event->ascii;
  290. mLastEvent.modifier = event->modifier;
  291. mLastEvent.keyCode = (U8)event->objInst;
  292. U32 eventModifier = event->modifier;
  293. if(eventModifier & SI_SHIFT)
  294. eventModifier |= SI_SHIFT;
  295. if(eventModifier & SI_CTRL)
  296. eventModifier |= SI_CTRL;
  297. if(eventModifier & SI_ALT)
  298. eventModifier |= SI_ALT;
  299. if (event->action == SI_MAKE)
  300. {
  301. //see if we should tab next/prev
  302. //see if we should now pass the event to the first responder
  303. if (mFirstResponder)
  304. {
  305. if(mFirstResponder->onKeyDown(mLastEvent))
  306. return true;
  307. }
  308. if ( isCursorON() && ( event->objInst == KEY_TAB ) )
  309. {
  310. if (size() > 0)
  311. {
  312. if (event->modifier & SI_SHIFT)
  313. {
  314. if(tabPrev())
  315. return true;
  316. }
  317. else if (event->modifier == 0)
  318. {
  319. if(tabNext())
  320. return true;
  321. }
  322. }
  323. }
  324. //if not handled, search for an accelerator
  325. for (U32 i = 0; i < (U32)mAcceleratorMap.size(); i++)
  326. {
  327. if ((U32)mAcceleratorMap[i].IsKeyCodeEqual(event->objInst) && (U32)mAcceleratorMap[i].modifier == eventModifier)
  328. {
  329. mAcceleratorMap[i].ctrl->acceleratorKeyPress(mAcceleratorMap[i].index);
  330. return true;
  331. }
  332. }
  333. }
  334. else if(event->action == SI_BREAK)
  335. {
  336. if(mFirstResponder)
  337. {
  338. if(mFirstResponder->onKeyUp(mLastEvent))
  339. return true;
  340. }
  341. //see if there's an accelerator
  342. for (U32 i = 0; i < (U32)mAcceleratorMap.size(); i++)
  343. {
  344. if ((U32)mAcceleratorMap[i].keyCode == (U32)event->objInst && (U32)mAcceleratorMap[i].modifier == eventModifier)
  345. {
  346. mAcceleratorMap[i].ctrl->acceleratorKeyRelease(mAcceleratorMap[i].index);
  347. return true;
  348. }
  349. }
  350. }
  351. else if(event->action == SI_REPEAT)
  352. {
  353. if (mFirstResponder)
  354. {
  355. if (mFirstResponder->onKeyRepeat(mLastEvent))
  356. return true;
  357. }
  358. //if not handled, search for an accelerator
  359. for (U32 i = 0; i < (U32)mAcceleratorMap.size(); i++)
  360. {
  361. if ((U32)mAcceleratorMap[i].keyCode == (U32)event->objInst && (U32)mAcceleratorMap[i].modifier == eventModifier)
  362. {
  363. mAcceleratorMap[i].ctrl->acceleratorKeyPress(mAcceleratorMap[i].index);
  364. return true;
  365. }
  366. }
  367. }
  368. }
  369. else if(event->deviceType == MouseDeviceType && cursorON)
  370. {
  371. //copy the modifier into the new event
  372. mLastEvent.modifier = event->modifier;
  373. if(event->objType == SI_XAXIS || event->objType == SI_YAXIS)
  374. {
  375. bool moved = false;
  376. Point2I oldpt((S32)cursorPt.x, (S32)cursorPt.y);
  377. Point2F pt(cursorPt.x, cursorPt.y);
  378. if (event->objType == SI_XAXIS)
  379. {
  380. pt.x += (event->fValues[0] * mPixelsPerMickey);
  381. cursorPt.x = (F32)getMax(0, getMin((S32)pt.x, mBounds.extent.x - 1));
  382. if (oldpt.x != S32(cursorPt.x))
  383. moved = true;
  384. }
  385. else
  386. {
  387. pt.y += (event->fValues[0] * mPixelsPerMickey);
  388. cursorPt.y = (F32)getMax(0, getMin((S32)pt.y, mBounds.extent.y - 1));
  389. if (oldpt.y != S32(cursorPt.y))
  390. moved = true;
  391. }
  392. if (moved)
  393. {
  394. mLastEvent.mousePoint.x = S32(cursorPt.x);
  395. mLastEvent.mousePoint.y = S32(cursorPt.y);
  396. mLastEvent.eventID = 0;
  397. #ifdef TORQUE_ALLOW_JOURNALING
  398. // [tom, 9/8/2006] If we're journaling, we need to update the plat cursor
  399. if(Game->isJournalReading())
  400. Input::setCursorPos((S32)cursorPt.x, (S32)cursorPt.y);
  401. #endif //TORQUE_ALLOW_JOURNALING
  402. if (mMouseButtonDown)
  403. rootMouseDragged(mLastEvent);
  404. else if (mMouseRightButtonDown)
  405. rootRightMouseDragged(mLastEvent);
  406. else if(mMouseMiddleButtonDown)
  407. rootMiddleMouseDragged(mLastEvent);
  408. else
  409. rootMouseMove(mLastEvent);
  410. }
  411. return true;
  412. }
  413. else if ( event->objType == SI_ZAXIS )
  414. {
  415. mLastEvent.mousePoint.x = S32( cursorPt.x );
  416. mLastEvent.mousePoint.y = S32( cursorPt.y );
  417. mLastEvent.eventID = 0;
  418. if ( event->fValues[0] < 0.0f )
  419. rootMouseWheelDown( mLastEvent );
  420. else
  421. rootMouseWheelUp( mLastEvent );
  422. }
  423. else if(event->objType == SI_BUTTON)
  424. {
  425. //copy the cursor point into the event
  426. mLastEvent.mousePoint.x = S32(cursorPt.x);
  427. mLastEvent.mousePoint.y = S32(cursorPt.y);
  428. mLastEvent.eventID = 0;
  429. mMouseDownPoint = cursorPt;
  430. if(event->objInst == KEY_BUTTON0) // left button
  431. {
  432. //see if button was pressed
  433. if (event->action == SI_MAKE)
  434. {
  435. U32 curTime = Platform::getVirtualMilliseconds();
  436. mNextMouseTime = curTime + mInitialMouseDelay;
  437. //if the last button pressed was the left...
  438. if (mLeftMouseLast)
  439. {
  440. //if it was within the double click time count the clicks
  441. if ((S32)curTime - mLastMouseDownTime <= mDoubleClickTime)
  442. mLastMouseClickCount++;
  443. else
  444. mLastMouseClickCount = 1;
  445. }
  446. else
  447. {
  448. mLeftMouseLast = true;
  449. mLastMouseClickCount = 1;
  450. }
  451. mLastMouseDownTime = curTime;
  452. mLastEvent.mouseClickCount = mLastMouseClickCount;
  453. if(mHideCursorBecauseOfTouch)
  454. {
  455. mPotentialMouseEventCount = 0;
  456. }
  457. if(mPotentialTouchEvent)
  458. {
  459. mHideCursorBecauseOfTouch = true;
  460. }
  461. rootMouseDown(mLastEvent);
  462. }
  463. //else button was released
  464. else
  465. {
  466. mNextMouseTime = 0xFFFFFFFF;
  467. rootMouseUp(mLastEvent);
  468. }
  469. return true;
  470. }
  471. else if(event->objInst == KEY_BUTTON1) // right button
  472. {
  473. mHideCursorBecauseOfTouch = false;
  474. if(event->action == SI_MAKE)
  475. {
  476. U32 curTime = Platform::getVirtualMilliseconds();
  477. //if the last button pressed was the right...
  478. if (mRightMouseLast)
  479. {
  480. //if it was within the double click time count the clicks
  481. if ((S32)curTime - mLastMouseDownTime <= mDoubleClickTime)
  482. mLastMouseClickCount++;
  483. else
  484. mLastMouseClickCount = 1;
  485. }
  486. else
  487. {
  488. mRightMouseLast = true;
  489. mLastMouseClickCount = 1;
  490. }
  491. mLastMouseDownTime = curTime;
  492. mLastEvent.mouseClickCount = mLastMouseClickCount;
  493. rootRightMouseDown(mLastEvent);
  494. }
  495. else // it was a mouse up
  496. rootRightMouseUp(mLastEvent);
  497. return true;
  498. }
  499. else if(event->objInst == KEY_BUTTON2) // middle button
  500. {
  501. mHideCursorBecauseOfTouch = false;
  502. if(event->action == SI_MAKE)
  503. {
  504. U32 curTime = Platform::getVirtualMilliseconds();
  505. //if the last button pressed was the right...
  506. if (mMiddleMouseLast)
  507. {
  508. //if it was within the double click time count the clicks
  509. if ((S32)curTime - mLastMouseDownTime <= mDoubleClickTime)
  510. mLastMouseClickCount++;
  511. else
  512. mLastMouseClickCount = 1;
  513. }
  514. else
  515. {
  516. mMiddleMouseLast = true;
  517. mLastMouseClickCount = 1;
  518. }
  519. mLastMouseDownTime = curTime;
  520. mLastEvent.mouseClickCount = mLastMouseClickCount;
  521. rootMiddleMouseDown(mLastEvent);
  522. }
  523. else // it was a mouse up
  524. rootMiddleMouseUp(mLastEvent);
  525. return true;
  526. }
  527. }
  528. }
  529. return false;
  530. }
  531. void GuiCanvas::rootMouseDown(const GuiEvent &event)
  532. {
  533. mPrevMouseTime = Platform::getVirtualMilliseconds();
  534. mMouseButtonDown = true;
  535. //pass the event to the mouse locked control
  536. if (bool(mMouseCapturedControl))
  537. mMouseCapturedControl->onTouchDown(event);
  538. //else pass it to whoever is underneath the cursor
  539. else
  540. {
  541. handleTouchDown(event, event.mousePoint);
  542. }
  543. if (bool(mMouseControl))
  544. mMouseControlClicked = true;
  545. }
  546. void GuiCanvas::findMouseControl(const GuiEvent &event)
  547. {
  548. if(size() == 0)
  549. {
  550. mMouseControl = NULL;
  551. return;
  552. }
  553. GuiControl* leavingStack = static_cast<GuiControl*>(mMouseControl);
  554. GuiControl* controlHit = findHitControl(event.mousePoint);
  555. GuiControl* enteringStack = controlHit;
  556. if(leavingStack != enteringStack)
  557. {
  558. if (bool(mMouseControl))
  559. {
  560. hoverControlStart = Platform::getRealMilliseconds();
  561. hoverPositionSet = false;
  562. //figure out how much of the leaving stack we are leaving.
  563. while (!DoesControlStackContainControl(enteringStack, leavingStack))
  564. {
  565. leavingStack->onTouchLeave(event);
  566. leavingStack = leavingStack->getParent();
  567. if (!leavingStack)
  568. break;
  569. }
  570. }
  571. //figure out how much of the entering stack we are entering.
  572. if (leavingStack)
  573. {
  574. while (!DoesControlStackContainControl(leavingStack, enteringStack))
  575. {
  576. enteringStack->onTouchEnter(event);
  577. enteringStack = enteringStack->getParent();
  578. if(!enteringStack)
  579. break;
  580. }
  581. }
  582. mMouseControl = controlHit;
  583. mMouseControl->onTouchEnter(event);
  584. }
  585. }
  586. bool GuiCanvas::DoesControlStackContainControl(GuiControl* stack, const GuiControl* ctrl)
  587. {
  588. GuiControl* pen = stack;
  589. do
  590. {
  591. if (pen)
  592. {
  593. if (pen == ctrl)
  594. {
  595. return true;
  596. }
  597. pen = pen->getParent();
  598. }
  599. else
  600. {
  601. return false;
  602. }
  603. } while (pen);
  604. return false;
  605. }
  606. //Luma: Some fixes from the forums, Dave Calabrese
  607. //http://www.garagegames.com/community/forums/viewthread/93467/1#comment-669559
  608. void GuiCanvas::rootScreenTouchDown(const GuiEvent &event)
  609. {
  610. mPrevMouseTime = Platform::getVirtualMilliseconds();
  611. mMouseButtonDown = true;
  612. iterator i;
  613. i = end();
  614. while (i != begin())
  615. {
  616. i--;
  617. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  618. if (ctrl->mUseInput)
  619. {
  620. GuiControl* controlHit = ctrl->findHitControl(event.mousePoint);
  621. //If the control we hit is not the same one that is locked,
  622. // then unlock the existing control.
  623. if (bool(mMouseCapturedControl) && mMouseCapturedControl->isMouseLocked() && mMouseCapturedControl != controlHit)
  624. {
  625. mMouseCapturedControl->onTouchLeave(event);
  626. }
  627. //Regardless of what the control does, it has the user's focus.
  628. controlHit->onFocus(false);
  629. if (controlHit->mUseInput)
  630. {
  631. controlHit->mPassEventThru = false;//If true after the call then pass the event to the next control below it.
  632. controlHit->onTouchDown(event);
  633. if (!controlHit->mPassEventThru)
  634. {
  635. break;
  636. }
  637. }
  638. }
  639. }
  640. if (bool(mMouseControl))
  641. mMouseControlClicked = true;
  642. }
  643. void GuiCanvas::rootScreenTouchUp(const GuiEvent &event)
  644. {
  645. mPrevMouseTime = Platform::getVirtualMilliseconds();
  646. mMouseButtonDown = false;
  647. iterator i;
  648. i = end();
  649. while (i != begin())
  650. {
  651. i--;
  652. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  653. if (ctrl->mUseInput)
  654. {
  655. GuiControl* controlHit = ctrl->findHitControl(event.mousePoint);
  656. if (controlHit->mActive && controlHit->mUseInput)
  657. {
  658. controlHit->mPassEventThru = false;//If true after the call then pass the event to the next control below it.
  659. controlHit->onTouchUp(event);
  660. if (!controlHit->mPassEventThru)
  661. {
  662. break;
  663. }
  664. }
  665. }
  666. }
  667. }
  668. void GuiCanvas::rootScreenTouchMove(const GuiEvent &event)
  669. {
  670. //pass the event to the mouse locked control
  671. if (bool(mMouseCapturedControl))
  672. {
  673. checkLockMouseMove(event);
  674. if(!mMouseCapturedControl.isNull())
  675. mMouseCapturedControl->onTouchDragged(event);
  676. }
  677. else
  678. {
  679. findMouseControl(event);
  680. if(bool(mMouseControl))
  681. {
  682. mMouseControl->onTouchDragged(event);
  683. }
  684. }
  685. }
  686. void GuiCanvas::refreshMouseControl()
  687. {
  688. GuiEvent evt;
  689. evt.mousePoint.x = S32(cursorPt.x);
  690. evt.mousePoint.y = S32(cursorPt.y);
  691. findMouseControl(evt);
  692. }
  693. void GuiCanvas::rootMouseUp(const GuiEvent &event)
  694. {
  695. mPrevMouseTime = Platform::getVirtualMilliseconds();
  696. mMouseButtonDown = false;
  697. //pass the event to the mouse locked control
  698. if (bool(mMouseCapturedControl))
  699. mMouseCapturedControl->onTouchUp(event);
  700. else
  701. {
  702. findMouseControl(event);
  703. if (bool(mMouseControl))
  704. {
  705. handleTouchUp(event, event.mousePoint);
  706. }
  707. }
  708. }
  709. void GuiCanvas::checkLockMouseMove(const GuiEvent &event)
  710. {
  711. GuiControl *controlHit = findHitControl(event.mousePoint);
  712. if(controlHit != mMouseControl)
  713. {
  714. if(mMouseControl == mMouseCapturedControl)
  715. mMouseCapturedControl->onTouchLeave(event);
  716. else if(controlHit == mMouseCapturedControl)
  717. mMouseCapturedControl->onTouchEnter(event);
  718. mMouseControl = controlHit;
  719. }
  720. }
  721. void GuiCanvas::rootMouseDragged(const GuiEvent &event)
  722. {
  723. //pass the event to the mouse locked control
  724. if (bool(mMouseCapturedControl))
  725. {
  726. checkLockMouseMove(event);
  727. if(!mMouseCapturedControl.isNull())
  728. mMouseCapturedControl->onTouchDragged(event);
  729. //Luma: Mouse dragged calls mouse Moved on iPhone
  730. #if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
  731. mMouseCapturedControl->onTouchMove(event);
  732. #endif //TORQUE_OS_IOS
  733. }
  734. else
  735. {
  736. findMouseControl(event);
  737. if(bool(mMouseControl))
  738. {
  739. mMouseControl->onTouchDragged(event);
  740. #if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
  741. mMouseControl->onTouchMove(event);
  742. #endif //TORQUE_OS_IOS
  743. }
  744. }
  745. }
  746. void GuiCanvas::rootMouseMove(const GuiEvent &event)
  747. {
  748. if(mMouseCapturedControl != NULL)
  749. {
  750. checkLockMouseMove(event);
  751. if(mMouseCapturedControl != NULL)
  752. mMouseCapturedControl->onTouchMove(event);
  753. }
  754. else
  755. {
  756. findMouseControl(event);
  757. if (bool(mMouseControl))
  758. {
  759. handleTouchMove(event, event.mousePoint);
  760. }
  761. }
  762. }
  763. void GuiCanvas::rootRightMouseDown(const GuiEvent &event)
  764. {
  765. mPrevMouseTime = Platform::getVirtualMilliseconds();
  766. mMouseRightButtonDown = true;
  767. if (bool(mMouseCapturedControl))
  768. mMouseCapturedControl->onRightMouseDown(event);
  769. else
  770. {
  771. findMouseControl(event);
  772. if(bool(mMouseControl))
  773. {
  774. mMouseControl->onRightMouseDown(event);
  775. }
  776. }
  777. }
  778. void GuiCanvas::rootRightMouseUp(const GuiEvent &event)
  779. {
  780. mPrevMouseTime = Platform::getVirtualMilliseconds();
  781. mMouseRightButtonDown = false;
  782. if (bool(mMouseCapturedControl))
  783. mMouseCapturedControl->onRightMouseUp(event);
  784. else
  785. {
  786. findMouseControl(event);
  787. if(bool(mMouseControl))
  788. mMouseControl->onRightMouseUp(event);
  789. }
  790. }
  791. void GuiCanvas::rootRightMouseDragged(const GuiEvent &event)
  792. {
  793. mPrevMouseTime = Platform::getVirtualMilliseconds();
  794. if (bool(mMouseCapturedControl))
  795. {
  796. checkLockMouseMove(event);
  797. mMouseCapturedControl->onRightMouseDragged(event);
  798. }
  799. else
  800. {
  801. findMouseControl(event);
  802. if(bool(mMouseControl))
  803. mMouseControl->onRightMouseDragged(event);
  804. }
  805. }
  806. void GuiCanvas::rootMiddleMouseDown(const GuiEvent &event)
  807. {
  808. mPrevMouseTime = Platform::getVirtualMilliseconds();
  809. mMouseMiddleButtonDown = true;
  810. if (bool(mMouseCapturedControl))
  811. mMouseCapturedControl->onMiddleMouseDown(event);
  812. else
  813. {
  814. findMouseControl(event);
  815. if(bool(mMouseControl))
  816. {
  817. mMouseControl->onMiddleMouseDown(event);
  818. }
  819. }
  820. }
  821. void GuiCanvas::rootMiddleMouseUp(const GuiEvent &event)
  822. {
  823. mPrevMouseTime = Platform::getVirtualMilliseconds();
  824. mMouseMiddleButtonDown = false;
  825. if (bool(mMouseCapturedControl))
  826. mMouseCapturedControl->onMiddleMouseUp(event);
  827. else
  828. {
  829. findMouseControl(event);
  830. if(bool(mMouseControl))
  831. mMouseControl->onMiddleMouseUp(event);
  832. }
  833. }
  834. void GuiCanvas::rootMiddleMouseDragged(const GuiEvent &event)
  835. {
  836. mPrevMouseTime = Platform::getVirtualMilliseconds();
  837. if (bool(mMouseCapturedControl))
  838. {
  839. checkLockMouseMove(event);
  840. mMouseCapturedControl->onMiddleMouseDragged(event);
  841. }
  842. else
  843. {
  844. findMouseControl(event);
  845. if(bool(mMouseControl))
  846. mMouseControl->onMiddleMouseDragged(event);
  847. }
  848. }
  849. void GuiCanvas::rootMouseWheelUp(const GuiEvent &event)
  850. {
  851. if (bool(mMouseCapturedControl))
  852. mMouseCapturedControl->onMouseWheelUp(event);
  853. else
  854. {
  855. findMouseControl(event);
  856. if (bool(mMouseControl))
  857. mMouseControl->onMouseWheelUp(event);
  858. }
  859. }
  860. void GuiCanvas::rootMouseWheelDown(const GuiEvent &event)
  861. {
  862. if (bool(mMouseCapturedControl))
  863. mMouseCapturedControl->onMouseWheelDown(event);
  864. else
  865. {
  866. findMouseControl(event);
  867. if (bool(mMouseControl))
  868. mMouseControl->onMouseWheelDown(event);
  869. }
  870. }
  871. void GuiCanvas::setContentControl(GuiControl *gui)
  872. {
  873. if(!gui)
  874. return;
  875. // If we're setting the same content, don't do anything
  876. if( gui == at(0) )
  877. return;
  878. //remove all dialogs on layer 0
  879. U32 index = 0;
  880. while ((U32)size() > index)
  881. {
  882. GuiControl *ctrl = static_cast<GuiControl*>((*this)[index]);
  883. if (ctrl == gui || ctrl->mLayer != 0)
  884. index++;
  885. removeObject(ctrl);
  886. Sim::getGuiGroup()->addObject(ctrl);
  887. }
  888. // lose the first responder from the old GUI
  889. GuiControl* responder = gui->findFirstTabable();
  890. if(responder)
  891. responder->setFirstResponder();
  892. //add the gui to the front
  893. if(!size() || gui != (*this)[0])
  894. {
  895. // automatically wakes objects in GuiControl::onWake
  896. addObject(gui);
  897. if (size() >= 2)
  898. reOrder(gui, *begin());
  899. }
  900. //refresh the entire gui
  901. resetUpdateRegions();
  902. //rebuild the accelerator map
  903. mAcceleratorMap.clear();
  904. for(iterator i = end(); i != begin() ; )
  905. {
  906. i--;
  907. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  908. ctrl->buildAcceleratorMap();
  909. if (ctrl->mUseInput)
  910. {
  911. break;
  912. }
  913. }
  914. refreshMouseControl();
  915. // Force the canvas to update the sizing of the new content control
  916. maintainSizing();
  917. }
  918. GuiControl *GuiCanvas::getContentControl()
  919. {
  920. if(size() > 0)
  921. return (GuiControl *) first();
  922. return NULL;
  923. }
  924. void GuiCanvas::pushDialogControl(GuiControl *gui, S32 layer)
  925. {
  926. //add the gui
  927. gui->mLayer = layer;
  928. // GuiControl::addObject wakes the object
  929. addObject(gui);
  930. //reorder it to the correct layer
  931. iterator i;
  932. for (i = begin(); i != end(); i++)
  933. {
  934. GuiControl *ctrl = static_cast<GuiControl*>(*i);
  935. if (ctrl->mLayer > gui->mLayer)
  936. {
  937. reOrder(gui, ctrl);
  938. break;
  939. }
  940. }
  941. //call the dialog push method
  942. gui->onDialogPush();
  943. //find the top most dialog
  944. //find the first responder
  945. GuiControl* responder = gui->findFirstTabable();
  946. if(responder)
  947. responder->setFirstResponder();
  948. // call the 'onWake' method?
  949. //if(wakedGui)
  950. // Con::executef(gui, 1, "onWake");
  951. //refresh the entire gui
  952. resetUpdateRegions();
  953. //rebuild the accelerator map
  954. mAcceleratorMap.clear();
  955. if (size() > 0)
  956. {
  957. GuiControl *ctrl = static_cast<GuiControl*>(last());
  958. ctrl->buildAcceleratorMap();
  959. }
  960. refreshMouseControl();
  961. }
  962. void GuiCanvas::popDialogControl(GuiControl *gui)
  963. {
  964. if (size() < 1)
  965. return;
  966. //first, find the dialog, and call the "onDialogPop()" method
  967. GuiControl *ctrl = NULL;
  968. if (gui)
  969. {
  970. //make sure the gui really exists on the stack
  971. iterator i;
  972. bool found = false;
  973. for(i = begin(); i != end(); i++)
  974. {
  975. GuiControl *check = static_cast<GuiControl *>(*i);
  976. if (check == gui)
  977. {
  978. ctrl = check;
  979. found = true;
  980. }
  981. }
  982. if (! found)
  983. return;
  984. }
  985. else
  986. ctrl = static_cast<GuiControl*>(last());
  987. //call the "on pop" function
  988. ctrl->onDialogPop();
  989. // sleep the object
  990. //now pop the last child (will sleep if awake)
  991. removeObject(ctrl);
  992. // Save the old responder:
  993. Sim::getGuiGroup()->addObject(ctrl);
  994. if (size() > 0)
  995. {
  996. GuiControl *ctrl = static_cast<GuiControl *>(last());
  997. if(ctrl->mFirstResponder)
  998. ctrl->mFirstResponder->setFirstResponder();
  999. }
  1000. else
  1001. {
  1002. setFirstResponder(NULL);
  1003. }
  1004. //refresh the entire gui
  1005. resetUpdateRegions();
  1006. //rebuild the accelerator map
  1007. mAcceleratorMap.clear();
  1008. if (size() > 0)
  1009. {
  1010. GuiControl *ctrl = static_cast<GuiControl*>(last());
  1011. ctrl->buildAcceleratorMap();
  1012. }
  1013. refreshMouseControl();
  1014. }
  1015. void GuiCanvas::popDialogControl(S32 layer)
  1016. {
  1017. if (size() < 1)
  1018. return;
  1019. GuiControl *ctrl = NULL;
  1020. iterator i = end(); // find in z order (last to first)
  1021. while (i != begin())
  1022. {
  1023. i--;
  1024. ctrl = static_cast<GuiControl*>(*i);
  1025. if (ctrl->mLayer == layer)
  1026. break;
  1027. }
  1028. if (ctrl)
  1029. popDialogControl(ctrl);
  1030. }
  1031. void GuiCanvas::mouseLock(GuiControl *lockingControl)
  1032. {
  1033. if (bool(mMouseCapturedControl))
  1034. return;
  1035. mMouseCapturedControl = lockingControl;
  1036. if(mMouseControl && mMouseControl != mMouseCapturedControl)
  1037. {
  1038. GuiEvent evt;
  1039. evt.mousePoint.x = S32(cursorPt.x);
  1040. evt.mousePoint.y = S32(cursorPt.y);
  1041. mMouseControl->onTouchLeave(evt);
  1042. }
  1043. }
  1044. void GuiCanvas::mouseUnlock(GuiControl *lockingControl)
  1045. {
  1046. if (static_cast<GuiControl*>(mMouseCapturedControl) != lockingControl)
  1047. return;
  1048. GuiEvent evt;
  1049. evt.mousePoint.x = S32(cursorPt.x);
  1050. evt.mousePoint.y = S32(cursorPt.y);
  1051. GuiControl * controlHit = findHitControl(evt.mousePoint);
  1052. if(controlHit != mMouseCapturedControl)
  1053. {
  1054. mMouseControl = controlHit;
  1055. mMouseControlClicked = false;
  1056. if(bool(mMouseControl))
  1057. mMouseControl->onTouchEnter(evt);
  1058. }
  1059. mMouseCapturedControl = NULL;
  1060. }
  1061. void GuiCanvas::paint()
  1062. {
  1063. resetUpdateRegions();
  1064. // inhibit explicit refreshes in the case we're swapped out
  1065. if (TextureManager::mDGLRender)
  1066. renderFrame(false);
  1067. }
  1068. void GuiCanvas::maintainSizing()
  1069. {
  1070. Point2I size = Platform::getWindowSize();
  1071. if(size.x == 0 || size.y == 0)
  1072. return;
  1073. RectI screenRect(0, 0, size.x, size.y);
  1074. mBounds = screenRect;
  1075. //all bottom level controls should be the same dimensions as the canvas
  1076. //this is necessary for passing mouse events accurately
  1077. iterator i;
  1078. for (i = begin(); i != end(); i++)
  1079. {
  1080. AssertFatal(static_cast<GuiControl*>((*i))->isAwake(), "GuiCanvas::renderFrame: ctrl is not awake");
  1081. GuiControl *ctrl = static_cast<GuiControl*>(*i);
  1082. Point2I ext = ctrl->getExtent();
  1083. Point2I pos = ctrl->getPosition();
  1084. if(pos != screenRect.point || ext != screenRect.extent)
  1085. {
  1086. ctrl->resize(screenRect.point, screenRect.extent);
  1087. resetUpdateRegions();
  1088. }
  1089. }
  1090. }
  1091. void GuiCanvas::renderFrame(bool preRenderOnly, bool bufferSwap /* = true */)
  1092. {
  1093. PROFILE_START(CanvasPreRender);
  1094. #if !defined TORQUE_OS_IOS && !defined TORQUE_OS_ANDROID && !defined TORQUE_OS_EMSCRIPTEN
  1095. if(mRenderFront)
  1096. glDrawBuffer(GL_FRONT);
  1097. else
  1098. glDrawBuffer(GL_BACK);
  1099. #endif
  1100. // Make sure the root control is the size of the canvas.
  1101. Point2I size = Platform::getWindowSize();
  1102. if(size.x == 0 || size.y == 0)
  1103. {
  1104. //Luma: Fixed missing PROFILE_END()
  1105. PROFILE_END();
  1106. return;
  1107. }
  1108. RectI screenRect(0, 0, size.x, size.y);
  1109. maintainSizing();
  1110. //preRender (recursive) all controls
  1111. preRender();
  1112. PROFILE_END();
  1113. if(preRenderOnly)
  1114. return;
  1115. // for now, just always reset the update regions - this is a
  1116. // fix for FSAA on ATI cards
  1117. resetUpdateRegions();
  1118. // Moved this below object integration for performance reasons. -JDD
  1119. // // finish the gl render so we don't get too far ahead of ourselves
  1120. //#if defined(TORQUE_OS_WIN32)
  1121. // PROFILE_START(glFinish);
  1122. // glFinish();
  1123. // PROFILE_END();
  1124. //#endif
  1125. //draw the mouse, but not using tags...
  1126. PROFILE_START(CanvasRenderControls);
  1127. GuiCursor *mouseCursor = NULL;
  1128. bool cursorVisible = true;
  1129. if(bool(mMouseCapturedControl))
  1130. mMouseCapturedControl->getCursor(mouseCursor, cursorVisible, mLastEvent);
  1131. else if(bool(mMouseControl))
  1132. mMouseControl->getCursor(mouseCursor, cursorVisible, mLastEvent);
  1133. Point2I cursorPos((S32)cursorPt.x, (S32)cursorPt.y);
  1134. if(!mouseCursor)
  1135. mouseCursor = defaultCursor;
  1136. if(lastCursorON && lastCursor)
  1137. {
  1138. Point2I spot = lastCursor->getHotSpot();
  1139. Point2I cext = lastCursor->getExtent();
  1140. Point2I pos = lastCursorPt - spot;
  1141. addUpdateRegion(pos - Point2I(2, 2), Point2I(cext.x + 4, cext.y + 4));
  1142. }
  1143. if(cursorVisible && mouseCursor)
  1144. {
  1145. Point2I spot = mouseCursor->getHotSpot();
  1146. Point2I cext = mouseCursor->getExtent();
  1147. Point2I pos = cursorPos - spot;
  1148. addUpdateRegion(pos - Point2I(2, 2), Point2I(cext.x + 4, cext.y + 4));
  1149. }
  1150. lastCursorON = cursorVisible;
  1151. lastCursor = mouseCursor;
  1152. lastCursorPt = cursorPos;
  1153. RectI updateUnion;
  1154. buildUpdateUnion(&updateUnion);
  1155. if (updateUnion.intersect(screenRect))
  1156. {
  1157. // Clear the background color if requested.
  1158. if ( mUseBackgroundColor )
  1159. {
  1160. glClearColor( mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, mBackgroundColor.alpha );
  1161. glClear(GL_COLOR_BUFFER_BIT);
  1162. }
  1163. //render the dialogs
  1164. iterator i;
  1165. for(i = begin(); i != end(); i++)
  1166. {
  1167. GuiControl *contentCtrl = static_cast<GuiControl*>(*i);
  1168. if (contentCtrl->isVisible())
  1169. {
  1170. dglSetClipRect(updateUnion);
  1171. glDisable(GL_CULL_FACE);
  1172. contentCtrl->onRender(contentCtrl->getPosition(), updateUnion);
  1173. }
  1174. }
  1175. // Tooltip resource
  1176. if(bool(mMouseControl))
  1177. {
  1178. U32 curTime = Platform::getRealMilliseconds();
  1179. if(hoverControl == mMouseControl)
  1180. {
  1181. if(hoverPositionSet || (curTime - hoverControlStart) >= (U32)hoverControl->mTipHoverTime || (curTime - hoverLeftControlTime) <= (U32)hoverControl->mTipHoverTime)
  1182. {
  1183. // MM: Controls whether the tooltip tracks the mouse cursor or not.
  1184. #if 0
  1185. if(!hoverPositionSet)
  1186. {
  1187. hoverPosition = cursorPos;
  1188. }
  1189. #else
  1190. hoverPosition = cursorPos;
  1191. #endif
  1192. hoverPositionSet = mMouseControl->renderTooltip(hoverPosition);
  1193. }
  1194. } else
  1195. {
  1196. if(hoverPositionSet)
  1197. {
  1198. hoverLeftControlTime = curTime;
  1199. hoverPositionSet = false;
  1200. }
  1201. hoverControl = mMouseControl;
  1202. hoverControlStart = curTime;
  1203. }
  1204. }
  1205. //end tooltip
  1206. dglSetClipRect(updateUnion);
  1207. //temp draw the mouse
  1208. if (cursorON && mShowCursor && !mouseCursor && Canvas->getUseNativeCursor())
  1209. {
  1210. #if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
  1211. glColor4ub(255, 0, 0, 255);
  1212. GLfloat vertices[] = {
  1213. (GLfloat)(cursorPt.x),(GLfloat)(cursorPt.y),
  1214. (GLfloat)(cursorPt.x + 2),(GLfloat)(cursorPt.y),
  1215. (GLfloat)(cursorPt.x + 2),(GLfloat)(cursorPt.y + 2),
  1216. (GLfloat)(cursorPt.x),(GLfloat)(cursorPt.y + 2),
  1217. };
  1218. glEnableClientState(GL_VERTEX_ARRAY);
  1219. glVertexPointer(2, GL_FLOAT, 0, vertices);
  1220. glDrawArrays(GL_LINE_LOOP, 0, 4);
  1221. #else
  1222. glColor4ub(255, 0, 0, 255);
  1223. glRecti((S32)cursorPt.x, (S32)cursorPt.y, (S32)(cursorPt.x + 2), (S32)(cursorPt.y + 2));
  1224. #endif
  1225. }
  1226. //DEBUG
  1227. //draw the help ctrl
  1228. //if (helpCtrl)
  1229. //{
  1230. // helpCtrl->render(srf);
  1231. //}
  1232. if (cursorON && mouseCursor && mShowCursor && !mHideCursorBecauseOfTouch)
  1233. {
  1234. Point2I pos((S32)cursorPt.x, (S32)cursorPt.y);
  1235. Point2I spot = mouseCursor->getHotSpot();
  1236. pos -= spot;
  1237. mouseCursor->render(pos);
  1238. }
  1239. }
  1240. PROFILE_END();
  1241. if( bufferSwap )
  1242. swapBuffers();
  1243. //#if defined(TORQUE_OS_WIN32)
  1244. // PROFILE_START(glFinish);
  1245. // glFinish(); // This was changed to work with the D3D layer -pw
  1246. // PROFILE_END();
  1247. //#endif
  1248. }
  1249. void GuiCanvas::swapBuffers()
  1250. {
  1251. PROFILE_START(SwapBuffers);
  1252. //flip the surface
  1253. if(!mRenderFront)
  1254. Video::swapBuffers();
  1255. PROFILE_END();
  1256. }
  1257. void GuiCanvas::buildUpdateUnion(RectI *updateUnion)
  1258. {
  1259. *updateUnion = mOldUpdateRects[0];
  1260. //the update region should encompass the oldUpdateRects, and the curUpdateRect
  1261. Point2I upperL;
  1262. Point2I lowerR;
  1263. upperL.x = getMin(mOldUpdateRects[0].point.x, mOldUpdateRects[1].point.x);
  1264. upperL.x = getMin(upperL.x, mCurUpdateRect.point.x);
  1265. upperL.y = getMin(mOldUpdateRects[0].point.y, mOldUpdateRects[1].point.y);
  1266. upperL.y = getMin(upperL.y, mCurUpdateRect.point.y);
  1267. lowerR.x = getMax(mOldUpdateRects[0].point.x + mOldUpdateRects[0].extent.x, mOldUpdateRects[1].point.x + mOldUpdateRects[1].extent.x);
  1268. lowerR.x = getMax(lowerR.x, mCurUpdateRect.point.x + mCurUpdateRect.extent.x);
  1269. lowerR.y = getMax(mOldUpdateRects[0].point.y + mOldUpdateRects[0].extent.y, mOldUpdateRects[1].point.y + mOldUpdateRects[1].extent.y);
  1270. lowerR.y = getMax(lowerR.y, mCurUpdateRect.point.y + mCurUpdateRect.extent.y);
  1271. updateUnion->point = upperL;
  1272. updateUnion->extent = lowerR - upperL;
  1273. //shift the oldUpdateRects
  1274. mOldUpdateRects[0] = mOldUpdateRects[1];
  1275. mOldUpdateRects[1] = mCurUpdateRect;
  1276. mCurUpdateRect.point.set(0,0);
  1277. mCurUpdateRect.extent.set(0,0);
  1278. }
  1279. void GuiCanvas::addUpdateRegion(Point2I pos, Point2I ext)
  1280. {
  1281. if(mCurUpdateRect.extent.x == 0)
  1282. {
  1283. mCurUpdateRect.point = pos;
  1284. mCurUpdateRect.extent = ext;
  1285. }
  1286. else
  1287. {
  1288. Point2I upperL;
  1289. upperL.x = getMin(mCurUpdateRect.point.x, pos.x);
  1290. upperL.y = getMin(mCurUpdateRect.point.y, pos.y);
  1291. Point2I lowerR;
  1292. lowerR.x = getMax(mCurUpdateRect.point.x + mCurUpdateRect.extent.x, pos.x + ext.x);
  1293. lowerR.y = getMax(mCurUpdateRect.point.y + mCurUpdateRect.extent.y, pos.y + ext.y);
  1294. mCurUpdateRect.point = upperL;
  1295. mCurUpdateRect.extent = lowerR - upperL;
  1296. }
  1297. }
  1298. void GuiCanvas::resetUpdateRegions()
  1299. {
  1300. //DEBUG - get surface width and height
  1301. mOldUpdateRects[0].set(mBounds.point, mBounds.extent);
  1302. mOldUpdateRects[1] = mOldUpdateRects[0];
  1303. mCurUpdateRect = mOldUpdateRects[0];
  1304. }
  1305. void GuiCanvas::onFocus(bool foundFirstResponder)
  1306. {
  1307. if (!foundFirstResponder && mFirstResponder)
  1308. {
  1309. mFirstResponder->onLoseFirstResponder();
  1310. mFirstResponder = NULL;
  1311. }
  1312. }
  1313. void GuiCanvas::setFirstResponder( GuiControl* newResponder )
  1314. {
  1315. GuiControl* oldResponder = mFirstResponder;
  1316. Parent::setFirstResponder( newResponder );
  1317. if ( oldResponder && ( oldResponder != mFirstResponder ) )
  1318. oldResponder->onLoseFirstResponder();
  1319. }
  1320. bool GuiCanvas::isEditMode()
  1321. {
  1322. //If we've walked up the chain all the way to canvas and haven't found the
  1323. //editor then we are not in edit mode.
  1324. return false;
  1325. }