mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Added loop setting to vertical drum picker.
This commit is contained in:
parent
7b7016c4b3
commit
7fda14ccca
2 changed files with 72 additions and 23 deletions
|
@ -46,20 +46,28 @@ VerticalDrumPicker::VerticalDrumPicker(
|
||||||
PaintItemCallback &&paintCallback,
|
PaintItemCallback &&paintCallback,
|
||||||
int itemsCount,
|
int itemsCount,
|
||||||
int itemHeight,
|
int itemHeight,
|
||||||
int startIndex)
|
int startIndex,
|
||||||
|
bool looped)
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
, _itemsCount(itemsCount)
|
, _itemsCount(itemsCount)
|
||||||
, _itemHeight(itemHeight)
|
, _itemHeight(itemHeight)
|
||||||
, _paintCallback(std::move(paintCallback))
|
, _paintCallback(std::move(paintCallback))
|
||||||
, _pendingStartIndex(startIndex) {
|
, _pendingStartIndex(startIndex)
|
||||||
|
, _loopData({ .looped = looped }) {
|
||||||
Expects(_paintCallback != nullptr);
|
Expects(_paintCallback != nullptr);
|
||||||
|
|
||||||
sizeValue(
|
sizeValue(
|
||||||
) | rpl::start_with_next([=](const QSize &s) {
|
) | rpl::start_with_next([=](const QSize &s) {
|
||||||
_itemsVisibleCount = std::ceil(float64(s.height()) / _itemHeight);
|
_itemsVisible.count = std::ceil(float64(s.height()) / _itemHeight);
|
||||||
if (_pendingStartIndex && _itemsVisibleCount) {
|
_itemsVisible.centerOffset = _itemsVisible.count / 2;
|
||||||
|
if (_pendingStartIndex && _itemsVisible.count) {
|
||||||
_index = normalizedIndex(base::take(_pendingStartIndex)
|
_index = normalizedIndex(base::take(_pendingStartIndex)
|
||||||
- _itemsVisibleCount / 2);
|
- _itemsVisible.centerOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_loopData.looped) {
|
||||||
|
_loopData.minIndex = -_itemsVisible.centerOffset;
|
||||||
|
_loopData.maxIndex = _itemsCount - 1 - _itemsVisible.centerOffset;
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
@ -70,11 +78,15 @@ VerticalDrumPicker::VerticalDrumPicker(
|
||||||
const auto outerWidth = width();
|
const auto outerWidth = width();
|
||||||
const auto centerY = height() / 2.;
|
const auto centerY = height() / 2.;
|
||||||
const auto shiftedY = _itemHeight * _shift;
|
const auto shiftedY = _itemHeight * _shift;
|
||||||
for (auto i = -1; i < (_itemsVisibleCount + 1); i++) {
|
for (auto i = -1; i < (_itemsVisible.count + 1); i++) {
|
||||||
|
const auto index = normalizedIndex(i + _index);
|
||||||
|
if (!isIndexInRange(index)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const auto y = (_itemHeight * i + shiftedY);
|
const auto y = (_itemHeight * i + shiftedY);
|
||||||
_paintCallback(
|
_paintCallback(
|
||||||
p,
|
p,
|
||||||
normalizedIndex(i + _index),
|
index,
|
||||||
y,
|
y,
|
||||||
((y + _itemHeight / 2.) - centerY) / centerY,
|
((y + _itemHeight / 2.) - centerY) / centerY,
|
||||||
outerWidth);
|
outerWidth);
|
||||||
|
@ -88,15 +100,32 @@ VerticalDrumPicker::VerticalDrumPicker(
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerticalDrumPicker::increaseShift(float64 by) {
|
void VerticalDrumPicker::increaseShift(float64 by) {
|
||||||
_shift += by;
|
// Guard input.
|
||||||
if (_shift >= 1.) {
|
if (by >= 1.) {
|
||||||
_shift -= 1.;
|
by = .99;
|
||||||
_index--;
|
}
|
||||||
_index = normalizedIndex(_index);
|
|
||||||
} else if (_shift <= -1.) {
|
auto shift = _shift;
|
||||||
_shift += 1.;
|
auto index = _index;
|
||||||
_index++;
|
shift += by;
|
||||||
_index = normalizedIndex(_index);
|
if (shift >= 1.) {
|
||||||
|
shift -= 1.;
|
||||||
|
index--;
|
||||||
|
index = normalizedIndex(index);
|
||||||
|
} else if (shift <= -1.) {
|
||||||
|
shift += 1.;
|
||||||
|
index++;
|
||||||
|
index = normalizedIndex(index);
|
||||||
|
}
|
||||||
|
if (!_loopData.looped && (index <= _loopData.minIndex)) {
|
||||||
|
_shift = std::min(0., shift);
|
||||||
|
_index = _loopData.minIndex;
|
||||||
|
} else if (!_loopData.looped && (index >= _loopData.maxIndex)) {
|
||||||
|
_shift = std::max(0., shift);
|
||||||
|
_index = _loopData.maxIndex;
|
||||||
|
} else {
|
||||||
|
_shift = shift;
|
||||||
|
_index = index;
|
||||||
}
|
}
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
@ -109,7 +138,7 @@ void VerticalDrumPicker::handleWheelEvent(not_null<QWheelEvent*> e) {
|
||||||
const auto delta = e->pixelDelta().y()
|
const auto delta = e->pixelDelta().y()
|
||||||
? e->pixelDelta().y()
|
? e->pixelDelta().y()
|
||||||
: e->angleDelta().y();
|
: e->angleDelta().y();
|
||||||
increaseShift(std::min(delta / float64(_itemHeight), 0.99));
|
increaseShift(delta / float64(_itemHeight));
|
||||||
if (e->phase() == Qt::ScrollEnd) {
|
if (e->phase() == Qt::ScrollEnd) {
|
||||||
animationDataFromIndex();
|
animationDataFromIndex();
|
||||||
_animation.jumpToOffset(0);
|
_animation.jumpToOffset(0);
|
||||||
|
@ -121,11 +150,11 @@ void VerticalDrumPicker::handleKeyEvent(not_null<QKeyEvent*> e) {
|
||||||
if (e->key() == Qt::Key_Left || e->key() == Qt::Key_Up) {
|
if (e->key() == Qt::Key_Left || e->key() == Qt::Key_Up) {
|
||||||
_animation.jumpToOffset(1);
|
_animation.jumpToOffset(1);
|
||||||
} else if (e->key() == Qt::Key_PageUp && !e->isAutoRepeat()) {
|
} else if (e->key() == Qt::Key_PageUp && !e->isAutoRepeat()) {
|
||||||
_animation.jumpToOffset(_itemsVisibleCount);
|
_animation.jumpToOffset(_itemsVisible.count);
|
||||||
} else if (e->key() == Qt::Key_Right || e->key() == Qt::Key_Down) {
|
} else if (e->key() == Qt::Key_Right || e->key() == Qt::Key_Down) {
|
||||||
_animation.jumpToOffset(-1);
|
_animation.jumpToOffset(-1);
|
||||||
} else if (e->key() == Qt::Key_PageDown && !e->isAutoRepeat()) {
|
} else if (e->key() == Qt::Key_PageDown && !e->isAutoRepeat()) {
|
||||||
_animation.jumpToOffset(-_itemsVisibleCount);
|
_animation.jumpToOffset(-_itemsVisible.count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +176,7 @@ void VerticalDrumPicker::handleMouseEvent(not_null<QMouseEvent*> e) {
|
||||||
_animation.jumpToOffset(0);
|
_animation.jumpToOffset(0);
|
||||||
} else {
|
} else {
|
||||||
_mouse.lastPositionY = e->pos().y();
|
_mouse.lastPositionY = e->pos().y();
|
||||||
const auto toOffset = (_itemsVisibleCount / 2)
|
const auto toOffset = _itemsVisible.centerOffset
|
||||||
- (_mouse.lastPositionY / _itemHeight);
|
- (_mouse.lastPositionY / _itemHeight);
|
||||||
_animation.jumpToOffset(toOffset);
|
_animation.jumpToOffset(toOffset);
|
||||||
}
|
}
|
||||||
|
@ -183,7 +212,14 @@ void VerticalDrumPicker::animationDataFromIndex() {
|
||||||
std::round(_index + _shift));
|
std::round(_index + _shift));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VerticalDrumPicker::isIndexInRange(int index) const {
|
||||||
|
return (index >= 0) && (index < _itemsCount);
|
||||||
|
}
|
||||||
|
|
||||||
int VerticalDrumPicker::normalizedIndex(int index) const {
|
int VerticalDrumPicker::normalizedIndex(int index) const {
|
||||||
|
if (!_loopData.looped) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
index += _itemsCount;
|
index += _itemsCount;
|
||||||
} else if (index >= _itemsCount) {
|
} else if (index >= _itemsCount) {
|
||||||
|
@ -193,7 +229,7 @@ int VerticalDrumPicker::normalizedIndex(int index) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int VerticalDrumPicker::index() const {
|
int VerticalDrumPicker::index() const {
|
||||||
return normalizedIndex(_index + _itemsVisibleCount / 2);
|
return normalizedIndex(_index + _itemsVisible.centerOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -48,7 +48,8 @@ public:
|
||||||
PaintItemCallback &&paintCallback,
|
PaintItemCallback &&paintCallback,
|
||||||
int itemsCount,
|
int itemsCount,
|
||||||
int itemHeight,
|
int itemHeight,
|
||||||
int startIndex = 0);
|
int startIndex = 0,
|
||||||
|
bool looped = false);
|
||||||
|
|
||||||
[[nodiscard]] int index() const;
|
[[nodiscard]] int index() const;
|
||||||
|
|
||||||
|
@ -67,6 +68,7 @@ private:
|
||||||
void increaseShift(float64 by);
|
void increaseShift(float64 by);
|
||||||
void animationDataFromIndex();
|
void animationDataFromIndex();
|
||||||
[[nodiscard]] int normalizedIndex(int index) const;
|
[[nodiscard]] int normalizedIndex(int index) const;
|
||||||
|
[[nodiscard]] bool isIndexInRange(int index) const;
|
||||||
|
|
||||||
const int _itemsCount;
|
const int _itemsCount;
|
||||||
const int _itemHeight;
|
const int _itemHeight;
|
||||||
|
@ -74,10 +76,21 @@ private:
|
||||||
PaintItemCallback _paintCallback;
|
PaintItemCallback _paintCallback;
|
||||||
|
|
||||||
int _pendingStartIndex = 0;
|
int _pendingStartIndex = 0;
|
||||||
int _itemsVisibleCount = 0;
|
|
||||||
|
struct {
|
||||||
|
int count = 0;
|
||||||
|
int centerOffset = 0;
|
||||||
|
} _itemsVisible;
|
||||||
|
|
||||||
int _index = 0;
|
int _index = 0;
|
||||||
float64 _shift = 0.;
|
float64 _shift = 0.;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
const bool looped;
|
||||||
|
int minIndex = 0;
|
||||||
|
int maxIndex = 0;
|
||||||
|
} _loopData;
|
||||||
|
|
||||||
PickerAnimation _animation;
|
PickerAnimation _animation;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
Loading…
Add table
Reference in a new issue