Use TouchGFX
This commit is contained in:
@ -0,0 +1,384 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2018(-2023) STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file is part of the TouchGFX 4.21.2 distribution.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file in
|
||||
* the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <touchgfx/containers/scrollers/DrawableList.hpp>
|
||||
|
||||
namespace touchgfx
|
||||
{
|
||||
DrawableList::DrawableList()
|
||||
: Container(),
|
||||
isHorizontal(false),
|
||||
isCircular(false),
|
||||
offset(0),
|
||||
itemSize(0),
|
||||
itemMargin(0),
|
||||
numItems(0),
|
||||
numDrawables(0),
|
||||
firstItem(0),
|
||||
firstDrawable(0),
|
||||
drawablesInitialized(false),
|
||||
firstDrawableIndex(0),
|
||||
drawableItems(0),
|
||||
updateDrawable(0)
|
||||
{
|
||||
}
|
||||
|
||||
void DrawableList::setWidth(int16_t width)
|
||||
{
|
||||
Container::setWidth(width);
|
||||
refreshDrawables();
|
||||
}
|
||||
|
||||
void DrawableList::setHeight(int16_t height)
|
||||
{
|
||||
Container::setHeight(height);
|
||||
refreshDrawables();
|
||||
}
|
||||
|
||||
void DrawableList::setHorizontal(bool horizontal)
|
||||
{
|
||||
if ((horizontal && !isHorizontal) || (!horizontal && isHorizontal))
|
||||
{
|
||||
isHorizontal = horizontal;
|
||||
refreshDrawables();
|
||||
}
|
||||
}
|
||||
|
||||
bool DrawableList::getHorizontal() const
|
||||
{
|
||||
return isHorizontal;
|
||||
}
|
||||
|
||||
void DrawableList::setCircular(bool circular)
|
||||
{
|
||||
if ((circular && !isCircular) || (!circular && isCircular))
|
||||
{
|
||||
isCircular = circular;
|
||||
refreshDrawables();
|
||||
}
|
||||
}
|
||||
|
||||
bool DrawableList::getCircular() const
|
||||
{
|
||||
return isCircular;
|
||||
}
|
||||
|
||||
void DrawableList::setDrawableSize(int16_t drawableSize, int16_t drawableMargin)
|
||||
{
|
||||
itemSize = drawableSize + 2 * drawableMargin;
|
||||
itemMargin = drawableMargin;
|
||||
}
|
||||
|
||||
void DrawableList::setDrawables(DrawableListItemsInterface& drawableListItems,
|
||||
int16_t drawableItemIndexOffset,
|
||||
GenericCallback<DrawableListItemsInterface*, int16_t, int16_t>& updateDrawableCallback)
|
||||
{
|
||||
drawableItems = &drawableListItems;
|
||||
firstDrawableIndex = drawableItemIndexOffset;
|
||||
updateDrawable = &updateDrawableCallback;
|
||||
|
||||
refreshDrawables();
|
||||
}
|
||||
|
||||
int16_t DrawableList::getNumberOfDrawables() const
|
||||
{
|
||||
return numDrawables;
|
||||
}
|
||||
|
||||
int16_t DrawableList::getItemSize() const
|
||||
{
|
||||
return itemSize;
|
||||
}
|
||||
|
||||
int16_t DrawableList::getDrawableSize() const
|
||||
{
|
||||
return itemSize - 2 * itemMargin;
|
||||
}
|
||||
|
||||
int16_t DrawableList::getDrawableMargin() const
|
||||
{
|
||||
return itemMargin;
|
||||
}
|
||||
|
||||
void DrawableList::setNumberOfItems(int16_t numberOfItems)
|
||||
{
|
||||
numItems = numberOfItems;
|
||||
refreshDrawables();
|
||||
}
|
||||
|
||||
int16_t DrawableList::getNumberOfItems() const
|
||||
{
|
||||
return numItems;
|
||||
}
|
||||
|
||||
int16_t DrawableList::getRequiredNumberOfDrawables() const
|
||||
{
|
||||
if (drawableItems == 0 || itemSize <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate number of required drawables. Worst case is one pixel visible of drawable at top and rest stacked tightly
|
||||
int16_t requiredDrawables = 1 + (((isHorizontal ? getWidth() : getHeight()) - 1) + (itemSize - 1)) / itemSize;
|
||||
if (!isCircular)
|
||||
{
|
||||
// We never require more drawables than the number of elements on non-circular list.
|
||||
if (requiredDrawables > numItems)
|
||||
{
|
||||
requiredDrawables = numItems;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t numberOfDrawables = drawableItems->getNumberOfDrawables();
|
||||
return MIN((numberOfDrawables - firstDrawableIndex), requiredDrawables);
|
||||
}
|
||||
|
||||
void DrawableList::setOffset(int32_t ofs)
|
||||
{
|
||||
offset = ofs;
|
||||
|
||||
if (numDrawables == 0 || numItems == 0 || itemSize == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!updateDrawable || !updateDrawable->isValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// ofs is the offset of item[0]
|
||||
// 0 => item[0] is perfectly selected, -itemSize => item[1] is perfectly selected, itemSize => item[N-1] is perfectly selected etc.
|
||||
int16_t newFirstItem = 0;
|
||||
if (ofs > 0)
|
||||
{
|
||||
int numberOfItems = ofs / itemSize + 1;
|
||||
newFirstItem -= numberOfItems;
|
||||
ofs -= numberOfItems * itemSize;
|
||||
}
|
||||
if (ofs <= -itemSize)
|
||||
{
|
||||
int numberOfItems = ofs / itemSize;
|
||||
newFirstItem -= numberOfItems;
|
||||
ofs -= numberOfItems * itemSize;
|
||||
}
|
||||
if (isCircular)
|
||||
{
|
||||
// Make sure that firstIndex is "in range"
|
||||
newFirstItem %= numItems;
|
||||
if (newFirstItem < 0)
|
||||
{
|
||||
newFirstItem += numItems;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newFirstItem < 0)
|
||||
{
|
||||
ofs -= newFirstItem * itemSize;
|
||||
newFirstItem = 0;
|
||||
}
|
||||
else if (newFirstItem + numDrawables > numItems)
|
||||
{
|
||||
int x = numItems - (newFirstItem + numDrawables);
|
||||
ofs += x * itemSize;
|
||||
newFirstItem += x;
|
||||
}
|
||||
}
|
||||
|
||||
int drawableDelta = 0;
|
||||
if (drawablesInitialized && firstItem != newFirstItem)
|
||||
{
|
||||
drawableDelta = numDrawables;
|
||||
for (int i = 1; i < numDrawables; i++)
|
||||
{
|
||||
int fi = (firstItem + i);
|
||||
int nfi = (newFirstItem + i);
|
||||
if (isCircular)
|
||||
{
|
||||
fi %= numItems;
|
||||
nfi %= numItems;
|
||||
}
|
||||
if (fi == newFirstItem)
|
||||
{
|
||||
drawableDelta = -i;
|
||||
break;
|
||||
}
|
||||
if (nfi == firstItem)
|
||||
{
|
||||
drawableDelta = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
firstDrawable = ((firstDrawable - drawableDelta) + numDrawables) % numDrawables;
|
||||
firstItem = newFirstItem;
|
||||
|
||||
for (int i = 0; i < numDrawables; i++)
|
||||
{
|
||||
int drawableIndex = (firstDrawable + i) % numDrawables;
|
||||
Drawable* drawable = drawableItems->getDrawable(drawableIndex + firstDrawableIndex);
|
||||
if (isHorizontal)
|
||||
{
|
||||
drawable->moveTo(ofs + i * itemSize + itemMargin, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawable->moveTo(0, ofs + i * itemSize + itemMargin);
|
||||
}
|
||||
|
||||
int itemIndex = i + firstItem;
|
||||
if (isCircular)
|
||||
{
|
||||
itemIndex %= numItems;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (itemIndex < 0 || itemIndex >= numItems)
|
||||
{
|
||||
itemIndex = -1;
|
||||
}
|
||||
}
|
||||
if (itemIndex < 0)
|
||||
{
|
||||
drawable->setVisible(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawable->setVisible(true);
|
||||
// Only fill if first time or outside old range
|
||||
if (!drawablesInitialized || (i < drawableDelta || i >= numDrawables + drawableDelta))
|
||||
{
|
||||
if (updateDrawable->isValid())
|
||||
{
|
||||
updateDrawable->execute(drawableItems, drawableIndex + firstDrawableIndex, itemIndex);
|
||||
drawable->invalidateContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
drawablesInitialized = true;
|
||||
}
|
||||
|
||||
int32_t DrawableList::getOffset() const
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
|
||||
int16_t DrawableList::getItemIndex(int16_t drawableIndex) const
|
||||
{
|
||||
if (drawableIndex < 0 || drawableIndex >= numDrawables || numDrawables == 0 || numItems == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
int16_t itemNumber = ((drawableIndex + numDrawables - firstDrawable) % numDrawables) + firstItem;
|
||||
if (isCircular)
|
||||
{
|
||||
itemNumber %= numItems;
|
||||
}
|
||||
if (itemNumber < 0 || itemNumber >= numItems)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return itemNumber;
|
||||
}
|
||||
|
||||
int16_t DrawableList::getDrawableIndices(int16_t itemIndex, int16_t* drawableIndexArray, int16_t arraySize) const
|
||||
{
|
||||
int16_t numFound = 0;
|
||||
int16_t drawableIndex = -1;
|
||||
while ((drawableIndex = getDrawableIndex(itemIndex, drawableIndex)) >= 0)
|
||||
{
|
||||
if (numFound < arraySize)
|
||||
{
|
||||
drawableIndexArray[numFound] = drawableIndex;
|
||||
numFound++;
|
||||
}
|
||||
}
|
||||
return numFound;
|
||||
}
|
||||
|
||||
int16_t DrawableList::getDrawableIndex(int16_t itemIndex, int16_t prevDrawableIndex /*= -1*/) const
|
||||
{
|
||||
if (prevDrawableIndex < -1 || prevDrawableIndex >= numDrawables || numDrawables == 0 || numItems == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (prevDrawableIndex >= 0)
|
||||
{
|
||||
prevDrawableIndex = ((prevDrawableIndex - firstDrawable) + numDrawables) % numDrawables;
|
||||
}
|
||||
for (int16_t i = prevDrawableIndex + 1; i < numDrawables; i++)
|
||||
{
|
||||
int16_t currentItemIndex = firstItem + i;
|
||||
if (isCircular)
|
||||
{
|
||||
currentItemIndex %= numItems;
|
||||
}
|
||||
if (itemIndex == currentItemIndex)
|
||||
{
|
||||
int16_t drawableIndex = (firstDrawable + i) % numDrawables;
|
||||
return drawableIndex;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void DrawableList::refreshDrawables()
|
||||
{
|
||||
if (drawableItems == 0)
|
||||
{
|
||||
numDrawables = 0;
|
||||
return;
|
||||
}
|
||||
numDrawables = getRequiredNumberOfDrawables();
|
||||
// Remove everything
|
||||
Container::removeAll();
|
||||
// Add the itemDrawables
|
||||
for (int drawableIndex = 0; drawableIndex < numDrawables; drawableIndex++)
|
||||
{
|
||||
Drawable* drawable = drawableItems->getDrawable(drawableIndex + firstDrawableIndex);
|
||||
// Resize the drawables, X/Y ignored for now.
|
||||
if (isHorizontal)
|
||||
{
|
||||
drawable->setPosition(0, 0, itemSize - 2 * itemMargin, getHeight());
|
||||
}
|
||||
else
|
||||
{
|
||||
drawable->setPosition(0, 0, getWidth(), itemSize - 2 * itemMargin);
|
||||
}
|
||||
// Add each drawable for later positioning
|
||||
if (drawable->getParent() != 0)
|
||||
{
|
||||
// Remove drawable from the current parent
|
||||
static_cast<Container*>(drawable->getParent())->remove(*drawable);
|
||||
}
|
||||
Container::add(*drawable);
|
||||
}
|
||||
|
||||
drawablesInitialized = false;
|
||||
firstItem = 0;
|
||||
firstDrawable = 0;
|
||||
setOffset(offset);
|
||||
}
|
||||
|
||||
void DrawableList::itemChanged(int16_t itemIndex)
|
||||
{
|
||||
if (updateDrawable && updateDrawable->isValid())
|
||||
{
|
||||
int16_t drawableIndex = -1;
|
||||
while ((drawableIndex = getDrawableIndex(itemIndex, drawableIndex)) != -1)
|
||||
{
|
||||
updateDrawable->execute(drawableItems, drawableIndex + firstDrawableIndex, itemIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace touchgfx
|
||||
@ -0,0 +1,339 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2018(-2023) STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file is part of the TouchGFX 4.21.2 distribution.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file in
|
||||
* the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <touchgfx/Application.hpp>
|
||||
#include <touchgfx/Drawable.hpp>
|
||||
#include <touchgfx/Utils.hpp>
|
||||
#include <touchgfx/containers/scrollers/ScrollBase.hpp>
|
||||
|
||||
namespace touchgfx
|
||||
{
|
||||
ScrollBase::ScrollBase()
|
||||
: Container(),
|
||||
list(),
|
||||
numberOfDrawables(0),
|
||||
distanceBeforeAlignedItem(0),
|
||||
itemSize(0),
|
||||
swipeAcceleration(10),
|
||||
dragAcceleration(10),
|
||||
maxSwipeItems(0),
|
||||
easingEquation(&EasingEquations::backEaseOut),
|
||||
defaultAnimationSteps(30),
|
||||
overshootPercentage(75),
|
||||
itemSelectedCallback(0),
|
||||
itemLockedInCallback(0),
|
||||
animationEndedCallback(0),
|
||||
itemPressedCallback(0),
|
||||
currentAnimationState(NO_ANIMATION),
|
||||
gestureStep(0),
|
||||
gestureStepsTotal(0),
|
||||
gestureStart(0),
|
||||
gestureEnd(0),
|
||||
xClick(0),
|
||||
yClick(0),
|
||||
initialSwipeOffset(0),
|
||||
draggableX(false),
|
||||
draggableY(false)
|
||||
{
|
||||
Container::add(list);
|
||||
list.setXY(0, 0);
|
||||
list.setHorizontal(false);
|
||||
list.setCircular(false);
|
||||
setTouchable(true);
|
||||
}
|
||||
|
||||
void ScrollBase::setWidth(int16_t width)
|
||||
{
|
||||
Container::setWidth(width);
|
||||
list.setWidth(width);
|
||||
}
|
||||
|
||||
void ScrollBase::setHeight(int16_t height)
|
||||
{
|
||||
Container::setHeight(height);
|
||||
list.setHeight(height);
|
||||
}
|
||||
|
||||
void ScrollBase::setHorizontal(bool horizontal)
|
||||
{
|
||||
allowVerticalDrag(horizontal);
|
||||
allowHorizontalDrag(!horizontal);
|
||||
list.setHorizontal(horizontal);
|
||||
}
|
||||
|
||||
bool ScrollBase::getHorizontal() const
|
||||
{
|
||||
return list.getHorizontal();
|
||||
}
|
||||
|
||||
void ScrollBase::setCircular(bool circular)
|
||||
{
|
||||
list.setCircular(circular);
|
||||
}
|
||||
|
||||
bool ScrollBase::getCircular() const
|
||||
{
|
||||
return list.getCircular();
|
||||
}
|
||||
|
||||
void ScrollBase::setDrawableSize(int16_t drawableSize, int16_t drawableMargin)
|
||||
{
|
||||
itemSize = drawableSize + drawableMargin * 2;
|
||||
list.setDrawableSize(drawableSize, drawableMargin);
|
||||
}
|
||||
|
||||
int16_t ScrollBase::getDrawableSize() const
|
||||
{
|
||||
return list.getDrawableSize();
|
||||
}
|
||||
|
||||
int16_t ScrollBase::getDrawableMargin() const
|
||||
{
|
||||
return list.getDrawableMargin();
|
||||
}
|
||||
|
||||
void ScrollBase::setNumberOfItems(int16_t numberOfItems)
|
||||
{
|
||||
if (numberOfItems != getNumberOfItems())
|
||||
{
|
||||
list.setNumberOfItems(numberOfItems);
|
||||
if (!getCircular())
|
||||
{
|
||||
animateToPosition(keepOffsetInsideLimits(getOffset(), 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int16_t ScrollBase::getNumberOfItems() const
|
||||
{
|
||||
return list.getNumberOfItems();
|
||||
}
|
||||
|
||||
void ScrollBase::setEasingEquation(EasingEquation equation)
|
||||
{
|
||||
easingEquation = equation;
|
||||
}
|
||||
|
||||
void ScrollBase::setAnimationSteps(int16_t steps)
|
||||
{
|
||||
defaultAnimationSteps = steps;
|
||||
}
|
||||
|
||||
uint16_t ScrollBase::getAnimationSteps() const
|
||||
{
|
||||
return defaultAnimationSteps;
|
||||
}
|
||||
|
||||
void ScrollBase::setSwipeAcceleration(uint16_t acceleration)
|
||||
{
|
||||
swipeAcceleration = acceleration;
|
||||
}
|
||||
|
||||
uint16_t ScrollBase::getSwipeAcceleration() const
|
||||
{
|
||||
return swipeAcceleration;
|
||||
}
|
||||
|
||||
void ScrollBase::setMaxSwipeItems(uint16_t maxItems)
|
||||
{
|
||||
maxSwipeItems = maxItems;
|
||||
}
|
||||
|
||||
uint16_t ScrollBase::getMaxSwipeItems() const
|
||||
{
|
||||
return maxSwipeItems;
|
||||
}
|
||||
|
||||
void ScrollBase::setDragAcceleration(uint16_t acceleration)
|
||||
{
|
||||
dragAcceleration = acceleration;
|
||||
}
|
||||
|
||||
uint16_t ScrollBase::getDragAcceleration() const
|
||||
{
|
||||
return dragAcceleration;
|
||||
}
|
||||
|
||||
void ScrollBase::allowHorizontalDrag(bool enable)
|
||||
{
|
||||
draggableX = enable;
|
||||
}
|
||||
|
||||
void ScrollBase::allowVerticalDrag(bool enable)
|
||||
{
|
||||
draggableY = enable;
|
||||
}
|
||||
|
||||
void ScrollBase::animateToItem(int16_t itemIndex, int16_t animationSteps /*= -1*/)
|
||||
{
|
||||
int32_t position = getPositionForItem(itemIndex);
|
||||
animateToPosition(position, animationSteps);
|
||||
}
|
||||
|
||||
void ScrollBase::setItemSelectedCallback(GenericCallback<int16_t>& callback)
|
||||
{
|
||||
itemSelectedCallback = &callback;
|
||||
}
|
||||
|
||||
void ScrollBase::setAnimationEndedCallback(GenericCallback<>& callback)
|
||||
{
|
||||
animationEndedCallback = &callback;
|
||||
}
|
||||
|
||||
void ScrollBase::setItemPressedCallback(GenericCallback<int16_t>& callback)
|
||||
{
|
||||
itemPressedCallback = &callback;
|
||||
}
|
||||
|
||||
bool ScrollBase::isAnimating() const
|
||||
{
|
||||
return currentAnimationState != NO_ANIMATION;
|
||||
}
|
||||
|
||||
void ScrollBase::stopAnimation()
|
||||
{
|
||||
if (currentAnimationState == ANIMATING_GESTURE)
|
||||
{
|
||||
Application::getInstance()->unregisterTimerWidget(this);
|
||||
setOffset(gestureEnd);
|
||||
}
|
||||
currentAnimationState = NO_ANIMATION;
|
||||
}
|
||||
|
||||
void ScrollBase::handleDragEvent(const DragEvent& event)
|
||||
{
|
||||
stopAnimation();
|
||||
currentAnimationState = ANIMATING_DRAG;
|
||||
int32_t newOffset = getOffset() + (getHorizontal() ? event.getDeltaX() : event.getDeltaY()) * dragAcceleration / 10;
|
||||
newOffset = keepOffsetInsideLimits(newOffset, muldiv(itemSize, overshootPercentage, 100));
|
||||
setOffset(newOffset);
|
||||
}
|
||||
|
||||
void ScrollBase::handleGestureEvent(const GestureEvent& event)
|
||||
{
|
||||
if (event.getType() == (getHorizontal() ? GestureEvent::SWIPE_HORIZONTAL : GestureEvent::SWIPE_VERTICAL))
|
||||
{
|
||||
int16_t velocity = abs(event.getVelocity());
|
||||
int16_t direction = event.getVelocity() < 0 ? -1 : 1;
|
||||
int16_t steps = MAX(1, velocity - 4) * 7;
|
||||
int32_t newOffset = getOffset() + direction * steps * swipeAcceleration / 10;
|
||||
if (maxSwipeItems > 0)
|
||||
{
|
||||
int32_t maxDistance = maxSwipeItems * itemSize;
|
||||
newOffset = MIN(newOffset, initialSwipeOffset + maxDistance);
|
||||
newOffset = MAX(newOffset, initialSwipeOffset - maxDistance);
|
||||
}
|
||||
newOffset = keepOffsetInsideLimits(newOffset, 0);
|
||||
steps = MIN(steps, defaultAnimationSteps);
|
||||
animateToPosition(newOffset, steps);
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollBase::handleTickEvent()
|
||||
{
|
||||
if (currentAnimationState == ANIMATING_GESTURE)
|
||||
{
|
||||
gestureStep++;
|
||||
int newPosition = gestureStart + easingEquation(gestureStep, 0, gestureEnd - gestureStart, gestureStepsTotal);
|
||||
setOffset(newPosition);
|
||||
if (gestureStep > gestureStepsTotal)
|
||||
{
|
||||
currentAnimationState = NO_ANIMATION;
|
||||
gestureStep = 0;
|
||||
Application::getInstance()->unregisterTimerWidget(this);
|
||||
setOffset(getNormalizedOffset(gestureEnd));
|
||||
// Also adjust initialSwipeOffset in case it is being used.
|
||||
initialSwipeOffset += getOffset() - gestureEnd;
|
||||
|
||||
// Item has settled, call back
|
||||
if (animationEndedCallback && animationEndedCallback->isValid())
|
||||
{
|
||||
animationEndedCallback->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollBase::itemChanged(int itemIndex)
|
||||
{
|
||||
list.itemChanged(itemIndex);
|
||||
}
|
||||
|
||||
void ScrollBase::setOffset(int32_t offset)
|
||||
{
|
||||
list.setOffset(offset + distanceBeforeAlignedItem);
|
||||
}
|
||||
|
||||
int32_t ScrollBase::getOffset() const
|
||||
{
|
||||
return list.getOffset() - distanceBeforeAlignedItem;
|
||||
}
|
||||
|
||||
int ScrollBase::getNormalizedOffset(int offset) const
|
||||
{
|
||||
int16_t numItems = getNumberOfItems();
|
||||
if (numItems == 0 || itemSize == 0)
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
int32_t listSize = numItems * itemSize;
|
||||
offset %= listSize;
|
||||
return offset > 0 ? offset - listSize : offset;
|
||||
}
|
||||
|
||||
int32_t ScrollBase::getNearestAlignedOffset(int32_t offset) const
|
||||
{
|
||||
if (itemSize == 0)
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
if (getCircular())
|
||||
{
|
||||
if (offset < 0)
|
||||
{
|
||||
return (((offset - (itemSize / 2)) / itemSize) * itemSize);
|
||||
}
|
||||
return ((offset + (itemSize / 2)) / itemSize) * itemSize;
|
||||
}
|
||||
offset = keepOffsetInsideLimits(offset, 0);
|
||||
return ((offset - (itemSize / 2)) / itemSize) * itemSize;
|
||||
}
|
||||
|
||||
void ScrollBase::animateToPosition(int32_t position, int16_t steps)
|
||||
{
|
||||
int32_t currentPosition = getOffset();
|
||||
position = getNearestAlignedOffset(position);
|
||||
if (steps < 0)
|
||||
{
|
||||
steps = defaultAnimationSteps;
|
||||
}
|
||||
const int32_t distance = abs(position - currentPosition);
|
||||
steps = MIN(steps, distance);
|
||||
if (steps < 1)
|
||||
{
|
||||
setOffset(position);
|
||||
currentAnimationState = NO_ANIMATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
gestureStart = currentPosition;
|
||||
gestureEnd = position;
|
||||
gestureStep = 0;
|
||||
gestureStepsTotal = steps;
|
||||
if (currentAnimationState != ANIMATING_GESTURE)
|
||||
{
|
||||
Application::getInstance()->registerTimerWidget(this);
|
||||
currentAnimationState = ANIMATING_GESTURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace touchgfx
|
||||
@ -0,0 +1,257 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2018(-2023) STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file is part of the TouchGFX 4.21.2 distribution.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file in
|
||||
* the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <touchgfx/Utils.hpp>
|
||||
#include <touchgfx/containers/scrollers/ScrollList.hpp>
|
||||
|
||||
namespace touchgfx
|
||||
{
|
||||
ScrollList::ScrollList()
|
||||
: ScrollBase(),
|
||||
paddingAfterLastItem(0),
|
||||
snapping(false),
|
||||
windowSize(1)
|
||||
{
|
||||
}
|
||||
|
||||
void ScrollList::setWidth(int16_t width)
|
||||
{
|
||||
ScrollBase::setWidth(width);
|
||||
if (getHorizontal())
|
||||
{
|
||||
setWindowSize(windowSize);
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollList::setHeight(int16_t height)
|
||||
{
|
||||
ScrollBase::setHeight(height);
|
||||
if (!getHorizontal())
|
||||
{
|
||||
setWindowSize(windowSize);
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollList::setDrawableSize(int16_t drawableSize, int16_t drawableMargin)
|
||||
{
|
||||
ScrollBase::setDrawableSize(drawableSize, drawableMargin);
|
||||
setWindowSize(windowSize);
|
||||
}
|
||||
|
||||
void ScrollList::setDrawables(DrawableListItemsInterface& drawableListItems, GenericCallback<DrawableListItemsInterface*, int16_t, int16_t>& updateDrawableCallback)
|
||||
{
|
||||
stopAnimation();
|
||||
numberOfDrawables = drawableListItems.getNumberOfDrawables();
|
||||
list.setDrawables(drawableListItems, 0, updateDrawableCallback);
|
||||
setOffset(0);
|
||||
}
|
||||
|
||||
void ScrollList::setWindowSize(int16_t items)
|
||||
{
|
||||
if (itemSize > 0)
|
||||
{
|
||||
const int16_t widgetSize = getHorizontal() ? getWidth() : getHeight();
|
||||
const int16_t activeWidgetSize = widgetSize - (distanceBeforeAlignedItem + paddingAfterLastItem);
|
||||
const int16_t numberOfVisibleItems = (activeWidgetSize + itemSize / 2) / itemSize; // Round up
|
||||
items = MIN(items, numberOfVisibleItems); // No more than numberOfVisibleItems
|
||||
}
|
||||
windowSize = MAX(1, items); // No less than 1
|
||||
animateToPosition(keepOffsetInsideLimits(getOffset(), 0));
|
||||
}
|
||||
|
||||
void ScrollList::setPadding(int16_t paddingBefore, int16_t paddingAfter)
|
||||
{
|
||||
int32_t currentOffset = getOffset();
|
||||
distanceBeforeAlignedItem = paddingBefore;
|
||||
paddingAfterLastItem = paddingAfter;
|
||||
setOffset(currentOffset);
|
||||
list.refreshDrawables();
|
||||
}
|
||||
|
||||
int16_t ScrollList::getPaddingBefore() const
|
||||
{
|
||||
return distanceBeforeAlignedItem;
|
||||
}
|
||||
|
||||
int16_t ScrollList::getPaddingAfter() const
|
||||
{
|
||||
return paddingAfterLastItem;
|
||||
}
|
||||
|
||||
void ScrollList::setSnapping(bool snap)
|
||||
{
|
||||
snapping = snap;
|
||||
if (snapping)
|
||||
{
|
||||
setOffset(getNearestAlignedOffset(getOffset()));
|
||||
}
|
||||
}
|
||||
|
||||
bool ScrollList::getSnapping() const
|
||||
{
|
||||
return snapping;
|
||||
}
|
||||
|
||||
int32_t ScrollList::getPositionForItem(int16_t itemIndex)
|
||||
{
|
||||
int32_t currentOffset = getNormalizedOffset(getOffset());
|
||||
if (itemIndex < 0 || itemIndex >= list.getNumberOfItems() || itemSize == 0)
|
||||
{
|
||||
return currentOffset;
|
||||
}
|
||||
int32_t itemOffset = -itemIndex * itemSize;
|
||||
// Get the visible size
|
||||
const int16_t widgetSize = getHorizontal() ? getWidth() : getHeight();
|
||||
const int16_t activeWidgetSize = widgetSize - (distanceBeforeAlignedItem + paddingAfterLastItem);
|
||||
if (list.getCircular())
|
||||
{
|
||||
int32_t offset = currentOffset;
|
||||
// Important this is a do-while of visibleSize < itemSize in which case we need to check at least one time
|
||||
do
|
||||
{
|
||||
int16_t i = (-getNormalizedOffset(offset)) / itemSize; // Item index of first
|
||||
if (itemIndex == i)
|
||||
{
|
||||
return currentOffset;
|
||||
}
|
||||
offset -= itemSize;
|
||||
} while (offset >= currentOffset - (activeWidgetSize - itemSize));
|
||||
int32_t allItemsSize = list.getNumberOfItems() * itemSize;
|
||||
// Either scroll left from the first item or right from the last item. Find out which is closest
|
||||
int32_t leftScrollDistance = itemOffset - currentOffset;
|
||||
int32_t leftScrollDistance2 = (itemOffset + allItemsSize) - currentOffset;
|
||||
int32_t rightItemOffset = getNormalizedOffset(currentOffset - (activeWidgetSize - itemSize));
|
||||
int32_t rightScrollDistance = rightItemOffset - itemOffset;
|
||||
int32_t rightScrollDistance2 = rightItemOffset - (itemOffset - allItemsSize);
|
||||
if (abs(leftScrollDistance2) < abs(leftScrollDistance))
|
||||
{
|
||||
leftScrollDistance = leftScrollDistance2;
|
||||
}
|
||||
if (abs(rightScrollDistance2) < abs(rightScrollDistance))
|
||||
{
|
||||
rightScrollDistance = rightScrollDistance2;
|
||||
}
|
||||
if (abs(rightScrollDistance) < abs(leftScrollDistance))
|
||||
{
|
||||
return currentOffset - rightScrollDistance;
|
||||
}
|
||||
return currentOffset + leftScrollDistance;
|
||||
}
|
||||
|
||||
if (itemOffset > currentOffset) // First item on screen is higher than the itemIndex. Scroll itemIndex to top position
|
||||
{
|
||||
return itemOffset;
|
||||
}
|
||||
const int16_t numberOfVisibleItems = activeWidgetSize / itemSize;
|
||||
int32_t itemOffsetAtEnd = itemOffset;
|
||||
if (numberOfVisibleItems > 0)
|
||||
{
|
||||
if (snapping)
|
||||
{
|
||||
itemOffsetAtEnd = itemOffset + (numberOfVisibleItems - 1) * itemSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemOffsetAtEnd = itemOffset + activeWidgetSize - itemSize;
|
||||
}
|
||||
}
|
||||
if (itemOffsetAtEnd < currentOffset)
|
||||
{
|
||||
return itemOffsetAtEnd;
|
||||
}
|
||||
return currentOffset;
|
||||
}
|
||||
|
||||
void ScrollList::handleClickEvent(const ClickEvent& event)
|
||||
{
|
||||
ScrollBase::handleClickEvent(event);
|
||||
if (event.getType() == ClickEvent::PRESSED)
|
||||
{
|
||||
xClick = event.getX();
|
||||
yClick = event.getY();
|
||||
initialSwipeOffset = getOffset();
|
||||
|
||||
setOffset(getNearestAlignedOffset(initialSwipeOffset));
|
||||
if (itemPressedCallback && itemPressedCallback->isValid())
|
||||
{
|
||||
int16_t click = (getHorizontal() ? xClick : yClick);
|
||||
int32_t offset = click - getOffset();
|
||||
int32_t listSize = getNumberOfItems() * itemSize;
|
||||
if (getCircular())
|
||||
{
|
||||
offset += listSize;
|
||||
offset %= listSize;
|
||||
}
|
||||
if (offset >= 0 && offset < listSize)
|
||||
{
|
||||
int16_t item = offset / itemSize;
|
||||
itemPressedCallback->execute(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (event.getType() == ClickEvent::RELEASED)
|
||||
{
|
||||
if (currentAnimationState == NO_ANIMATION)
|
||||
{
|
||||
// For a tiny drag, start by re-aligning (no animation(!))
|
||||
setOffset(getNearestAlignedOffset(getOffset()));
|
||||
if (itemSelectedCallback && itemSelectedCallback->isValid())
|
||||
{
|
||||
int16_t click = (getHorizontal() ? xClick : yClick);
|
||||
int32_t offset = click - getOffset();
|
||||
int32_t listSize = getNumberOfItems() * itemSize;
|
||||
if (getCircular())
|
||||
{
|
||||
offset += listSize;
|
||||
offset %= listSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset -= distanceBeforeAlignedItem;
|
||||
}
|
||||
if (offset >= 0 && offset < listSize)
|
||||
{
|
||||
int16_t item = offset / itemSize;
|
||||
itemSelectedCallback->execute(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (currentAnimationState == ANIMATING_DRAG)
|
||||
{
|
||||
// click + drag + release. Find best Y to scroll to
|
||||
animateToPosition(getNearestAlignedOffset(getOffset()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t ScrollList::getNearestAlignedOffset(int32_t offset) const
|
||||
{
|
||||
if (snapping)
|
||||
{
|
||||
// ScrollBase implementation will snap
|
||||
return ScrollBase::getNearestAlignedOffset(offset);
|
||||
}
|
||||
|
||||
return keepOffsetInsideLimits(offset, 0);
|
||||
}
|
||||
|
||||
int32_t ScrollList::keepOffsetInsideLimits(int32_t newOffset, int16_t overShoot) const
|
||||
{
|
||||
if (!getCircular())
|
||||
{
|
||||
newOffset = MIN(newOffset, overShoot);
|
||||
int maxOffToTheStart = windowSize < getNumberOfItems() ? getNumberOfItems() - windowSize : 0;
|
||||
newOffset = MAX(newOffset, -(itemSize * maxOffToTheStart) - overShoot);
|
||||
}
|
||||
return newOffset;
|
||||
}
|
||||
} // namespace touchgfx
|
||||
@ -0,0 +1,26 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2018(-2023) STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file is part of the TouchGFX 4.21.2 distribution.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file in
|
||||
* the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <touchgfx/containers/scrollers/ScrollWheel.hpp>
|
||||
|
||||
namespace touchgfx
|
||||
{
|
||||
void ScrollWheel::setDrawables(DrawableListItemsInterface& drawableListItems, GenericCallback<DrawableListItemsInterface*, int16_t, int16_t>& updateDrawableCallback)
|
||||
{
|
||||
stopAnimation();
|
||||
numberOfDrawables = drawableListItems.getNumberOfDrawables();
|
||||
|
||||
list.setDrawables(drawableListItems, 0, updateDrawableCallback);
|
||||
|
||||
setOffset(0);
|
||||
}
|
||||
} // namespace touchgfx
|
||||
@ -0,0 +1,177 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2018(-2023) STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file is part of the TouchGFX 4.21.2 distribution.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file in
|
||||
* the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <touchgfx/Drawable.hpp>
|
||||
#include <touchgfx/Utils.hpp>
|
||||
#include <touchgfx/containers/scrollers/ScrollWheelBase.hpp>
|
||||
|
||||
namespace touchgfx
|
||||
{
|
||||
ScrollWheelBase::ScrollWheelBase()
|
||||
: ScrollBase(),
|
||||
animateToCallback(0)
|
||||
{
|
||||
ScrollWheelBase::setHorizontal(false);
|
||||
setTouchable(true);
|
||||
}
|
||||
|
||||
void ScrollWheelBase::setSelectedItemOffset(int16_t offset)
|
||||
{
|
||||
int32_t currentOffset = getOffset();
|
||||
distanceBeforeAlignedItem = offset;
|
||||
setOffset(currentOffset);
|
||||
}
|
||||
|
||||
int16_t ScrollWheelBase::getSelectedItemOffset() const
|
||||
{
|
||||
return distanceBeforeAlignedItem;
|
||||
}
|
||||
|
||||
int32_t ScrollWheelBase::getPositionForItem(int16_t itemIndex)
|
||||
{
|
||||
int32_t newOffset = -itemIndex * itemSize;
|
||||
if (getCircular())
|
||||
{
|
||||
// Check if it is closer to scroll backwards
|
||||
int32_t otherOffset = newOffset + getNumberOfItems() * itemSize;
|
||||
int32_t offset = getOffset();
|
||||
if (abs(otherOffset - offset) < abs(newOffset - offset))
|
||||
{
|
||||
newOffset = otherOffset;
|
||||
}
|
||||
}
|
||||
return newOffset;
|
||||
}
|
||||
|
||||
void ScrollWheelBase::animateToPosition(int32_t position, int16_t steps)
|
||||
{
|
||||
if (itemSize == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (animateToCallback && animateToCallback->isValid() && itemSize > 0)
|
||||
{
|
||||
position = getNearestAlignedOffset(position);
|
||||
int16_t itemIndex = (-position) / itemSize;
|
||||
animateToCallback->execute(itemIndex);
|
||||
}
|
||||
ScrollBase::animateToPosition(position, steps);
|
||||
}
|
||||
|
||||
int ScrollWheelBase::getSelectedItem() const
|
||||
{
|
||||
if (itemSize == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (currentAnimationState == ANIMATING_GESTURE)
|
||||
{
|
||||
// Scroll in progress, get the destination value
|
||||
return (-getNormalizedOffset(gestureEnd)) / itemSize;
|
||||
}
|
||||
return (-getNormalizedOffset(getOffset())) / itemSize;
|
||||
}
|
||||
|
||||
int32_t ScrollWheelBase::keepOffsetInsideLimits(int32_t newOffset, int16_t overShoot) const
|
||||
{
|
||||
if (!getCircular())
|
||||
{
|
||||
newOffset = MIN(newOffset, overShoot);
|
||||
int16_t numberOfItems = getNumberOfItems();
|
||||
newOffset = MAX(newOffset, -(itemSize * (numberOfItems - 1)) - overShoot);
|
||||
}
|
||||
return newOffset;
|
||||
}
|
||||
|
||||
void ScrollWheelBase::handleClickEvent(const ClickEvent& event)
|
||||
{
|
||||
if (itemSize == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int32_t offset = getOffset();
|
||||
if (event.getType() == ClickEvent::PRESSED)
|
||||
{
|
||||
xClick = event.getX();
|
||||
yClick = event.getY();
|
||||
initialSwipeOffset = offset;
|
||||
|
||||
if (itemPressedCallback && itemPressedCallback->isValid())
|
||||
{
|
||||
itemPressedCallback->execute(getSelectedItem());
|
||||
}
|
||||
}
|
||||
else if (event.getType() == ClickEvent::RELEASED)
|
||||
{
|
||||
if (currentAnimationState == NO_ANIMATION)
|
||||
{
|
||||
int16_t click = getHorizontal() ? xClick : yClick;
|
||||
// Click => move to clicked position
|
||||
if (click < distanceBeforeAlignedItem)
|
||||
{
|
||||
animateToPosition(offset + ((distanceBeforeAlignedItem - click) / itemSize + 1) * itemSize);
|
||||
}
|
||||
else if (click > distanceBeforeAlignedItem + itemSize)
|
||||
{
|
||||
animateToPosition(offset - ((click - distanceBeforeAlignedItem) / itemSize) * itemSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
animateToPosition(offset);
|
||||
}
|
||||
}
|
||||
else if (currentAnimationState == ANIMATING_DRAG)
|
||||
{
|
||||
// click + drag + release. Find best Y to scroll to
|
||||
animateToPosition(offset);
|
||||
}
|
||||
|
||||
if (itemSelectedCallback && itemSelectedCallback->isValid())
|
||||
{
|
||||
itemSelectedCallback->execute(getSelectedItem());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollWheelBase::handleDragEvent(const DragEvent& event)
|
||||
{
|
||||
currentAnimationState = ANIMATING_DRAG;
|
||||
int newOffset = getOffset() + (getHorizontal() ? event.getDeltaX() : event.getDeltaY()) * dragAcceleration / 10;
|
||||
if (!getCircular())
|
||||
{
|
||||
newOffset = MIN(newOffset, itemSize * 3 / 4);
|
||||
int16_t numberOfItems = getNumberOfItems();
|
||||
newOffset = MAX(newOffset, -(itemSize * (numberOfItems - 1)) - itemSize * 3 / 4);
|
||||
}
|
||||
setOffset(newOffset);
|
||||
}
|
||||
|
||||
void ScrollWheelBase::handleGestureEvent(const GestureEvent& event)
|
||||
{
|
||||
if (event.getType() == (getHorizontal() ? GestureEvent::SWIPE_HORIZONTAL : GestureEvent::SWIPE_VERTICAL))
|
||||
{
|
||||
int32_t newOffset = getOffset() + event.getVelocity() * swipeAcceleration / 10;
|
||||
if (maxSwipeItems > 0)
|
||||
{
|
||||
int32_t maxDistance = maxSwipeItems * itemSize;
|
||||
newOffset = MIN(newOffset, initialSwipeOffset + maxDistance);
|
||||
newOffset = MAX(newOffset, initialSwipeOffset - maxDistance);
|
||||
}
|
||||
animateToPosition(newOffset);
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollWheelBase::setAnimateToCallback(GenericCallback<int16_t>& callback)
|
||||
{
|
||||
animateToCallback = &callback;
|
||||
}
|
||||
} // namespace touchgfx
|
||||
@ -0,0 +1,202 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2018(-2023) STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file is part of the TouchGFX 4.21.2 distribution.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file in
|
||||
* the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <touchgfx/containers/scrollers/ScrollWheelWithSelectionStyle.hpp>
|
||||
|
||||
namespace touchgfx
|
||||
{
|
||||
ScrollWheelWithSelectionStyle::ScrollWheelWithSelectionStyle()
|
||||
: ScrollWheelBase(),
|
||||
drawablesInFirstList(0),
|
||||
list1(),
|
||||
list2(),
|
||||
extraSizeBeforeSelectedItem(0),
|
||||
extraSizeAfterSelectedItem(0),
|
||||
marginBeforeSelectedItem(0),
|
||||
marginAfterSelectedItem(0),
|
||||
drawables(0),
|
||||
centerDrawables(0),
|
||||
originalUpdateDrawableCallback(0),
|
||||
originalUpdateCenterDrawableCallback(0)
|
||||
{
|
||||
ScrollWheelBase::add(list2);
|
||||
ScrollWheelBase::add(list1); // Put center list at top of the first/last list.
|
||||
}
|
||||
|
||||
void ScrollWheelWithSelectionStyle::setWidth(int16_t width)
|
||||
{
|
||||
ScrollWheelBase::setWidth(width);
|
||||
if (getHorizontal())
|
||||
{
|
||||
refreshDrawableListsLayout();
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollWheelWithSelectionStyle::setHeight(int16_t height)
|
||||
{
|
||||
ScrollWheelBase::setHeight(height);
|
||||
if (!getHorizontal())
|
||||
{
|
||||
refreshDrawableListsLayout();
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollWheelWithSelectionStyle::setHorizontal(bool horizontal)
|
||||
{
|
||||
ScrollWheelBase::setHorizontal(horizontal);
|
||||
list1.setHorizontal(horizontal);
|
||||
list2.setHorizontal(horizontal);
|
||||
refreshDrawableListsLayout();
|
||||
}
|
||||
|
||||
void ScrollWheelWithSelectionStyle::setCircular(bool circular)
|
||||
{
|
||||
ScrollWheelBase::setCircular(circular);
|
||||
list1.setCircular(circular);
|
||||
list2.setCircular(circular);
|
||||
}
|
||||
|
||||
void ScrollWheelWithSelectionStyle::setNumberOfItems(int16_t numberOfItems)
|
||||
{
|
||||
if (numberOfItems != getNumberOfItems())
|
||||
{
|
||||
ScrollWheelBase::setNumberOfItems(numberOfItems);
|
||||
list1.setNumberOfItems(numberOfItems);
|
||||
list2.setNumberOfItems(numberOfItems);
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollWheelWithSelectionStyle::setSelectedItemOffset(int16_t offset)
|
||||
{
|
||||
ScrollWheelBase::setSelectedItemOffset(offset);
|
||||
refreshDrawableListsLayout();
|
||||
}
|
||||
|
||||
void ScrollWheelWithSelectionStyle::setSelectedItemExtraSize(int16_t extraSizeBefore, int16_t extraSizeAfter)
|
||||
{
|
||||
extraSizeBeforeSelectedItem = extraSizeBefore;
|
||||
extraSizeAfterSelectedItem = extraSizeAfter;
|
||||
refreshDrawableListsLayout();
|
||||
}
|
||||
|
||||
int16_t ScrollWheelWithSelectionStyle::getSelectedItemExtraSizeBefore() const
|
||||
{
|
||||
return extraSizeBeforeSelectedItem;
|
||||
}
|
||||
|
||||
int16_t ScrollWheelWithSelectionStyle::getSelectedItemExtraSizeAfter() const
|
||||
{
|
||||
return extraSizeAfterSelectedItem;
|
||||
}
|
||||
|
||||
void ScrollWheelWithSelectionStyle::setSelectedItemMargin(int16_t marginBefore, int16_t marginAfter)
|
||||
{
|
||||
marginBeforeSelectedItem = marginBefore;
|
||||
marginAfterSelectedItem = marginAfter;
|
||||
refreshDrawableListsLayout();
|
||||
}
|
||||
|
||||
int16_t ScrollWheelWithSelectionStyle::getSelectedItemMarginBefore() const
|
||||
{
|
||||
return marginBeforeSelectedItem;
|
||||
}
|
||||
|
||||
int16_t ScrollWheelWithSelectionStyle::getSelectedItemMarginAfter() const
|
||||
{
|
||||
return marginAfterSelectedItem;
|
||||
}
|
||||
|
||||
void ScrollWheelWithSelectionStyle::setSelectedItemPosition(int16_t offset, int16_t extraSizeBefore, int16_t extraSizeAfter, int16_t marginBefore, int16_t marginAfter)
|
||||
{
|
||||
setSelectedItemOffset(offset);
|
||||
setSelectedItemExtraSize(extraSizeBefore, extraSizeAfter);
|
||||
setSelectedItemMargin(marginBefore, marginAfter);
|
||||
}
|
||||
|
||||
void ScrollWheelWithSelectionStyle::setDrawableSize(int16_t drawableSize, int16_t drawableMargin)
|
||||
{
|
||||
ScrollWheelBase::setDrawableSize(drawableSize, drawableMargin);
|
||||
list1.setDrawableSize(drawableSize, drawableMargin);
|
||||
list2.setDrawableSize(drawableSize, drawableMargin);
|
||||
|
||||
// Resize the three lists
|
||||
setSelectedItemOffset(distanceBeforeAlignedItem);
|
||||
|
||||
// Changing the drawable size alters number of required drawables, so refresh this
|
||||
refreshDrawableListsLayout();
|
||||
}
|
||||
|
||||
void ScrollWheelWithSelectionStyle::setDrawables(DrawableListItemsInterface& drawableListItems, GenericCallback<DrawableListItemsInterface*, int16_t, int16_t>& updateDrawableCallback,
|
||||
DrawableListItemsInterface& centerDrawableListItems, GenericCallback<DrawableListItemsInterface*, int16_t, int16_t>& updateCenterDrawableCallback)
|
||||
{
|
||||
drawables = &drawableListItems;
|
||||
centerDrawables = ¢erDrawableListItems;
|
||||
|
||||
currentAnimationState = NO_ANIMATION;
|
||||
|
||||
originalUpdateDrawableCallback = &updateDrawableCallback;
|
||||
originalUpdateCenterDrawableCallback = &updateCenterDrawableCallback;
|
||||
|
||||
refreshDrawableListsLayout();
|
||||
|
||||
setOffset(0);
|
||||
}
|
||||
|
||||
void ScrollWheelWithSelectionStyle::setOffset(int32_t offset)
|
||||
{
|
||||
ScrollWheelBase::setOffset(offset);
|
||||
list1.setOffset((distanceBeforeAlignedItem - (distanceBeforeAlignedItem - extraSizeBeforeSelectedItem)) + offset);
|
||||
list2.setOffset((distanceBeforeAlignedItem - (distanceBeforeAlignedItem + itemSize + extraSizeAfterSelectedItem + marginAfterSelectedItem)) + offset);
|
||||
}
|
||||
|
||||
void ScrollWheelWithSelectionStyle::itemChanged(int itemIndex)
|
||||
{
|
||||
ScrollWheelBase::itemChanged(itemIndex);
|
||||
list1.itemChanged(itemIndex);
|
||||
list2.itemChanged(itemIndex);
|
||||
}
|
||||
|
||||
void ScrollWheelWithSelectionStyle::refreshDrawableListsLayout()
|
||||
{
|
||||
if (drawables != 0 && centerDrawables != 0)
|
||||
{
|
||||
int32_t currentOffset = getOffset();
|
||||
|
||||
int16_t list1Pos = distanceBeforeAlignedItem - extraSizeBeforeSelectedItem;
|
||||
int16_t list2Pos = distanceBeforeAlignedItem + itemSize + (extraSizeAfterSelectedItem + marginAfterSelectedItem);
|
||||
int16_t list0Size = list1Pos - marginBeforeSelectedItem;
|
||||
int16_t list1Size = itemSize + extraSizeBeforeSelectedItem + extraSizeAfterSelectedItem;
|
||||
|
||||
if (getHorizontal())
|
||||
{
|
||||
int16_t list2Size = getWidth() - list2Pos;
|
||||
list.setPosition(0, 0, list0Size, getHeight());
|
||||
list1.setPosition(list1Pos, 0, list1Size, getHeight());
|
||||
list2.setPosition(list2Pos, 0, list2Size, getHeight());
|
||||
}
|
||||
else
|
||||
{
|
||||
int16_t list2Size = getHeight() - list2Pos;
|
||||
list.setPosition(0, 0, getWidth(), list0Size);
|
||||
list1.setPosition(0, list1Pos, getWidth(), list1Size);
|
||||
list2.setPosition(0, list2Pos, getWidth(), list2Size);
|
||||
}
|
||||
|
||||
list.setDrawables(*drawables, 0, *originalUpdateDrawableCallback);
|
||||
drawablesInFirstList = list.getNumberOfDrawables();
|
||||
list1.setDrawables(*centerDrawables, 0, *originalUpdateCenterDrawableCallback);
|
||||
list2.setDrawables(*drawables, drawablesInFirstList, *originalUpdateDrawableCallback);
|
||||
|
||||
setOffset(keepOffsetInsideLimits(currentOffset, 0));
|
||||
}
|
||||
}
|
||||
} // namespace touchgfx
|
||||
Reference in New Issue
Block a user