guiCanvas.cc 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528
  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. if(mFirstResponder->onKeyUp(mLastEvent))
  338. return true;
  339. //see if there's an accelerator
  340. for (U32 i = 0; i < (U32)mAcceleratorMap.size(); i++)
  341. {
  342. if ((U32)mAcceleratorMap[i].keyCode == (U32)event->objInst && (U32)mAcceleratorMap[i].modifier == eventModifier)
  343. {
  344. mAcceleratorMap[i].ctrl->acceleratorKeyRelease(mAcceleratorMap[i].index);
  345. return true;
  346. }
  347. }
  348. }
  349. else if(event->action == SI_REPEAT)
  350. {
  351. //if not handled, search for an accelerator
  352. for (U32 i = 0; i < (U32)mAcceleratorMap.size(); i++)
  353. {
  354. if ((U32)mAcceleratorMap[i].keyCode == (U32)event->objInst && (U32)mAcceleratorMap[i].modifier == eventModifier)
  355. {
  356. mAcceleratorMap[i].ctrl->acceleratorKeyPress(mAcceleratorMap[i].index);
  357. return true;
  358. }
  359. }
  360. if(mFirstResponder)
  361. mFirstResponder->onKeyRepeat(mLastEvent);
  362. return true;
  363. }
  364. }
  365. else if(event->deviceType == MouseDeviceType && cursorON)
  366. {
  367. //copy the modifier into the new event
  368. mLastEvent.modifier = event->modifier;
  369. if(event->objType == SI_XAXIS || event->objType == SI_YAXIS)
  370. {
  371. bool moved = false;
  372. Point2I oldpt((S32)cursorPt.x, (S32)cursorPt.y);
  373. Point2F pt(cursorPt.x, cursorPt.y);
  374. if (event->objType == SI_XAXIS)
  375. {
  376. pt.x += (event->fValues[0] * mPixelsPerMickey);
  377. cursorPt.x = (F32)getMax(0, getMin((S32)pt.x, mBounds.extent.x - 1));
  378. if (oldpt.x != S32(cursorPt.x))
  379. moved = true;
  380. }
  381. else
  382. {
  383. pt.y += (event->fValues[0] * mPixelsPerMickey);
  384. cursorPt.y = (F32)getMax(0, getMin((S32)pt.y, mBounds.extent.y - 1));
  385. if (oldpt.y != S32(cursorPt.y))
  386. moved = true;
  387. }
  388. if (moved)
  389. {
  390. mLastEvent.mousePoint.x = S32(cursorPt.x);
  391. mLastEvent.mousePoint.y = S32(cursorPt.y);
  392. mLastEvent.eventID = 0;
  393. #ifdef TORQUE_ALLOW_JOURNALING
  394. // [tom, 9/8/2006] If we're journaling, we need to update the plat cursor
  395. if(Game->isJournalReading())
  396. Input::setCursorPos((S32)cursorPt.x, (S32)cursorPt.y);
  397. #endif //TORQUE_ALLOW_JOURNALING
  398. if (mMouseButtonDown)
  399. rootMouseDragged(mLastEvent);
  400. else if (mMouseRightButtonDown)
  401. rootRightMouseDragged(mLastEvent);
  402. else if(mMouseMiddleButtonDown)
  403. rootMiddleMouseDragged(mLastEvent);
  404. else
  405. rootMouseMove(mLastEvent);
  406. }
  407. return true;
  408. }
  409. else if ( event->objType == SI_ZAXIS )
  410. {
  411. mLastEvent.mousePoint.x = S32( cursorPt.x );
  412. mLastEvent.mousePoint.y = S32( cursorPt.y );
  413. mLastEvent.eventID = 0;
  414. if ( event->fValues[0] < 0.0f )
  415. rootMouseWheelDown( mLastEvent );
  416. else
  417. rootMouseWheelUp( mLastEvent );
  418. }
  419. else if(event->objType == SI_BUTTON)
  420. {
  421. //copy the cursor point into the event
  422. mLastEvent.mousePoint.x = S32(cursorPt.x);
  423. mLastEvent.mousePoint.y = S32(cursorPt.y);
  424. mLastEvent.eventID = 0;
  425. mMouseDownPoint = cursorPt;
  426. if(event->objInst == KEY_BUTTON0) // left button
  427. {
  428. //see if button was pressed
  429. if (event->action == SI_MAKE)
  430. {
  431. U32 curTime = Platform::getVirtualMilliseconds();
  432. mNextMouseTime = curTime + mInitialMouseDelay;
  433. //if the last button pressed was the left...
  434. if (mLeftMouseLast)
  435. {
  436. //if it was within the double click time count the clicks
  437. if ((S32)curTime - mLastMouseDownTime <= mDoubleClickTime)
  438. mLastMouseClickCount++;
  439. else
  440. mLastMouseClickCount = 1;
  441. }
  442. else
  443. {
  444. mLeftMouseLast = true;
  445. mLastMouseClickCount = 1;
  446. }
  447. mLastMouseDownTime = curTime;
  448. mLastEvent.mouseClickCount = mLastMouseClickCount;
  449. if(mHideCursorBecauseOfTouch)
  450. {
  451. mPotentialMouseEventCount = 0;
  452. }
  453. if(mPotentialTouchEvent)
  454. {
  455. mHideCursorBecauseOfTouch = true;
  456. }
  457. rootMouseDown(mLastEvent);
  458. }
  459. //else button was released
  460. else
  461. {
  462. mNextMouseTime = 0xFFFFFFFF;
  463. rootMouseUp(mLastEvent);
  464. }
  465. return true;
  466. }
  467. else if(event->objInst == KEY_BUTTON1) // right button
  468. {
  469. mHideCursorBecauseOfTouch = false;
  470. if(event->action == SI_MAKE)
  471. {
  472. U32 curTime = Platform::getVirtualMilliseconds();
  473. //if the last button pressed was the right...
  474. if (mRightMouseLast)
  475. {
  476. //if it was within the double click time count the clicks
  477. if ((S32)curTime - mLastMouseDownTime <= mDoubleClickTime)
  478. mLastMouseClickCount++;
  479. else
  480. mLastMouseClickCount = 1;
  481. }
  482. else
  483. {
  484. mRightMouseLast = true;
  485. mLastMouseClickCount = 1;
  486. }
  487. mLastMouseDownTime = curTime;
  488. mLastEvent.mouseClickCount = mLastMouseClickCount;
  489. rootRightMouseDown(mLastEvent);
  490. }
  491. else // it was a mouse up
  492. rootRightMouseUp(mLastEvent);
  493. return true;
  494. }
  495. else if(event->objInst == KEY_BUTTON2) // middle button
  496. {
  497. mHideCursorBecauseOfTouch = false;
  498. if(event->action == SI_MAKE)
  499. {
  500. U32 curTime = Platform::getVirtualMilliseconds();
  501. //if the last button pressed was the right...
  502. if (mMiddleMouseLast)
  503. {
  504. //if it was within the double click time count the clicks
  505. if ((S32)curTime - mLastMouseDownTime <= mDoubleClickTime)
  506. mLastMouseClickCount++;
  507. else
  508. mLastMouseClickCount = 1;
  509. }
  510. else
  511. {
  512. mMiddleMouseLast = true;
  513. mLastMouseClickCount = 1;
  514. }
  515. mLastMouseDownTime = curTime;
  516. mLastEvent.mouseClickCount = mLastMouseClickCount;
  517. rootMiddleMouseDown(mLastEvent);
  518. }
  519. else // it was a mouse up
  520. rootMiddleMouseUp(mLastEvent);
  521. return true;
  522. }
  523. }
  524. }
  525. return false;
  526. }
  527. void GuiCanvas::rootMouseDown(const GuiEvent &event)
  528. {
  529. mPrevMouseTime = Platform::getVirtualMilliseconds();
  530. mMouseButtonDown = true;
  531. //pass the event to the mouse locked control
  532. if (bool(mMouseCapturedControl))
  533. mMouseCapturedControl->onTouchDown(event);
  534. //else pass it to whoever is underneath the cursor
  535. else
  536. {
  537. iterator i;
  538. i = end();
  539. while (i != begin())
  540. {
  541. i--;
  542. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  543. if (ctrl->mUseInput)
  544. {
  545. GuiControl* controlHit = ctrl->findHitControl(event.mousePoint);
  546. //Regardless of what the control does, it has the user's focus.
  547. controlHit->onFocus();
  548. if (controlHit->mUseInput)
  549. {
  550. controlHit->onTouchDown(event);
  551. break;
  552. }
  553. }
  554. }
  555. }
  556. if (bool(mMouseControl))
  557. mMouseControlClicked = true;
  558. }
  559. void GuiCanvas::findMouseControl(const GuiEvent &event)
  560. {
  561. if(size() == 0)
  562. {
  563. mMouseControl = NULL;
  564. return;
  565. }
  566. GuiControl* leavingStack = static_cast<GuiControl*>(mMouseControl);
  567. GuiControl* controlHit = findHitControl(event.mousePoint);
  568. GuiControl* enteringStack = controlHit;
  569. if(leavingStack != enteringStack)
  570. {
  571. if (bool(mMouseControl))
  572. {
  573. hoverControlStart = Platform::getRealMilliseconds();
  574. hoverPositionSet = false;
  575. //figure out how much of the leaving stack we are leaving.
  576. while (!DoesControlStackContainControl(enteringStack, leavingStack))
  577. {
  578. leavingStack->onTouchLeave(event);
  579. leavingStack = leavingStack->getParent();
  580. if (!leavingStack)
  581. break;
  582. }
  583. }
  584. //figure out how much of the entering stack we are entering.
  585. if (leavingStack)
  586. {
  587. while (!DoesControlStackContainControl(leavingStack, enteringStack))
  588. {
  589. enteringStack->onTouchEnter(event);
  590. enteringStack = enteringStack->getParent();
  591. if(!enteringStack)
  592. break;
  593. }
  594. }
  595. mMouseControl = controlHit;
  596. mMouseControl->onTouchEnter(event);
  597. }
  598. }
  599. bool GuiCanvas::DoesControlStackContainControl(GuiControl* stack, const GuiControl* ctrl)
  600. {
  601. GuiControl* pen = stack;
  602. do
  603. {
  604. if (pen)
  605. {
  606. if (pen == ctrl)
  607. {
  608. return true;
  609. }
  610. pen = pen->getParent();
  611. }
  612. else
  613. {
  614. return false;
  615. }
  616. } while (pen);
  617. return false;
  618. }
  619. //Luma: Some fixes from the forums, Dave Calabrese
  620. //http://www.garagegames.com/community/forums/viewthread/93467/1#comment-669559
  621. void GuiCanvas::rootScreenTouchDown(const GuiEvent &event)
  622. {
  623. mPrevMouseTime = Platform::getVirtualMilliseconds();
  624. mMouseButtonDown = true;
  625. iterator i;
  626. i = end();
  627. while (i != begin())
  628. {
  629. i--;
  630. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  631. if (ctrl->mUseInput)
  632. {
  633. GuiControl* controlHit = ctrl->findHitControl(event.mousePoint);
  634. //If the control we hit is not the same one that is locked,
  635. // then unlock the existing control.
  636. if (bool(mMouseCapturedControl) && mMouseCapturedControl->isMouseLocked() && mMouseCapturedControl != controlHit)
  637. {
  638. mMouseCapturedControl->onTouchLeave(event);
  639. }
  640. //Regardless of what the control does, it has the user's focus.
  641. controlHit->onFocus();
  642. if (controlHit->mUseInput)
  643. {
  644. controlHit->onTouchDown(event);
  645. break;
  646. }
  647. }
  648. }
  649. if (bool(mMouseControl))
  650. mMouseControlClicked = true;
  651. }
  652. void GuiCanvas::rootScreenTouchUp(const GuiEvent &event)
  653. {
  654. mPrevMouseTime = Platform::getVirtualMilliseconds();
  655. mMouseButtonDown = false;
  656. iterator i;
  657. i = end();
  658. while (i != begin())
  659. {
  660. i--;
  661. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  662. if (ctrl->mUseInput)
  663. {
  664. GuiControl* controlHit = ctrl->findHitControl(event.mousePoint);
  665. if (controlHit->mActive && controlHit->mUseInput)
  666. {
  667. controlHit->onTouchUp(event);
  668. break;
  669. }
  670. }
  671. }
  672. }
  673. void GuiCanvas::rootScreenTouchMove(const GuiEvent &event)
  674. {
  675. //pass the event to the mouse locked control
  676. if (bool(mMouseCapturedControl))
  677. {
  678. checkLockMouseMove(event);
  679. if(!mMouseCapturedControl.isNull())
  680. mMouseCapturedControl->onTouchDragged(event);
  681. }
  682. else
  683. {
  684. findMouseControl(event);
  685. if(bool(mMouseControl))
  686. {
  687. mMouseControl->onTouchDragged(event);
  688. }
  689. }
  690. }
  691. void GuiCanvas::refreshMouseControl()
  692. {
  693. GuiEvent evt;
  694. evt.mousePoint.x = S32(cursorPt.x);
  695. evt.mousePoint.y = S32(cursorPt.y);
  696. findMouseControl(evt);
  697. }
  698. void GuiCanvas::rootMouseUp(const GuiEvent &event)
  699. {
  700. mPrevMouseTime = Platform::getVirtualMilliseconds();
  701. mMouseButtonDown = false;
  702. //pass the event to the mouse locked control
  703. if (bool(mMouseCapturedControl))
  704. mMouseCapturedControl->onTouchUp(event);
  705. else
  706. {
  707. findMouseControl(event);
  708. if(bool(mMouseControl))
  709. mMouseControl->onTouchUp(event);
  710. }
  711. }
  712. void GuiCanvas::checkLockMouseMove(const GuiEvent &event)
  713. {
  714. GuiControl *controlHit = findHitControl(event.mousePoint);
  715. if(controlHit != mMouseControl)
  716. {
  717. if(mMouseControl == mMouseCapturedControl)
  718. mMouseCapturedControl->onTouchLeave(event);
  719. else if(controlHit == mMouseCapturedControl)
  720. mMouseCapturedControl->onTouchEnter(event);
  721. mMouseControl = controlHit;
  722. }
  723. }
  724. void GuiCanvas::rootMouseDragged(const GuiEvent &event)
  725. {
  726. //pass the event to the mouse locked control
  727. if (bool(mMouseCapturedControl))
  728. {
  729. checkLockMouseMove(event);
  730. if(!mMouseCapturedControl.isNull())
  731. mMouseCapturedControl->onTouchDragged(event);
  732. //Luma: Mouse dragged calls mouse Moved on iPhone
  733. #if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
  734. mMouseCapturedControl->onTouchMove(event);
  735. #endif //TORQUE_OS_IOS
  736. }
  737. else
  738. {
  739. findMouseControl(event);
  740. if(bool(mMouseControl))
  741. {
  742. mMouseControl->onTouchDragged(event);
  743. #if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID)
  744. mMouseControl->onTouchMove(event);
  745. #endif //TORQUE_OS_IOS
  746. }
  747. }
  748. }
  749. void GuiCanvas::rootMouseMove(const GuiEvent &event)
  750. {
  751. if(mMouseCapturedControl != NULL)
  752. {
  753. checkLockMouseMove(event);
  754. if(mMouseCapturedControl != NULL)
  755. mMouseCapturedControl->onTouchMove(event);
  756. }
  757. else
  758. {
  759. findMouseControl(event);
  760. if(bool(mMouseControl))
  761. mMouseControl->onTouchMove(event);
  762. }
  763. }
  764. void GuiCanvas::rootRightMouseDown(const GuiEvent &event)
  765. {
  766. mPrevMouseTime = Platform::getVirtualMilliseconds();
  767. mMouseRightButtonDown = true;
  768. if (bool(mMouseCapturedControl))
  769. mMouseCapturedControl->onRightMouseDown(event);
  770. else
  771. {
  772. findMouseControl(event);
  773. if(bool(mMouseControl))
  774. {
  775. mMouseControl->onRightMouseDown(event);
  776. }
  777. }
  778. }
  779. void GuiCanvas::rootRightMouseUp(const GuiEvent &event)
  780. {
  781. mPrevMouseTime = Platform::getVirtualMilliseconds();
  782. mMouseRightButtonDown = false;
  783. if (bool(mMouseCapturedControl))
  784. mMouseCapturedControl->onRightMouseUp(event);
  785. else
  786. {
  787. findMouseControl(event);
  788. if(bool(mMouseControl))
  789. mMouseControl->onRightMouseUp(event);
  790. }
  791. }
  792. void GuiCanvas::rootRightMouseDragged(const GuiEvent &event)
  793. {
  794. mPrevMouseTime = Platform::getVirtualMilliseconds();
  795. if (bool(mMouseCapturedControl))
  796. {
  797. checkLockMouseMove(event);
  798. mMouseCapturedControl->onRightMouseDragged(event);
  799. }
  800. else
  801. {
  802. findMouseControl(event);
  803. if(bool(mMouseControl))
  804. mMouseControl->onRightMouseDragged(event);
  805. }
  806. }
  807. void GuiCanvas::rootMiddleMouseDown(const GuiEvent &event)
  808. {
  809. mPrevMouseTime = Platform::getVirtualMilliseconds();
  810. mMouseMiddleButtonDown = true;
  811. if (bool(mMouseCapturedControl))
  812. mMouseCapturedControl->onMiddleMouseDown(event);
  813. else
  814. {
  815. findMouseControl(event);
  816. if(bool(mMouseControl))
  817. {
  818. mMouseControl->onMiddleMouseDown(event);
  819. }
  820. }
  821. }
  822. void GuiCanvas::rootMiddleMouseUp(const GuiEvent &event)
  823. {
  824. mPrevMouseTime = Platform::getVirtualMilliseconds();
  825. mMouseMiddleButtonDown = false;
  826. if (bool(mMouseCapturedControl))
  827. mMouseCapturedControl->onMiddleMouseUp(event);
  828. else
  829. {
  830. findMouseControl(event);
  831. if(bool(mMouseControl))
  832. mMouseControl->onMiddleMouseUp(event);
  833. }
  834. }
  835. void GuiCanvas::rootMiddleMouseDragged(const GuiEvent &event)
  836. {
  837. mPrevMouseTime = Platform::getVirtualMilliseconds();
  838. if (bool(mMouseCapturedControl))
  839. {
  840. checkLockMouseMove(event);
  841. mMouseCapturedControl->onMiddleMouseDragged(event);
  842. }
  843. else
  844. {
  845. findMouseControl(event);
  846. if(bool(mMouseControl))
  847. mMouseControl->onMiddleMouseDragged(event);
  848. }
  849. }
  850. void GuiCanvas::rootMouseWheelUp(const GuiEvent &event)
  851. {
  852. if (bool(mMouseCapturedControl))
  853. mMouseCapturedControl->onMouseWheelUp(event);
  854. else
  855. {
  856. findMouseControl(event);
  857. if (bool(mMouseControl))
  858. mMouseControl->onMouseWheelUp(event);
  859. }
  860. }
  861. void GuiCanvas::rootMouseWheelDown(const GuiEvent &event)
  862. {
  863. if (bool(mMouseCapturedControl))
  864. mMouseCapturedControl->onMouseWheelDown(event);
  865. else
  866. {
  867. findMouseControl(event);
  868. if (bool(mMouseControl))
  869. mMouseControl->onMouseWheelDown(event);
  870. }
  871. }
  872. void GuiCanvas::setContentControl(GuiControl *gui)
  873. {
  874. if(!gui)
  875. return;
  876. // If we're setting the same content, don't do anything
  877. if( gui == at(0) )
  878. return;
  879. //remove all dialogs on layer 0
  880. U32 index = 0;
  881. while ((U32)size() > index)
  882. {
  883. GuiControl *ctrl = static_cast<GuiControl*>((*this)[index]);
  884. if (ctrl == gui || ctrl->mLayer != 0)
  885. index++;
  886. removeObject(ctrl);
  887. Sim::getGuiGroup()->addObject(ctrl);
  888. }
  889. // lose the first responder from the old GUI
  890. GuiControl* responder = gui->findFirstTabable();
  891. if(responder)
  892. responder->setFirstResponder();
  893. //add the gui to the front
  894. if(!size() || gui != (*this)[0])
  895. {
  896. // automatically wakes objects in GuiControl::onWake
  897. addObject(gui);
  898. if (size() >= 2)
  899. reOrder(gui, *begin());
  900. }
  901. //refresh the entire gui
  902. resetUpdateRegions();
  903. //rebuild the accelerator map
  904. mAcceleratorMap.clear();
  905. for(iterator i = end(); i != begin() ; )
  906. {
  907. i--;
  908. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  909. ctrl->buildAcceleratorMap();
  910. if (ctrl->mUseInput)
  911. {
  912. break;
  913. }
  914. }
  915. refreshMouseControl();
  916. // Force the canvas to update the sizing of the new content control
  917. maintainSizing();
  918. }
  919. GuiControl *GuiCanvas::getContentControl()
  920. {
  921. if(size() > 0)
  922. return (GuiControl *) first();
  923. return NULL;
  924. }
  925. void GuiCanvas::pushDialogControl(GuiControl *gui, S32 layer)
  926. {
  927. //add the gui
  928. gui->mLayer = layer;
  929. // GuiControl::addObject wakes the object
  930. addObject(gui);
  931. //reorder it to the correct layer
  932. iterator i;
  933. for (i = begin(); i != end(); i++)
  934. {
  935. GuiControl *ctrl = static_cast<GuiControl*>(*i);
  936. if (ctrl->mLayer > gui->mLayer)
  937. {
  938. reOrder(gui, ctrl);
  939. break;
  940. }
  941. }
  942. //call the dialog push method
  943. gui->onDialogPush();
  944. //find the top most dialog
  945. //find the first responder
  946. GuiControl* responder = gui->findFirstTabable();
  947. if(responder)
  948. responder->setFirstResponder();
  949. // call the 'onWake' method?
  950. //if(wakedGui)
  951. // Con::executef(gui, 1, "onWake");
  952. //refresh the entire gui
  953. resetUpdateRegions();
  954. //rebuild the accelerator map
  955. mAcceleratorMap.clear();
  956. if (size() > 0)
  957. {
  958. GuiControl *ctrl = static_cast<GuiControl*>(last());
  959. ctrl->buildAcceleratorMap();
  960. }
  961. refreshMouseControl();
  962. }
  963. void GuiCanvas::popDialogControl(GuiControl *gui)
  964. {
  965. if (size() < 1)
  966. return;
  967. //first, find the dialog, and call the "onDialogPop()" method
  968. GuiControl *ctrl = NULL;
  969. if (gui)
  970. {
  971. //make sure the gui really exists on the stack
  972. iterator i;
  973. bool found = false;
  974. for(i = begin(); i != end(); i++)
  975. {
  976. GuiControl *check = static_cast<GuiControl *>(*i);
  977. if (check == gui)
  978. {
  979. ctrl = check;
  980. found = true;
  981. }
  982. }
  983. if (! found)
  984. return;
  985. }
  986. else
  987. ctrl = static_cast<GuiControl*>(last());
  988. //call the "on pop" function
  989. ctrl->onDialogPop();
  990. // sleep the object
  991. //now pop the last child (will sleep if awake)
  992. removeObject(ctrl);
  993. // Save the old responder:
  994. Sim::getGuiGroup()->addObject(ctrl);
  995. if (size() > 0)
  996. {
  997. GuiControl *ctrl = static_cast<GuiControl *>(last());
  998. if(ctrl->mFirstResponder)
  999. ctrl->mFirstResponder->setFirstResponder();
  1000. }
  1001. else
  1002. {
  1003. setFirstResponder(NULL);
  1004. }
  1005. //refresh the entire gui
  1006. resetUpdateRegions();
  1007. //rebuild the accelerator map
  1008. mAcceleratorMap.clear();
  1009. if (size() > 0)
  1010. {
  1011. GuiControl *ctrl = static_cast<GuiControl*>(last());
  1012. ctrl->buildAcceleratorMap();
  1013. }
  1014. refreshMouseControl();
  1015. }
  1016. void GuiCanvas::popDialogControl(S32 layer)
  1017. {
  1018. if (size() < 1)
  1019. return;
  1020. GuiControl *ctrl = NULL;
  1021. iterator i = end(); // find in z order (last to first)
  1022. while (i != begin())
  1023. {
  1024. i--;
  1025. ctrl = static_cast<GuiControl*>(*i);
  1026. if (ctrl->mLayer == layer)
  1027. break;
  1028. }
  1029. if (ctrl)
  1030. popDialogControl(ctrl);
  1031. }
  1032. void GuiCanvas::mouseLock(GuiControl *lockingControl)
  1033. {
  1034. if (bool(mMouseCapturedControl))
  1035. return;
  1036. mMouseCapturedControl = lockingControl;
  1037. if(mMouseControl && mMouseControl != mMouseCapturedControl)
  1038. {
  1039. GuiEvent evt;
  1040. evt.mousePoint.x = S32(cursorPt.x);
  1041. evt.mousePoint.y = S32(cursorPt.y);
  1042. mMouseControl->onTouchLeave(evt);
  1043. }
  1044. }
  1045. void GuiCanvas::mouseUnlock(GuiControl *lockingControl)
  1046. {
  1047. if (static_cast<GuiControl*>(mMouseCapturedControl) != lockingControl)
  1048. return;
  1049. GuiEvent evt;
  1050. evt.mousePoint.x = S32(cursorPt.x);
  1051. evt.mousePoint.y = S32(cursorPt.y);
  1052. GuiControl * controlHit = findHitControl(evt.mousePoint);
  1053. if(controlHit != mMouseCapturedControl)
  1054. {
  1055. mMouseControl = controlHit;
  1056. mMouseControlClicked = false;
  1057. if(bool(mMouseControl))
  1058. mMouseControl->onTouchEnter(evt);
  1059. }
  1060. mMouseCapturedControl = NULL;
  1061. }
  1062. void GuiCanvas::paint()
  1063. {
  1064. resetUpdateRegions();
  1065. // inhibit explicit refreshes in the case we're swapped out
  1066. if (TextureManager::mDGLRender)
  1067. renderFrame(false);
  1068. }
  1069. void GuiCanvas::maintainSizing()
  1070. {
  1071. Point2I size = Platform::getWindowSize();
  1072. if(size.x == 0 || size.y == 0)
  1073. return;
  1074. RectI screenRect(0, 0, size.x, size.y);
  1075. mBounds = screenRect;
  1076. //all bottom level controls should be the same dimensions as the canvas
  1077. //this is necessary for passing mouse events accurately
  1078. iterator i;
  1079. for (i = begin(); i != end(); i++)
  1080. {
  1081. AssertFatal(static_cast<GuiControl*>((*i))->isAwake(), "GuiCanvas::renderFrame: ctrl is not awake");
  1082. GuiControl *ctrl = static_cast<GuiControl*>(*i);
  1083. Point2I ext = ctrl->getExtent();
  1084. Point2I pos = ctrl->getPosition();
  1085. if(pos != screenRect.point || ext != screenRect.extent)
  1086. {
  1087. ctrl->resize(screenRect.point, screenRect.extent);
  1088. resetUpdateRegions();
  1089. }
  1090. }
  1091. }
  1092. void GuiCanvas::renderFrame(bool preRenderOnly, bool bufferSwap /* = true */)
  1093. {
  1094. PROFILE_START(CanvasPreRender);
  1095. #if !defined TORQUE_OS_IOS && !defined TORQUE_OS_ANDROID && !defined TORQUE_OS_EMSCRIPTEN
  1096. if(mRenderFront)
  1097. glDrawBuffer(GL_FRONT);
  1098. else
  1099. glDrawBuffer(GL_BACK);
  1100. #endif
  1101. // Make sure the root control is the size of the canvas.
  1102. Point2I size = Platform::getWindowSize();
  1103. if(size.x == 0 || size.y == 0)
  1104. {
  1105. //Luma: Fixed missing PROFILE_END()
  1106. PROFILE_END();
  1107. return;
  1108. }
  1109. RectI screenRect(0, 0, size.x, size.y);
  1110. maintainSizing();
  1111. //preRender (recursive) all controls
  1112. preRender();
  1113. PROFILE_END();
  1114. if(preRenderOnly)
  1115. return;
  1116. // for now, just always reset the update regions - this is a
  1117. // fix for FSAA on ATI cards
  1118. resetUpdateRegions();
  1119. // Moved this below object integration for performance reasons. -JDD
  1120. // // finish the gl render so we don't get too far ahead of ourselves
  1121. //#if defined(TORQUE_OS_WIN32)
  1122. // PROFILE_START(glFinish);
  1123. // glFinish();
  1124. // PROFILE_END();
  1125. //#endif
  1126. //draw the mouse, but not using tags...
  1127. PROFILE_START(CanvasRenderControls);
  1128. GuiCursor *mouseCursor = NULL;
  1129. bool cursorVisible = true;
  1130. if(bool(mMouseCapturedControl))
  1131. mMouseCapturedControl->getCursor(mouseCursor, cursorVisible, mLastEvent);
  1132. else if(bool(mMouseControl))
  1133. mMouseControl->getCursor(mouseCursor, cursorVisible, mLastEvent);
  1134. Point2I cursorPos((S32)cursorPt.x, (S32)cursorPt.y);
  1135. if(!mouseCursor)
  1136. mouseCursor = defaultCursor;
  1137. if(lastCursorON && lastCursor)
  1138. {
  1139. Point2I spot = lastCursor->getHotSpot();
  1140. Point2I cext = lastCursor->getExtent();
  1141. Point2I pos = lastCursorPt - spot;
  1142. addUpdateRegion(pos - Point2I(2, 2), Point2I(cext.x + 4, cext.y + 4));
  1143. }
  1144. if(cursorVisible && mouseCursor)
  1145. {
  1146. Point2I spot = mouseCursor->getHotSpot();
  1147. Point2I cext = mouseCursor->getExtent();
  1148. Point2I pos = cursorPos - spot;
  1149. addUpdateRegion(pos - Point2I(2, 2), Point2I(cext.x + 4, cext.y + 4));
  1150. }
  1151. lastCursorON = cursorVisible;
  1152. lastCursor = mouseCursor;
  1153. lastCursorPt = cursorPos;
  1154. RectI updateUnion;
  1155. buildUpdateUnion(&updateUnion);
  1156. if (updateUnion.intersect(screenRect))
  1157. {
  1158. // Clear the background color if requested.
  1159. if ( mUseBackgroundColor )
  1160. {
  1161. glClearColor( mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, mBackgroundColor.alpha );
  1162. glClear(GL_COLOR_BUFFER_BIT);
  1163. }
  1164. //render the dialogs
  1165. iterator i;
  1166. for(i = begin(); i != end(); i++)
  1167. {
  1168. GuiControl *contentCtrl = static_cast<GuiControl*>(*i);
  1169. if (contentCtrl->isVisible())
  1170. {
  1171. dglSetClipRect(updateUnion);
  1172. glDisable(GL_CULL_FACE);
  1173. contentCtrl->onRender(contentCtrl->getPosition(), updateUnion);
  1174. }
  1175. }
  1176. // Tooltip resource
  1177. if(bool(mMouseControl))
  1178. {
  1179. U32 curTime = Platform::getRealMilliseconds();
  1180. if(hoverControl == mMouseControl)
  1181. {
  1182. if(hoverPositionSet || (curTime - hoverControlStart) >= (U32)hoverControl->mTipHoverTime || (curTime - hoverLeftControlTime) <= (U32)hoverControl->mTipHoverTime)
  1183. {
  1184. // MM: Controls whether the tooltip tracks the mouse cursor or not.
  1185. #if 0
  1186. if(!hoverPositionSet)
  1187. {
  1188. hoverPosition = cursorPos;
  1189. }
  1190. #else
  1191. hoverPosition = cursorPos;
  1192. #endif
  1193. hoverPositionSet = mMouseControl->renderTooltip(hoverPosition);
  1194. }
  1195. } else
  1196. {
  1197. if(hoverPositionSet)
  1198. {
  1199. hoverLeftControlTime = curTime;
  1200. hoverPositionSet = false;
  1201. }
  1202. hoverControl = mMouseControl;
  1203. hoverControlStart = curTime;
  1204. }
  1205. }
  1206. //end tooltip
  1207. dglSetClipRect(updateUnion);
  1208. //temp draw the mouse
  1209. if (cursorON && mShowCursor && !mouseCursor && Canvas->getUseNativeCursor())
  1210. {
  1211. #if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
  1212. glColor4ub(255, 0, 0, 255);
  1213. GLfloat vertices[] = {
  1214. (GLfloat)(cursorPt.x),(GLfloat)(cursorPt.y),
  1215. (GLfloat)(cursorPt.x + 2),(GLfloat)(cursorPt.y),
  1216. (GLfloat)(cursorPt.x + 2),(GLfloat)(cursorPt.y + 2),
  1217. (GLfloat)(cursorPt.x),(GLfloat)(cursorPt.y + 2),
  1218. };
  1219. glEnableClientState(GL_VERTEX_ARRAY);
  1220. glVertexPointer(2, GL_FLOAT, 0, vertices);
  1221. glDrawArrays(GL_LINE_LOOP, 0, 4);
  1222. #else
  1223. glColor4ub(255, 0, 0, 255);
  1224. glRecti((S32)cursorPt.x, (S32)cursorPt.y, (S32)(cursorPt.x + 2), (S32)(cursorPt.y + 2));
  1225. #endif
  1226. }
  1227. //DEBUG
  1228. //draw the help ctrl
  1229. //if (helpCtrl)
  1230. //{
  1231. // helpCtrl->render(srf);
  1232. //}
  1233. if (cursorON && mouseCursor && mShowCursor && !mHideCursorBecauseOfTouch)
  1234. {
  1235. Point2I pos((S32)cursorPt.x, (S32)cursorPt.y);
  1236. Point2I spot = mouseCursor->getHotSpot();
  1237. pos -= spot;
  1238. mouseCursor->render(pos);
  1239. }
  1240. }
  1241. PROFILE_END();
  1242. if( bufferSwap )
  1243. swapBuffers();
  1244. //#if defined(TORQUE_OS_WIN32)
  1245. // PROFILE_START(glFinish);
  1246. // glFinish(); // This was changed to work with the D3D layer -pw
  1247. // PROFILE_END();
  1248. //#endif
  1249. }
  1250. void GuiCanvas::swapBuffers()
  1251. {
  1252. PROFILE_START(SwapBuffers);
  1253. //flip the surface
  1254. if(!mRenderFront)
  1255. Video::swapBuffers();
  1256. PROFILE_END();
  1257. }
  1258. void GuiCanvas::buildUpdateUnion(RectI *updateUnion)
  1259. {
  1260. *updateUnion = mOldUpdateRects[0];
  1261. //the update region should encompass the oldUpdateRects, and the curUpdateRect
  1262. Point2I upperL;
  1263. Point2I lowerR;
  1264. upperL.x = getMin(mOldUpdateRects[0].point.x, mOldUpdateRects[1].point.x);
  1265. upperL.x = getMin(upperL.x, mCurUpdateRect.point.x);
  1266. upperL.y = getMin(mOldUpdateRects[0].point.y, mOldUpdateRects[1].point.y);
  1267. upperL.y = getMin(upperL.y, mCurUpdateRect.point.y);
  1268. lowerR.x = getMax(mOldUpdateRects[0].point.x + mOldUpdateRects[0].extent.x, mOldUpdateRects[1].point.x + mOldUpdateRects[1].extent.x);
  1269. lowerR.x = getMax(lowerR.x, mCurUpdateRect.point.x + mCurUpdateRect.extent.x);
  1270. lowerR.y = getMax(mOldUpdateRects[0].point.y + mOldUpdateRects[0].extent.y, mOldUpdateRects[1].point.y + mOldUpdateRects[1].extent.y);
  1271. lowerR.y = getMax(lowerR.y, mCurUpdateRect.point.y + mCurUpdateRect.extent.y);
  1272. updateUnion->point = upperL;
  1273. updateUnion->extent = lowerR - upperL;
  1274. //shift the oldUpdateRects
  1275. mOldUpdateRects[0] = mOldUpdateRects[1];
  1276. mOldUpdateRects[1] = mCurUpdateRect;
  1277. mCurUpdateRect.point.set(0,0);
  1278. mCurUpdateRect.extent.set(0,0);
  1279. }
  1280. void GuiCanvas::addUpdateRegion(Point2I pos, Point2I ext)
  1281. {
  1282. if(mCurUpdateRect.extent.x == 0)
  1283. {
  1284. mCurUpdateRect.point = pos;
  1285. mCurUpdateRect.extent = ext;
  1286. }
  1287. else
  1288. {
  1289. Point2I upperL;
  1290. upperL.x = getMin(mCurUpdateRect.point.x, pos.x);
  1291. upperL.y = getMin(mCurUpdateRect.point.y, pos.y);
  1292. Point2I lowerR;
  1293. lowerR.x = getMax(mCurUpdateRect.point.x + mCurUpdateRect.extent.x, pos.x + ext.x);
  1294. lowerR.y = getMax(mCurUpdateRect.point.y + mCurUpdateRect.extent.y, pos.y + ext.y);
  1295. mCurUpdateRect.point = upperL;
  1296. mCurUpdateRect.extent = lowerR - upperL;
  1297. }
  1298. }
  1299. void GuiCanvas::resetUpdateRegions()
  1300. {
  1301. //DEBUG - get surface width and height
  1302. mOldUpdateRects[0].set(mBounds.point, mBounds.extent);
  1303. mOldUpdateRects[1] = mOldUpdateRects[0];
  1304. mCurUpdateRect = mOldUpdateRects[0];
  1305. }
  1306. void GuiCanvas::setFirstResponder( GuiControl* newResponder )
  1307. {
  1308. GuiControl* oldResponder = mFirstResponder;
  1309. Parent::setFirstResponder( newResponder );
  1310. if ( oldResponder && ( oldResponder != mFirstResponder ) )
  1311. oldResponder->onLoseFirstResponder();
  1312. }