guiScrollCtrl.cpp 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "platform/typetraits.h"
  24. #include "gui/containers/guiScrollCtrl.h"
  25. #include "console/engineAPI.h"
  26. #include "console/console.h"
  27. #include "gfx/bitmap/gBitmap.h"
  28. #include "gui/core/guiDefaultControlRender.h"
  29. #include "gfx/gfxDevice.h"
  30. #include "gfx/gfxDrawUtil.h"
  31. #include "gui/core/guiCanvas.h"
  32. IMPLEMENT_CONOBJECT( GuiScrollCtrl );
  33. ConsoleDocClass( GuiScrollCtrl,
  34. "@brief A container that allows to view one or more possibly larger controls inside its area by "
  35. "providing horizontal and/or vertical scroll bars.\n\n"
  36. "@ingroup GuiContainers"
  37. );
  38. ImplementEnumType( GuiScrollBarBehavior,
  39. "Display behavior of a scroll bar. Determines when a scrollbar will be visible.\n\n"
  40. "@ingroup GuiContainers" )
  41. { GuiScrollCtrl::ScrollBarAlwaysOn, "alwaysOn", "Always visible." },
  42. { GuiScrollCtrl::ScrollBarAlwaysOff, "alwaysOff", "Never visible." },
  43. { GuiScrollCtrl::ScrollBarDynamic, "dynamic", "Only visible when actually needed, i.e. when the child control(s) exceed the visible space on the given axis." },
  44. EndImplementEnumType;
  45. IMPLEMENT_CALLBACK( GuiScrollCtrl, onScroll, void, (), (),
  46. "Called each time the child controls are scrolled by some amount." );
  47. //-----------------------------------------------------------------------------
  48. GuiScrollCtrl::GuiScrollCtrl()
  49. : mBorderThickness( 1 ),
  50. mChildMargin( 0, 0 ),
  51. mScrollBarThickness( 16 ),
  52. mScrollBarArrowBtnLength( 16 ),
  53. mScrollBarDragTolerance( 130 ),
  54. mStateDepressed( false ),
  55. mHitRegion( None ),
  56. mForceVScrollBar( ScrollBarAlwaysOn ),
  57. mUseConstantHeightThumb( false ),
  58. mWillFirstRespond( true ),
  59. mForceHScrollBar( ScrollBarAlwaysOn ),
  60. mLockHorizScroll( false ),
  61. mLockVertScroll( false ),
  62. mIgnoreChildResized( false ),
  63. mAnimating( false ),
  64. mScrollAnimSpeed( -1 ),
  65. mChildPos(0, 0),
  66. mChildExt(0, 0),
  67. mScrollTargetPos( -1, -1 ),
  68. mBaseThumbSize(0),
  69. mHBarEnabled(false),
  70. mVBarEnabled(false),
  71. mHasHScrollBar(false),
  72. mHasVScrollBar(false),
  73. mHThumbSize(1),
  74. mHThumbPos(0),
  75. mVThumbSize(1),
  76. mVThumbPos(0),
  77. mThumbMouseDelta(0)
  78. {
  79. mBitmapBounds = NULL;
  80. mIsContainer = true;
  81. setExtent(200,200);
  82. mLastPreRender = Platform::getVirtualMilliseconds();
  83. mLastUpdated = Platform::getVirtualMilliseconds();
  84. }
  85. //-----------------------------------------------------------------------------
  86. void GuiScrollCtrl::initPersistFields()
  87. {
  88. addGroup( "Scolling" );
  89. addField( "willFirstRespond", TypeBool, Offset(mWillFirstRespond, GuiScrollCtrl));
  90. addField( "hScrollBar", TYPEID< ScrollBarBehavior >(), Offset(mForceHScrollBar, GuiScrollCtrl),
  91. "When to display the horizontal scrollbar.");
  92. addField( "vScrollBar", TYPEID< ScrollBarBehavior >(), Offset(mForceVScrollBar, GuiScrollCtrl),
  93. "When to display the vertical scrollbar.");
  94. addField( "lockHorizScroll", TypeBool, Offset(mLockHorizScroll, GuiScrollCtrl),
  95. "Horizontal scrolling not allowed if set.");
  96. addField( "lockVertScroll", TypeBool, Offset(mLockVertScroll, GuiScrollCtrl),
  97. "Vertical scrolling not allowed if set.");
  98. addField( "constantThumbHeight", TypeBool, Offset(mUseConstantHeightThumb, GuiScrollCtrl));
  99. addField( "childMargin", TypePoint2I, Offset(mChildMargin, GuiScrollCtrl),
  100. "Padding region to put around child contents." );
  101. addField( "mouseWheelScrollSpeed", TypeS32, Offset(mScrollAnimSpeed, GuiScrollCtrl),
  102. "Pixels/Tick - if not positive then mousewheel scrolling occurs instantly (like other scrolling).");
  103. endGroup( "Scrolling" );
  104. Parent::initPersistFields();
  105. }
  106. //-----------------------------------------------------------------------------
  107. bool GuiScrollCtrl::resize(const Point2I &newPos, const Point2I &newExt)
  108. {
  109. if( !Parent::resize(newPos, newExt) )
  110. return false;
  111. computeSizes();
  112. return true;
  113. }
  114. //-----------------------------------------------------------------------------
  115. void GuiScrollCtrl::childResized(GuiControl *child)
  116. {
  117. if ( mIgnoreChildResized )
  118. return;
  119. Parent::childResized(child);
  120. computeSizes();
  121. }
  122. //-----------------------------------------------------------------------------
  123. bool GuiScrollCtrl::onWake()
  124. {
  125. if (! Parent::onWake())
  126. return false;
  127. mTextureObject = mProfile->getBitmapResource();
  128. if (mTextureObject && (mProfile->constructBitmapArray() >= BmpStates * BmpCount))
  129. {
  130. mBitmapBounds = mProfile->mBitmapArrayRects.address();
  131. //init
  132. mBaseThumbSize = mBitmapBounds[BmpStates * BmpVThumbTopCap].extent.y +
  133. mBitmapBounds[BmpStates * BmpVThumbBottomCap].extent.y;
  134. mScrollBarThickness = mBitmapBounds[BmpStates * BmpVPage].extent.x;
  135. mScrollBarArrowBtnLength = mBitmapBounds[BmpStates * BmpUp].extent.y;
  136. computeSizes();
  137. }
  138. else
  139. {
  140. Con::warnf("No texture loaded for scroll control named %s with profile %s", getName(), mProfile->getName());
  141. }
  142. return true;
  143. }
  144. //-----------------------------------------------------------------------------
  145. void GuiScrollCtrl::onSleep()
  146. {
  147. // Reset the mouse tracking state of this control
  148. // when it is put to sleep
  149. mStateDepressed = false;
  150. mHitRegion = None;
  151. Parent::onSleep();
  152. mTextureObject = NULL;
  153. }
  154. //-----------------------------------------------------------------------------
  155. bool GuiScrollCtrl::calcChildExtents()
  156. {
  157. // scroll control should deal well with multiple gui controls
  158. if( !size() )
  159. return false;
  160. // Find size and relative position of the client rectangle.
  161. Point2I maxPos( TypeTraits< S32 >::MIN, TypeTraits< S32 >::MIN );
  162. Point2I minPos( TypeTraits< S32 >::MAX, TypeTraits< S32 >::MAX );
  163. bool haveVisibleChild = false;
  164. for( U32 i = 0; i < size(); i++ )
  165. {
  166. GuiControl *ctrl = (GuiControl*)at(i);
  167. if( ctrl->isVisible() )
  168. {
  169. haveVisibleChild = true;
  170. minPos.x = getMin( ctrl->getPosition().x, minPos.x );
  171. minPos.y = getMin( ctrl->getPosition().y, minPos.y );
  172. // This is +1 but the remaining code here all works with extents +1.
  173. Point2I ctrlMax = ctrl->getPosition() + ctrl->getExtent();
  174. maxPos.x = getMax( ctrlMax.x, maxPos.x );
  175. maxPos.y = getMax( ctrlMax.y, maxPos.y );
  176. }
  177. }
  178. if( !haveVisibleChild )
  179. return false;
  180. mChildPos = minPos;
  181. mChildExt = maxPos - minPos;
  182. return true;
  183. }
  184. //-----------------------------------------------------------------------------
  185. void GuiScrollCtrl::scrollRectVisible(RectI rect)
  186. {
  187. // rect is passed in virtual client space
  188. if(rect.extent.x > mContentExt.x)
  189. rect.extent.x = mContentExt.x;
  190. if(rect.extent.y > mContentExt.y)
  191. rect.extent.y = mContentExt.y;
  192. // Determine the points bounding the requested rectangle
  193. Point2I rectUpperLeft = rect.point;
  194. Point2I rectLowerRight = rect.point + rect.extent;
  195. // Determine the points bounding the actual visible area...
  196. Point2I visUpperLeft = mChildRelPos;
  197. Point2I visLowerRight = mChildRelPos + mContentExt;
  198. Point2I delta(0,0);
  199. // We basically try to make sure that first the top left of the given
  200. // rect is visible, and if it is, then that the bottom right is visible.
  201. // Make sure the rectangle is visible along the X axis...
  202. if(rectUpperLeft.x < visUpperLeft.x)
  203. delta.x = rectUpperLeft.x - visUpperLeft.x;
  204. else if(rectLowerRight.x > visLowerRight.x)
  205. delta.x = rectLowerRight.x - visLowerRight.x;
  206. // Make sure the rectangle is visible along the Y axis...
  207. if(rectUpperLeft.y < visUpperLeft.y)
  208. delta.y = rectUpperLeft.y - visUpperLeft.y;
  209. else if(rectLowerRight.y > visLowerRight.y)
  210. delta.y = rectLowerRight.y - visLowerRight.y;
  211. // If we had any changes, scroll, otherwise don't.
  212. if(delta.x || delta.y)
  213. scrollDelta(delta.x, delta.y);
  214. }
  215. //-----------------------------------------------------------------------------
  216. bool GuiScrollCtrl::isPointVisible( const Point2I& point )
  217. {
  218. return ( point.x >= mChildRelPos.x && point.x <= ( mChildRelPos.x + mContentExt.x ) )
  219. && ( point.y >= mChildRelPos.y && point.y <= ( mChildRelPos.y + mContentExt.y ) );
  220. }
  221. //-----------------------------------------------------------------------------
  222. bool GuiScrollCtrl::isRectCompletelyVisible(const RectI& rect)
  223. {
  224. // rect is passed in virtual client space
  225. // Determine the points bounding the requested rectangle
  226. Point2I rectUpperLeft = rect.point;
  227. Point2I rectLowerRight = rect.point + rect.extent;
  228. // Determine the points bounding the actual visible area...
  229. Point2I visUpperLeft = mChildRelPos;
  230. Point2I visLowerRight = mChildRelPos + mContentExt;
  231. // Make sure the rectangle is visible along the X axis...
  232. if(rectUpperLeft.x < visUpperLeft.x)
  233. return false;
  234. else if(rectLowerRight.x > visLowerRight.x)
  235. return false;
  236. // Make sure the rectangle is visible along the Y axis...
  237. if(rectUpperLeft.y < visUpperLeft.y)
  238. return false;
  239. else if(rectLowerRight.y > visLowerRight.y)
  240. return false;
  241. return true;
  242. }
  243. //-----------------------------------------------------------------------------
  244. void GuiScrollCtrl::addObject(SimObject *object)
  245. {
  246. Parent::addObject(object);
  247. computeSizes();
  248. }
  249. //-----------------------------------------------------------------------------
  250. GuiControl* GuiScrollCtrl::findHitControl(const Point2I &pt, S32 initialLayer)
  251. {
  252. if(pt.x < mProfile->mBorderThickness || pt.y < mProfile->mBorderThickness)
  253. return this;
  254. if(pt.x >= getWidth() - mProfile->mBorderThickness - (mHasVScrollBar ? mScrollBarThickness : 0) ||
  255. pt.y >= getHeight() - mProfile->mBorderThickness - (mHasHScrollBar ? mScrollBarThickness : 0))
  256. return this;
  257. return Parent::findHitControl(pt, initialLayer);
  258. }
  259. //-----------------------------------------------------------------------------
  260. void GuiScrollCtrl::computeSizes()
  261. {
  262. S32 thickness = (mProfile ? mProfile->mBorderThickness : 1);
  263. Point2I borderExtent(thickness, thickness);
  264. mContentPos = borderExtent + mChildMargin;
  265. mContentExt = getExtent() - (mChildMargin * 2)
  266. - (borderExtent * 2);
  267. Point2I childLowerRight;
  268. mHBarEnabled = false;
  269. mVBarEnabled = false;
  270. mHasVScrollBar = (mForceVScrollBar == ScrollBarAlwaysOn);
  271. mHasHScrollBar = (mForceHScrollBar == ScrollBarAlwaysOn);
  272. setUpdate();
  273. if (calcChildExtents())
  274. {
  275. childLowerRight = mChildPos + mChildExt;
  276. if (mHasVScrollBar)
  277. mContentExt.x -= mScrollBarThickness;
  278. if (mHasHScrollBar)
  279. mContentExt.y -= mScrollBarThickness;
  280. if (mChildExt.x > mContentExt.x && (mForceHScrollBar == ScrollBarDynamic))
  281. {
  282. mHasHScrollBar = true;
  283. mContentExt.y -= mScrollBarThickness;
  284. }
  285. if (mChildExt.y > mContentExt.y && (mForceVScrollBar == ScrollBarDynamic))
  286. {
  287. mHasVScrollBar = true;
  288. mContentExt.x -= mScrollBarThickness;
  289. // If Extent X Changed, check Horiz Scrollbar.
  290. if (mChildExt.x > mContentExt.x && !mHasHScrollBar && (mForceHScrollBar == ScrollBarDynamic))
  291. {
  292. mHasHScrollBar = true;
  293. mContentExt.y -= mScrollBarThickness;
  294. }
  295. }
  296. Point2I contentLowerRight = mContentPos + mContentExt;
  297. // see if the child controls need to be repositioned (null space in control)
  298. Point2I delta(0,0);
  299. if (mChildPos.x > mContentPos.x)
  300. delta.x = mContentPos.x - mChildPos.x;
  301. else if (contentLowerRight.x > childLowerRight.x)
  302. {
  303. S32 diff = contentLowerRight.x - childLowerRight.x;
  304. delta.x = getMin(mContentPos.x - mChildPos.x, diff);
  305. }
  306. //reposition the children if the child extent > the scroll content extent
  307. if (mChildPos.y > mContentPos.y)
  308. delta.y = mContentPos.y - mChildPos.y;
  309. else if (contentLowerRight.y > childLowerRight.y)
  310. {
  311. S32 diff = contentLowerRight.y - childLowerRight.y;
  312. delta.y = getMin(mContentPos.y - mChildPos.y, diff);
  313. }
  314. // apply the deltas to the children...
  315. if (delta.x || delta.y)
  316. {
  317. SimGroup::iterator i;
  318. for(i = begin(); i != end();i++)
  319. {
  320. GuiControl *ctrl = (GuiControl *) (*i);
  321. ctrl->setPosition( ctrl->getPosition() + delta );
  322. }
  323. mChildPos += delta;
  324. childLowerRight += delta;
  325. }
  326. // enable needed scroll bars
  327. if (mChildExt.x > mContentExt.x)
  328. mHBarEnabled = true;
  329. if (mChildExt.y > mContentExt.y)
  330. mVBarEnabled = true;
  331. mChildRelPos = mContentPos - mChildPos;
  332. }
  333. // Prevent resizing our children from recalling this function!
  334. mIgnoreChildResized = true;
  335. if ( mLockVertScroll )
  336. {
  337. // If vertical scroll is locked we size our child's height to our own
  338. SimGroup::iterator i;
  339. for(i = begin(); i != end();i++)
  340. {
  341. GuiControl *ctrl = (GuiControl *) (*i);
  342. ctrl->setHeight( mContentExt.y );
  343. }
  344. }
  345. if ( mLockHorizScroll )
  346. {
  347. // If horizontal scroll is locked we size our child's width to our own
  348. SimGroup::iterator i;
  349. for(i = begin(); i != end();i++)
  350. {
  351. GuiControl *ctrl = (GuiControl *) (*i);
  352. ctrl->setWidth( mContentExt.x );
  353. }
  354. }
  355. mIgnoreChildResized = false;
  356. // build all the rectangles and such...
  357. calcScrollRects();
  358. calcThumbs();
  359. }
  360. //-----------------------------------------------------------------------------
  361. void GuiScrollCtrl::calcScrollRects(void)
  362. {
  363. S32 thickness = ( mProfile ? mProfile->mBorderThickness : 1 );
  364. if (mHasHScrollBar)
  365. {
  366. mLeftArrowRect.set(thickness,
  367. getHeight() - thickness - mScrollBarThickness,
  368. mScrollBarArrowBtnLength,
  369. mScrollBarThickness);
  370. mRightArrowRect.set(getWidth() - thickness - (mHasVScrollBar ? mScrollBarThickness - 1 : 0) - mScrollBarArrowBtnLength,
  371. getHeight() - thickness - mScrollBarThickness,
  372. mScrollBarArrowBtnLength,
  373. mScrollBarThickness);
  374. mHTrackRect.set(mLeftArrowRect.point.x + mLeftArrowRect.extent.x,
  375. mLeftArrowRect.point.y,
  376. mRightArrowRect.point.x - (mLeftArrowRect.point.x + mLeftArrowRect.extent.x),
  377. mScrollBarThickness);
  378. }
  379. if (mHasVScrollBar)
  380. {
  381. mUpArrowRect.set(getWidth() - thickness - mScrollBarThickness,
  382. thickness,
  383. mScrollBarThickness,
  384. mScrollBarArrowBtnLength);
  385. mDownArrowRect.set(getWidth() - thickness - mScrollBarThickness,
  386. getHeight() - thickness - (mHasHScrollBar ? mScrollBarThickness - 1 : 0) - mScrollBarArrowBtnLength,
  387. mScrollBarThickness,
  388. mScrollBarArrowBtnLength);
  389. mVTrackRect.set(mUpArrowRect.point.x,
  390. mUpArrowRect.point.y + mUpArrowRect.extent.y,
  391. mScrollBarThickness,
  392. mDownArrowRect.point.y - (mUpArrowRect.point.y + mUpArrowRect.extent.y) );
  393. }
  394. }
  395. //-----------------------------------------------------------------------------
  396. void GuiScrollCtrl::calcThumbs()
  397. {
  398. if (mHBarEnabled && mChildExt.x > 0)
  399. {
  400. U32 trackSize = mHTrackRect.len_x();
  401. if (mUseConstantHeightThumb)
  402. mHThumbSize = mBaseThumbSize;
  403. else
  404. mHThumbSize = getMax(mBaseThumbSize, ( S32 )mCeil( ( F32 )( mContentExt.x * trackSize) / ( F32 )mChildExt.x ) );
  405. mHThumbPos = mHTrackRect.point.x + (mChildRelPos.x * (trackSize - mHThumbSize)) / (mChildExt.x - mContentExt.x);
  406. }
  407. if (mVBarEnabled && mChildExt.y > 0)
  408. {
  409. U32 trackSize = mVTrackRect.len_y();
  410. if (mUseConstantHeightThumb)
  411. mVThumbSize = mBaseThumbSize;
  412. else
  413. mVThumbSize = getMax(mBaseThumbSize, ( S32 )mCeil( ( F32 )( mContentExt.y * trackSize ) / ( F32 )mChildExt.y ) );
  414. mVThumbPos = mVTrackRect.point.y + (mChildRelPos.y * (trackSize - mVThumbSize)) / (mChildExt.y - mContentExt.y);
  415. }
  416. }
  417. //-----------------------------------------------------------------------------
  418. void GuiScrollCtrl::scrollDelta(S32 deltaX, S32 deltaY)
  419. {
  420. scrollTo(mChildRelPos.x + deltaX, mChildRelPos.y + deltaY);
  421. onScroll_callback();
  422. }
  423. //-----------------------------------------------------------------------------
  424. void GuiScrollCtrl::scrollDeltaAnimate(S32 x, S32 y)
  425. {
  426. if ( !size() )
  427. return;
  428. if ( mAnimating )
  429. mScrollTargetPos += Point2I( x, y );
  430. else
  431. mScrollTargetPos = mChildRelPos + Point2I( x, y );
  432. setUpdate();
  433. mScrollTargetPos.setMin( mChildExt - mContentExt );
  434. mScrollTargetPos.setMax( Point2I::Zero );
  435. mAnimating = true;
  436. }
  437. //-----------------------------------------------------------------------------
  438. void GuiScrollCtrl::scrollTo(S32 x, S32 y)
  439. {
  440. if( !size() )
  441. return;
  442. if ( x == mChildRelPos.x && y == mChildRelPos.y )
  443. return;
  444. setUpdate();
  445. if (x > mChildExt.x - mContentExt.x)
  446. x = mChildExt.x - mContentExt.x;
  447. if (x < 0)
  448. x = 0;
  449. if (y > mChildExt.y - mContentExt.y)
  450. y = mChildExt.y - mContentExt.y;
  451. if (y < 0)
  452. y = 0;
  453. Point2I delta(x - mChildRelPos.x, y - mChildRelPos.y);
  454. mChildRelPos += delta;
  455. mChildPos -= delta;
  456. for(SimSet::iterator i = begin(); i != end();i++)
  457. {
  458. GuiControl *ctrl = (GuiControl *) (*i);
  459. ctrl->setPosition( ctrl->getPosition() - delta );
  460. }
  461. calcThumbs();
  462. onScroll_callback();
  463. }
  464. //-----------------------------------------------------------------------------
  465. void GuiScrollCtrl::scrollToObject(GuiControl *targetControl)
  466. {
  467. bool isValidChild = false;
  468. Point2I relativePosition = targetControl->getPosition();
  469. GuiControl* parentControl = targetControl->getParent();
  470. while (parentControl)
  471. {
  472. GuiScrollCtrl* scrollControl = dynamic_cast<GuiScrollCtrl*>(parentControl);
  473. if (scrollControl == this)
  474. {
  475. relativePosition += scrollControl->getChildRelPos();
  476. isValidChild = true;
  477. break;
  478. }
  479. relativePosition += parentControl->getPosition();
  480. parentControl = parentControl->getParent();
  481. }
  482. if (isValidChild)
  483. {
  484. scrollRectVisible(RectI(relativePosition, targetControl->getExtent()));
  485. }
  486. else
  487. {
  488. Con::errorf("GuiScrollCtrl::scrollToObject() - Specified object is not a child of this scroll control (%d)!", targetControl->getId());
  489. }
  490. }
  491. //-----------------------------------------------------------------------------
  492. GuiScrollCtrl::Region GuiScrollCtrl::findHitRegion(const Point2I &pt)
  493. {
  494. if (mVBarEnabled && mHasVScrollBar)
  495. {
  496. if (mUpArrowRect.pointInRect(pt))
  497. return UpArrow;
  498. else if (mDownArrowRect.pointInRect(pt))
  499. return DownArrow;
  500. else if (mVTrackRect.pointInRect(pt))
  501. {
  502. if (pt.y < mVThumbPos)
  503. return UpPage;
  504. else if (pt.y < mVThumbPos + mVThumbSize)
  505. return VertThumb;
  506. else
  507. return DownPage;
  508. }
  509. }
  510. if (mHBarEnabled && mHasHScrollBar)
  511. {
  512. if (mLeftArrowRect.pointInRect(pt))
  513. return LeftArrow;
  514. else if (mRightArrowRect.pointInRect(pt))
  515. return RightArrow;
  516. else if (mHTrackRect.pointInRect(pt))
  517. {
  518. if (pt.x < mHThumbPos)
  519. return LeftPage;
  520. else if (pt.x < mHThumbPos + mHThumbSize)
  521. return HorizThumb;
  522. else
  523. return RightPage;
  524. }
  525. }
  526. return None;
  527. }
  528. //-----------------------------------------------------------------------------
  529. bool GuiScrollCtrl::wantsTabListMembership()
  530. {
  531. return true;
  532. }
  533. //-----------------------------------------------------------------------------
  534. bool GuiScrollCtrl::loseFirstResponder()
  535. {
  536. setUpdate();
  537. return true;
  538. }
  539. //-----------------------------------------------------------------------------
  540. bool GuiScrollCtrl::becomeFirstResponder()
  541. {
  542. setUpdate();
  543. return mWillFirstRespond;
  544. }
  545. //-----------------------------------------------------------------------------
  546. bool GuiScrollCtrl::onKeyDown(const GuiEvent &event)
  547. {
  548. if (mWillFirstRespond)
  549. {
  550. switch (event.keyCode)
  551. {
  552. case KEY_RIGHT:
  553. scrollByRegion(RightArrow);
  554. return true;
  555. case KEY_LEFT:
  556. scrollByRegion(LeftArrow);
  557. return true;
  558. case KEY_DOWN:
  559. scrollByRegion(DownArrow);
  560. return true;
  561. case KEY_UP:
  562. scrollByRegion(UpArrow);
  563. return true;
  564. case KEY_PAGE_UP:
  565. scrollByRegion(UpPage);
  566. return true;
  567. case KEY_PAGE_DOWN:
  568. scrollByRegion(DownPage);
  569. return true;
  570. default:
  571. break;
  572. }
  573. }
  574. return Parent::onKeyDown(event);
  575. }
  576. //-----------------------------------------------------------------------------
  577. void GuiScrollCtrl::_onMouseDown( const GuiEvent &event, bool lockMouse )
  578. {
  579. if( lockMouse )
  580. {
  581. mouseLock();
  582. mStateDepressed = true;
  583. }
  584. setUpdate();
  585. Point2I curMousePos = globalToLocalCoord(event.mousePoint);
  586. mHitRegion = findHitRegion(curMousePos);
  587. // Set a 0.5 second delay before we start scrolling
  588. mLastUpdated = Platform::getVirtualMilliseconds() + 500;
  589. scrollByRegion(mHitRegion);
  590. if (mHitRegion == VertThumb)
  591. {
  592. mChildRelPosAnchor = mChildRelPos;
  593. mThumbMouseDelta = curMousePos.y - mVThumbPos;
  594. }
  595. else if (mHitRegion == HorizThumb)
  596. {
  597. mChildRelPosAnchor = mChildRelPos;
  598. mThumbMouseDelta = curMousePos.x - mHThumbPos;
  599. }
  600. }
  601. //-----------------------------------------------------------------------------
  602. void GuiScrollCtrl::onMouseDown(const GuiEvent &event)
  603. {
  604. _onMouseDown( event, true );
  605. }
  606. //-----------------------------------------------------------------------------
  607. bool GuiScrollCtrl::onMouseDownEditor( const GuiEvent& event, Point2I offset )
  608. {
  609. // If ALT is pressed while clicking on a horizontal or vertical scrollbar,
  610. // do a scroll.
  611. if( event.modifier & SI_PRIMARY_ALT )
  612. {
  613. Region hitRegion = findHitRegion( globalToLocalCoord( event.mousePoint ) );
  614. if( hitRegion != None )
  615. {
  616. _onMouseDown( event, false );
  617. return true;
  618. }
  619. }
  620. return false;
  621. }
  622. //-----------------------------------------------------------------------------
  623. void GuiScrollCtrl::onMouseUp(const GuiEvent &)
  624. {
  625. mouseUnlock();
  626. setUpdate();
  627. mHitRegion = None;
  628. mStateDepressed = false;
  629. }
  630. //-----------------------------------------------------------------------------
  631. void GuiScrollCtrl::onMouseDragged(const GuiEvent &event)
  632. {
  633. Point2I curMousePos = globalToLocalCoord(event.mousePoint);
  634. setUpdate();
  635. if ( (mHitRegion != VertThumb) && (mHitRegion != HorizThumb) )
  636. {
  637. Region hit = findHitRegion(curMousePos);
  638. if (hit != mHitRegion)
  639. mStateDepressed = false;
  640. else
  641. mStateDepressed = true;
  642. return;
  643. }
  644. // ok... if the mouse is 'near' the scroll bar, scroll with it
  645. // otherwise, snap back to the previous position.
  646. if (mHitRegion == VertThumb)
  647. {
  648. if (curMousePos.x >= mVTrackRect.point.x - mScrollBarDragTolerance &&
  649. curMousePos.x <= mVTrackRect.point.x + mVTrackRect.extent.x - 1 + mScrollBarDragTolerance &&
  650. curMousePos.y >= mVTrackRect.point.y - mScrollBarDragTolerance &&
  651. curMousePos.y <= mVTrackRect.point.y + mVTrackRect.extent.y - 1 + mScrollBarDragTolerance)
  652. {
  653. S32 newVThumbPos = curMousePos.y - mThumbMouseDelta;
  654. if(newVThumbPos != mVThumbPos)
  655. {
  656. S32 newVPos = (newVThumbPos - mVTrackRect.point.y) *
  657. (mChildExt.y - mContentExt.y) /
  658. (mVTrackRect.extent.y - mVThumbSize);
  659. scrollTo(mChildRelPosAnchor.x, newVPos);
  660. }
  661. }
  662. else
  663. scrollTo(mChildRelPosAnchor.x, mChildRelPosAnchor.y);
  664. }
  665. else if (mHitRegion == HorizThumb)
  666. {
  667. if (curMousePos.x >= mHTrackRect.point.x - mScrollBarDragTolerance &&
  668. curMousePos.x <= mHTrackRect.point.x + mHTrackRect.extent.x - 1 + mScrollBarDragTolerance &&
  669. curMousePos.y >= mHTrackRect.point.y - mScrollBarDragTolerance &&
  670. curMousePos.y <= mHTrackRect.point.y + mHTrackRect.extent.y - 1 + mScrollBarDragTolerance)
  671. {
  672. S32 newHThumbPos = curMousePos.x - mThumbMouseDelta;
  673. if(newHThumbPos != mHThumbPos)
  674. {
  675. S32 newHPos = (newHThumbPos - mHTrackRect.point.x) *
  676. (mChildExt.x - mContentExt.x) /
  677. (mHTrackRect.extent.x - mHThumbSize);
  678. scrollTo(newHPos, mChildRelPosAnchor.y);
  679. }
  680. }
  681. else
  682. scrollTo(mChildRelPosAnchor.x, mChildRelPosAnchor.y);
  683. }
  684. }
  685. //-----------------------------------------------------------------------------
  686. bool GuiScrollCtrl::onMouseWheelUp(const GuiEvent &event)
  687. {
  688. if ( !mAwake || !mVisible )
  689. return false;
  690. scrollByMouseWheel( event );
  691. return true;
  692. }
  693. //-----------------------------------------------------------------------------
  694. bool GuiScrollCtrl::onMouseWheelDown(const GuiEvent &event)
  695. {
  696. if ( !mAwake || !mVisible )
  697. return false;
  698. scrollByMouseWheel( event );
  699. return true;
  700. }
  701. //-----------------------------------------------------------------------------
  702. void GuiScrollCtrl::updateChildMousePos()
  703. {
  704. // We pass a fake GuiEvent to child controls onMouseMove
  705. // since although the mouse has not moved 'they' have.
  706. //
  707. // Its possible this could cause problems if a GuiControl
  708. // responds to more than just the mouse position in the onMouseMove
  709. // event, like for example doing something different depending on
  710. // a modifier key, which we aren't filling in to the structure!
  711. GuiEvent event;
  712. event.mousePoint = getRoot()->getCursorPos();
  713. iterator itr;
  714. for ( itr = begin(); itr != end(); itr++ )
  715. {
  716. GuiControl *child = static_cast<GuiControl*>( *itr );
  717. child->onMouseMove( event );
  718. }
  719. }
  720. //-----------------------------------------------------------------------------
  721. void GuiScrollCtrl::onPreRender()
  722. {
  723. Parent::onPreRender();
  724. S32 currentTime = Platform::getVirtualMilliseconds();
  725. S32 deltaMs = currentTime - mLastPreRender;
  726. mLastPreRender = currentTime;
  727. // Update mouse-wheel scroll animation if we are currently doing one...
  728. if ( mAnimating )
  729. {
  730. //U32 frames = Con::getIntVariable( "$frames", 0 );
  731. //frames++;
  732. //Con::setIntVariable( "$frames", frames );
  733. F32 deltaTicks = deltaMs / 32.0f;
  734. if ( mScrollAnimSpeed <= 0 )
  735. {
  736. scrollTo( mScrollTargetPos.x, mScrollTargetPos.y );
  737. }
  738. else
  739. {
  740. S32 maxPixels = deltaTicks * mScrollAnimSpeed;
  741. Point2I toTarget = mScrollTargetPos - mChildRelPos;
  742. S32 signx = toTarget.x > 0 ? 1 : -1;
  743. S32 signy = toTarget.y > 0 ? 1 : -1;
  744. S32 deltaX = getMin( mAbs(toTarget.x), maxPixels ) * signx;
  745. S32 deltaY = getMin( mAbs(toTarget.y), maxPixels ) * signy;
  746. scrollDelta( deltaX, deltaY );
  747. }
  748. if ( mChildRelPos == mScrollTargetPos )
  749. {
  750. //Con::printf( "Animated Frames : %d", frames );
  751. //Con::setIntVariable( "$frames", 0 );
  752. mAnimating = false;
  753. }
  754. updateChildMousePos();
  755. }
  756. // Now scroll in response to a 'depressed state' if appropriate...
  757. // Short circuit if not depressed to save cycles
  758. if( mStateDepressed != true )
  759. return;
  760. //default to one second, though it shouldn't be necessary
  761. U32 timeThreshold = 1000;
  762. // We don't want to scroll by pages at an interval the same as when we're scrolling
  763. // using the arrow buttons, so adjust accordingly.
  764. switch( mHitRegion )
  765. {
  766. case UpPage:
  767. case DownPage:
  768. case LeftPage:
  769. case RightPage:
  770. timeThreshold = 200;
  771. break;
  772. case UpArrow:
  773. case DownArrow:
  774. case LeftArrow:
  775. case RightArrow:
  776. timeThreshold = 20;
  777. break;
  778. default:
  779. // Neither a button or a page, don't scroll (shouldn't get here)
  780. return;
  781. break;
  782. };
  783. S32 timeElapsed = Platform::getVirtualMilliseconds() - mLastUpdated;
  784. if ( ( timeElapsed > 0 ) && ( timeElapsed > timeThreshold ) )
  785. {
  786. mLastUpdated = Platform::getVirtualMilliseconds();
  787. scrollByRegion(mHitRegion);
  788. }
  789. }
  790. //-----------------------------------------------------------------------------
  791. void GuiScrollCtrl::scrollByRegion(Region reg)
  792. {
  793. setUpdate();
  794. if(!size())
  795. return;
  796. GuiControl *content = (GuiControl *) front();
  797. U32 rowHeight, columnWidth;
  798. U32 pageHeight, pageWidth;
  799. content->getScrollLineSizes(&rowHeight, &columnWidth);
  800. if(rowHeight >= mContentExt.y)
  801. pageHeight = 1;
  802. else
  803. pageHeight = mContentExt.y - rowHeight;
  804. if(columnWidth >= mContentExt.x)
  805. pageWidth = 1;
  806. else
  807. pageWidth = mContentExt.x - columnWidth;
  808. if (mVBarEnabled)
  809. {
  810. switch(reg)
  811. {
  812. case UpPage:
  813. scrollDelta(0, -(S32)pageHeight);
  814. break;
  815. case DownPage:
  816. scrollDelta(0, pageHeight);
  817. break;
  818. case UpArrow:
  819. scrollDelta(0, -(S32)rowHeight);
  820. break;
  821. case DownArrow:
  822. scrollDelta(0, rowHeight);
  823. break;
  824. default:
  825. break;
  826. }
  827. }
  828. if (mHBarEnabled)
  829. {
  830. switch(reg)
  831. {
  832. case LeftPage:
  833. scrollDelta(-(S32)pageWidth, 0);
  834. break;
  835. case RightPage:
  836. scrollDelta(pageWidth, 0);
  837. break;
  838. case LeftArrow:
  839. scrollDelta(-(S32)columnWidth, 0);
  840. break;
  841. case RightArrow:
  842. scrollDelta(columnWidth, 0);
  843. break;
  844. default:
  845. break;
  846. }
  847. }
  848. }
  849. //-----------------------------------------------------------------------------
  850. void GuiScrollCtrl::scrollByMouseWheel( const GuiEvent &event )
  851. {
  852. setUpdate();
  853. if ( !size() )
  854. return;
  855. if( event.mouseAxis == 1 )
  856. scrollDeltaAnimate( 0, -event.fval );
  857. else
  858. scrollDeltaAnimate( -event.fval, 0 );
  859. }
  860. //-----------------------------------------------------------------------------
  861. void GuiScrollCtrl::onRender(Point2I offset, const RectI &updateRect)
  862. {
  863. // draw content controls
  864. // create a rect to intersect with the updateRect
  865. RectI contentRect(mContentPos.x + offset.x, mContentPos.y + offset.y, mContentExt.x, mContentExt.y);
  866. contentRect.intersect(updateRect);
  867. // Always call parent
  868. Parent::onRender(offset, contentRect);
  869. if( mTextureObject )
  870. {
  871. // Reset the ClipRect as the parent call can modify it when rendering
  872. // the child controls
  873. GFX->setClipRect( updateRect );
  874. //draw the scroll corner
  875. if (mHasVScrollBar && mHasHScrollBar)
  876. drawScrollCorner(offset);
  877. // draw scroll bars
  878. if (mHasVScrollBar)
  879. drawVScrollBar(offset);
  880. if (mHasHScrollBar)
  881. drawHScrollBar(offset);
  882. }
  883. }
  884. //-----------------------------------------------------------------------------
  885. void GuiScrollCtrl::drawBorder( const Point2I &offset, bool /*isFirstResponder*/ )
  886. {
  887. }
  888. //-----------------------------------------------------------------------------
  889. void GuiScrollCtrl::drawVScrollBar(const Point2I &offset)
  890. {
  891. if ( mTextureObject.isNull() )
  892. {
  893. return;
  894. }
  895. // Start Point.
  896. Point2I pos = ( offset + mUpArrowRect.point );
  897. // Up Arrow.
  898. S32 upArrowBitmap = ( BmpStates * BmpUp );
  899. if ( !mVBarEnabled )
  900. {
  901. upArrowBitmap += BmpDisabled;
  902. }
  903. else if ( mHitRegion == UpArrow && mStateDepressed )
  904. {
  905. upArrowBitmap += BmpHilite;
  906. }
  907. // Render Up Arrow.
  908. GFXDrawUtil* drawUtil = GFX->getDrawUtil();
  909. drawUtil->clearBitmapModulation();
  910. drawUtil->drawBitmapSR(mTextureObject, pos, mBitmapBounds[upArrowBitmap]);
  911. // Update Pos.
  912. pos.y += mBitmapBounds[upArrowBitmap].extent.y;
  913. // Track.
  914. S32 trackBitmap = ( BmpStates * BmpVPage );
  915. if ( !mVBarEnabled )
  916. {
  917. trackBitmap += BmpDisabled;
  918. }
  919. else if ( mHitRegion == DownPage && mStateDepressed )
  920. {
  921. trackBitmap += BmpHilite;
  922. }
  923. // Determine the Track Rect.
  924. RectI trackRect;
  925. trackRect.point = pos;
  926. trackRect.extent.x = mBitmapBounds[trackBitmap].extent.x;
  927. trackRect.extent.y = ( offset.y + mDownArrowRect.point.y ) - pos.y;
  928. // Render Track?
  929. if ( trackRect.extent.y > 0 )
  930. {
  931. // Render Track.
  932. drawUtil->clearBitmapModulation();
  933. drawUtil->drawBitmapStretchSR(mTextureObject, trackRect, mBitmapBounds[trackBitmap]);
  934. }
  935. // Update Pos.
  936. pos.y += trackRect.extent.y;
  937. // Down Arrow.
  938. S32 downArrowBitmap = ( BmpStates * BmpDown );
  939. if ( !mVBarEnabled )
  940. {
  941. downArrowBitmap += BmpDisabled;
  942. }
  943. else if ( mHitRegion == DownArrow && mStateDepressed )
  944. {
  945. downArrowBitmap += BmpHilite;
  946. }
  947. // Render Down Arrow.
  948. drawUtil->clearBitmapModulation();
  949. drawUtil->drawBitmapSR(mTextureObject, pos, mBitmapBounds[downArrowBitmap]);
  950. // Render the Thumb?
  951. if ( !mVBarEnabled )
  952. {
  953. // Nope.
  954. return;
  955. }
  956. // Reset the Pos.
  957. pos.y = ( offset.y + mVThumbPos );
  958. // Determine the Bitmaps.
  959. S32 thumbBitmapTop = ( BmpStates * BmpVThumbTopCap );
  960. S32 thumbBitmapMiddle = ( BmpStates * BmpVThumb );
  961. S32 thumbBitmapBottom = ( BmpStates * BmpVThumbBottomCap );
  962. if ( mHitRegion == VertThumb && mStateDepressed )
  963. {
  964. thumbBitmapTop += BmpHilite;
  965. thumbBitmapMiddle += BmpHilite;
  966. thumbBitmapBottom += BmpHilite;
  967. }
  968. // Render Thumb Top.
  969. drawUtil->clearBitmapModulation();
  970. drawUtil->drawBitmapSR(mTextureObject, pos, mBitmapBounds[thumbBitmapTop]);
  971. // Update Pos.
  972. pos.y += mBitmapBounds[thumbBitmapTop].extent.y;
  973. // Determine the Thumb Rect.
  974. RectI thumbRect;
  975. thumbRect.point = pos;
  976. thumbRect.extent.x = mBitmapBounds[thumbBitmapMiddle].extent.x;
  977. thumbRect.extent.y = mVThumbSize - ( mBitmapBounds[thumbBitmapTop].extent.y + mBitmapBounds[thumbBitmapBottom].extent.y );
  978. // Render Thumb?
  979. if ( thumbRect.extent.y > 0 )
  980. {
  981. // Render Track.
  982. drawUtil->clearBitmapModulation();
  983. drawUtil->drawBitmapStretchSR(mTextureObject, thumbRect, mBitmapBounds[thumbBitmapMiddle]);
  984. }
  985. // Update Pos.
  986. pos.y += thumbRect.extent.y;
  987. // Render the Thumb Bottom.
  988. drawUtil->clearBitmapModulation();
  989. drawUtil->drawBitmapSR(mTextureObject, pos, mBitmapBounds[thumbBitmapBottom]);
  990. }
  991. //-----------------------------------------------------------------------------
  992. void GuiScrollCtrl::drawHScrollBar(const Point2I &offset)
  993. {
  994. if ( mTextureObject.isNull() )
  995. {
  996. return;
  997. }
  998. // Start Point.
  999. Point2I pos = ( offset + mLeftArrowRect.point );
  1000. // Left Arrow.
  1001. S32 leftArrowBitmap = ( BmpStates * BmpLeft );
  1002. if ( !mHBarEnabled )
  1003. {
  1004. leftArrowBitmap += BmpDisabled;
  1005. }
  1006. else if ( mHitRegion == LeftArrow && mStateDepressed )
  1007. {
  1008. leftArrowBitmap += BmpHilite;
  1009. }
  1010. // Render Up Arrow.
  1011. GFXDrawUtil* drawUtil = GFX->getDrawUtil();
  1012. drawUtil->clearBitmapModulation();
  1013. drawUtil->drawBitmapSR(mTextureObject, pos, mBitmapBounds[leftArrowBitmap]);
  1014. // Update Pos.
  1015. pos.x += mBitmapBounds[leftArrowBitmap].extent.x;
  1016. // Track.
  1017. S32 trackBitmap = ( BmpStates * BmpHPage );
  1018. if ( !mHBarEnabled )
  1019. {
  1020. trackBitmap += BmpDisabled;
  1021. }
  1022. else if ( mHitRegion == LeftPage && mStateDepressed )
  1023. {
  1024. trackBitmap += BmpHilite;
  1025. }
  1026. // Determine the Track Rect.
  1027. RectI trackRect;
  1028. trackRect.point = pos;
  1029. trackRect.extent.x = ( offset.x + mRightArrowRect.point.x ) - pos.x;
  1030. trackRect.extent.y = mBitmapBounds[trackBitmap].extent.y;
  1031. // Render Track?
  1032. if ( trackRect.extent.x > 0 )
  1033. {
  1034. // Render Track.
  1035. drawUtil->clearBitmapModulation();
  1036. drawUtil->drawBitmapStretchSR(mTextureObject, trackRect, mBitmapBounds[trackBitmap]);
  1037. }
  1038. // Update Pos.
  1039. pos.x += trackRect.extent.x;
  1040. // Right Arrow.
  1041. S32 rightArrowBitmap = ( BmpStates * BmpRight );
  1042. if ( !mHBarEnabled )
  1043. {
  1044. rightArrowBitmap += BmpDisabled;
  1045. }
  1046. else if ( mHitRegion == RightArrow && mStateDepressed )
  1047. {
  1048. rightArrowBitmap += BmpHilite;
  1049. }
  1050. // Render Right Arrow.
  1051. drawUtil->clearBitmapModulation();
  1052. drawUtil->drawBitmapSR(mTextureObject, pos, mBitmapBounds[rightArrowBitmap]);
  1053. // Render the Thumb?
  1054. if ( !mHBarEnabled )
  1055. {
  1056. // Nope.
  1057. return;
  1058. }
  1059. // Reset the Pos.
  1060. pos.x = ( offset.x + mHThumbPos );
  1061. // Determine the Bitmaps.
  1062. S32 thumbBitmapLeft = ( BmpStates * BmpHThumbLeftCap );
  1063. S32 thumbBitmapMiddle = ( BmpStates * BmpHThumb );
  1064. S32 thumbBitmapRight = ( BmpStates * BmpHThumbRightCap );
  1065. if ( mHitRegion == HorizThumb && mStateDepressed )
  1066. {
  1067. thumbBitmapLeft += BmpHilite;
  1068. thumbBitmapMiddle += BmpHilite;
  1069. thumbBitmapRight += BmpHilite;
  1070. }
  1071. // Render Thumb Left.
  1072. drawUtil->clearBitmapModulation();
  1073. drawUtil->drawBitmapSR(mTextureObject, pos, mBitmapBounds[thumbBitmapLeft]);
  1074. // Update Pos.
  1075. pos.x += mBitmapBounds[thumbBitmapLeft].extent.x;
  1076. // Determine the Thumb Rect.
  1077. RectI thumbRect;
  1078. thumbRect.point = pos;
  1079. thumbRect.extent.x = mHThumbSize - ( mBitmapBounds[thumbBitmapLeft].extent.x + mBitmapBounds[thumbBitmapRight].extent.x );
  1080. thumbRect.extent.y = mBitmapBounds[thumbBitmapMiddle].extent.y;
  1081. // Render Thumb?
  1082. if ( thumbRect.extent.x > 0 )
  1083. {
  1084. // Render Track.
  1085. drawUtil->clearBitmapModulation();
  1086. drawUtil->drawBitmapStretchSR(mTextureObject, thumbRect, mBitmapBounds[thumbBitmapMiddle]);
  1087. }
  1088. // Update Pos.
  1089. pos.x += thumbRect.extent.x;
  1090. // Render the Thumb Bottom.
  1091. drawUtil->clearBitmapModulation();
  1092. drawUtil->drawBitmapSR(mTextureObject, pos, mBitmapBounds[thumbBitmapRight]);
  1093. }
  1094. //-----------------------------------------------------------------------------
  1095. void GuiScrollCtrl::drawScrollCorner(const Point2I &offset)
  1096. {
  1097. Point2I pos = offset;
  1098. pos.x += mRightArrowRect.point.x + mRightArrowRect.extent.x - 1;
  1099. pos.y += mRightArrowRect.point.y;
  1100. GFX->getDrawUtil()->clearBitmapModulation();
  1101. GFX->getDrawUtil()->drawBitmapSR(mTextureObject, pos, mBitmapBounds[BmpStates * BmpResize]);
  1102. }
  1103. //-----------------------------------------------------------------------------
  1104. void GuiScrollCtrl::autoScroll(Region reg)
  1105. {
  1106. scrollByRegion(reg);
  1107. }
  1108. //=============================================================================
  1109. // API.
  1110. //=============================================================================
  1111. // MARK: ---- API ----
  1112. //-----------------------------------------------------------------------------
  1113. DefineEngineMethod( GuiScrollCtrl, scrollToTop, void, (),,
  1114. "Scroll all the way to the top of the vertical and left of the horizontal scrollbar." )
  1115. {
  1116. object->scrollTo( 0, 0 );
  1117. }
  1118. //-----------------------------------------------------------------------------
  1119. DefineEngineMethod( GuiScrollCtrl, scrollToBottom, void, (),,
  1120. "Scroll all the way to the bottom of the vertical scrollbar and the left of the horizontal bar." )
  1121. {
  1122. object->scrollTo( 0, 0x7FFFFFFF );
  1123. }
  1124. //-----------------------------------------------------------------------------
  1125. DefineEngineMethod( GuiScrollCtrl, setScrollPosition, void, ( S32 x, S32 y ),,
  1126. "Set the position of the scrolled content.\n\n"
  1127. "@param x Position on X axis.\n"
  1128. "@param y Position on y axis.\n" )
  1129. {
  1130. object->scrollTo( x, y );
  1131. }
  1132. //-----------------------------------------------------------------------------
  1133. DefineEngineMethod( GuiScrollCtrl, scrollToObject, void, ( GuiControl* control ),,
  1134. "Scroll the control so that the given child @a control is visible.\n\n"
  1135. "@param control A child control." )
  1136. {
  1137. if( control )
  1138. object->scrollToObject( control );
  1139. }
  1140. //-----------------------------------------------------------------------------
  1141. DefineEngineMethod( GuiScrollCtrl, getScrollPosition, Point2I, (),,
  1142. "Get the current coordinates of the scrolled content.\n\n"
  1143. "@return The current position of the scrolled content." )
  1144. {
  1145. return object->getChildRelPos();
  1146. }
  1147. //-----------------------------------------------------------------------------
  1148. DefineEngineMethod( GuiScrollCtrl, getScrollPositionX, S32, (),,
  1149. "Get the current X coordinate of the scrolled content.\n\n"
  1150. "@return The current X coordinate of the scrolled content." )
  1151. {
  1152. return object->getChildRelPos().x;
  1153. }
  1154. //-----------------------------------------------------------------------------
  1155. DefineEngineMethod( GuiScrollCtrl, getScrollPositionY, S32, (),,
  1156. "Get the current Y coordinate of the scrolled content."
  1157. "@return The current Y coordinate of the scrolled content." )
  1158. {
  1159. return object->getChildRelPos().y;
  1160. }
  1161. //-----------------------------------------------------------------------------
  1162. DefineEngineMethod( GuiScrollCtrl, computeSizes, void, (),,
  1163. "Refresh sizing and positioning of child controls." )
  1164. {
  1165. object->computeSizes();
  1166. }