guiWindowCtrl.cc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  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::onMouseDown(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->onMouseDown(event);
  211. }
  212. }
  213. void GuiWindowCtrl::onMouseDragged(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::onMouseUp(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::drawWinRect(const RectI &myRect)
  470. {
  471. Point2I bl = myRect.point;
  472. Point2I tr;
  473. tr.x = myRect.point.x + myRect.extent.x - 1;
  474. tr.y = myRect.point.y + myRect.extent.y - 1;
  475. dglDrawRectFill(myRect, mProfile->mFillColor);
  476. dglDrawLine(Point2I(bl.x + 1, tr.y), Point2I(bl.x + 1, bl.y), ColorI(255, 255, 255));
  477. dglDrawLine(Point2I(bl.x, tr.y + 1), Point2I(tr.x, tr.y + 1), ColorI(255, 255, 255));
  478. //dglDrawRect(myRect, ColorI(0, 0, 0)); // Taken out, this is controled via mProfile->mBorder
  479. }
  480. void GuiWindowCtrl::onRender(Point2I offset, const RectI &updateRect)
  481. {
  482. if( !mProfile || mProfile->mFont.isNull() || mProfile->mBitmapArrayRects.size() < NumBitmaps )
  483. return Parent::onRender( offset, updateRect );
  484. //draw the outline
  485. RectI winRect;
  486. winRect.point = offset;
  487. winRect.extent = mBounds.extent;
  488. GuiCanvas *root = getRoot();
  489. GuiControl *firstResponder = root ? root->getFirstResponder() : NULL;
  490. bool isKey = (!firstResponder || ControlIsChild(firstResponder));
  491. U32 topBase = isKey ? BorderTopLeftKey : BorderTopLeftNoKey;
  492. winRect.point.x += mBitmapBounds[BorderLeft].extent.x;
  493. winRect.point.y += mBitmapBounds[topBase + 2].extent.y;
  494. winRect.extent.x -= mBitmapBounds[BorderLeft].extent.x + mBitmapBounds[BorderRight].extent.x;
  495. winRect.extent.y -= mBitmapBounds[topBase + 2].extent.y + mBitmapBounds[BorderBottom].extent.y;
  496. dglDrawRectFill(winRect, mProfile->mFillColor);
  497. dglClearBitmapModulation();
  498. dglDrawBitmapSR(mTextureHandle, offset, mBitmapBounds[topBase]);
  499. dglDrawBitmapSR(mTextureHandle, Point2I(offset.x + mBounds.extent.x - mBitmapBounds[topBase+1].extent.x, offset.y),
  500. mBitmapBounds[topBase + 1]);
  501. RectI destRect;
  502. destRect.point.x = offset.x + mBitmapBounds[topBase].extent.x;
  503. destRect.point.y = offset.y;
  504. destRect.extent.x = mBounds.extent.x - mBitmapBounds[topBase].extent.x - mBitmapBounds[topBase + 1].extent.x;
  505. destRect.extent.y = mBitmapBounds[topBase + 2].extent.y;
  506. RectI stretchRect = mBitmapBounds[topBase + 2];
  507. stretchRect.inset(1,0);
  508. dglDrawBitmapStretchSR(mTextureHandle, destRect, stretchRect);
  509. destRect.point.x = offset.x;
  510. destRect.point.y = offset.y + mBitmapBounds[topBase].extent.y;
  511. destRect.extent.x = mBitmapBounds[BorderLeft].extent.x;
  512. destRect.extent.y = mBounds.extent.y - mBitmapBounds[topBase].extent.y - mBitmapBounds[BorderBottomLeft].extent.y;
  513. stretchRect = mBitmapBounds[BorderLeft];
  514. stretchRect.inset(0,1);
  515. dglDrawBitmapStretchSR(mTextureHandle, destRect, stretchRect);
  516. destRect.point.x = offset.x + mBounds.extent.x - mBitmapBounds[BorderRight].extent.x;
  517. destRect.extent.x = mBitmapBounds[BorderRight].extent.x;
  518. destRect.point.y = offset.y + mBitmapBounds[topBase + 1].extent.y;
  519. destRect.extent.y = mBounds.extent.y - mBitmapBounds[topBase + 1].extent.y - mBitmapBounds[BorderBottomRight].extent.y;
  520. stretchRect = mBitmapBounds[BorderRight];
  521. stretchRect.inset(0,1);
  522. dglDrawBitmapStretchSR(mTextureHandle, destRect, stretchRect);
  523. dglDrawBitmapSR(mTextureHandle, offset + Point2I(0, mBounds.extent.y - mBitmapBounds[BorderBottomLeft].extent.y), mBitmapBounds[BorderBottomLeft]);
  524. dglDrawBitmapSR(mTextureHandle, offset + mBounds.extent - mBitmapBounds[BorderBottomRight].extent, mBitmapBounds[BorderBottomRight]);
  525. destRect.point.x = offset.x + mBitmapBounds[BorderBottomLeft].extent.x;
  526. destRect.extent.x = mBounds.extent.x - mBitmapBounds[BorderBottomLeft].extent.x - mBitmapBounds[BorderBottomRight].extent.x;
  527. destRect.point.y = offset.y + mBounds.extent.y - mBitmapBounds[BorderBottom].extent.y;
  528. destRect.extent.y = mBitmapBounds[BorderBottom].extent.y;
  529. stretchRect = mBitmapBounds[BorderBottom];
  530. stretchRect.inset(1,0);
  531. dglDrawBitmapStretchSR(mTextureHandle, destRect, stretchRect);
  532. //draw the title
  533. // dhc addition: copied/modded from renderJustifiedText, since we enforce a
  534. // different color usage here. NOTE: it currently CAN overdraw the controls
  535. // if mis-positioned or 'scrunched' in a small width.
  536. dglSetBitmapModulation(mProfile->mFontColor);
  537. S32 textWidth = mProfile->mFont->getStrWidth((const UTF8 *)mText);
  538. Point2I start(0,0);
  539. // align the horizontal
  540. if ( mProfile->mAlignment == GuiControlProfile::RightJustify )
  541. start.set( winRect.extent.x - textWidth, 0 );
  542. else if ( mProfile->mAlignment == GuiControlProfile::CenterJustify )
  543. start.set( ( winRect.extent.x - textWidth) / 2, 0 );
  544. else // GuiControlProfile::LeftJustify or garbage... ;)
  545. start.set( 0, 0 );
  546. // If the text is longer then the box size, (it'll get clipped) so force Left Justify
  547. if( textWidth > winRect.extent.x ) start.set( 0, 0 );
  548. // center the vertical
  549. // start.y = ( winRect.extent.y - ( font->getHeight() - 2 ) ) / 2;
  550. dglDrawText(mFont, start + offset + mProfile->mTextOffset, mText);
  551. // deal with rendering the titlebar controls
  552. AssertFatal(root, "Unable to get the root Canvas.");
  553. Point2I localPoint = globalToLocalCoord(root->getCursorPos());
  554. //draw the close button
  555. Point2I tempUL;
  556. Point2I tempLR;
  557. S32 bmp = BmpStates * BmpClose;
  558. if( mCanClose ) {
  559. if( mCloseButton.pointInRect( localPoint ) && mPressClose )
  560. bmp += BmpHilite;
  561. dglClearBitmapModulation();
  562. dglDrawBitmapSR(mTextureHandle, offset + mCloseButton.point, mBitmapBounds[bmp]);
  563. }
  564. //draw the maximize button
  565. if( mMaximized )
  566. bmp = BmpStates * BmpNormal;
  567. else
  568. bmp = BmpStates * BmpMaximize;
  569. if( mCanMaximize ) {
  570. if( mMaximizeButton.pointInRect( localPoint ) && mPressMaximize )
  571. bmp += BmpHilite;
  572. dglClearBitmapModulation();
  573. dglDrawBitmapSR( mTextureHandle, offset + mMaximizeButton.point, mBitmapBounds[bmp] );
  574. }
  575. //draw the minimize button
  576. if( mMinimized )
  577. bmp = BmpStates * BmpNormal;
  578. else
  579. bmp = BmpStates * BmpMinimize;
  580. if( mCanMinimize ) {
  581. if( mMinimizeButton.pointInRect( localPoint ) && mPressMinimize )
  582. bmp += BmpHilite;
  583. dglClearBitmapModulation();
  584. dglDrawBitmapSR( mTextureHandle, offset + mMinimizeButton.point, mBitmapBounds[bmp] );
  585. }
  586. if( !mMinimized )
  587. {
  588. //render the children
  589. renderChildControls( offset, updateRect );
  590. }
  591. }
  592. void GuiWindowCtrl::getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent)
  593. {
  594. Point2I mousePos = lastGuiEvent.mousePoint;
  595. RectI winRect = mBounds;
  596. RectI rightRect = RectI( ( ( winRect.extent.x + winRect.point.x ) - mResizeRightWidth), winRect.point.y, mResizeRightWidth, winRect.extent.y );
  597. RectI bottomRect = RectI( winRect.point.x, ( ( winRect.point.y + winRect.extent.y ) - mResizeBottomHeight), winRect.extent.x , mResizeBottomHeight );
  598. bool resizeRight = rightRect.pointInRect( mousePos );
  599. bool resizeBottom = bottomRect.pointInRect( mousePos );
  600. if ( resizeRight && resizeBottom && mResizeHeight && mResizeWidth )
  601. {
  602. if(GuiControl::smCursorChanged != CursorManager::curResizeNWSE)
  603. {
  604. // We've already changed the cursor,
  605. // so set it back before we change it again.
  606. if(GuiControl::smCursorChanged != -1)
  607. Input::popCursor();
  608. // Now change the cursor shape
  609. Input::pushCursor(CursorManager::curResizeNWSE);
  610. GuiControl::smCursorChanged = CursorManager::curResizeNWSE;
  611. }
  612. //cursor = mNWSECursor;
  613. }
  614. else if ( resizeBottom && mResizeHeight )
  615. {
  616. if(GuiControl::smCursorChanged != CursorManager::curResizeHorz)
  617. {
  618. // We've already changed the cursor,
  619. // so set it back before we change it again.
  620. if(GuiControl::smCursorChanged != -1)
  621. Input::popCursor();
  622. // Now change the cursor shape
  623. Input::pushCursor(CursorManager::curResizeHorz);
  624. GuiControl::smCursorChanged = CursorManager::curResizeHorz;
  625. }
  626. //cursor = mUpDownCursor;
  627. }
  628. else if ( resizeRight && mResizeWidth )
  629. {
  630. if(GuiControl::smCursorChanged != CursorManager::curResizeVert)
  631. {
  632. // We've already changed the cursor,
  633. // so set it back before we change it again.
  634. if(GuiControl::smCursorChanged != -1)
  635. Input::popCursor();
  636. // Now change the cursor shape
  637. Input::pushCursor(CursorManager::curResizeVert);
  638. GuiControl::smCursorChanged = CursorManager::curResizeVert;
  639. }
  640. //cursor = mLeftRightCursor;
  641. }
  642. else
  643. {
  644. if(GuiControl::smCursorChanged != -1)
  645. {
  646. // We've already changed the cursor,
  647. // so set it back before we change it again.
  648. Input::popCursor();
  649. // We haven't changed it
  650. GuiControl::smCursorChanged = -1;
  651. }
  652. return;
  653. }
  654. }