123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2013 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "console/consoleTypes.h"
- #include "console/console.h"
- #include "graphics/gBitmap.h"
- #include "graphics/TextureManager.h"
- #include "io/resource/resourceManager.h"
- #include "platform/event.h"
- #include "graphics/dgl.h"
- #include "gui/guiArrayCtrl.h"
- #include "gui/containers/guiScrollCtrl.h"
- #include "gui/guiDefaultControlRender.h"
- IMPLEMENT_CONOBJECT(GuiScrollCtrl);
- // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
- GuiScrollCtrl::GuiScrollCtrl()
- {
- mBounds.extent.set(200,200);
- mChildMargin.set(0,0);
- mBorderThickness = 1;
- mScrollBarThickness = 16;
- mScrollBarArrowBtnLength = 16;
- mScrollBarDragTolerance = 130;
- stateDepressed = false;
- curHitRegion = None;
- mWillFirstRespond = true;
- mUseConstantHeightThumb = false;
- mIsContainer = true;
- mForceVScrollBar = ScrollBarAlwaysOn;
- mForceHScrollBar = ScrollBarAlwaysOn;
- }
- static EnumTable::Enums scrollBarEnums[] =
- {
- { GuiScrollCtrl::ScrollBarAlwaysOn, "alwaysOn" },
- { GuiScrollCtrl::ScrollBarAlwaysOff, "alwaysOff" },
- { GuiScrollCtrl::ScrollBarDynamic, "dynamic" },
- };
- static EnumTable gScrollBarTable(3, &scrollBarEnums[0]);
- ConsoleMethod(GuiScrollCtrl, scrollToTop, void, 2, 2, "() Use the scrollToTop method to scroll the scroll control to the top of the child content area.\n"
- "@return No return value.\n"
- "@sa scrollToBottom")
- {
- object->scrollTo( 0, 0 );
- }
- ConsoleMethod(GuiScrollCtrl, scrollToBottom, void, 2, 2, "() Use the scrollToBottom method to scroll the scroll control to the bottom of the child content area.\n"
- "@return No return value.\n"
- "@sa scrollToTop")
- {
- object->scrollTo( 0, 0x7FFFFFFF );
- }
- ConsoleMethod(GuiScrollCtrl, setScrollPosition, void, 4, 4, "(x, y) - scrolls the scroll control to the specified position.")
- {
- object->scrollTo(dAtoi(argv[2]), dAtoi(argv[3]));
- }
- ConsoleMethod(GuiScrollCtrl, getScrollPositionX, S32, 2, 2, "() - get the current x scroll position of the scroll control.")
- {
- return object->getChildRelPos().x;
- }
- ConsoleMethod(GuiScrollCtrl, getScrollPositionY, S32, 2, 2, "() - get the current y scroll position of the scroll control.")
- {
- return object->getChildRelPos().y;
- }
- ConsoleMethod(GuiScrollCtrl, computeSizes, void, 2, 2, "() - refresh all the contents in this scroll container.")
- {
- return object->computeSizes();
- }
- ConsoleMethod(GuiScrollCtrl, getUseScrollEvents, bool, 2, 2, "() - get the current scroll callback state of the scroll control.")
- {
- return object->getUseScrollEvents();
- }
- ConsoleMethod(GuiScrollCtrl, setUseScrollEvents, void, 3, 3, "() - set the scroll callback state of the scroll control.")
- {
- object->setUseScrollEvents(dAtoi(argv[2]));
- }
- void GuiScrollCtrl::initPersistFields()
- {
- Parent::initPersistFields();
- addField("willFirstRespond", TypeBool, Offset(mWillFirstRespond, GuiScrollCtrl));
- addField("hScrollBar", TypeEnum, Offset(mForceHScrollBar, GuiScrollCtrl), 1, &gScrollBarTable);
- addField("vScrollBar", TypeEnum, Offset(mForceVScrollBar, GuiScrollCtrl), 1, &gScrollBarTable);
- addField("constantThumbHeight", TypeBool, Offset(mUseConstantHeightThumb, GuiScrollCtrl));
- addField("childMargin", TypePoint2I, Offset(mChildMargin, GuiScrollCtrl));
- }
- void GuiScrollCtrl::resize(const Point2I &newPos, const Point2I &newExt)
- {
- Parent::resize(newPos, newExt);
- computeSizes();
- }
- void GuiScrollCtrl::childResized(GuiControl *child)
- {
- Parent::childResized(child);
- computeSizes();
- }
- bool GuiScrollCtrl::onWake()
- {
- if (! Parent::onWake())
- return false;
- mTextureHandle = mProfile->mTextureHandle;
- mTextureHandle.setFilter(GL_NEAREST);;
- bool result;
- result = mProfile->constructBitmapArray() >= BmpStates * BmpCount;
- //AssertFatal(result, "Failed to create the bitmap array");
- if (!result)
- Con::warnf("Failed to create the bitmap array for %s", mProfile->mBitmapName);
- mBitmapBounds = mProfile->mBitmapArrayRects.address();
- //init
- mBaseThumbSize = mBitmapBounds[BmpStates * BmpVThumbTopCap].extent.y +
- mBitmapBounds[BmpStates * BmpVThumbBottomCap].extent.y;
- mScrollBarThickness = mBitmapBounds[BmpStates * BmpVPage].extent.x;
- mScrollBarArrowBtnLength = mBitmapBounds[BmpStates * BmpUp].extent.y;
- computeSizes();
- return true;
- }
- void GuiScrollCtrl::onSleep()
- {
- Parent::onSleep();
- mTextureHandle = NULL;
- }
- bool GuiScrollCtrl::calcChildExtents()
- {
- // right now the scroll control really only deals well with a single
- // child control for its content
- if (!size())
- return false;
- GuiControl *ctrl = (GuiControl *) front();
- mChildExt = ctrl->mBounds.extent;
- mChildPos = ctrl->mBounds.point;
- return true;
- }
- RectI lastVisRect;
- void GuiScrollCtrl::scrollRectVisible(RectI rect)
- {
- // rect is passed in virtual client space
- if(rect.extent.x > mContentExt.x)
- rect.extent.x = mContentExt.x;
- if(rect.extent.y > mContentExt.y)
- rect.extent.y = mContentExt.y;
- // Determine the points bounding the requested rectangle
- Point2I rectUpperLeft = rect.point;
- Point2I rectLowerRight = rect.point + rect.extent;
- lastVisRect = rect;
- // Determine the points bounding the actual visible area...
- Point2I visUpperLeft = mChildRelPos;
- Point2I visLowerRight = mChildRelPos + mContentExt;
- Point2I delta(0,0);
- // We basically try to make sure that first the top left of the given
- // rect is visible, and if it is, then that the bottom right is visible.
- // Make sure the rectangle is visible along the X axis...
- if(rectUpperLeft.x < visUpperLeft.x)
- delta.x = rectUpperLeft.x - visUpperLeft.x;
- else if(rectLowerRight.x > visLowerRight.x)
- delta.x = rectLowerRight.x - visLowerRight.x;
- // Make sure the rectangle is visible along the Y axis...
- if(rectUpperLeft.y < visUpperLeft.y)
- delta.y = rectUpperLeft.y - visUpperLeft.y;
- else if(rectLowerRight.y > visLowerRight.y)
- delta.y = rectLowerRight.y - visLowerRight.y;
- // If we had any changes, scroll, otherwise don't.
- if(delta.x || delta.y)
- scrollDelta(delta.x, delta.y);
- }
- void GuiScrollCtrl::addObject(SimObject *object)
- {
- Parent::addObject(object);
- computeSizes();
- }
- GuiControl* GuiScrollCtrl::findHitControl(const Point2I &pt, S32 initialLayer)
- {
- if(pt.x < mProfile->mBorderThickness || pt.y < mProfile->mBorderThickness)
- return this;
- if(pt.x >= mBounds.extent.x - mProfile->mBorderThickness - (mHasVScrollBar ? mScrollBarThickness : 0) ||
- pt.y >= mBounds.extent.y - mProfile->mBorderThickness - (mHasHScrollBar ? mScrollBarThickness : 0))
- return this;
- return Parent::findHitControl(pt, initialLayer);
- }
- void GuiScrollCtrl::computeSizes()
- {
- S32 thickness = (mProfile ? mProfile->mBorderThickness : 1);
- Point2I borderExtent(thickness, thickness);
- mContentPos = borderExtent + mChildMargin;
- mContentExt = mBounds.extent - (mChildMargin * 2)
- - (borderExtent * 2);
- Point2I childLowerRight;
- mHBarEnabled = false;
- mVBarEnabled = false;
- mHasVScrollBar = (mForceVScrollBar == ScrollBarAlwaysOn);
- mHasHScrollBar = (mForceHScrollBar == ScrollBarAlwaysOn);
- setUpdate();
- if (calcChildExtents())
- {
- childLowerRight = mChildPos + mChildExt;
- if (mHasVScrollBar)
- mContentExt.x -= mScrollBarThickness;
- if (mHasHScrollBar)
- mContentExt.y -= mScrollBarThickness;
- if (mChildExt.x > mContentExt.x && (mForceHScrollBar == ScrollBarDynamic))
- {
- mHasHScrollBar = true;
- mContentExt.y -= mScrollBarThickness;
- }
- if (mChildExt.y > mContentExt.y && (mForceVScrollBar == ScrollBarDynamic))
- {
- mHasVScrollBar = true;
- mContentExt.x -= mScrollBarThickness;
- // If Extent X Changed, check Horiz Scrollbar.
- if (mChildExt.x > mContentExt.x && !mHasHScrollBar && (mForceHScrollBar == ScrollBarDynamic))
- {
- mHasHScrollBar = true;
- mContentExt.y -= mScrollBarThickness;
- }
- }
- Point2I contentLowerRight = mContentPos + mContentExt;
- // see if the child controls need to be repositioned (null space in control)
- Point2I delta(0,0);
- if (mChildPos.x > mContentPos.x)
- delta.x = mContentPos.x - mChildPos.x;
- else if (contentLowerRight.x > childLowerRight.x)
- {
- S32 diff = contentLowerRight.x - childLowerRight.x;
- delta.x = getMin(mContentPos.x - mChildPos.x, diff);
- }
- //reposition the children if the child extent > the scroll content extent
- if (mChildPos.y > mContentPos.y)
- delta.y = mContentPos.y - mChildPos.y;
- else if (contentLowerRight.y > childLowerRight.y)
- {
- S32 diff = contentLowerRight.y - childLowerRight.y;
- delta.y = getMin(mContentPos.y - mChildPos.y, diff);
- }
- // apply the deltas to the children...
- if (delta.x || delta.y)
- {
- SimGroup::iterator i;
- for(i = begin(); i != end();i++)
- {
- GuiControl *ctrl = (GuiControl *) (*i);
- ctrl->mBounds.point += delta;
- }
- mChildPos += delta;
- childLowerRight += delta;
- }
- // enable needed scroll bars
- if (mChildExt.x > mContentExt.x)
- mHBarEnabled = true;
- if (mChildExt.y > mContentExt.y)
- mVBarEnabled = true;
- mChildRelPos = mContentPos - mChildPos;
- }
- // build all the rectangles and such...
- calcScrollRects();
- calcThumbs();
- }
- void GuiScrollCtrl::calcScrollRects(void)
- {
- S32 thickness = ( mProfile ? mProfile->mBorderThickness : 1 );
- if (mHasHScrollBar)
- {
- mLeftArrowRect.set(thickness,
- mBounds.extent.y - thickness - mScrollBarThickness - 1,
- mScrollBarArrowBtnLength,
- mScrollBarThickness);
- mRightArrowRect.set(mBounds.extent.x - thickness - (mHasVScrollBar ? mScrollBarThickness : 0) - mScrollBarArrowBtnLength,
- mBounds.extent.y - thickness - mScrollBarThickness - 1,
- mScrollBarArrowBtnLength,
- mScrollBarThickness);
- mHTrackRect.set(mLeftArrowRect.point.x + mLeftArrowRect.extent.x,
- mLeftArrowRect.point.y,
- mRightArrowRect.point.x - (mLeftArrowRect.point.x + mLeftArrowRect.extent.x),
- mScrollBarThickness);
- }
- if (mHasVScrollBar)
- {
- mUpArrowRect.set(mBounds.extent.x - thickness - mScrollBarThickness,
- thickness,
- mScrollBarThickness,
- mScrollBarArrowBtnLength);
- mDownArrowRect.set(mBounds.extent.x - thickness - mScrollBarThickness,
- mBounds.extent.y - thickness - mScrollBarArrowBtnLength - (mHasHScrollBar ? ( mScrollBarThickness + 1 ) : 0),
- mScrollBarThickness,
- mScrollBarArrowBtnLength);
- mVTrackRect.set(mUpArrowRect.point.x,
- mUpArrowRect.point.y + mUpArrowRect.extent.y,
- mScrollBarThickness,
- mDownArrowRect.point.y - (mUpArrowRect.point.y + mUpArrowRect.extent.y) );
- }
- }
- void GuiScrollCtrl::calcThumbs()
- {
- if (mHBarEnabled)
- {
- U32 trackSize = mHTrackRect.len_x();
- if (mUseConstantHeightThumb)
- mHThumbSize = mBaseThumbSize;
- else
- mHThumbSize = getMax(mBaseThumbSize, S32((mContentExt.x * trackSize) / mChildExt.x));
- mHThumbPos = mHTrackRect.point.x + (mChildRelPos.x * (trackSize - mHThumbSize)) / (mChildExt.x - mContentExt.x);
- }
- if (mVBarEnabled)
- {
- U32 trackSize = mVTrackRect.len_y();
- if (mUseConstantHeightThumb)
- mVThumbSize = mBaseThumbSize;
- else
- mVThumbSize = getMax(mBaseThumbSize, S32((mContentExt.y * trackSize) / mChildExt.y));
- mVThumbPos = mVTrackRect.point.y + (mChildRelPos.y * (trackSize - mVThumbSize)) / (mChildExt.y - mContentExt.y);
- }
- }
- void GuiScrollCtrl::scrollDelta(S32 deltaX, S32 deltaY)
- {
- scrollTo(mChildRelPos.x + deltaX, mChildRelPos.y + deltaY);
- }
- void GuiScrollCtrl::scrollTo(S32 x, S32 y)
- {
- if(!size())
- return;
- // keep scroll start state
- Point2I startPoint = mChildPos;
- Point2I startPointRel = mChildRelPos;
- setUpdate();
- if (x > mChildExt.x - mContentExt.x)
- x = mChildExt.x - mContentExt.x;
- if (x < 0)
- x = 0;
- if (y > mChildExt.y - mContentExt.y)
- y = mChildExt.y - mContentExt.y;
- if (y < 0)
- y = 0;
- Point2I delta(x - mChildRelPos.x, y - mChildRelPos.y);
- mChildRelPos += delta;
- mChildPos -= delta;
- for(SimSet::iterator i = begin(); i != end();i++)
- {
- GuiControl *ctrl = (GuiControl *) (*i);
- ctrl->mBounds.point -= delta;
- }
- calcThumbs();
- // Execute callback
- if (mUseScrollEvents)
- {
- char buf[4][32];
- dSprintf(buf[0], 32, "%d %d", startPoint.x, startPoint.y);
- dSprintf(buf[1], 32, "%d %d", startPointRel.x, startPointRel.y);
- dSprintf(buf[2], 32, "%d %d", mChildPos.x, mChildPos.y);
- dSprintf(buf[3], 32, "%d %d", mChildRelPos.x, mChildRelPos.y);
- Con::executef(this, 5, "onScroll", buf[0], buf[1], buf[2], buf[3]);
- }
- }
- GuiScrollCtrl::Region GuiScrollCtrl::findHitRegion(const Point2I &pt)
- {
- if (mVBarEnabled && mHasVScrollBar)
- {
- if (mUpArrowRect.pointInRect(pt))
- return UpArrow;
- else if (mDownArrowRect.pointInRect(pt))
- return DownArrow;
- else if (mVTrackRect.pointInRect(pt))
- {
- if (pt.y < mVThumbPos)
- return UpPage;
- else if (pt.y < mVThumbPos + mVThumbSize)
- return VertThumb;
- else
- return DownPage;
- }
- }
- if (mHBarEnabled && mHasHScrollBar)
- {
- if (mLeftArrowRect.pointInRect(pt))
- return LeftArrow;
- else if (mRightArrowRect.pointInRect(pt))
- return RightArrow;
- else if (mHTrackRect.pointInRect(pt))
- {
- if (pt.x < mHThumbPos)
- return LeftPage;
- else if (pt.x < mHThumbPos + mHThumbSize)
- return HorizThumb;
- else
- return RightPage;
- }
- }
- return None;
- }
- bool GuiScrollCtrl::wantsTabListMembership()
- {
- return true;
- }
- bool GuiScrollCtrl::loseFirstResponder()
- {
- setUpdate();
- return true;
- }
- bool GuiScrollCtrl::becomeFirstResponder()
- {
- setUpdate();
- return mWillFirstRespond;
- }
- bool GuiScrollCtrl::onKeyDown(const GuiEvent &event)
- {
- if (mWillFirstRespond)
- {
- switch (event.keyCode)
- {
- case KEY_RIGHT:
- scrollByRegion(RightArrow);
- return true;
- case KEY_LEFT:
- scrollByRegion(LeftArrow);
- return true;
- case KEY_DOWN:
- scrollByRegion(DownArrow);
- return true;
- case KEY_UP:
- scrollByRegion(UpArrow);
- return true;
- case KEY_PAGE_UP:
- scrollByRegion(UpPage);
- return true;
- case KEY_PAGE_DOWN:
- scrollByRegion(DownPage);
- return true;
- }
- }
- return Parent::onKeyDown(event);
- }
- void GuiScrollCtrl::onMouseDown(const GuiEvent &event)
- {
- mouseLock();
- setUpdate();
- Point2I curMousePos = globalToLocalCoord(event.mousePoint);
- curHitRegion = findHitRegion(curMousePos);
- stateDepressed = true;
- // Set a 0.5 second delay before we start scrolling
- mLastUpdated = Platform::getVirtualMilliseconds() + 500;
- scrollByRegion(curHitRegion);
- if (curHitRegion == VertThumb)
- {
- mChildRelPosAnchor = mChildRelPos;
- mThumbMouseDelta = curMousePos.y - mVThumbPos;
- }
- else if (curHitRegion == HorizThumb)
- {
- mChildRelPosAnchor = mChildRelPos;
- mThumbMouseDelta = curMousePos.x - mHThumbPos;
- }
- }
- void GuiScrollCtrl::onMouseUp(const GuiEvent &)
- {
- mouseUnlock();
- setUpdate();
- curHitRegion = None;
- stateDepressed = false;
- }
- void GuiScrollCtrl::onMouseDragged(const GuiEvent &event)
- {
- Point2I curMousePos = globalToLocalCoord(event.mousePoint);
- setUpdate();
- if ( (curHitRegion != VertThumb) && (curHitRegion != HorizThumb) )
- {
- Region hit = findHitRegion(curMousePos);
- if (hit != curHitRegion)
- stateDepressed = false;
- else
- stateDepressed = true;
- return;
- }
- // ok... if the mouse is 'near' the scroll bar, scroll with it
- // otherwise, snap back to the previous position.
- if (curHitRegion == VertThumb)
- {
- if (curMousePos.x >= mVTrackRect.point.x - mScrollBarDragTolerance &&
- curMousePos.x <= mVTrackRect.point.x + mVTrackRect.extent.x - 1 + mScrollBarDragTolerance &&
- curMousePos.y >= mVTrackRect.point.y - mScrollBarDragTolerance &&
- curMousePos.y <= mVTrackRect.point.y + mVTrackRect.extent.y - 1 + mScrollBarDragTolerance)
- {
- S32 newVThumbPos = curMousePos.y - mThumbMouseDelta;
- if(newVThumbPos != mVThumbPos)
- {
- S32 newVPos = (newVThumbPos - mVTrackRect.point.y) *
- (mChildExt.y - mContentExt.y) /
- (mVTrackRect.extent.y - mVThumbSize);
- scrollTo(mChildRelPosAnchor.x, newVPos);
- }
- }
- else
- scrollTo(mChildRelPosAnchor.x, mChildRelPosAnchor.y);
- }
- else if (curHitRegion == HorizThumb)
- {
- if (curMousePos.x >= mHTrackRect.point.x - mScrollBarDragTolerance &&
- curMousePos.x <= mHTrackRect.point.x + mHTrackRect.extent.x - 1 + mScrollBarDragTolerance &&
- curMousePos.y >= mHTrackRect.point.y - mScrollBarDragTolerance &&
- curMousePos.y <= mHTrackRect.point.y + mHTrackRect.extent.y - 1 + mScrollBarDragTolerance)
- {
- S32 newHThumbPos = curMousePos.x - mThumbMouseDelta;
- if(newHThumbPos != mHThumbPos)
- {
- S32 newHPos = (newHThumbPos - mHTrackRect.point.x) *
- (mChildExt.x - mContentExt.x) /
- (mHTrackRect.extent.x - mHThumbSize);
- scrollTo(newHPos, mChildRelPosAnchor.y);
- }
- }
- else
- scrollTo(mChildRelPosAnchor.x, mChildRelPosAnchor.y);
- }
- }
- bool GuiScrollCtrl::onMouseWheelUp(const GuiEvent &event)
- {
- if ( !mAwake || !mVisible )
- return( false );
- Point2I previousPos = mChildPos;
- scrollByRegion((event.modifier & SI_CTRL) ? UpPage : UpArrow);
- // Tell the kids that the mouse moved (relatively):
- iterator itr;
- for ( itr = begin(); itr != end(); itr++ )
- {
- GuiControl* grandKid = static_cast<GuiControl*>( *itr );
- grandKid->onMouseMove( event );
- }
- // If no scrolling happened (already at the top), pass it on to the parent.
- GuiControl* parent = getParent();
- if (parent && (previousPos == mChildPos))
- return parent->onMouseWheelUp(event);
- return true;
- }
- bool GuiScrollCtrl::onMouseWheelDown(const GuiEvent &event)
- {
- if ( !mAwake || !mVisible )
- return( false );
- Point2I previousPos = mChildPos;
- scrollByRegion((event.modifier & SI_CTRL) ? DownPage : DownArrow);
- // Tell the kids that the mouse moved (relatively):
- iterator itr;
- for ( itr = begin(); itr != end(); itr++ )
- {
- GuiControl* grandKid = static_cast<GuiControl *>( *itr );
- grandKid->onMouseMove( event );
- }
- // If no scrolling happened (already at the bottom), pass it on to the parent.
- GuiControl* parent = getParent();
- if (parent && (previousPos == mChildPos))
- return parent->onMouseWheelDown(event);
- return true;
- }
- void GuiScrollCtrl::onPreRender()
- {
- Parent::onPreRender();
- // Short circuit if not depressed to save cycles
- if( stateDepressed != true )
- return;
- //default to one second, though it shouldn't be necessary
- U32 timeThreshold = 1000;
- // We don't want to scroll by pages at an interval the same as when we're scrolling
- // using the arrow buttons, so adjust accordingly.
- switch( curHitRegion )
- {
- case UpPage:
- case DownPage:
- case LeftPage:
- case RightPage:
- timeThreshold = 200;
- break;
- case UpArrow:
- case DownArrow:
- case LeftArrow:
- case RightArrow:
- timeThreshold = 20;
- break;
- default:
- // Neither a button or a page, don't scroll (shouldn't get here)
- return;
- break;
- };
- S32 timeElapsed = Platform::getVirtualMilliseconds() - mLastUpdated;
- if ( ( timeElapsed > 0 ) && ( timeElapsed > (S32)timeThreshold ) )
- {
- mLastUpdated = Platform::getVirtualMilliseconds();
- scrollByRegion(curHitRegion);
- }
- }
- void GuiScrollCtrl::scrollByRegion(Region reg)
- {
- setUpdate();
- if(!size())
- return;
- GuiControl *content = (GuiControl *) front();
- U32 rowHeight, columnWidth;
- U32 pageHeight, pageWidth;
- content->getScrollLineSizes(&rowHeight, &columnWidth);
- if(rowHeight >= (U32)mContentExt.y)
- pageHeight = 1;
- else
- pageHeight = mContentExt.y - rowHeight;
- if(columnWidth >= (U32)mContentExt.x)
- pageWidth = 1;
- else
- pageWidth = mContentExt.x - columnWidth;
- if (mVBarEnabled)
- {
- switch(reg)
- {
- case UpPage:
- scrollDelta(0, -(S32)pageHeight);
- break;
- case DownPage:
- scrollDelta(0, pageHeight);
- break;
- case UpArrow:
- scrollDelta(0, -(S32)rowHeight);
- break;
- case DownArrow:
- scrollDelta(0, rowHeight);
- break;
- case LeftArrow:
- case RightArrow:
- case LeftPage:
- case RightPage:
- case VertThumb:
- case HorizThumb:
- case None:
- {
- //Con::errorf("Unhandled case in GuiScrollCtrl::scrollByRegion");
- }
- }
- }
- if (mHBarEnabled)
- {
- switch(reg)
- {
- case LeftPage:
- scrollDelta(-(S32)pageWidth, 0);
- break;
- case RightPage:
- scrollDelta(pageWidth, 0);
- break;
- case LeftArrow:
- scrollDelta(-(S32)columnWidth, 0);
- break;
- case RightArrow:
- scrollDelta(columnWidth, 0);
- break;
- case UpArrow:
- case DownArrow:
- case UpPage:
- case DownPage:
- case VertThumb:
- case HorizThumb:
- case None:
- {
- //Con::errorf("Unhandled case in GuiScrollCtrl::scrollByRegion");
- break;
- }
- }
- }
- }
- void GuiScrollCtrl::onRender(Point2I offset, const RectI &updateRect)
- {
- RectI r(offset.x, offset.y, mBounds.extent.x, mBounds.extent.y);
- if (mProfile->mOpaque)
- dglDrawRectFill(r, mProfile->mFillColor);
- if (mProfile->mBorder)
- renderFilledBorder(r, mProfile);
- // draw scroll bars
- if (mHasVScrollBar)
- drawVScrollBar(offset);
- if (mHasHScrollBar)
- drawHScrollBar(offset);
- //draw the scroll corner
- if (mHasVScrollBar && mHasHScrollBar)
- drawScrollCorner(offset);
- // draw content controls
- // create a rect to intersect with the updateRect
- RectI contentRect(mContentPos.x + offset.x, mContentPos.y + offset.y, mContentExt.x, mContentExt.y);
- if(contentRect.intersect(updateRect))
- renderChildControls(offset, contentRect);
- // Finally draw the last vis rect (debug aid, BJG)
- //RectI renderRect = lastVisRect;
- //renderRect.point += mContentPos + offset;
- //dglSetClipRect(r);
- //dglDrawRect(renderRect, ColorI(0, 255, 0));
- }
- void GuiScrollCtrl::drawBorder( const Point2I &offset, bool /*isFirstResponder*/ )
- {
- }
- void GuiScrollCtrl::drawVScrollBar(const Point2I &offset)
- {
- Point2I pos = offset + mUpArrowRect.point;
- S32 bitmap = (mVBarEnabled ? ((curHitRegion == UpArrow && stateDepressed) ?
- BmpStates * BmpUp + BmpHilite : BmpStates * BmpUp) : BmpStates * BmpUp + BmpDisabled);
- dglClearBitmapModulation();
- dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[bitmap]);
- pos.y += mScrollBarArrowBtnLength;
- S32 end;
- if (mVBarEnabled)
- end = mVThumbPos + offset.y;
- else
- end = mDownArrowRect.point.y + offset.y;
- bitmap = (mVBarEnabled ? ((curHitRegion == DownPage && stateDepressed) ?
- BmpStates * BmpVPage + BmpHilite : BmpStates * BmpVPage) : BmpStates * BmpVPage + BmpDisabled);
- if (end > pos.y)
- {
- dglClearBitmapModulation();
- dglDrawBitmapStretchSR(mTextureHandle, RectI(pos, Point2I(mBitmapBounds[bitmap].extent.x, end - pos.y)), mBitmapBounds[bitmap]);
- }
- pos.y = end;
- if (mVBarEnabled)
- {
- bool thumbSelected = (curHitRegion == VertThumb && stateDepressed);
- S32 ttop = (thumbSelected ? BmpStates * BmpVThumbTopCap + BmpHilite : BmpStates * BmpVThumbTopCap);
- S32 tmid = (thumbSelected ? BmpStates * BmpVThumb + BmpHilite : BmpStates * BmpVThumb);
- S32 tbot = (thumbSelected ? BmpStates * BmpVThumbBottomCap + BmpHilite : BmpStates * BmpVThumbBottomCap);
- // draw the thumb
- dglClearBitmapModulation();
- dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[ttop]);
- pos.y += mBitmapBounds[ttop].extent.y;
- end = mVThumbPos + mVThumbSize - mBitmapBounds[tbot].extent.y + offset.y;
- if (end > pos.y)
- {
- dglClearBitmapModulation();
- dglDrawBitmapStretchSR(mTextureHandle, RectI(pos, Point2I(mBitmapBounds[tmid].extent.x, end - pos.y)), mBitmapBounds[tmid]);
- }
- pos.y = end;
- dglClearBitmapModulation();
- dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[tbot]);
- pos.y += mBitmapBounds[tbot].extent.y;
- end = mVTrackRect.point.y + mVTrackRect.extent.y - 1 + offset.y;
- bitmap = (curHitRegion == DownPage && stateDepressed) ? BmpStates * BmpVPage + BmpHilite : BmpStates * BmpVPage;
- if (end > pos.y)
- {
- dglClearBitmapModulation();
- dglDrawBitmapStretchSR(mTextureHandle, RectI(pos, Point2I(mBitmapBounds[bitmap].extent.x, end - pos.y)), mBitmapBounds[bitmap]);
- }
- pos.y = end;
- }
- bitmap = (mVBarEnabled ? ((curHitRegion == DownArrow && stateDepressed ) ?
- BmpStates * BmpDown + BmpHilite : BmpStates * BmpDown) : BmpStates * BmpDown + BmpDisabled);
- dglClearBitmapModulation();
- dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[bitmap]);
- }
- void GuiScrollCtrl::drawHScrollBar(const Point2I &offset)
- {
- S32 bitmap;
- //draw the left arrow
- bitmap = (mHBarEnabled ? ((curHitRegion == LeftArrow && stateDepressed) ?
- BmpStates * BmpLeft + BmpHilite : BmpStates * BmpLeft) : BmpStates * BmpLeft + BmpDisabled);
- Point2I pos = offset;
- pos += mLeftArrowRect.point;
- dglClearBitmapModulation();
- dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[bitmap]);
- pos.x += mLeftArrowRect.extent.x;
- //draw the left page
- S32 end;
- if (mHBarEnabled)
- end = mHThumbPos + offset.x;
- else
- end = mRightArrowRect.point.x + offset.x;
- bitmap = (mHBarEnabled ? ((curHitRegion == LeftPage && stateDepressed) ?
- BmpStates * BmpHPage + BmpHilite : BmpStates * BmpHPage) : BmpStates * BmpHPage + BmpDisabled);
- if (end > pos.x)
- {
- dglClearBitmapModulation();
- dglDrawBitmapStretchSR(mTextureHandle, RectI(pos, Point2I(end - pos.x, mBitmapBounds[bitmap].extent.y)), mBitmapBounds[bitmap]);
- }
- pos.x = end;
- //draw the thumb and the rightPage
- if (mHBarEnabled)
- {
- bool thumbSelected = (curHitRegion == HorizThumb && stateDepressed);
- S32 ttop = (thumbSelected ? BmpStates * BmpHThumbLeftCap + BmpHilite : BmpStates * BmpHThumbLeftCap );
- S32 tmid = (thumbSelected ? BmpStates * BmpHThumb + BmpHilite : BmpStates * BmpHThumb);
- S32 tbot = (thumbSelected ? BmpStates * BmpHThumbRightCap + BmpHilite : BmpStates * BmpHThumbRightCap);
- // draw the thumb
- dglClearBitmapModulation();
- dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[ttop]);
- pos.x += mBitmapBounds[ttop].extent.x;
- end = mHThumbPos + mHThumbSize - mBitmapBounds[tbot].extent.x + offset.x;
- if (end > pos.x)
- {
- dglClearBitmapModulation();
- dglDrawBitmapStretchSR(mTextureHandle, RectI(pos, Point2I(end - pos.x, mBitmapBounds[tmid].extent.y)), mBitmapBounds[tmid]);
- }
- pos.x = end;
- dglClearBitmapModulation();
- dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[tbot]);
- pos.x += mBitmapBounds[tbot].extent.x;
- end = mHTrackRect.point.x + mHTrackRect.extent.x - 1 + offset.x;
- bitmap = ((curHitRegion == RightPage && stateDepressed) ? BmpStates * BmpHPage + BmpHilite : BmpStates * BmpHPage);
- if (end > pos.x)
- {
- dglClearBitmapModulation();
- dglDrawBitmapStretchSR(mTextureHandle, RectI(pos, Point2I(end - pos.x, mBitmapBounds[bitmap].extent.y)), mBitmapBounds[bitmap]);
- }
- pos.x = end;
- }
- bitmap = (mHBarEnabled ? ((curHitRegion == RightArrow && stateDepressed) ?
- BmpStates * BmpRight + BmpHilite : BmpStates * BmpRight) : BmpStates * BmpRight + BmpDisabled);
- dglClearBitmapModulation();
- dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[bitmap]);
- }
- void GuiScrollCtrl::drawScrollCorner(const Point2I &offset)
- {
- Point2I pos = offset;
- pos.x += mRightArrowRect.point.x + mRightArrowRect.extent.x;
- pos.y += mRightArrowRect.point.y;
- dglClearBitmapModulation();
- dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[BmpStates * BmpResize]);
- }
- void GuiScrollCtrl::autoScroll(Region reg)
- {
- scrollByRegion(reg);
- }
|