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