axmol/extensions/fairygui/ScrollPane.cpp

1797 lines
51 KiB
C++

#include "ScrollPane.h"
#include "GList.h"
#include "GScrollBar.h"
#include "UIConfig.h"
#include "UIPackage.h"
#include "event/InputProcessor.h"
#include "tween/GTween.h"
#include "utils/ByteBuffer.h"
NS_FGUI_BEGIN
USING_NS_AX;
ScrollPane* ScrollPane::_draggingPane = nullptr;
int ScrollPane::_gestureFlag = 0;
static const float TWEEN_TIME_GO = 0.5f; //tween time for SetPos(ani)
static const float TWEEN_TIME_DEFAULT = 0.3f; //min tween time for inertial scroll
static const float PULL_RATIO = 0.5f; //pull down/up ratio
static inline float sp_getField(const Vec2& pt, int axis) { return axis == 0 ? pt.x : pt.y; }
static void sp_setField(Vec2& pt, int axis, float value)
{
if (axis == 0)
pt.x = value;
else
pt.y = value;
}
static void sp_incField(Vec2& pt, int axis, float value)
{
if (axis == 0)
pt.x += value;
else
pt.y += value;
}
static inline float sp_EaseFunc(float t, float d)
{
t = t / d - 1;
return t * t * t + 1; //cubicOut
}
// clang-format off
ScrollPane::ScrollPane(GComponent* owner)
: _vtScrollBar(nullptr),
_hzScrollBar(nullptr),
_header(nullptr),
_footer(nullptr),
_pageController(nullptr),
_needRefresh(false),
_refreshBarAxis(0),
_aniFlag(0),
_loop(0),
_headerLockedSize(0),
_footerLockedSize(0),
_vScrollNone(false),
_hScrollNone(false),
_tweening(0),
_xPos(0),
_yPos(0),
_floating(false),
_dontClipMargin(false),
_mouseWheelEnabled(true),
_hover(false),
_dragged(false),
_owner(owner),
_scrollStep(UIConfig::defaultScrollStep),
_mouseWheelStep(UIConfig::defaultScrollStep * 2),
_decelerationRate(UIConfig::defaultScrollDecelerationRate),
_touchEffect(UIConfig::defaultScrollTouchEffect),
_bouncebackEffect(UIConfig::defaultScrollBounceEffect),
_pageSize(Vec2::ONE)
{
_maskContainer = FUIContainer::create();
_maskContainer->setCascadeOpacityEnabled(true);
_owner->displayObject()->addChild(_maskContainer);
_container = (FUIInnerContainer*)_owner->displayObject()->getChildren().at(0);
_container->setPosition2(0, 0);
_container->removeFromParent();
_maskContainer->addChild(_container, 1);
_owner->addEventListener(UIEventType::MouseWheel, AX_CALLBACK_1(ScrollPane::onMouseWheel, this));
_owner->addEventListener(UIEventType::TouchBegin, AX_CALLBACK_1(ScrollPane::onTouchBegin, this));
_owner->addEventListener(UIEventType::TouchMove, AX_CALLBACK_1(ScrollPane::onTouchMove, this));
_owner->addEventListener(UIEventType::TouchEnd, AX_CALLBACK_1(ScrollPane::onTouchEnd, this));
_owner->addEventListener(UIEventType::Exit, [this](EventContext*) {
if (_draggingPane == this)
_draggingPane = nullptr;
});
}
// clang-format on
ScrollPane::~ScrollPane()
{
CALL_PER_FRAME_CANCEL(ScrollPane, tweenUpdate);
CALL_LATER_CANCEL(ScrollPane, refresh);
if (_hzScrollBar)
_hzScrollBar->release();
if (_vtScrollBar)
_vtScrollBar->release();
if (_header)
_header->release();
if (_footer)
_footer->release();
if (_draggingPane == this)
_draggingPane = nullptr;
}
void ScrollPane::setup(ByteBuffer* buffer)
{
_scrollType = (ScrollType)buffer->readByte();
ScrollBarDisplayType scrollBarDisplay = (ScrollBarDisplayType)buffer->readByte();
int flags = buffer->readInt();
if (buffer->readBool())
{
_scrollBarMargin.top = buffer->readInt();
_scrollBarMargin.bottom = buffer->readInt();
_scrollBarMargin.left = buffer->readInt();
_scrollBarMargin.right = buffer->readInt();
}
const std::string& vtScrollBarRes = buffer->readS();
const std::string& hzScrollBarRes = buffer->readS();
const std::string& headerRes = buffer->readS();
const std::string& footerRes = buffer->readS();
_displayOnLeft = (flags & 1) != 0;
_snapToItem = (flags & 2) != 0;
_displayInDemand = (flags & 4) != 0;
_pageMode = (flags & 8) != 0;
if ((flags & 16) != 0)
_touchEffect = true;
else if ((flags & 32) != 0)
_touchEffect = false;
if ((flags & 64) != 0)
_bouncebackEffect = true;
else if ((flags & 128) != 0)
_bouncebackEffect = false;
_inertiaDisabled = (flags & 256) != 0;
_maskContainer->setClippingEnabled((flags & 512) == 0);
_floating = (flags & 1024) != 0;
_dontClipMargin = (flags & 2048) != 0;
if (scrollBarDisplay == ScrollBarDisplayType::DEFAULT)
{
#ifdef AX_PLATFORM_PC
scrollBarDisplay = UIConfig::defaultScrollBarDisplay;
#else
scrollBarDisplay = ScrollBarDisplayType::AUTO;
#endif
}
if (scrollBarDisplay != ScrollBarDisplayType::HIDDEN)
{
if (_scrollType == ScrollType::BOTH || _scrollType == ScrollType::VERTICAL)
{
const std::string& res = vtScrollBarRes.size() == 0 ? UIConfig::verticalScrollBar : vtScrollBarRes;
if (res.length() > 0)
{
_vtScrollBar = dynamic_cast<GScrollBar*>(UIPackage::createObjectFromURL(res));
if (_vtScrollBar == nullptr)
AXLOGWARN("FairyGUI: cannot create scrollbar from %s", res.c_str());
else
{
_vtScrollBar->retain();
_vtScrollBar->setScrollPane(this, true);
_vtScrollBar->_alignToBL = true;
_owner->displayObject()->addChild(_vtScrollBar->displayObject());
}
}
}
if (_scrollType == ScrollType::BOTH || _scrollType == ScrollType::HORIZONTAL)
{
const std::string& res = hzScrollBarRes.length() == 0 ? UIConfig::horizontalScrollBar : hzScrollBarRes;
if (res.length() > 0)
{
_hzScrollBar = dynamic_cast<GScrollBar*>(UIPackage::createObjectFromURL(res));
if (_hzScrollBar == nullptr)
AXLOGWARN("FairyGUI: cannot create scrollbar from %s", res.c_str());
else
{
_hzScrollBar->retain();
_hzScrollBar->setScrollPane(this, false);
_hzScrollBar->_alignToBL = true;
_owner->displayObject()->addChild(_hzScrollBar->displayObject());
}
}
}
_scrollBarDisplayAuto = scrollBarDisplay == ScrollBarDisplayType::AUTO;
if (_scrollBarDisplayAuto)
{
if (_vtScrollBar != nullptr)
_vtScrollBar->setVisible(false);
if (_hzScrollBar != nullptr)
_hzScrollBar->setVisible(false);
_owner->addEventListener(UIEventType::RollOver, AX_CALLBACK_1(ScrollPane::onRollOver, this));
_owner->addEventListener(UIEventType::RollOut, AX_CALLBACK_1(ScrollPane::onRollOut, this));
}
}
else
_mouseWheelEnabled = false;
if (headerRes.length() > 0)
{
_header = dynamic_cast<GComponent*>(UIPackage::createObjectFromURL(headerRes));
if (_header == nullptr)
AXLOGWARN("FairyGUI: cannot create scrollPane header from %s", headerRes.c_str());
else
{
_header->retain();
_header->setVisible(false);
_header->_alignToBL = true;
_owner->displayObject()->addChild(_header->displayObject());
}
}
if (footerRes.length() > 0)
{
_footer = dynamic_cast<GComponent*>(UIPackage::createObjectFromURL(footerRes));
if (_footer == nullptr)
AXLOGWARN("FairyGUI: cannot create scrollPane footer from %s", footerRes.c_str());
else
{
_footer->retain();
_footer->setVisible(false);
_footer->_alignToBL = true;
_owner->displayObject()->addChild(_footer->displayObject());
}
}
if (_header != nullptr || _footer != nullptr)
_refreshBarAxis = (_scrollType == ScrollType::BOTH || _scrollType == ScrollType::VERTICAL) ? 1 : 0;
setSize(_owner->getWidth(), _owner->getHeight());
}
void ScrollPane::setScrollStep(float value)
{
_scrollStep = value;
if (_scrollStep == 0)
_scrollStep = UIConfig::defaultScrollStep;
_mouseWheelStep = _scrollStep * 2;
}
void ScrollPane::setPosX(float value, bool ani)
{
_owner->ensureBoundsCorrect();
if (_loop == 1)
loopCheckingNewPos(value, 0);
value = clampf(value, 0, _overlapSize.width);
if (value != _xPos)
{
_xPos = value;
posChanged(ani);
}
}
void ScrollPane::setPosY(float value, bool ani)
{
_owner->ensureBoundsCorrect();
if (_loop == 2)
loopCheckingNewPos(value, 1);
value = clampf(value, 0, _overlapSize.height);
if (value != _yPos)
{
_yPos = value;
posChanged(ani);
}
}
float ScrollPane::getPercX() const
{
return _overlapSize.width == 0 ? 0 : _xPos / _overlapSize.width;
}
void ScrollPane::setPercX(float value, bool ani)
{
_owner->ensureBoundsCorrect();
setPosX(_overlapSize.width * clampf(value, 0, 1), ani);
}
float ScrollPane::getPercY() const
{
return _overlapSize.height == 0 ? 0 : _yPos / _overlapSize.height;
}
void ScrollPane::setPercY(float value, bool ani)
{
_owner->ensureBoundsCorrect();
setPosY(_overlapSize.height * clampf(value, 0, 1), ani);
}
bool ScrollPane::isBottomMost() const
{
return _yPos == _overlapSize.height || _overlapSize.height == 0;
}
bool ScrollPane::isRightMost() const
{
return _xPos == _overlapSize.width || _overlapSize.width == 0;
}
void ScrollPane::scrollLeft(float ratio, bool ani)
{
if (_pageMode)
setPosX(_xPos - _pageSize.width * ratio, ani);
else
setPosX(_xPos - _scrollStep * ratio, ani);
}
void ScrollPane::scrollRight(float ratio, bool ani)
{
if (_pageMode)
setPosX(_xPos + _pageSize.width * ratio, ani);
else
setPosX(_xPos + _scrollStep * ratio, ani);
}
void ScrollPane::scrollUp(float ratio, bool ani)
{
if (_pageMode)
setPosY(_yPos - _pageSize.height * ratio, ani);
else
setPosY(_yPos - _scrollStep * ratio, ani);
}
void ScrollPane::scrollDown(float ratio, bool ani)
{
if (_pageMode)
setPosY(_yPos + _pageSize.height * ratio, ani);
else
setPosY(_yPos + _scrollStep * ratio, ani);
}
void ScrollPane::scrollTop(bool ani)
{
setPercY(0, ani);
}
void ScrollPane::scrollBottom(bool ani)
{
setPercY(1, ani);
}
void ScrollPane::scrollToView(GObject* obj, bool ani, bool setFirst)
{
_owner->ensureBoundsCorrect();
if (_needRefresh)
refresh();
Rect rect = Rect(obj->getX(), obj->getY(), obj->getWidth(), obj->getHeight());
if (obj->getParent() != _owner)
rect = obj->getParent()->transformRect(rect, _owner);
scrollToView(rect, ani, setFirst);
}
void ScrollPane::scrollToView(const ax::Rect& rect, bool ani, bool setFirst)
{
_owner->ensureBoundsCorrect();
if (_needRefresh)
refresh();
if (_overlapSize.height > 0)
{
float bottom = _yPos + _viewSize.height;
if (setFirst || rect.origin.y <= _yPos || rect.size.height >= _viewSize.height)
{
if (_pageMode)
setPosY(floor(rect.origin.y / _pageSize.height) * _pageSize.height, ani);
else
setPosY(rect.origin.y, ani);
}
else if (rect.getMaxY() > bottom)
{
if (_pageMode)
setPosY(floor(rect.origin.y / _pageSize.height) * _pageSize.height, ani);
else if (rect.size.height <= _viewSize.height / 2)
setPosY(rect.origin.y + rect.size.height * 2 - _viewSize.height, ani);
else
setPosY(rect.getMaxY() - _viewSize.height, ani);
}
}
if (_overlapSize.width > 0)
{
float right = _xPos + _viewSize.width;
if (setFirst || rect.origin.x <= _xPos || rect.size.width >= _viewSize.width)
{
if (_pageMode)
setPosX(floor(rect.origin.x / _pageSize.width) * _pageSize.width, ani);
setPosX(rect.origin.x, ani);
}
else if (rect.getMaxX() > right)
{
if (_pageMode)
setPosX(floor(rect.origin.x / _pageSize.width) * _pageSize.width, ani);
else if (rect.size.width <= _viewSize.width / 2)
setPosX(rect.origin.x + rect.size.width * 2 - _viewSize.width, ani);
else
setPosX(rect.getMaxX() - _viewSize.width, ani);
}
}
if (!ani && _needRefresh)
refresh();
}
bool ScrollPane::isChildInView(GObject* obj) const
{
if (_overlapSize.height > 0)
{
float dist = obj->getY() + _container->getPositionY2();
if (dist <= -obj->getHeight() || dist >= _viewSize.height)
return false;
}
if (_overlapSize.width > 0)
{
float dist = obj->getX() + _container->getPositionX();
if (dist <= -obj->getWidth() || dist >= _viewSize.width)
return false;
}
return true;
}
int ScrollPane::getPageX() const
{
if (!_pageMode)
return 0;
int page = floor(_xPos / _pageSize.width);
if (_xPos - page * _pageSize.width > _pageSize.width * 0.5f)
page++;
return page;
}
void ScrollPane::setPageX(int value, bool ani)
{
if (!_pageMode)
return;
_owner->ensureBoundsCorrect();
if (_overlapSize.width > 0)
setPosX(value * _pageSize.width, ani);
}
int ScrollPane::getPageY() const
{
if (!_pageMode)
return 0;
int page = floor(_yPos / _pageSize.height);
if (_yPos - page * _pageSize.height > _pageSize.height * 0.5f)
page++;
return page;
}
void ScrollPane::setPageY(int value, bool ani)
{
if (!_pageMode)
return;
_owner->ensureBoundsCorrect();
if (_overlapSize.height > 0)
setPosY(value * _pageSize.height, ani);
}
float ScrollPane::getScrollingPosX() const
{
return clampf(-_container->getPositionX(), 0, _overlapSize.width);
}
float ScrollPane::getScrollingPosY() const
{
return clampf(-_container->getPositionY2(), 0, _overlapSize.height);
}
void ScrollPane::setViewWidth(float value)
{
value = value + _owner->_margin.left + _owner->_margin.right;
if (_vtScrollBar != nullptr && !_floating)
value += _vtScrollBar->getWidth();
_owner->setWidth(value);
}
void ScrollPane::setViewHeight(float value)
{
value = value + _owner->_margin.top + _owner->_margin.bottom;
if (_hzScrollBar != nullptr && !_floating)
value += _hzScrollBar->getHeight();
_owner->setHeight(value);
}
void ScrollPane::lockHeader(int size)
{
if (_headerLockedSize == size)
return;
Vec2 cpos = _container->getPosition2();
_headerLockedSize = size;
if (!_owner->isDispatchingEvent(UIEventType::PullDownRelease) && sp_getField(cpos, _refreshBarAxis) >= 0)
{
_tweenStart = cpos;
_tweenChange.setZero();
sp_setField(_tweenChange, _refreshBarAxis, _headerLockedSize - sp_getField(_tweenStart, _refreshBarAxis));
_tweenDuration.set(TWEEN_TIME_DEFAULT, TWEEN_TIME_DEFAULT);
startTween(2);
CALL_PER_FRAME(ScrollPane, tweenUpdate);
}
}
void ScrollPane::lockFooter(int size)
{
if (_footerLockedSize == size)
return;
Vec2 cpos = _container->getPosition2();
_footerLockedSize = size;
if (!_owner->isDispatchingEvent(UIEventType::PullUpRelease) && sp_getField(cpos, _refreshBarAxis) >= 0)
{
_tweenStart = cpos;
_tweenChange.setZero();
float max = sp_getField(_overlapSize, _refreshBarAxis);
if (max == 0)
max = MAX(sp_getField(_contentSize, _refreshBarAxis) + _footerLockedSize - sp_getField(_viewSize, _refreshBarAxis), 0);
else
max += _footerLockedSize;
sp_setField(_tweenChange, _refreshBarAxis, -max - sp_getField(_tweenStart, _refreshBarAxis));
_tweenDuration.set(TWEEN_TIME_DEFAULT, TWEEN_TIME_DEFAULT);
startTween(2);
CALL_PER_FRAME(ScrollPane, tweenUpdate);
}
}
void ScrollPane::cancelDragging()
{
if (_draggingPane == this)
_draggingPane = nullptr;
_gestureFlag = 0;
_dragged = false;
}
void ScrollPane::handleControllerChanged(GController* c)
{
if (_pageController == c)
{
if (_scrollType == ScrollType::HORIZONTAL)
setPageX(c->getSelectedIndex(), true);
else
setPageY(c->getSelectedIndex(), true);
}
}
void ScrollPane::updatePageController()
{
if (_pageController != nullptr && !_pageController->changing)
{
int index;
if (_scrollType == ScrollType::HORIZONTAL)
index = getPageX();
else
index = getPageY();
if (index < _pageController->getPageCount())
{
GController* c = _pageController;
_pageController = nullptr; //avoid calling handleControllerChanged
c->setSelectedIndex(index);
_pageController = c;
}
}
}
void ScrollPane::adjustMaskContainer()
{
float mx, my;
if (_displayOnLeft && _vtScrollBar != nullptr && !_floating)
mx = floor(_owner->_margin.left + _vtScrollBar->getWidth());
else
mx = floor(_owner->_margin.left);
my = floor(_owner->_margin.top);
mx += _owner->_alignOffset.x;
my += _owner->_alignOffset.y;
_maskContainer->setPosition(Vec2(mx, _owner->getHeight() - _viewSize.height - my));
}
void ScrollPane::onOwnerSizeChanged()
{
setSize(_owner->getWidth(), _owner->getHeight());
posChanged(false);
}
void ScrollPane::setSize(float wv, float hv)
{
if (_hzScrollBar != nullptr)
{
_hzScrollBar->setY(hv - _hzScrollBar->getHeight());
if (_vtScrollBar != nullptr)
{
_hzScrollBar->setWidth(wv - _vtScrollBar->getWidth() - _scrollBarMargin.left - _scrollBarMargin.right);
if (_displayOnLeft)
_hzScrollBar->setX(_scrollBarMargin.left + _vtScrollBar->getWidth());
else
_hzScrollBar->setX(_scrollBarMargin.left);
}
else
{
_hzScrollBar->setWidth(wv - _scrollBarMargin.left - _scrollBarMargin.right);
_hzScrollBar->setX(_scrollBarMargin.left);
}
}
if (_vtScrollBar != nullptr)
{
if (!_displayOnLeft)
_vtScrollBar->setX(wv - _vtScrollBar->getWidth());
if (_hzScrollBar != nullptr)
_vtScrollBar->setHeight(hv - _hzScrollBar->getHeight() - _scrollBarMargin.top - _scrollBarMargin.bottom);
else
_vtScrollBar->setHeight(hv - _scrollBarMargin.top - _scrollBarMargin.bottom);
_vtScrollBar->setY(_scrollBarMargin.top);
}
_viewSize.width = wv;
_viewSize.height = hv;
if (_hzScrollBar != nullptr && !_floating)
_viewSize.height -= _hzScrollBar->getHeight();
if (_vtScrollBar != nullptr && !_floating)
_viewSize.width -= _vtScrollBar->getWidth();
_viewSize.width -= (_owner->_margin.left + _owner->_margin.right);
_viewSize.height -= (_owner->_margin.top + _owner->_margin.bottom);
_viewSize.width = MAX(1, _viewSize.width);
_viewSize.height = MAX(1, _viewSize.height);
_pageSize = _viewSize;
adjustMaskContainer();
handleSizeChanged();
}
void ScrollPane::setContentSize(float wv, float hv)
{
if (_contentSize.width == wv && _contentSize.height == hv)
return;
_contentSize.width = wv;
_contentSize.height = hv;
handleSizeChanged();
}
void ScrollPane::changeContentSizeOnScrolling(float deltaWidth, float deltaHeight, float deltaPosX, float deltaPosY)
{
bool isRightmost = _xPos == _overlapSize.width;
bool isBottom = _yPos == _overlapSize.height;
_contentSize.width += deltaWidth;
_contentSize.height += deltaHeight;
handleSizeChanged();
if (_tweening == 1)
{
if (deltaWidth != 0 && isRightmost && _tweenChange.x < 0)
{
_xPos = _overlapSize.width;
_tweenChange.x = -_xPos - _tweenStart.x;
}
if (deltaHeight != 0 && isBottom && _tweenChange.y < 0)
{
_yPos = _overlapSize.height;
_tweenChange.y = -_yPos - _tweenStart.y;
}
}
else if (_tweening == 2)
{
if (deltaPosX != 0)
{
_container->setPositionX(_container->getPositionX() - deltaPosX);
_tweenStart.x -= deltaPosX;
_xPos = -_container->getPositionX();
}
if (deltaPosY != 0)
{
_container->setPositionY2(_container->getPositionY2() - deltaPosY);
_tweenStart.y -= deltaPosY;
_yPos = -_container->getPositionY2();
}
}
else if (_dragged)
{
if (deltaPosX != 0)
{
_container->setPositionX(_container->getPositionX() - deltaPosX);
_containerPos.x -= deltaPosX;
_xPos = -_container->getPositionX();
}
if (deltaPosY != 0)
{
_container->setPositionY2(_container->getPositionY2() - deltaPosY);
_containerPos.y -= deltaPosY;
_yPos = -_container->getPositionY2();
}
}
else
{
if (deltaWidth != 0 && isRightmost)
{
_xPos = _overlapSize.width;
_container->setPositionX(-_xPos);
}
if (deltaHeight != 0 && isBottom)
{
_yPos = _overlapSize.height;
_container->setPositionY2(-_yPos);
}
}
if (_pageMode)
updatePageController();
}
void ScrollPane::handleSizeChanged()
{
if (_displayInDemand)
{
_vScrollNone = _contentSize.height <= _viewSize.height;
_hScrollNone = _contentSize.width <= _viewSize.width;
}
if (_vtScrollBar != nullptr)
{
if (_contentSize.height == 0)
_vtScrollBar->setDisplayPerc(0);
else
_vtScrollBar->setDisplayPerc(MIN(1, _viewSize.height / _contentSize.height));
}
if (_hzScrollBar != nullptr)
{
if (_contentSize.width == 0)
_hzScrollBar->setDisplayPerc(0);
else
_hzScrollBar->setDisplayPerc(MIN(1, _viewSize.width / _contentSize.width));
}
updateScrollBarVisible();
_maskContainer->setContentSize(_viewSize);
Rect maskRect(Vec2(-_owner->_alignOffset.x, _owner->_alignOffset.y), _viewSize);
if (_vScrollNone && _vtScrollBar != nullptr)
maskRect.size.width += _vtScrollBar->getWidth();
if (_hScrollNone && _hzScrollBar != nullptr)
maskRect.size.height += _hzScrollBar->getHeight();
if (_dontClipMargin)
{
maskRect.origin.x -= _owner->_margin.left;
maskRect.size.width += _owner->_margin.left + _owner->_margin.right;
maskRect.origin.y -= _owner->_margin.top;
maskRect.size.height += _owner->_margin.top + _owner->_margin.bottom;
}
_maskContainer->setClippingRegion(maskRect);
if (_vtScrollBar)
_vtScrollBar->handlePositionChanged();
if (_hzScrollBar)
_hzScrollBar->handlePositionChanged();
if (_header)
_header->handlePositionChanged();
if (_footer)
_footer->handlePositionChanged();
if (_scrollType == ScrollType::HORIZONTAL || _scrollType == ScrollType::BOTH)
_overlapSize.width = ceil(MAX(0, _contentSize.width - _viewSize.width));
else
_overlapSize.width = 0;
if (_scrollType == ScrollType::VERTICAL || _scrollType == ScrollType::BOTH)
_overlapSize.height = ceil(MAX(0, _contentSize.height - _viewSize.height));
else
_overlapSize.height = 0;
_xPos = clampf(_xPos, 0, _overlapSize.width);
_yPos = clampf(_yPos, 0, _overlapSize.height);
float max = sp_getField(_overlapSize, _refreshBarAxis);
if (max == 0)
max = MAX(sp_getField(_contentSize, _refreshBarAxis) + _footerLockedSize - sp_getField(_viewSize, _refreshBarAxis), 0);
else
max += _footerLockedSize;
if (_refreshBarAxis == 0)
_container->setPosition2(clampf(_container->getPositionX(), -max, _headerLockedSize),
clampf(_container->getPositionY2(), -_overlapSize.height, 0));
else
_container->setPosition2(clampf(_container->getPositionX(), -_overlapSize.width, 0),
clampf(_container->getPositionY2(), -max, _headerLockedSize));
if (_header != nullptr)
{
if (_refreshBarAxis == 0)
_header->setHeight(_viewSize.height);
else
_header->setWidth(_viewSize.width);
}
if (_footer != nullptr)
{
if (_refreshBarAxis == 0)
_footer->setHeight(_viewSize.height);
else
_footer->setWidth(_viewSize.width);
}
updateScrollBarPos();
if (_pageMode)
updatePageController();
}
GObject* ScrollPane::hitTest(const ax::Vec2& pt, const ax::Camera* camera)
{
GObject* target = nullptr;
if (_vtScrollBar)
{
target = _vtScrollBar->hitTest(pt, camera);
if (target)
return target;
}
if (_hzScrollBar)
{
target = _hzScrollBar->hitTest(pt, camera);
if (target)
return target;
}
if (_header && _header->displayObject()->getParent() != nullptr)
{
target = _header->hitTest(pt, camera);
if (target)
return target;
}
if (_footer && _footer->displayObject()->getParent() != nullptr)
{
target = _footer->hitTest(pt, camera);
if (target)
return target;
}
if (_maskContainer->isClippingEnabled())
{
Vec2 localPoint = _maskContainer->convertToNodeSpace(pt);
if (_maskContainer->getClippingRegion().containsPoint(localPoint))
return _owner;
else
return nullptr;
}
else
return _owner;
}
void ScrollPane::posChanged(bool ani)
{
if (_aniFlag == 0)
_aniFlag = ani ? 1 : -1;
else if (_aniFlag == 1 && !ani)
_aniFlag = -1;
_needRefresh = true;
CALL_LATER(ScrollPane, refresh);
}
void ScrollPane::refresh()
{
CALL_LATER_CANCEL(ScrollPane, refresh);
_needRefresh = false;
if (_pageMode || _snapToItem)
{
Vec2 pos(-_xPos, -_yPos);
alignPosition(pos, false);
_xPos = -pos.x;
_yPos = -pos.y;
}
refresh2();
_owner->dispatchEvent(UIEventType::Scroll);
if (_needRefresh) //pos may change in onScroll
{
_needRefresh = false;
CALL_LATER_CANCEL(ScrollPane, refresh);
refresh2();
}
updateScrollBarPos();
_aniFlag = 0;
}
void ScrollPane::refresh2()
{
if (_aniFlag == 1 && !_dragged)
{
Vec2 pos;
if (_overlapSize.width > 0)
pos.x = -(int)_xPos;
else
{
if (_container->getPositionX() != 0)
_container->setPositionX(0);
pos.x = 0;
}
if (_overlapSize.height > 0)
pos.y = -(int)_yPos;
else
{
if (_container->getPositionY2() != 0)
_container->setPositionY2(0);
pos.y = 0;
}
if (pos.x != _container->getPositionX() || pos.y != _container->getPositionY2())
{
_tweenDuration.set(TWEEN_TIME_GO, TWEEN_TIME_GO);
_tweenStart = _container->getPosition2();
_tweenChange = pos - _tweenStart;
startTween(1);
}
else if (_tweening != 0)
killTween();
}
else
{
if (_tweening != 0)
killTween();
_container->setPosition2(Vec2((int)-_xPos, (int)-_yPos));
loopCheckingCurrent();
}
if (_pageMode)
updatePageController();
}
void ScrollPane::updateScrollBarPos()
{
if (_vtScrollBar != nullptr)
_vtScrollBar->setScrollPerc(_overlapSize.height == 0 ? 0 : clampf(-_container->getPositionY2(), 0, _overlapSize.height) / _overlapSize.height);
if (_hzScrollBar != nullptr)
_hzScrollBar->setScrollPerc(_overlapSize.width == 0 ? 0 : clampf(-_container->getPositionX(), 0, _overlapSize.width) / _overlapSize.width);
checkRefreshBar();
}
void ScrollPane::updateScrollBarVisible()
{
if (_vtScrollBar != nullptr)
{
if (_viewSize.height <= _vtScrollBar->getMinSize() || _vScrollNone)
_vtScrollBar->setVisible(false);
else
updateScrollBarVisible2(_vtScrollBar);
}
if (_hzScrollBar != nullptr)
{
if (_viewSize.width <= _hzScrollBar->getMinSize() || _hScrollNone)
_hzScrollBar->setVisible(false);
else
updateScrollBarVisible2(_hzScrollBar);
}
}
void ScrollPane::updateScrollBarVisible2(GScrollBar* bar)
{
if (_scrollBarDisplayAuto)
GTween::kill(bar, TweenPropType::Alpha, false);
if (_scrollBarDisplayAuto && !_hover && _tweening == 0 && !_dragged && !bar->_gripDragging)
{
if (bar->isVisible())
GTween::to(1, 0, 0.5f)
->setDelay(0.5f)
->onComplete1(AX_CALLBACK_1(ScrollPane::onBarTweenComplete, this))
->setTarget(bar, TweenPropType::Alpha);
}
else
{
bar->setAlpha(1);
bar->setVisible(true);
}
}
void ScrollPane::onBarTweenComplete(GTweener* tweener)
{
GObject* bar = (GObject*)tweener->getTarget();
bar->setAlpha(1);
bar->setVisible(false);
}
float ScrollPane::getLoopPartSize(float division, int axis)
{
return (sp_getField(_contentSize, axis) + (axis == 0 ? ((GList*)_owner)->getColumnGap() : ((GList*)_owner)->getLineGap())) / division;
}
bool ScrollPane::loopCheckingCurrent()
{
bool changed = false;
if (_loop == 1 && _overlapSize.width > 0)
{
if (_xPos < 0.001f)
{
_xPos += getLoopPartSize(2, 0);
changed = true;
}
else if (_xPos >= _overlapSize.width)
{
_xPos -= getLoopPartSize(2, 0);
changed = true;
}
}
else if (_loop == 2 && _overlapSize.height > 0)
{
if (_yPos < 0.001f)
{
_yPos += getLoopPartSize(2, 1);
changed = true;
}
else if (_yPos >= _overlapSize.height)
{
_yPos -= getLoopPartSize(2, 1);
changed = true;
}
}
if (changed)
_container->setPosition2(Vec2((int)-_xPos, (int)-_yPos));
return changed;
}
void ScrollPane::loopCheckingTarget(ax::Vec2& endPos)
{
if (_loop == 1)
loopCheckingTarget(endPos, 0);
if (_loop == 2)
loopCheckingTarget(endPos, 1);
}
void ScrollPane::loopCheckingTarget(ax::Vec2& endPos, int axis)
{
if (sp_getField(endPos, axis) > 0)
{
float halfSize = getLoopPartSize(2, axis);
float tmp = sp_getField(_tweenStart, axis) - halfSize;
if (tmp <= 0 && tmp >= -sp_getField(_overlapSize, axis))
{
sp_incField(endPos, axis, -halfSize);
sp_setField(_tweenStart, axis, tmp);
}
}
else if (sp_getField(endPos, axis) < -sp_getField(_overlapSize, axis))
{
float halfSize = getLoopPartSize(2, axis);
float tmp = sp_getField(_tweenStart, axis) + halfSize;
if (tmp <= 0 && tmp >= -sp_getField(_overlapSize, axis))
{
sp_incField(endPos, axis, halfSize);
sp_setField(_tweenStart, axis, tmp);
}
}
}
void ScrollPane::loopCheckingNewPos(float& value, int axis)
{
float overlapSize = sp_getField(_overlapSize, axis);
if (overlapSize == 0)
return;
float pos = axis == 0 ? _xPos : _yPos;
bool changed = false;
if (value < 0.001f)
{
value += getLoopPartSize(2, axis);
if (value > pos)
{
float v = getLoopPartSize(6, axis);
v = ceil((value - pos) / v) * v;
pos = clampf(pos + v, 0, overlapSize);
changed = true;
}
}
else if (value >= overlapSize)
{
value -= getLoopPartSize(2, axis);
if (value < pos)
{
float v = getLoopPartSize(6, axis);
v = ceil((pos - value) / v) * v;
pos = clampf(pos - v, 0, overlapSize);
changed = true;
}
}
if (changed)
{
if (axis == 0)
_container->setPositionX(-(int)pos);
else
_container->setPositionY2(-(int)pos);
}
}
void ScrollPane::alignPosition(Vec2& pos, bool inertialScrolling)
{
if (_pageMode)
{
pos.x = alignByPage(pos.x, 0, inertialScrolling);
pos.y = alignByPage(pos.y, 1, inertialScrolling);
}
else if (_snapToItem)
{
Vec2 tmp = _owner->getSnappingPosition(-pos);
if (pos.x < 0 && pos.x > -_overlapSize.width)
pos.x = -tmp.x;
if (pos.y < 0 && pos.y > -_overlapSize.height)
pos.y = -tmp.y;
}
}
float ScrollPane::alignByPage(float pos, int axis, bool inertialScrolling)
{
int page;
float pageSize = sp_getField(_pageSize, axis);
float overlapSize = sp_getField(_overlapSize, axis);
float contentSize = sp_getField(_contentSize, axis);
if (pos > 0)
page = 0;
else if (pos < -overlapSize)
page = ceil(contentSize / pageSize) - 1;
else
{
page = floor(-pos / pageSize);
float change = inertialScrolling ? (pos - sp_getField(_containerPos, axis)) : (pos - sp_getField(_container->getPosition2(), axis));
float testPageSize = MIN(pageSize, contentSize - (page + 1) * pageSize);
float delta = -pos - page * pageSize;
if (std::abs(change) > pageSize)
{
if (delta > testPageSize * 0.5f)
page++;
}
else
{
if (delta > testPageSize * (change < 0 ? 0.3f : 0.7f))
page++;
}
pos = -page * pageSize;
if (pos < -overlapSize)
pos = -overlapSize;
}
if (inertialScrolling)
{
float oldPos = sp_getField(_tweenStart, axis);
int oldPage;
if (oldPos > 0)
oldPage = 0;
else if (oldPos < -overlapSize)
oldPage = ceil(contentSize / pageSize) - 1;
else
oldPage = floor(-oldPos / pageSize);
int startPage = floor(-sp_getField(_containerPos, axis) / pageSize);
if (abs(page - startPage) > 1 && abs(oldPage - startPage) <= 1)
{
if (page > startPage)
page = startPage + 1;
else
page = startPage - 1;
pos = -page * pageSize;
}
}
return pos;
}
ax::Vec2 ScrollPane::updateTargetAndDuration(const ax::Vec2& orignPos)
{
Vec2 ret(0, 0);
ret.x = updateTargetAndDuration(orignPos.x, 0);
ret.y = updateTargetAndDuration(orignPos.y, 1);
return ret;
}
float ScrollPane::updateTargetAndDuration(float pos, int axis)
{
float v = sp_getField(_velocity, axis);
float duration = 0;
if (pos > 0)
pos = 0;
else if (pos < -sp_getField(_overlapSize, axis))
pos = -sp_getField(_overlapSize, axis);
else
{
float v2 = std::abs(v) * _velocityScale;
float ratio = 0;
#ifdef AX_PLATFORM_PC
if (v2 > 500)
ratio = pow((v2 - 500) / 500, 2);
#else
const ax::Size& winSize = Director::getInstance()->getWinSizeInPixels();
v2 *= 1136.0f / MAX(winSize.width, winSize.height);
if (_pageMode)
{
if (v2 > 500)
ratio = pow((v2 - 500) / 500, 2);
}
else
{
if (v2 > 1000)
ratio = pow((v2 - 1000) / 1000, 2);
}
#endif
if (ratio != 0)
{
if (ratio > 1)
ratio = 1;
v2 *= ratio;
v *= ratio;
sp_setField(_velocity, axis, v);
duration = log(60 / v2) / log(_decelerationRate) / 60;
float change = (int)(v * duration * 0.4f);
pos += change;
}
}
if (duration < TWEEN_TIME_DEFAULT)
duration = TWEEN_TIME_DEFAULT;
sp_setField(_tweenDuration, axis, duration);
return pos;
}
void ScrollPane::fixDuration(int axis, float oldChange)
{
float tweenChange = sp_getField(_tweenChange, axis);
if (tweenChange == 0 || std::abs(tweenChange) >= std::abs(oldChange))
return;
float newDuration = std::abs(tweenChange / oldChange) * sp_getField(_tweenDuration, axis);
if (newDuration < TWEEN_TIME_DEFAULT)
newDuration = TWEEN_TIME_DEFAULT;
sp_setField(_tweenDuration, axis, newDuration);
}
void ScrollPane::startTween(int type)
{
_tweenTime.setZero();
_tweening = type;
CALL_PER_FRAME(ScrollPane, tweenUpdate);
updateScrollBarVisible();
}
void ScrollPane::killTween()
{
if (_tweening == 1)
{
Vec2 t = _tweenStart + _tweenChange;
_container->setPosition2(t);
_owner->dispatchEvent(UIEventType::Scroll);
}
_tweening = 0;
CALL_PER_FRAME_CANCEL(ScrollPane, tweenUpdate);
_owner->dispatchEvent(UIEventType::ScrollEnd);
}
void ScrollPane::checkRefreshBar()
{
if (_header == nullptr && _footer == nullptr)
return;
float pos = sp_getField(_container->getPosition2(), _refreshBarAxis);
if (_header != nullptr)
{
if (pos > 0)
{
_header->setVisible(true);
Vec2 vec;
vec = _header->getSize();
sp_setField(vec, _refreshBarAxis, pos);
_header->setSize(vec.x, vec.y);
}
else
_header->setVisible(false);
}
if (_footer != nullptr)
{
float max = sp_getField(_overlapSize, _refreshBarAxis);
if (pos < -max || (max == 0 && _footerLockedSize > 0))
{
_footer->setVisible(true);
Vec2 vec;
vec = _footer->getPosition();
if (max > 0)
sp_setField(vec, _refreshBarAxis, pos + sp_getField(_contentSize, _refreshBarAxis));
else
sp_setField(vec, _refreshBarAxis, MAX(MIN(pos + sp_getField(_viewSize, _refreshBarAxis), sp_getField(_viewSize, _refreshBarAxis) - _footerLockedSize), sp_getField(_viewSize, _refreshBarAxis) - sp_getField(_contentSize, _refreshBarAxis)));
_footer->setPosition(vec.x, vec.y);
vec = _footer->getSize();
if (max > 0)
sp_setField(vec, _refreshBarAxis, -max - pos);
else
sp_setField(vec, _refreshBarAxis, sp_getField(_viewSize, _refreshBarAxis) - sp_getField(_footer->getPosition(), _refreshBarAxis));
_footer->setSize(vec.x, vec.y);
}
else
_footer->setVisible(false);
}
}
void ScrollPane::tweenUpdate(float dt)
{
float nx = runTween(0, dt);
float ny = runTween(1, dt);
_container->setPosition2(nx, ny);
if (_tweening == 2)
{
if (_overlapSize.width > 0)
_xPos = clampf(-nx, 0, _overlapSize.width);
if (_overlapSize.height > 0)
_yPos = clampf(-ny, 0, _overlapSize.height);
if (_pageMode)
updatePageController();
}
if (_tweenChange.x == 0 && _tweenChange.y == 0)
{
_tweening = 0;
CALL_PER_FRAME_CANCEL(ScrollPane, tweenUpdate);
loopCheckingCurrent();
updateScrollBarPos();
updateScrollBarVisible();
_owner->dispatchEvent(UIEventType::Scroll);
_owner->dispatchEvent(UIEventType::ScrollEnd);
}
else
{
updateScrollBarPos();
_owner->dispatchEvent(UIEventType::Scroll);
}
}
float ScrollPane::runTween(int axis, float dt)
{
float newValue;
if (sp_getField(_tweenChange, axis) != 0)
{
sp_incField(_tweenTime, axis, dt);
if (sp_getField(_tweenTime, axis) >= sp_getField(_tweenDuration, axis))
{
newValue = sp_getField(_tweenStart, axis) + sp_getField(_tweenChange, axis);
sp_setField(_tweenChange, axis, 0);
}
else
{
float ratio = sp_EaseFunc(sp_getField(_tweenTime, axis), sp_getField(_tweenDuration, axis));
newValue = sp_getField(_tweenStart, axis) + (int)(sp_getField(_tweenChange, axis) * ratio);
}
float threshold1 = 0;
float threshold2 = -sp_getField(_overlapSize, axis);
if (_headerLockedSize > 0 && _refreshBarAxis == axis)
threshold1 = _headerLockedSize;
if (_footerLockedSize > 0 && _refreshBarAxis == axis)
{
float max = sp_getField(_overlapSize, _refreshBarAxis);
if (max == 0)
max = MAX(sp_getField(_contentSize, _refreshBarAxis) + _footerLockedSize - sp_getField(_viewSize, _refreshBarAxis), 0);
else
max += _footerLockedSize;
threshold2 = -max;
}
if (_tweening == 2 && _bouncebackEffect)
{
if ((newValue > 20 + threshold1 && sp_getField(_tweenChange, axis) > 0) || (newValue > threshold1 && sp_getField(_tweenChange, axis) == 0))
{
sp_setField(_tweenTime, axis, 0);
sp_setField(_tweenDuration, axis, TWEEN_TIME_DEFAULT);
sp_setField(_tweenChange, axis, -newValue + threshold1);
sp_setField(_tweenStart, axis, newValue);
}
else if ((newValue < threshold2 - 20 && sp_getField(_tweenChange, axis) < 0) || (newValue < threshold2 && sp_getField(_tweenChange, axis) == 0))
{
sp_setField(_tweenTime, axis, 0);
sp_setField(_tweenDuration, axis, TWEEN_TIME_DEFAULT);
sp_setField(_tweenChange, axis, threshold2 - newValue);
sp_setField(_tweenStart, axis, newValue);
}
}
else
{
if (newValue > threshold1)
{
newValue = threshold1;
sp_setField(_tweenChange, axis, 0);
}
else if (newValue < threshold2)
{
newValue = threshold2;
sp_setField(_tweenChange, axis, 0);
}
}
}
else
newValue = sp_getField(_container->getPosition2(), axis);
return newValue;
}
void ScrollPane::onTouchBegin(EventContext* context)
{
if (!_touchEffect)
return;
context->captureTouch();
InputEvent* evt = context->getInput();
Vec2 pt = _owner->globalToLocal(evt->getPosition());
if (_tweening != 0)
{
killTween();
evt->getProcessor()->cancelClick(evt->getTouchId());
_dragged = true;
}
else
_dragged = false;
_containerPos = _container->getPosition2();
_beginTouchPos = _lastTouchPos = pt;
_lastTouchGlobalPos = evt->getPosition();
_isHoldAreaDone = false;
_velocity.setZero();
_velocityScale = 1;
_lastMoveTime = clock();
}
void ScrollPane::onTouchMove(EventContext* context)
{
if (!_touchEffect)
return;
if ((_draggingPane != nullptr && _draggingPane != this) || GObject::getDraggingObject() != nullptr)
return;
InputEvent* evt = context->getInput();
Vec2 pt = _owner->globalToLocal(evt->getPosition());
int sensitivity;
#ifdef AX_PLATFORM_PC
sensitivity = 8;
#else
sensitivity = UIConfig::touchScrollSensitivity;
#endif
float diff;
bool sv = false, sh = false;
if (_scrollType == ScrollType::VERTICAL)
{
if (!_isHoldAreaDone)
{
_gestureFlag |= 1;
diff = std::abs(_beginTouchPos.y - pt.y);
if (diff < sensitivity)
return;
if ((_gestureFlag & 2) != 0)
{
float diff2 = std::abs(_beginTouchPos.x - pt.x);
if (diff < diff2)
return;
}
}
sv = true;
}
else if (_scrollType == ScrollType::HORIZONTAL)
{
if (!_isHoldAreaDone)
{
_gestureFlag |= 2;
diff = std::abs(_beginTouchPos.x - pt.x);
if (diff < sensitivity)
return;
if ((_gestureFlag & 1) != 0)
{
float diff2 = std::abs(_beginTouchPos.y - pt.y);
if (diff < diff2)
return;
}
}
sh = true;
}
else
{
_gestureFlag = 3;
if (!_isHoldAreaDone)
{
diff = std::abs(_beginTouchPos.y - pt.y);
if (diff < sensitivity)
{
diff = std::abs(_beginTouchPos.x - pt.x);
if (diff < sensitivity)
return;
}
}
sv = sh = true;
}
Vec2 newPos = _containerPos + pt - _beginTouchPos;
newPos.x = (int)newPos.x;
newPos.y = (int)newPos.y;
if (sv)
{
if (newPos.y > 0)
{
if (!_bouncebackEffect)
_container->setPositionY2(0);
else if (_header != nullptr && _header->maxSize.height != 0)
_container->setPositionY2(((int)MIN(newPos.y * 0.5f, _header->maxSize.height)));
else
_container->setPositionY2(((int)MIN(newPos.y * 0.5f, _viewSize.height * PULL_RATIO)));
}
else if (newPos.y < -_overlapSize.height)
{
if (!_bouncebackEffect)
_container->setPositionY2(-_overlapSize.height);
else if (_footer != nullptr && _footer->maxSize.height > 0)
_container->setPositionY2(((int)MAX((newPos.y + _overlapSize.height) * 0.5f, -_footer->maxSize.height) - _overlapSize.height));
else
_container->setPositionY2(((int)MAX((newPos.y + _overlapSize.height) * 0.5f, -_viewSize.height * PULL_RATIO) - _overlapSize.height));
}
else
_container->setPositionY2(newPos.y);
}
if (sh)
{
if (newPos.x > 0)
{
if (!_bouncebackEffect)
_container->setPositionX(0);
else if (_header != nullptr && _header->maxSize.width != 0)
_container->setPositionX((int)MIN(newPos.x * 0.5f, _header->maxSize.width));
else
_container->setPositionX((int)MIN(newPos.x * 0.5f, _viewSize.width * PULL_RATIO));
}
else if (newPos.x < 0 - _overlapSize.width)
{
if (!_bouncebackEffect)
_container->setPositionX(-_overlapSize.width);
else if (_footer != nullptr && _footer->maxSize.width > 0)
_container->setPositionX((int)MAX((newPos.x + _overlapSize.width) * 0.5f, -_footer->maxSize.width) - _overlapSize.width);
else
_container->setPositionX((int)MAX((newPos.x + _overlapSize.width) * 0.5f, -_viewSize.width * PULL_RATIO) - _overlapSize.width);
}
else
_container->setPositionX(newPos.x);
}
auto deltaTime = Director::getInstance()->getDeltaTime();
float elapsed = (clock() - _lastMoveTime) / (double)CLOCKS_PER_SEC;
elapsed = elapsed * 60 - 1;
if (elapsed > 1)
_velocity = _velocity * pow(0.833f, elapsed);
Vec2 deltaPosition = pt - _lastTouchPos;
if (!sh)
deltaPosition.x = 0;
if (!sv)
deltaPosition.y = 0;
_velocity = _velocity.lerp(deltaPosition / deltaTime, deltaTime * 10);
Vec2 deltaGlobalPosition = _lastTouchGlobalPos - evt->getPosition();
if (deltaPosition.x != 0)
_velocityScale = std::abs(deltaGlobalPosition.x / deltaPosition.x);
else if (deltaPosition.y != 0)
_velocityScale = std::abs(deltaGlobalPosition.y / deltaPosition.y);
_lastTouchPos = pt;
_lastTouchGlobalPos = evt->getPosition();
_lastMoveTime = clock();
if (_overlapSize.width > 0)
_xPos = clampf(-_container->getPositionX(), 0, _overlapSize.width);
if (_overlapSize.height > 0)
_yPos = clampf(-_container->getPositionY2(), 0, _overlapSize.height);
if (_loop != 0)
{
newPos = _container->getPosition2();
if (loopCheckingCurrent())
_containerPos += _container->getPosition2() - newPos;
}
_draggingPane = this;
_isHoldAreaDone = true;
_dragged = true;
updateScrollBarPos();
updateScrollBarVisible();
if (_pageMode)
updatePageController();
_owner->dispatchEvent(UIEventType::Scroll);
}
void ScrollPane::onTouchEnd(EventContext* context)
{
if (_draggingPane == this)
_draggingPane = nullptr;
_gestureFlag = 0;
if (!_dragged || !_touchEffect)
{
_dragged = false;
return;
}
_dragged = false;
_tweenStart = _container->getPosition2();
Vec2 endPos = _tweenStart;
bool flag = false;
if (_container->getPositionX() > 0)
{
endPos.x = 0;
flag = true;
}
else if (_container->getPositionX() < -_overlapSize.width)
{
endPos.x = -_overlapSize.width;
flag = true;
}
if (_container->getPositionY2() > 0)
{
endPos.y = 0;
flag = true;
}
else if (_container->getPositionY2() < -_overlapSize.height)
{
endPos.y = -_overlapSize.height;
flag = true;
}
if (flag)
{
_tweenChange = endPos - _tweenStart;
if (_tweenChange.x < -UIConfig::touchDragSensitivity || _tweenChange.y < -UIConfig::touchDragSensitivity)
_owner->dispatchEvent(UIEventType::PullDownRelease);
else if (_tweenChange.x > UIConfig::touchDragSensitivity || _tweenChange.y > UIConfig::touchDragSensitivity)
_owner->dispatchEvent(UIEventType::PullUpRelease);
if (_headerLockedSize > 0 && sp_getField(endPos, _refreshBarAxis) == 0)
{
sp_setField(endPos, _refreshBarAxis, _headerLockedSize);
_tweenChange = endPos - _tweenStart;
}
else if (_footerLockedSize > 0 && sp_getField(endPos, _refreshBarAxis) == -sp_getField(_overlapSize, _refreshBarAxis))
{
float max = sp_getField(_overlapSize, _refreshBarAxis);
if (max == 0)
max = MAX(sp_getField(_contentSize, _refreshBarAxis) + _footerLockedSize - sp_getField(_viewSize, _refreshBarAxis), 0);
else
max += _footerLockedSize;
sp_setField(endPos, _refreshBarAxis, -max);
_tweenChange = endPos - _tweenStart;
}
_tweenDuration.set(TWEEN_TIME_DEFAULT, TWEEN_TIME_DEFAULT);
}
else
{
if (!_inertiaDisabled)
{
float elapsed = (clock() - _lastMoveTime) / (double)CLOCKS_PER_SEC;
elapsed = elapsed * 60 - 1;
if (elapsed > 1)
_velocity = _velocity * pow(0.833f, elapsed);
endPos = updateTargetAndDuration(_tweenStart);
}
else
_tweenDuration.set(TWEEN_TIME_DEFAULT, TWEEN_TIME_DEFAULT);
Vec2 oldChange = endPos - _tweenStart;
loopCheckingTarget(endPos);
if (_pageMode || _snapToItem)
alignPosition(endPos, true);
_tweenChange = endPos - _tweenStart;
if (_tweenChange.x == 0 && _tweenChange.y == 0)
{
updateScrollBarVisible();
return;
}
if (_pageMode || _snapToItem)
{
fixDuration(0, oldChange.x);
fixDuration(1, oldChange.y);
}
}
startTween(2);
}
void ScrollPane::onMouseWheel(EventContext* context)
{
if (!_mouseWheelEnabled)
return;
InputEvent* evt = context->getInput();
int delta = evt->getMouseWheelDelta();
delta = delta > 0 ? 1 : -1;
if (_overlapSize.width > 0 && _overlapSize.height == 0)
{
if (_pageMode)
setPosX(_xPos + _pageSize.width * delta, false);
else
setPosX(_xPos + _mouseWheelStep * delta, false);
}
else
{
if (_pageMode)
setPosY(_yPos + _pageSize.height * delta, false);
else
setPosY(_yPos + _mouseWheelStep * delta, false);
}
}
void ScrollPane::onRollOver(EventContext* context)
{
_hover = true;
updateScrollBarVisible();
}
void ScrollPane::onRollOut(EventContext* context)
{
_hover = false;
updateScrollBarVisible();
}
NS_FGUI_END