Implement animated VerticalLayout reordering.

This commit is contained in:
John Preston 2020-03-20 16:33:29 +04:00
parent b051948e69
commit eaab3f9a8a
3 changed files with 65 additions and 6 deletions

View file

@ -55,6 +55,7 @@ void VerticalLayout::setVerticalShift(int index, int shift) {
if (const auto delta = shift - row.verticalShift) {
row.verticalShift = shift;
row.widget->move(row.widget->x(), row.widget->y() + delta);
row.widget->update();
}
}

View file

@ -7,6 +7,7 @@
#include "ui/wrap/vertical_layout_reorder.h"
#include "ui/wrap/vertical_layout.h"
#include "styles/style_basic.h"
#include <QtGui/QtEvents>
#include <QtWidgets/QApplication>
@ -95,7 +96,8 @@ void VerticalLayoutReorder::checkForStart(QPoint position) {
void VerticalLayoutReorder::updateOrder(int index, QPoint position) {
const auto shift = position.y() - _currentStart;
auto &current = _entries[index];
current.shift = shift;
current.shiftAnimation.stop();
current.shift = current.finalShift = shift;
_layout->setVerticalShift(index, shift);
const auto count = _entries.size();
@ -186,19 +188,69 @@ void VerticalLayoutReorder::finishCurrent() {
const auto widget = _currentWidget;
_currentState = State::Cancelled;
_currentWidget = nullptr;
auto &current = _entries[index];
const auto height = current.widget->height();
if (index < result) {
auto sum = 0;
for (auto i = index; i != result; ++i) {
auto &entry = _entries[i + 1];
const auto widget = entry.widget;
entry.deltaShift += height;
updateShift(widget, i + 1);
sum += widget->height();
}
current.finalShift -= sum;
} else if (index > result) {
auto sum = 0;
for (auto i = result; i != index; ++i) {
auto &entry = _entries[i];
const auto widget = entry.widget;
entry.deltaShift -= height;
updateShift(widget, i);
sum += widget->height();
}
current.finalShift += sum;
}
base::reorder(_entries, index, result);
_layout->reorderRows(index, _currentDesiredIndex);
for (auto i = 0, count = int(_entries.size()); i != count; ++i) {
moveToShift(i, 0);
}
_layout->reorderRows(index, _currentDesiredIndex);
base::reorder(_entries, index, result);
_updates.fire({ widget, index, result, State::Applied });
}
void VerticalLayoutReorder::moveToShift(int index, int shift) {
_layout->setVerticalShift(index, shift);
_entries[index].shift = shift;
auto &entry = _entries[index];
if (entry.finalShift + entry.deltaShift == shift) {
return;
}
const auto widget = entry.widget;
entry.shiftAnimation.start(
[=] { updateShift(widget, index); },
entry.finalShift,
shift - entry.deltaShift,
st::slideWrapDuration);
entry.finalShift = shift - entry.deltaShift;
}
void VerticalLayoutReorder::updateShift(
not_null<RpWidget*> widget,
int indexHint) {
Expects(indexHint >= 0 && indexHint < _entries.size());
const auto index = (_entries[indexHint].widget == widget)
? indexHint
: indexOf(widget);
auto &entry = _entries[index];
entry.shift = std::round(entry.shiftAnimation.value(entry.finalShift))
+ entry.deltaShift;
if (entry.deltaShift && !entry.shiftAnimation.animating()) {
entry.finalShift += entry.deltaShift;
entry.deltaShift = 0;
}
_layout->setVerticalShift(index, entry.shift);
}
int VerticalLayoutReorder::indexOf(not_null<RpWidget*> widget) const {

View file

@ -6,6 +6,8 @@
//
#pragma once
#include "ui/effects/animations.h"
namespace Ui {
class RpWidget;
@ -34,7 +36,10 @@ public:
private:
struct Entry {
not_null<RpWidget*> widget;
Ui::Animations::Simple shiftAnimation;
int shift = 0;
int finalShift = 0;
int deltaShift = 0;
};
void mouseMove(not_null<RpWidget*> widget, QPoint position);
@ -52,6 +57,7 @@ private:
[[nodiscard]] int indexOf(not_null<RpWidget*> widget) const;
void moveToShift(int index, int shift);
void updateShift(not_null<RpWidget*> widget, int indexHint);
const not_null<Ui::VerticalLayout*> _layout;