📄 guiscrollctrl.cc
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "console/consoleTypes.h"
#include "console/console.h"
#include "dgl/gBitmap.h"
#include "dgl/gTexManager.h"
#include "core/resManager.h"
#include "platform/event.h"
#include "dgl/dgl.h"
#include "gui/core/guiArrayCtrl.h"
#include "gui/containers/guiScrollCtrl.h"
#include "gui/core/guiDefaultControlRender.h"
IMPLEMENT_CONOBJECT(GuiScrollCtrl);
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
GuiScrollCtrl::GuiScrollCtrl()
{
mBounds.extent.set(200,200);
mChildMargin.set(0,0);
mBorderThickness = 1;
mScrollBarThickness = 16;
mScrollBarArrowBtnLength = 16;
stateDepressed = false;
curHitRegion = None;
mWillFirstRespond = true;
mUseConstantHeightThumb = false;
mForceVScrollBar = ScrollBarAlwaysOn;
mForceHScrollBar = ScrollBarAlwaysOn;
#ifdef TGE_RPG
m_bVBarAtLeft = false;
#endif
}
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, "() - scrolls the scroll control to the top of the child content area.")
{
argc; argv;
object->scrollTo( 0, 0 );
}
ConsoleMethod(GuiScrollCtrl, scrollToBottom, void, 2, 2, "() - scrolls the scroll control to the bottom of the child content area.")
{
argc; argv;
object->scrollTo( 0, 0x7FFFFFFF );
}
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));
#ifdef TGE_RPG
addField("vbarAtLeft", TypeBool, Offset(m_bVBarAtLeft, GuiScrollCtrl));
#endif
}
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;
/// TGE_Theme
//mTextureHandle = mProfile->mTextureHandle;
//mTextureHandle.setFilterNearest();
//bool result = mProfile->constructBitmapArray() >= BmpStates * BmpCount;
//AssertFatal(result, "Failed to create the bitmap array");
//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);
#ifdef TGE_RPG
if(m_bVBarAtLeft)
//if(mProfile->mAlignment == GuiControlProfile::LeftJustify)
mContentPos.x += mScrollBarThickness;
#endif
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;
// doh! ext.x changed, so check hscrollbar again
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)
{
#ifdef TGE_RPG
if(m_bVBarAtLeft)
//if(mProfile->mAlignment == GuiControlProfile::LeftJustify)
{
mUpArrowRect.set( thickness ,
thickness,
mScrollBarThickness,
mScrollBarArrowBtnLength);
mDownArrowRect.set( thickness,
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) );
}
else
{
#endif
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) );
#ifdef TGE_RPG
}
#endif
}
}
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;
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();
}
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -