From 07cd35b1a871711f17b5d7dd53a0243e213ad944 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 7 Jul 2023 14:41:30 +0300 Subject: [PATCH] Added fade animation to details widget on charts. --- .../SourceFiles/statistics/chart_widget.cpp | 56 +++++++++++++++---- .../SourceFiles/statistics/chart_widget.h | 2 + .../statistics/linear_chart_view.cpp | 1 + .../statistics/point_details_widget.cpp | 10 ++++ .../statistics/point_details_widget.h | 2 + 5 files changed, 60 insertions(+), 11 deletions(-) diff --git a/Telegram/SourceFiles/statistics/chart_widget.cpp b/Telegram/SourceFiles/statistics/chart_widget.cpp index 53b801159..fd52d6e40 100644 --- a/Telegram/SourceFiles/statistics/chart_widget.cpp +++ b/Telegram/SourceFiles/statistics/chart_widget.cpp @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "statistics/point_details_widget.h" #include "ui/abstract_button.h" #include "ui/effects/animation_value_f.h" +#include "ui/painter.h" #include "ui/rect.h" #include "styles/style_boxes.h" @@ -20,6 +21,7 @@ namespace Statistic { namespace { constexpr auto kHeightLimitsUpdateTimeout = crl::time(320); +constexpr auto kExpandingDelay = crl::time(100); inline float64 InterpolationRatio(float64 from, float64 to, float64 result) { return (result - from) / (to - from); @@ -341,7 +343,6 @@ void ChartWidget::ChartAnimationController::tick( if (!_animation.animating()) { return; } - constexpr auto kExpandingDelay = crl::time(100); constexpr auto kXExpandingDuration = 200.; constexpr auto kAlphaExpandingDuration = 200.; @@ -444,6 +445,20 @@ Limits ChartWidget::ChartAnimationController::finalHeightLimits() const { return _finalHeightLimits; } +float64 ChartWidget::ChartAnimationController::detailsProgress( + crl::time now) const { + return _animation.animating() + ? std::clamp( + (now - _animation.started()) / float64(kExpandingDelay), + 0., + 1.) + : 0.; +} + +bool ChartWidget::ChartAnimationController::animating() const { + return _animation.animating(); +} + auto ChartWidget::ChartAnimationController::heightAnimationStarts() const -> rpl::producer<> { return _heightAnimationStarts.events(); @@ -488,7 +503,9 @@ void ChartWidget::setupChartArea() { ) | rpl::start_with_next([=](const QRect &r) { auto p = QPainter(_chartArea.get()); - _animationController.tick(crl::now(), _horizontalLines); + const auto now = crl::now(); + + _animationController.tick(now, _horizontalLines); const auto chartRect = chartAreaRect(); @@ -498,14 +515,25 @@ void ChartWidget::setupChartArea() { PaintHorizontalLines(p, horizontalLine, chartRect); } - if (_details.currentX) { - const auto lineRect = QRectF( - _details.currentX - (st::lineWidth / 2.), - 0, - st::lineWidth, - _chartArea->height()); - p.setOpacity(1.); - p.fillRect(lineRect, st::windowSubTextFg); + const auto detailsAlpha = 1. + - _animationController.detailsProgress(now); + + if (_details.widget) { + if (!detailsAlpha && _details.currentX) { + _details.widget->hide(); + _details.widget->setXIndex(-1); + _details.currentX = 0; + } + if (_details.currentX) { + const auto lineRect = QRectF( + _details.currentX - (st::lineWidth / 2.), + 0, + st::lineWidth, + _chartArea->height()); + const auto opacity = ScopedPainterOpacity(p, detailsAlpha); + p.fillRect(lineRect, st::windowSubTextFg); + _details.widget->setAlpha(detailsAlpha); + } } if (_chartData) { @@ -515,7 +543,10 @@ void ChartWidget::setupChartArea() { _animationController.currentXLimits(), _animationController.currentHeightLimits(), chartRect, - { _details.widget ? _details.widget->xIndex() : -1, 1. }); + { + _details.widget ? _details.widget->xIndex() : -1, + detailsAlpha, + }); } for (auto &horizontalLine : _horizontalLines) { @@ -578,6 +609,9 @@ void ChartWidget::setupDetails() { _chartArea->mouseStateChanged( ) | rpl::start_with_next([=](const RpMouseWidget::State &state) { + if (_animationController.animating()) { + return; + } switch (state.mouseState) { case QEvent::MouseButtonPress: case QEvent::MouseMove: { diff --git a/Telegram/SourceFiles/statistics/chart_widget.h b/Telegram/SourceFiles/statistics/chart_widget.h index 781143a3f..039116ae5 100644 --- a/Telegram/SourceFiles/statistics/chart_widget.h +++ b/Telegram/SourceFiles/statistics/chart_widget.h @@ -48,6 +48,8 @@ private: [[nodiscard]] Limits finalXLimits() const; [[nodiscard]] Limits currentHeightLimits() const; [[nodiscard]] Limits finalHeightLimits() const; + [[nodiscard]] float64 detailsProgress(crl::time now) const; + [[nodiscard]] bool animating() const; [[nodiscard]] rpl::producer<> heightAnimationStarts() const; diff --git a/Telegram/SourceFiles/statistics/linear_chart_view.cpp b/Telegram/SourceFiles/statistics/linear_chart_view.cpp index 3ca17e222..503f268a5 100644 --- a/Telegram/SourceFiles/statistics/linear_chart_view.cpp +++ b/Telegram/SourceFiles/statistics/linear_chart_view.cpp @@ -74,6 +74,7 @@ void PaintLinearChartView( p.drawPath(chartPath); if (!detailsDotPoint.isNull()) { + ScopedPainterOpacity o(p, detailsPaintContext.progress); p.setBrush(st::boxBg); const auto r = st::statisticsDetailsDotRadius; p.drawEllipse(detailsDotPoint, r, r); diff --git a/Telegram/SourceFiles/statistics/point_details_widget.cpp b/Telegram/SourceFiles/statistics/point_details_widget.cpp index 92ceaf376..2d1bc123c 100644 --- a/Telegram/SourceFiles/statistics/point_details_widget.cpp +++ b/Telegram/SourceFiles/statistics/point_details_widget.cpp @@ -43,6 +43,9 @@ int PointDetailsWidget::xIndex() const { void PointDetailsWidget::setXIndex(int xIndex) { _xIndex = xIndex; + if (xIndex < 0) { + return; + } _header.setText(_headerStyle, _chartData.getDayString(xIndex)); _lines.clear(); @@ -58,6 +61,11 @@ void PointDetailsWidget::setXIndex(int xIndex) { } } +void PointDetailsWidget::setAlpha(float64 alpha) { + _alpha = alpha; + update(); +} + int PointDetailsWidget::lineYAt(int i) const { return _textRect.y() + _headerStyle.font->height @@ -69,6 +77,8 @@ int PointDetailsWidget::lineYAt(int i) const { void PointDetailsWidget::paintEvent(QPaintEvent *e) { auto p = QPainter(this); + p.setOpacity(_alpha); + const auto fullRect = rect(); Ui::Shadow::paint(p, _innerRect, width(), st::boxRoundShadow); diff --git a/Telegram/SourceFiles/statistics/point_details_widget.h b/Telegram/SourceFiles/statistics/point_details_widget.h index c8fb63d6d..64eb14e75 100644 --- a/Telegram/SourceFiles/statistics/point_details_widget.h +++ b/Telegram/SourceFiles/statistics/point_details_widget.h @@ -20,6 +20,7 @@ public: [[nodiscard]] int xIndex() const; void setXIndex(int xIndex); + void setAlpha(float64 alpha); protected: void paintEvent(QPaintEvent *e) override; @@ -42,6 +43,7 @@ private: QRect _textRect; int _xIndex = -1; + float64 _alpha = 1.; std::vector _lines;