guiWindowCtrl.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  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 "console/consoleTypes.h"
  23. #include "console/console.h"
  24. #include "graphics/dgl.h"
  25. #include "gui/guiCanvas.h"
  26. #include "gui/containers/guiWindowCtrl.h"
  27. #include "gui/guiDefaultControlRender.h"
  28. IMPLEMENT_CONOBJECT(GuiWindowCtrl);
  29. GuiWindowCtrl::GuiWindowCtrl(void)
  30. {
  31. mResizeWidth = true;
  32. mResizeHeight = true;
  33. mCanMove = true;
  34. mCanClose = true;
  35. mCanMinimize = true;
  36. mCanMaximize = true;
  37. mTitleHeight = 20;
  38. mResizeRightWidth = 10;
  39. mResizeBottomHeight = 10;
  40. mIsContainer = true;
  41. mCloseCommand = StringTable->EmptyString;
  42. mMinimized = false;
  43. mMaximized = false;
  44. mMouseMovingWin = false;
  45. mMouseResizeWidth = false;
  46. mMouseResizeHeight = false;
  47. mBounds.extent.set(100, 200);
  48. mMinSize.set(50, 50);
  49. mMinimizeIndex = -1;
  50. mTabIndex = -1;
  51. RectI closeRect(80, 2, 16, 16);
  52. mCloseButton = closeRect;
  53. closeRect.point.x -= 18;
  54. mMaximizeButton = closeRect;
  55. closeRect.point.x -= 18;
  56. mMinimizeButton = closeRect;
  57. //other defaults
  58. mActive = true;
  59. mPressClose = false;
  60. mPressMaximize = false;
  61. mPressMinimize = false;
  62. }
  63. void GuiWindowCtrl::initPersistFields()
  64. {
  65. Parent::initPersistFields();
  66. addField("resizeWidth", TypeBool, Offset(mResizeWidth, GuiWindowCtrl));
  67. addField("resizeHeight", TypeBool, Offset(mResizeHeight, GuiWindowCtrl));
  68. addField("canMove", TypeBool, Offset(mCanMove, GuiWindowCtrl));
  69. addField("canClose", TypeBool, Offset(mCanClose, GuiWindowCtrl));
  70. addField("canMinimize", TypeBool, Offset(mCanMinimize, GuiWindowCtrl));
  71. addField("canMaximize", TypeBool, Offset(mCanMaximize, GuiWindowCtrl));
  72. addField("minSize", TypePoint2I, Offset(mMinSize, GuiWindowCtrl));
  73. addField("closeCommand", TypeString, Offset(mCloseCommand, GuiWindowCtrl));
  74. }
  75. bool GuiWindowCtrl::isMinimized(S32 &index)
  76. {
  77. index = mMinimizeIndex;
  78. return mMinimized && mVisible;
  79. }
  80. // helper fn so button positioning shares code...
  81. void GuiWindowCtrl::PositionButtons(void)
  82. {
  83. if( !mBitmapBounds || !mAwake )
  84. return;
  85. S32 buttonWidth = mBitmapBounds[BmpStates * BmpClose].extent.x;
  86. S32 buttonHeight = mBitmapBounds[BmpStates * BmpClose].extent.y;
  87. Point2I mainOff = mProfile->mTextOffset;
  88. int minLeft = mBounds.extent.x - buttonWidth * 3 - mainOff.x;
  89. int minTop = mainOff.y;
  90. int minOff = buttonWidth + 2;
  91. RectI minRect(minLeft, minTop, buttonHeight, buttonWidth);
  92. mMinimizeButton = minRect;
  93. mMaximizeButton = minRect;
  94. minRect.point.x += minOff;
  95. mMaximizeButton = minRect;
  96. mCloseButton = minRect;
  97. minRect.point.x += minOff;
  98. mCloseButton = minRect;
  99. }
  100. bool GuiWindowCtrl::onWake()
  101. {
  102. if (! Parent::onWake())
  103. return false;
  104. //get the texture for the close, minimize, and maximize buttons
  105. bool result = mProfile->constructBitmapArray() >= NumBitmaps;
  106. mTextureHandle = mProfile->mTextureHandle;
  107. AssertFatal(result, "Failed to create the bitmap array");
  108. if(!result)
  109. return false;
  110. mBitmapBounds = mProfile->mBitmapArrayRects.address();
  111. S32 buttonHeight = mBitmapBounds[BmpStates * BmpClose].extent.y;
  112. mTitleHeight = buttonHeight + 4;
  113. mResizeRightWidth = mTitleHeight / 2;
  114. mResizeBottomHeight = mTitleHeight / 2;
  115. //set the button coords
  116. PositionButtons();
  117. //set the tab index
  118. mTabIndex = -1;
  119. GuiControl *parent = getParent();
  120. if (parent && mFirstResponder)
  121. {
  122. mTabIndex = 0;
  123. //count the number of windows preceeding this one
  124. iterator i;
  125. for (i = parent->begin(); i != parent->end(); i++)
  126. {
  127. GuiWindowCtrl *ctrl = dynamic_cast<GuiWindowCtrl *>(*i);
  128. if (ctrl)
  129. {
  130. if (ctrl == this) break;
  131. else if (ctrl->mFirstResponder) mTabIndex++;
  132. }
  133. }
  134. }
  135. return true;
  136. }
  137. void GuiWindowCtrl::onSleep()
  138. {
  139. mTextureHandle = NULL;
  140. Parent::onSleep();
  141. }
  142. GuiControl* GuiWindowCtrl::findHitControl(const Point2I &pt, S32 initialLayer)
  143. {
  144. if (! mMinimized)
  145. return Parent::findHitControl(pt, initialLayer);
  146. else
  147. return this;
  148. }
  149. void GuiWindowCtrl::resize(const Point2I &newPosition, const Point2I &newExtent)
  150. {
  151. Parent::resize(newPosition, newExtent);
  152. //set the button coords
  153. PositionButtons();
  154. }
  155. void GuiWindowCtrl::onTouchDown(const GuiEvent &event)
  156. {
  157. setUpdate();
  158. mOrigBounds = mBounds;
  159. mMouseDownPosition = event.mousePoint;
  160. Point2I localPoint = globalToLocalCoord(event.mousePoint);
  161. //select this window - move it to the front, and set the first responder
  162. selectWindow();
  163. //if we clicked within the title bar
  164. if (localPoint.y < mTitleHeight)
  165. {
  166. //if we clicked on the close button
  167. if (mCanClose && mCloseButton.pointInRect(localPoint))
  168. {
  169. mPressClose = mCanClose;
  170. }
  171. else if (mCanMaximize && mMaximizeButton.pointInRect(localPoint))
  172. {
  173. mPressMaximize = mCanMaximize;
  174. }
  175. else if (mCanMinimize && mMinimizeButton.pointInRect(localPoint))
  176. {
  177. mPressMinimize = mCanMinimize;
  178. }
  179. //else we clicked within the title
  180. else
  181. {
  182. mMouseMovingWin = mCanMove;
  183. mMouseResizeWidth = false;
  184. mMouseResizeHeight = false;
  185. }
  186. }
  187. else
  188. {
  189. mMouseMovingWin = false;
  190. //see if we clicked on the right edge
  191. if (mResizeWidth && (localPoint.x > mBounds.extent.x - mResizeRightWidth))
  192. {
  193. mMouseResizeWidth = true;
  194. }
  195. //see if we clicked on the bottom edge (as well)
  196. if (mResizeHeight && (localPoint.y > mBounds.extent.y - mResizeBottomHeight))
  197. {
  198. mMouseResizeHeight = true;
  199. }
  200. }
  201. if (mMouseMovingWin || mMouseResizeWidth || mMouseResizeHeight ||
  202. mPressClose || mPressMaximize || mPressMinimize)
  203. {
  204. mouseLock();
  205. }
  206. else
  207. {
  208. GuiControl *ctrl = findHitControl(localPoint);
  209. if (ctrl && ctrl != this)
  210. ctrl->onTouchDown(event);
  211. }
  212. }
  213. void GuiWindowCtrl::onTouchDragged(const GuiEvent &event)
  214. {
  215. GuiControl *parent = getParent();
  216. GuiCanvas *root = getRoot();
  217. if (! root) return;
  218. Point2I deltaMousePosition = event.mousePoint - mMouseDownPosition;
  219. Point2I newPosition = mBounds.point;
  220. Point2I newExtent = mBounds.extent;
  221. bool update = false;
  222. if (mMouseMovingWin && parent)
  223. {
  224. newPosition.x = getMax(0, getMin(parent->mBounds.extent.x - mBounds.extent.x, mOrigBounds.point.x + deltaMousePosition.x));
  225. newPosition.y = getMax(0, getMin(parent->mBounds.extent.y - mBounds.extent.y, mOrigBounds.point.y + deltaMousePosition.y));
  226. update = true;
  227. }
  228. else if(mPressClose || mPressMaximize || mPressMinimize)
  229. {
  230. setUpdate();
  231. }
  232. else
  233. {
  234. Point2I minExtent = getMinExtent();
  235. if (mMouseResizeWidth && parent)
  236. {
  237. newExtent.x = getMax(0, getMax(minExtent.x, getMin(parent->getWidth(), mOrigBounds.extent.x + deltaMousePosition.x)));
  238. update = true;
  239. }
  240. if (mMouseResizeHeight && parent)
  241. {
  242. newExtent.y = getMax(0, getMax(minExtent.y, getMin(parent->getHeight(), mOrigBounds.extent.y + deltaMousePosition.y)));
  243. update = true;
  244. }
  245. }
  246. if (update)
  247. {
  248. Point2I pos = parent->localToGlobalCoord(getPosition());
  249. root->addUpdateRegion(pos, getExtent());
  250. resize(newPosition, newExtent);
  251. }
  252. }
  253. void GuiWindowCtrl::onTouchUp(const GuiEvent &event)
  254. {
  255. bool closing = mPressClose;
  256. bool maximizing = mPressMaximize;
  257. bool minimizing = mPressMinimize;
  258. mPressClose = false;
  259. mPressMaximize = false;
  260. mPressMinimize = false;
  261. mouseUnlock();
  262. mMouseMovingWin = false;
  263. mMouseResizeWidth = false;
  264. mMouseResizeHeight = false;
  265. GuiControl *parent = getParent();
  266. if (! parent)
  267. return;
  268. //see if we take an action
  269. Point2I localPoint = globalToLocalCoord(event.mousePoint);
  270. if (closing && mCloseButton.pointInRect(localPoint))
  271. {
  272. Con::evaluate(mCloseCommand);
  273. }
  274. else if (maximizing && mMaximizeButton.pointInRect(localPoint))
  275. {
  276. if (mMaximized)
  277. {
  278. //resize to the previous position and extent, bounded by the parent
  279. resize(Point2I(getMax(0, getMin(parent->mBounds.extent.x - mStandardBounds.extent.x, mStandardBounds.point.x)),
  280. getMax(0, getMin(parent->mBounds.extent.y - mStandardBounds.extent.y, mStandardBounds.point.y))),
  281. mStandardBounds.extent);
  282. //set the flag
  283. mMaximized = false;
  284. }
  285. else
  286. {
  287. //only save the position if we're not minimized
  288. if (! mMinimized)
  289. {
  290. mStandardBounds = mBounds;
  291. }
  292. else
  293. {
  294. mMinimized = false;
  295. }
  296. //resize to fit the parent
  297. resize(Point2I(0, 0), parent->mBounds.extent);
  298. //set the flag
  299. mMaximized = true;
  300. }
  301. }
  302. else if (minimizing && mMinimizeButton.pointInRect(localPoint))
  303. {
  304. if (mMinimized)
  305. {
  306. //resize to the previous position and extent, bounded by the parent
  307. resize(Point2I(getMax(0, getMin(parent->mBounds.extent.x - mStandardBounds.extent.x, mStandardBounds.point.x)),
  308. getMax(0, getMin(parent->mBounds.extent.y - mStandardBounds.extent.y, mStandardBounds.point.y))),
  309. mStandardBounds.extent);
  310. //set the flag
  311. mMinimized = false;
  312. }
  313. else
  314. {
  315. if (parent->mBounds.extent.x < 100 || parent->mBounds.extent.y < mTitleHeight + 3)
  316. return;
  317. //only save the position if we're not maximized
  318. if (! mMaximized)
  319. {
  320. mStandardBounds = mBounds;
  321. }
  322. else
  323. {
  324. mMaximized = false;
  325. }
  326. //first find the lowest unused minimized index up to 32 minimized windows
  327. U32 indexMask = 0;
  328. iterator i;
  329. S32 count = 0;
  330. for (i = parent->begin(); i != parent->end() && count < 32; i++)
  331. {
  332. count++;
  333. S32 index;
  334. GuiWindowCtrl *ctrl = dynamic_cast<GuiWindowCtrl *>(*i);
  335. if (ctrl && ctrl->isMinimized(index))
  336. {
  337. indexMask |= (1 << index);
  338. }
  339. }
  340. //now find the first unused bit
  341. for (count = 0; count < 32; count++)
  342. {
  343. if (! (indexMask & (1 << count))) break;
  344. }
  345. //if we have more than 32 minimized windows, use the first position
  346. count = getMax(0, count);
  347. //this algorithm assumes all window have the same title height, and will minimize to 98 pix
  348. Point2I newExtent(98, mTitleHeight);
  349. //first, how many can fit across
  350. S32 numAcross = getMax(1, (parent->mBounds.extent.x / newExtent.x + 2));
  351. //find the new "mini position"
  352. Point2I newPosition;
  353. newPosition.x = (count % numAcross) * (newExtent.x + 2) + 2;
  354. newPosition.y = parent->mBounds.extent.y - (((count / numAcross) + 1) * (newExtent.y + 2)) - 2;
  355. //find the minimized position and extent
  356. resize(newPosition, newExtent);
  357. //set the index so other windows will not try to minimize to the same location
  358. mMinimizeIndex = count;
  359. //set the flag
  360. mMinimized = true;
  361. }
  362. }
  363. }
  364. GuiControl *GuiWindowCtrl::findNextTabable(GuiControl *curResponder, bool firstCall)
  365. {
  366. //set the global if this is the first call (directly from the canvas)
  367. if (firstCall)
  368. {
  369. GuiControl::smCurResponder = NULL;
  370. }
  371. //if the window does not already contain the first responder, return false
  372. //ie. Can't tab into or out of a window
  373. if (! ControlIsChild(curResponder))
  374. {
  375. return NULL;
  376. }
  377. //loop through, checking each child to see if it is the one that follows the firstResponder
  378. GuiControl *tabCtrl = NULL;
  379. iterator i;
  380. for (i = begin(); i != end(); i++)
  381. {
  382. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  383. tabCtrl = ctrl->findNextTabable(curResponder, false);
  384. if (tabCtrl) break;
  385. }
  386. //to ensure the tab cycles within the current window...
  387. if (! tabCtrl)
  388. {
  389. tabCtrl = findFirstTabable();
  390. }
  391. mFirstResponder = tabCtrl;
  392. return tabCtrl;
  393. }
  394. GuiControl *GuiWindowCtrl::findPrevTabable(GuiControl *curResponder, bool firstCall)
  395. {
  396. if (firstCall)
  397. {
  398. GuiControl::smPrevResponder = NULL;
  399. }
  400. //if the window does not already contain the first responder, return false
  401. //ie. Can't tab into or out of a window
  402. if (! ControlIsChild(curResponder))
  403. {
  404. return NULL;
  405. }
  406. //loop through, checking each child to see if it is the one that follows the firstResponder
  407. GuiControl *tabCtrl = NULL;
  408. iterator i;
  409. for (i = begin(); i != end(); i++)
  410. {
  411. GuiControl *ctrl = static_cast<GuiControl *>(*i);
  412. tabCtrl = ctrl->findPrevTabable(curResponder, false);
  413. if (tabCtrl) break;
  414. }
  415. //to ensure the tab cycles within the current window...
  416. if (! tabCtrl)
  417. {
  418. tabCtrl = findLastTabable();
  419. }
  420. mFirstResponder = tabCtrl;
  421. return tabCtrl;
  422. }
  423. bool GuiWindowCtrl::onKeyDown(const GuiEvent &event)
  424. {
  425. //if this control is a dead end, kill the event
  426. if ((! mVisible) || (! mActive) || (! mAwake)) return true;
  427. if ((event.keyCode == KEY_TAB) && (event.modifier & SI_CTRL))
  428. {
  429. //find the next sibling window, and select it
  430. GuiControl *parent = getParent();
  431. if (parent)
  432. {
  433. GuiWindowCtrl *firstWindow = NULL;
  434. iterator i;
  435. for (i = parent->begin(); i != parent->end(); i++)
  436. {
  437. GuiWindowCtrl *ctrl = dynamic_cast<GuiWindowCtrl *>(*i);
  438. if (ctrl && ctrl->getTabIndex() == mTabIndex + 1)
  439. {
  440. ctrl->selectWindow();
  441. return true;
  442. }
  443. else if (ctrl && ctrl->getTabIndex() == 0)
  444. {
  445. firstWindow = ctrl;
  446. }
  447. }
  448. //recycle from the beginning
  449. if (firstWindow != this)
  450. {
  451. firstWindow->selectWindow();
  452. return true;
  453. }
  454. }
  455. }
  456. return Parent::onKeyDown(event);
  457. }
  458. void GuiWindowCtrl::selectWindow(void)
  459. {
  460. //first make sure this window is the front most of its siblings
  461. GuiControl *parent = getParent();
  462. if (parent)
  463. {
  464. parent->pushObjectToBack(this);
  465. }
  466. //also set the first responder to be the one within this window
  467. setFirstResponder(mFirstResponder);
  468. }
  469. void GuiWindowCtrl::onRender(Point2I offset, const RectI &updateRect)
  470. {
  471. if( !mProfile || mProfile->mFont.isNull() || mProfile->mBitmapArrayRects.size() < NumBitmaps )
  472. return Parent::onRender( offset, updateRect );
  473. //draw the outline
  474. RectI winRect;
  475. winRect.point = offset;
  476. winRect.extent = mBounds.extent;
  477. GuiCanvas *root = getRoot();
  478. GuiControl *firstResponder = root ? root->getFirstResponder() : NULL;
  479. bool isKey = (!firstResponder || ControlIsChild(firstResponder));
  480. U32 topBase = isKey ? BorderTopLeftKey : BorderTopLeftNoKey;
  481. winRect.point.x += mBitmapBounds[BorderLeft].extent.x;
  482. winRect.point.y += mBitmapBounds[topBase + 2].extent.y;
  483. winRect.extent.x -= mBitmapBounds[BorderLeft].extent.x + mBitmapBounds[BorderRight].extent.x;
  484. winRect.extent.y -= mBitmapBounds[topBase + 2].extent.y + mBitmapBounds[BorderBottom].extent.y;
  485. dglDrawRectFill(winRect, mProfile->mFillColor);
  486. dglClearBitmapModulation();
  487. dglDrawBitmapSR(mTextureHandle, offset, mBitmapBounds[topBase]);
  488. dglDrawBitmapSR(mTextureHandle, Point2I(offset.x + mBounds.extent.x - mBitmapBounds[topBase+1].extent.x, offset.y),
  489. mBitmapBounds[topBase + 1]);
  490. RectI destRect;
  491. destRect.point.x = offset.x + mBitmapBounds[topBase].extent.x;
  492. destRect.point.y = offset.y;
  493. destRect.extent.x = mBounds.extent.x - mBitmapBounds[topBase].extent.x - mBitmapBounds[topBase + 1].extent.x;
  494. destRect.extent.y = mBitmapBounds[topBase + 2].extent.y;
  495. RectI stretchRect = mBitmapBounds[topBase + 2];
  496. stretchRect.inset(1,0);
  497. dglDrawBitmapStretchSR(mTextureHandle, destRect, stretchRect);
  498. destRect.point.x = offset.x;
  499. destRect.point.y = offset.y + mBitmapBounds[topBase].extent.y;
  500. destRect.extent.x = mBitmapBounds[BorderLeft].extent.x;
  501. destRect.extent.y = mBounds.extent.y - mBitmapBounds[topBase].extent.y - mBitmapBounds[BorderBottomLeft].extent.y;
  502. stretchRect = mBitmapBounds[BorderLeft];
  503. stretchRect.inset(0,1);
  504. dglDrawBitmapStretchSR(mTextureHandle, destRect, stretchRect);
  505. destRect.point.x = offset.x + mBounds.extent.x - mBitmapBounds[BorderRight].extent.x;
  506. destRect.extent.x = mBitmapBounds[BorderRight].extent.x;
  507. destRect.point.y = offset.y + mBitmapBounds[topBase + 1].extent.y;
  508. destRect.extent.y = mBounds.extent.y - mBitmapBounds[topBase + 1].extent.y - mBitmapBounds[BorderBottomRight].extent.y;
  509. stretchRect = mBitmapBounds[BorderRight];
  510. stretchRect.inset(0,1);
  511. dglDrawBitmapStretchSR(mTextureHandle, destRect, stretchRect);
  512. dglDrawBitmapSR(mTextureHandle, offset + Point2I(0, mBounds.extent.y - mBitmapBounds[BorderBottomLeft].extent.y), mBitmapBounds[BorderBottomLeft]);
  513. dglDrawBitmapSR(mTextureHandle, offset + mBounds.extent - mBitmapBounds[BorderBottomRight].extent, mBitmapBounds[BorderBottomRight]);
  514. destRect.point.x = offset.x + mBitmapBounds[BorderBottomLeft].extent.x;
  515. destRect.extent.x = mBounds.extent.x - mBitmapBounds[BorderBottomLeft].extent.x - mBitmapBounds[BorderBottomRight].extent.x;
  516. destRect.point.y = offset.y + mBounds.extent.y - mBitmapBounds[BorderBottom].extent.y;
  517. destRect.extent.y = mBitmapBounds[BorderBottom].extent.y;
  518. stretchRect = mBitmapBounds[BorderBottom];
  519. stretchRect.inset(1,0);
  520. dglDrawBitmapStretchSR(mTextureHandle, destRect, stretchRect);
  521. //draw the title
  522. // dhc addition: copied/modded from renderJustifiedText, since we enforce a
  523. // different color usage here. NOTE: it currently CAN overdraw the controls
  524. // if mis-positioned or 'scrunched' in a small width.
  525. dglSetBitmapModulation(mProfile->mFontColor);
  526. S32 textWidth = mProfile->mFont->getStrWidth((const UTF8 *)mText);
  527. Point2I start(0,0);
  528. // align the horizontal
  529. if ( mProfile->mAlignment == GuiControlProfile::RightAlign )
  530. start.set( winRect.extent.x - textWidth, 0 );
  531. else if ( mProfile->mAlignment == GuiControlProfile::CenterAlign )
  532. start.set( ( winRect.extent.x - textWidth) / 2, 0 );
  533. else // GuiControlProfile::LeftAlign or garbage... ;)
  534. start.set( 0, 0 );
  535. // If the text is longer then the box size, (it'll get clipped) so force Left Justify
  536. if( textWidth > winRect.extent.x ) start.set( 0, 0 );
  537. // center the vertical
  538. // start.y = ( winRect.extent.y - ( font->getHeight() - 2 ) ) / 2;
  539. dglDrawText(mProfile->mFont, start + offset + mProfile->mTextOffset, mText);
  540. // deal with rendering the titlebar controls
  541. AssertFatal(root, "Unable to get the root Canvas.");
  542. Point2I localPoint = globalToLocalCoord(root->getCursorPos());
  543. //draw the close button
  544. Point2I tempUL;
  545. Point2I tempLR;
  546. S32 bmp = BmpStates * BmpClose;
  547. if( mCanClose ) {
  548. if( mCloseButton.pointInRect( localPoint ) && mPressClose )
  549. bmp += BmpHilite;
  550. dglClearBitmapModulation();
  551. dglDrawBitmapSR(mTextureHandle, offset + mCloseButton.point, mBitmapBounds[bmp]);
  552. }
  553. //draw the maximize button
  554. if( mMaximized )
  555. bmp = BmpStates * BmpNormal;
  556. else
  557. bmp = BmpStates * BmpMaximize;
  558. if( mCanMaximize ) {
  559. if( mMaximizeButton.pointInRect( localPoint ) && mPressMaximize )
  560. bmp += BmpHilite;
  561. dglClearBitmapModulation();
  562. dglDrawBitmapSR( mTextureHandle, offset + mMaximizeButton.point, mBitmapBounds[bmp] );
  563. }
  564. //draw the minimize button
  565. if( mMinimized )
  566. bmp = BmpStates * BmpNormal;
  567. else
  568. bmp = BmpStates * BmpMinimize;
  569. if( mCanMinimize ) {
  570. if( mMinimizeButton.pointInRect( localPoint ) && mPressMinimize )
  571. bmp += BmpHilite;
  572. dglClearBitmapModulation();
  573. dglDrawBitmapSR( mTextureHandle, offset + mMinimizeButton.point, mBitmapBounds[bmp] );
  574. }
  575. if( !mMinimized )
  576. {
  577. //render the children
  578. renderChildControls( offset, mBounds, updateRect );
  579. }
  580. }
  581. void GuiWindowCtrl::getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent)
  582. {
  583. Point2I mousePos = lastGuiEvent.mousePoint;
  584. RectI winRect = mBounds;
  585. RectI rightRect = RectI( ( ( winRect.extent.x + winRect.point.x ) - mResizeRightWidth), winRect.point.y, mResizeRightWidth, winRect.extent.y );
  586. RectI bottomRect = RectI( winRect.point.x, ( ( winRect.point.y + winRect.extent.y ) - mResizeBottomHeight), winRect.extent.x , mResizeBottomHeight );
  587. bool resizeRight = rightRect.pointInRect( mousePos );
  588. bool resizeBottom = bottomRect.pointInRect( mousePos );
  589. if ( resizeRight && resizeBottom && mResizeHeight && mResizeWidth )
  590. {
  591. if(GuiControl::smCursorChanged != CursorManager::curResizeNWSE)
  592. {
  593. // We've already changed the cursor,
  594. // so set it back before we change it again.
  595. if(GuiControl::smCursorChanged != -1)
  596. Input::popCursor();
  597. // Now change the cursor shape
  598. Input::pushCursor(CursorManager::curResizeNWSE);
  599. GuiControl::smCursorChanged = CursorManager::curResizeNWSE;
  600. }
  601. //cursor = mNWSECursor;
  602. }
  603. else if ( resizeBottom && mResizeHeight )
  604. {
  605. if(GuiControl::smCursorChanged != CursorManager::curResizeHorz)
  606. {
  607. // We've already changed the cursor,
  608. // so set it back before we change it again.
  609. if(GuiControl::smCursorChanged != -1)
  610. Input::popCursor();
  611. // Now change the cursor shape
  612. Input::pushCursor(CursorManager::curResizeHorz);
  613. GuiControl::smCursorChanged = CursorManager::curResizeHorz;
  614. }
  615. //cursor = mUpDownCursor;
  616. }
  617. else if ( resizeRight && mResizeWidth )
  618. {
  619. if(GuiControl::smCursorChanged != CursorManager::curResizeVert)
  620. {
  621. // We've already changed the cursor,
  622. // so set it back before we change it again.
  623. if(GuiControl::smCursorChanged != -1)
  624. Input::popCursor();
  625. // Now change the cursor shape
  626. Input::pushCursor(CursorManager::curResizeVert);
  627. GuiControl::smCursorChanged = CursorManager::curResizeVert;
  628. }
  629. //cursor = mLeftRightCursor;
  630. }
  631. else
  632. {
  633. if(GuiControl::smCursorChanged != -1)
  634. {
  635. // We've already changed the cursor,
  636. // so set it back before we change it again.
  637. Input::popCursor();
  638. // We haven't changed it
  639. GuiControl::smCursorChanged = -1;
  640. }
  641. return;
  642. }
  643. }