From 3d8b303ab71dcacb2e42e8dc13cfa5b2c7590561 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 12 Jan 2022 14:41:33 +0300 Subject: [PATCH] Implement parabolic reaction drop. --- .../view/history_view_react_animation.cpp | 47 +++++++++++++++++-- .../view/history_view_react_animation.h | 5 ++ Telegram/SourceFiles/ui/chat/chat.style | 1 + 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/history/view/history_view_react_animation.cpp b/Telegram/SourceFiles/history/view/history_view_react_animation.cpp index c715d5ddf8..58857bb121 100644 --- a/Telegram/SourceFiles/history/view/history_view_react_animation.cpp +++ b/Telegram/SourceFiles/history/view/history_view_react_animation.cpp @@ -12,11 +12,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_message_reactions.h" #include "data/data_document.h" #include "data/data_document_media.h" +#include "styles/style_chat.h" namespace HistoryView::Reactions { namespace { -constexpr auto kFlyDuration = crl::time(200); +constexpr auto kFlyDuration = crl::time(300); } // namespace @@ -67,7 +68,10 @@ SendAnimation::SendAnimation( SendAnimation::~SendAnimation() = default; -QRect SendAnimation::paintGetArea(QPainter &p, QPoint origin, QRect target) const { +QRect SendAnimation::paintGetArea( + QPainter &p, + QPoint origin, + QRect target) const { if (!_flyIcon) { p.drawImage(target, _center->frame()); const auto wide = QRect( @@ -84,7 +88,7 @@ QRect SendAnimation::paintGetArea(QPainter &p, QPoint origin, QRect target) cons const auto progress = _fly.value(1.); const auto rect = QRect( anim::interpolate(from.x(), target.x(), progress), - anim::interpolate(from.y(), target.y(), progress), + computeParabolicTop(from.y(), target.y(), progress), anim::interpolate(from.width(), target.width(), progress), anim::interpolate(from.height(), target.height(), progress)); const auto wide = rect.marginsAdded(margins); @@ -101,6 +105,43 @@ QRect SendAnimation::paintGetArea(QPainter &p, QPoint origin, QRect target) cons return wide; } +int SendAnimation::computeParabolicTop( + int from, + int to, + float64 progress) const { + const auto t = progress; + const auto c = from; + + // result = a * t * t + b * t + c + + // y = a * t * t + b * t + // shift = y_1 = y(1) = a + b + // y_0 = y(t_0) = a * t_0 * t_0 + b * t_0 + // 0 = 2 * a * t_0 + b + // b = y_1 - a + // a = y_1 / (1 - 2 * t_0) + // b = 2 * t_0 * y_1 / (2 * t_0 - 1) + // t_0 = (y_0 / y_1) +- sqrt((y_0 / y_1) * (y_0 / y_1 - 1)) + const auto y_1 = to - from; + if (_cachedKey != y_1) { + const auto y_0 = std::min(0, y_1) - st::reactionFlyUp; + const auto ratio = y_1 ? (float64(y_0) / y_1) : 0.; + const auto root = y_1 ? sqrt(ratio * (ratio - 1)) : 0.; + const auto t_0 = !y_1 + ? 0.5 + : (y_1 > 0) + ? (ratio + root) + : (ratio - root); + const auto a = y_1 ? (y_1 / (1 - 2 * t_0)) : (-4 * y_0); + const auto b = y_1 - a; + _cachedKey = y_1; + _cachedA = a; + _cachedB = b; + } + + return int(base::SafeRound(_cachedA * t * t + _cachedB * t + from)); +} + void SendAnimation::startAnimations() { _center->animate([=] { callback(); }, 0, _center->framesCount() - 1); _effect->animate([=] { callback(); }, 0, _effect->framesCount() - 1); diff --git a/Telegram/SourceFiles/history/view/history_view_react_animation.h b/Telegram/SourceFiles/history/view/history_view_react_animation.h index c11864121e..0daca4982c 100644 --- a/Telegram/SourceFiles/history/view/history_view_react_animation.h +++ b/Telegram/SourceFiles/history/view/history_view_react_animation.h @@ -42,6 +42,7 @@ private: void flyCallback(); void startAnimations(); void callback(); + int computeParabolicTop(int from, int to, float64 progress) const; const not_null<::Data::Reactions*> _owner; const QString _emoji; @@ -53,6 +54,10 @@ private: QRect _flyFrom; bool _valid = false; + mutable std::optional _cachedKey; + mutable float64 _cachedA = 0.; + mutable float64 _cachedB = 0.; + }; } // namespace HistoryView::Reactions diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index 7a1af4f124..c25ce1ab5e 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -991,3 +991,4 @@ reactionGradientFadeSize: 24px; reactionAppearStartSkip: 2px; reactionMainAppearShift: 20px; reactionCollapseFadeThreshold: 40px; +reactionFlyUp: 50px;