Animate suggestions select-by-keyboard.

This commit is contained in:
John Preston 2019-04-01 15:16:16 +04:00
parent 1da9385fe2
commit c4357c7ad3
2 changed files with 85 additions and 26 deletions

View File

@ -25,6 +25,7 @@ namespace {
constexpr auto kShowExactDelay = crl::time(300); constexpr auto kShowExactDelay = crl::time(300);
constexpr auto kMaxNonScrolledEmoji = 7; constexpr auto kMaxNonScrolledEmoji = 7;
constexpr auto kAnimationDuration = crl::time(120);
} // namespace } // namespace
@ -145,7 +146,9 @@ void SuggestionsWidget::resizeToRows() {
? st::emojiSuggestionsScrolledWidth ? st::emojiSuggestionsScrolledWidth
: fullWidth; : fullWidth;
_scrollMax = std::max(0, fullWidth - newWidth); _scrollMax = std::max(0, fullWidth - newWidth);
_scroll = std::min(_scroll, _scrollMax); if (_scrollValue > _scrollMax || scrollCurrent() > _scrollMax) {
scrollTo(std::min(_scrollValue, _scrollMax));
}
resize(_padding.left() + newWidth + _padding.right(), height()); resize(_padding.left() + newWidth + _padding.right(), height());
update(); update();
} }
@ -165,22 +168,23 @@ void SuggestionsWidget::scrollByWheelEvent(not_null<QWheelEvent*> e) {
|| (e->orientation() == Qt::Horizontal); || (e->orientation() == Qt::Horizontal);
const auto vertical = (e->angleDelta().y() != 0) const auto vertical = (e->angleDelta().y() != 0)
|| (e->orientation() == Qt::Vertical); || (e->orientation() == Qt::Vertical);
const auto current = scrollCurrent();
const auto scroll = [&] { const auto scroll = [&] {
if (horizontal) { if (horizontal) {
const auto delta = e->pixelDelta().x() const auto delta = e->pixelDelta().x()
? e->pixelDelta().x() ? e->pixelDelta().x()
: e->angleDelta().x(); : e->angleDelta().x();
return snap(_scroll - ((rtl() ? -1 : 1) * delta), 0, _scrollMax); return snap(current - ((rtl() ? -1 : 1) * delta), 0, _scrollMax);
} else if (vertical) { } else if (vertical) {
const auto delta = e->pixelDelta().y() const auto delta = e->pixelDelta().y()
? e->pixelDelta().y() ? e->pixelDelta().y()
: e->angleDelta().y(); : e->angleDelta().y();
return snap(_scroll - delta, 0, _scrollMax); return snap(current - delta, 0, _scrollMax);
} }
return _scroll; return current;
}(); }();
if (_scroll != scroll) { if (current != scroll) {
_scroll = scroll; scrollTo(scroll);
if (!_lastMousePosition) { if (!_lastMousePosition) {
_lastMousePosition = QCursor::pos(); _lastMousePosition = QCursor::pos();
} }
@ -203,20 +207,23 @@ void SuggestionsWidget::paintEvent(QPaintEvent *e) {
(paint.x() + paint.width() + _oneWidth - 1) / _oneWidth, (paint.x() + paint.width() + _oneWidth - 1) / _oneWidth,
int(_rows.size())); int(_rows.size()));
const auto selected = (_pressed >= 0)
? _pressed
: _selectedAnimation.value(_selected);
if (selected > -1.) {
App::roundRect(
p,
QRect(selected * _oneWidth, 0, _oneWidth, _oneWidth),
st::emojiPanHover,
StickerHoverCorners);
}
for (auto i = from; i != till; ++i) { for (auto i = from; i != till; ++i) {
const auto &row = _rows[i]; const auto &row = _rows[i];
const auto emoji = row.emoji; const auto emoji = row.emoji;
const auto esize = Ui::Emoji::GetSizeLarge(); const auto esize = Ui::Emoji::GetSizeLarge();
const auto selected = (i == _selected || i == _pressed);
const auto x = i * _oneWidth; const auto x = i * _oneWidth;
const auto y = 0; const auto y = 0;
if (selected) {
App::roundRect(
p,
QRect(x, y, _oneWidth, _oneWidth),
st::emojiPanHover,
StickerHoverCorners);
}
Ui::Emoji::Draw( Ui::Emoji::Draw(
p, p,
emoji, emoji,
@ -228,8 +235,9 @@ void SuggestionsWidget::paintEvent(QPaintEvent *e) {
} }
void SuggestionsWidget::paintFadings(Painter &p) const { void SuggestionsWidget::paintFadings(Painter &p) const {
const auto scroll = scrollCurrent();
const auto o_left = snap( const auto o_left = snap(
_scroll / float64(st::emojiSuggestionsFadeAfter), scroll / float64(st::emojiSuggestionsFadeAfter),
0., 0.,
1.); 1.);
const auto shift = innerShift(); const auto shift = innerShift();
@ -244,7 +252,7 @@ void SuggestionsWidget::paintFadings(Painter &p) const {
p.setOpacity(1.); p.setOpacity(1.);
} }
const auto o_right = snap( const auto o_right = snap(
(_scrollMax - _scroll) / float64(st::emojiSuggestionsFadeAfter), (_scrollMax - scroll) / float64(st::emojiSuggestionsFadeAfter),
0., 0.,
1.); 1.);
if (o_right > 0.) { if (o_right > 0.) {
@ -298,14 +306,32 @@ bool SuggestionsWidget::handleKeyEvent(int key) {
_mouseSelection = false; _mouseSelection = false;
_lastMousePosition = std::nullopt; _lastMousePosition = std::nullopt;
setSelected(newSelected); setSelected(newSelected, anim::type::normal);
return true; return true;
} }
void SuggestionsWidget::setSelected(int selected) { void SuggestionsWidget::setSelected(int selected, anim::type animated) {
if (selected >= _rows.size()) { if (selected >= _rows.size()) {
selected = -1; selected = -1;
} }
if (animated == anim::type::normal) {
_selectedAnimation.start(
[=] { update(); },
_selected,
selected,
kAnimationDuration,
anim::sineInOut);
if (_scrollMax > 0) {
const auto selectedMax = int(_rows.size()) - 3;
const auto selectedForScroll = std::min(
std::max(selected, 1) - 1,
selectedMax);
scrollTo((_scrollMax * selectedForScroll) / selectedMax, animated);
}
} else if (_selectedAnimation.animating()) {
_selectedAnimation.stop();
update();
}
if (_selected != selected) { if (_selected != selected) {
updateSelectedItem(); updateSelectedItem();
_selected = selected; _selected = selected;
@ -313,6 +339,30 @@ void SuggestionsWidget::setSelected(int selected) {
} }
} }
int SuggestionsWidget::scrollCurrent() const {
return _scrollAnimation.value(_scrollValue);
}
void SuggestionsWidget::scrollTo(int value, anim::type animated) {
if (animated == anim::type::instant) {
_scrollAnimation.stop();
} else {
_scrollAnimation.start(
[=] { update(); },
_scrollValue,
value,
kAnimationDuration,
anim::sineInOut);
}
_scrollValue = value;
update();
}
void SuggestionsWidget::stopAnimations() {
_scrollValue = _scrollAnimation.value(_scrollValue);
_scrollAnimation.stop();
}
void SuggestionsWidget::setPressed(int pressed) { void SuggestionsWidget::setPressed(int pressed) {
if (pressed >= _rows.size()) { if (pressed >= _rows.size()) {
pressed = -1; pressed = -1;
@ -340,7 +390,7 @@ void SuggestionsWidget::clearSelection() {
void SuggestionsWidget::updateItem(int index) { void SuggestionsWidget::updateItem(int index) {
if (index >= 0 && index < _rows.size()) { if (index >= 0 && index < _rows.size()) {
update( update(
_padding.left() + index * _oneWidth - _scroll, _padding.left() + index * _oneWidth - scrollCurrent(),
_padding.top(), _padding.top(),
_oneWidth, _oneWidth,
_oneWidth); _oneWidth);
@ -356,7 +406,7 @@ QRect SuggestionsWidget::inner() const {
} }
QPoint SuggestionsWidget::innerShift() const { QPoint SuggestionsWidget::innerShift() const {
return QPoint(_scroll - _padding.left(), -_padding.top()); return QPoint(scrollCurrent() - _padding.left(), -_padding.top());
} }
QPoint SuggestionsWidget::mapToInner(QPoint globalPosition) const { QPoint SuggestionsWidget::mapToInner(QPoint globalPosition) const {
@ -371,8 +421,8 @@ void SuggestionsWidget::mouseMoveEvent(QMouseEvent *e) {
_dragScrollStart + (rtl() ? -1 : 1) * delta, _dragScrollStart + (rtl() ? -1 : 1) * delta,
0, 0,
_scrollMax); _scrollMax);
if (_scroll != scroll) { if (scrollCurrent() != scroll) {
_scroll = scroll; scrollTo(scroll);
update(); update();
} }
return; return;
@ -380,8 +430,9 @@ void SuggestionsWidget::mouseMoveEvent(QMouseEvent *e) {
&& (_scrollMax > 0) && (_scrollMax > 0)
&& ((_mousePressPosition - globalPosition).manhattanLength() && ((_mousePressPosition - globalPosition).manhattanLength()
>= QApplication::startDragDistance())) { >= QApplication::startDragDistance())) {
_dragScrollStart = _scroll; _dragScrollStart = scrollCurrent();
_mousePressPosition = globalPosition; _mousePressPosition = globalPosition;
scrollTo(_dragScrollStart);
} }
if (inner().contains(mapToInner(globalPosition))) { if (inner().contains(mapToInner(globalPosition))) {
if (!_lastMousePosition) { if (!_lastMousePosition) {

View File

@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "ui/effects/panel_animation.h" #include "ui/effects/animations.h"
#include "ui/rp_widget.h" #include "ui/rp_widget.h"
#include "base/unique_qptr.h" #include "base/unique_qptr.h"
#include "base/timer.h" #include "base/timer.h"
@ -52,7 +52,9 @@ private:
std::vector<Row> getRowsByQuery() const; std::vector<Row> getRowsByQuery() const;
void resizeToRows(); void resizeToRows();
void setSelected(int selected); void setSelected(
int selected,
anim::type animated = anim::type::instant);
void setPressed(int pressed); void setPressed(int pressed);
void clearMouseSelection(); void clearMouseSelection();
void clearSelection(); void clearSelection();
@ -65,6 +67,10 @@ private:
bool triggerSelectedRow() const; bool triggerSelectedRow() const;
void triggerRow(const Row &row) const; void triggerRow(const Row &row) const;
[[nodiscard]] int scrollCurrent() const;
void scrollTo(int value, anim::type animated = anim::type::instant);
void stopAnimations();
QString _query; QString _query;
std::vector<Row> _rows; std::vector<Row> _rows;
@ -73,7 +79,9 @@ private:
int _selected = -1; int _selected = -1;
int _pressed = -1; int _pressed = -1;
int _scroll = 0; int _scrollValue = 0;
Ui::Animations::Simple _scrollAnimation;
Ui::Animations::Simple _selectedAnimation;
int _scrollMax = 0; int _scrollMax = 0;
int _oneWidth = 0; int _oneWidth = 0;
QMargins _padding; QMargins _padding;