void ScrollView::startAutoScroll(const Vec2& deltaMove, float timeInSec, bool attenuated)
{
    Vec2 adjustedDeltaMove = flattenVectorByDirection(deltaMove);

    _autoScrolling = true;
    _autoScrollTargetDelta = adjustedDeltaMove;
    _autoScrollAttenuate = attenuated;
    _autoScrollStartPosition = _innerContainer->getPosition();
    _autoScrollTotalTime = timeInSec;
    _autoScrollAccumulatedTime = 0;
    _autoScrollBraking = false;
    _autoScrollBrakingStartPosition = Vec2::ZERO;

    // If the destination is also out of boundary of same side, start brake from beginning.
    Vec2 currentOutOfBoundary = getHowMuchOutOfBoundary();
    if (!fltEqualZero(currentOutOfBoundary))
    {
        _autoScrollCurrentlyOutOfBoundary = true;
        Vec2 afterOutOfBoundary = getHowMuchOutOfBoundary(adjustedDeltaMove);
        if(currentOutOfBoundary.x * afterOutOfBoundary.x > 0 || currentOutOfBoundary.y * afterOutOfBoundary.y > 0)
        {
            _autoScrollBraking = true;
        }
    }
}
Example #2
0
void ScrollView::processInertiaScrolling(float dt)
{
    _inertiaScrollElapsedTime += dt;
    if(isOutOfBoundaryLeftOrRight() || isOutOfBoundaryTopOrBottom())
    {
        // If the inner container is out of boundary, shorten the inertia time.
        _inertiaScrollElapsedTime += dt * (45000 / INERTIA_DEACCELERATION);
    }
    float percentage = _inertiaScrollElapsedTime / _inertiaScrollExpectedTime;
    if(percentage >= 1)
    {
        _inertiaScrolling = false;
        startBounceBackIfNeeded();
        return;
    }
    percentage = tweenfunc::quartEaseOut(percentage);
    
    Vec2 inertiaVelocity = _inertiaInitiVelocity * (1 - percentage);
    Vec2 displacement = inertiaVelocity * dt;
    if(!_bounceEnabled)
    {
        Vec2 outOfBoundary = getHowMuchOutOfBoundary(displacement);
        if(outOfBoundary != Vec2::ZERO)
        {
            // Don't allow to go out of boundary
            displacement += outOfBoundary;
            _inertiaScrolling = false;
        }
    }
    moveChildren(displacement.x, displacement.y);
}
Example #3
0
void ScrollView::moveChildrenToPosition(const Vec2& position)
{
    setInnerContainerPosition(position);
    
    Vec2 outOfBoundary = getHowMuchOutOfBoundary(Vec2::ZERO);
    updateScrollBar(outOfBoundary);
}
void ScrollView::onSizeChanged()
{
    Layout::onSizeChanged();
    _topBoundary = _contentSize.height;
    _rightBoundary = _contentSize.width;
    Size innerSize = _innerContainer->getContentSize();
    float orginInnerSizeWidth = innerSize.width;
    float orginInnerSizeHeight = innerSize.height;
    float innerSizeWidth = MAX(orginInnerSizeWidth, _contentSize.width);
    float innerSizeHeight = MAX(orginInnerSizeHeight, _contentSize.height);
    _innerContainer->setContentSize(Size(innerSizeWidth, innerSizeHeight));
    setInnerContainerPosition(Vec2(0, _contentSize.height - _innerContainer->getContentSize().height));

    if (_verticalScrollBar != nullptr)
        _verticalScrollBar->onScrolled(getHowMuchOutOfBoundary());
    if (_horizontalScrollBar != nullptr)
        _horizontalScrollBar->onScrolled(getHowMuchOutOfBoundary());
}
bool ScrollView::isOutOfBoundary(MoveDirection dir)
{
    Vec2 outOfBoundary = getHowMuchOutOfBoundary();
    switch(dir)
    {
        case MoveDirection::TOP: return outOfBoundary.y > 0;
        case MoveDirection::BOTTOM: return outOfBoundary.y < 0;
        case MoveDirection::LEFT: return outOfBoundary.x < 0;
        case MoveDirection::RIGHT: return outOfBoundary.x > 0;
    }
    return false;
}
void ScrollView::processAutoScrolling(float deltaTime)
{
    // Make auto scroll shorter if it needs to deaccelerate.
    float brakingFactor = (isNecessaryAutoScrollBrake() ? OUT_OF_BOUNDARY_BREAKING_FACTOR : 1);
    
    // Elapsed time
    _autoScrollAccumulatedTime += deltaTime * (1 / brakingFactor);
    
    // Calculate the progress percentage
    float percentage = MIN(1, _autoScrollAccumulatedTime / _autoScrollTotalTime);
    if(_autoScrollAttenuate)
    {
        // Use quintic(5th degree) polynomial
        percentage = tweenfunc::quintEaseOut(percentage);
    }
    
    // Calculate the new position
    Vec2 newPosition = _autoScrollStartPosition + (_autoScrollTargetDelta * percentage);
    bool reachedEnd = std::abs(percentage - 1) <= this->getAutoScrollStopEpsilon();
    
    if (reachedEnd)
    {
        newPosition = _autoScrollStartPosition + _autoScrollTargetDelta;
    }

    if(_bounceEnabled)
    {
        // The new position is adjusted if out of boundary
        newPosition = _autoScrollBrakingStartPosition + (newPosition - _autoScrollBrakingStartPosition) * brakingFactor;
    }
    else
    {
        // Don't let go out of boundary
        Vec2 moveDelta = newPosition - getInnerContainerPosition();
        Vec2 outOfBoundary = getHowMuchOutOfBoundary(moveDelta);
        if (!fltEqualZero(outOfBoundary))
        {
            newPosition += outOfBoundary;
            reachedEnd = true;
        }
    }

    // Finish auto scroll if it ended
    if(reachedEnd)
    {
        _autoScrolling = false;
        dispatchEvent(SCROLLVIEW_EVENT_AUTOSCROLL_ENDED, EventType::AUTOSCROLL_ENDED);
    }

    moveInnerContainer(newPosition - getInnerContainerPosition(), reachedEnd);
}
void ScrollView::moveInnerContainer(const Vec2& deltaMove, bool canStartBounceBack)
{
    Vec2 adjustedMove = flattenVectorByDirection(deltaMove);

    setInnerContainerPosition(getInnerContainerPosition() + adjustedMove);

    Vec2 outOfBoundary = getHowMuchOutOfBoundary();
    updateScrollBar(outOfBoundary);

    if(_bounceEnabled && canStartBounceBack)
    {
        startBounceBackIfNeeded();
    }
}
bool ScrollView::startBounceBackIfNeeded()
{
    if (!_bounceEnabled)
    {
        return false;
    }
    Vec2 bounceBackAmount = getHowMuchOutOfBoundary();
    if(fltEqualZero(bounceBackAmount))
    {
        return false;
    }

    startAutoScroll(bounceBackAmount, BOUNCE_BACK_DURATION, true);
    return true;
}
Example #9
0
bool ScrollView::startBounceBackIfNeeded()
{
    if (!_bounceEnabled)
    {
        return false;
    }
    Vec2 outOfBoundary = getHowMuchOutOfBoundary(Vec2::ZERO);
    if(outOfBoundary == Vec2::ZERO)
    {
        return false;
    }

    _bouncingBack = true;
    startAutoScroll(outOfBoundary, BOUNCE_BACK_DURATION, true);
    return true;
}
Example #10
0
void ListView::jumpToItem(ssize_t itemIndex, const Vec2& positionRatioInView, const Vec2& itemAnchorPoint)
{
    Widget* item = getItem(itemIndex);
    if (item == nullptr)
    {
        return;
    }
    doLayout();

    Vec2 destination = calculateItemDestination(positionRatioInView, item, itemAnchorPoint);
    if(!_bounceEnabled)
    {
        Vec2 delta = destination - getInnerContainerPosition();
        Vec2 outOfBoundary = getHowMuchOutOfBoundary(delta);
        destination += outOfBoundary;
    }
    jumpToDestination(destination);
}
Example #11
0
void ListView::startAttenuatingAutoScroll(const Vec2& deltaMove, const Vec2& initialVelocity)
{
    Vec2 adjustedDeltaMove = deltaMove;
    
    if(!_items.empty() && _magneticType != MagneticType::NONE)
    {
        adjustedDeltaMove = flattenVectorByDirection(adjustedDeltaMove);

        // If the destination is out of boundary, do nothing here. Because it will be handled by bouncing back.
        if(getHowMuchOutOfBoundary(adjustedDeltaMove) == Vec2::ZERO)
        {
            MagneticType magType = _magneticType;
            if(magType == MagneticType::BOTH_END)
            {
                if(_direction == Direction::HORIZONTAL)
                {
                    magType = (adjustedDeltaMove.x > 0 ? MagneticType::LEFT : MagneticType::RIGHT);
                }
                else if(_direction == Direction::VERTICAL)
                {
                    magType = (adjustedDeltaMove.y > 0 ? MagneticType::BOTTOM : MagneticType::TOP);
                }
            }
            
            // Adjust the delta move amount according to the magnetic type
            Vec2 magneticAnchorPoint = getAnchorPointByMagneticType(magType);
            Vec2 magneticPosition = -_innerContainer->getPosition();
            magneticPosition.x += getContentSize().width * magneticAnchorPoint.x;
            magneticPosition.y += getContentSize().height * magneticAnchorPoint.y;
            
            Widget* pTargetItem = getClosestItemToPosition(magneticPosition - adjustedDeltaMove, magneticAnchorPoint);
            Vec2 itemPosition = calculateItemPositionWithAnchor(pTargetItem, magneticAnchorPoint);
            adjustedDeltaMove = magneticPosition - itemPosition;
        }
    }
    ScrollView::startAttenuatingAutoScroll(adjustedDeltaMove, initialVelocity);
}
Example #12
0
void ScrollView::scrollChildren(const Vec2& deltaMove)
{
    Vec2 realMove = deltaMove;
    if(_bounceEnabled)
    {
        // If the position of the inner container is out of the boundary, the offsets should be divided by two.
        Vec2 outOfBoundary = getHowMuchOutOfBoundary();
        realMove.x *= (outOfBoundary.x == 0 ? 1 : 0.5f);
        realMove.y *= (outOfBoundary.y == 0 ? 1 : 0.5f);
    }

    if(!_bounceEnabled)
    {
        Vec2 outOfBoundary = getHowMuchOutOfBoundary(realMove);
        realMove += outOfBoundary;
    }

    bool scrolledToLeft = false;
    bool scrolledToRight = false;
    bool scrolledToTop = false;
    bool scrolledToBottom = false;
    if (realMove.y > 0.0f) // up
    {
        float icBottomPos = _innerContainer->getBottomBoundary();
        if (icBottomPos + realMove.y >= _bottomBoundary)
        {
            scrolledToBottom = true;
        }
    }
    else if (realMove.y < 0.0f) // down
    {
        float icTopPos = _innerContainer->getTopBoundary();
        if (icTopPos + realMove.y <= _topBoundary)
        {
            scrolledToTop = true;
        }
    }

    if (realMove.x < 0.0f) // left
    {
        float icRightPos = _innerContainer->getRightBoundary();
        if (icRightPos + realMove.x <= _rightBoundary)
        {
            scrolledToRight = true;
        }
    }
    else if (realMove.x > 0.0f) // right
    {
        float icLeftPos = _innerContainer->getLeftBoundary();
        if (icLeftPos + realMove.x >= _leftBoundary)
        {
            scrolledToLeft = true;
        }
    }
    moveInnerContainer(realMove, false);

    if(realMove.x != 0 || realMove.y != 0)
    {
        processScrollingEvent();
    }
    if(scrolledToBottom)
    {
        processScrollEvent(MoveDirection::BOTTOM, false);
    }
    if(scrolledToTop)
    {
        processScrollEvent(MoveDirection::TOP, false);
    }
    if(scrolledToLeft)
    {
        processScrollEvent(MoveDirection::LEFT, false);
    }
    if(scrolledToRight)
    {
        processScrollEvent(MoveDirection::RIGHT, false);
    }
}
Example #13
0
bool ScrollView::isOutOfBoundary()
{
    return !fltEqualZero(getHowMuchOutOfBoundary());
}
bool ScrollView::isOutOfBoundary()
{
    return getHowMuchOutOfBoundary() != Vec2::ZERO;
}