diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index d656ebe4d..72371cde2 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -1296,6 +1296,8 @@ PRIVATE statistics/statistics_data_deserialize.cpp statistics/statistics_data_deserialize.h statistics/view/abstract_chart_view.h + statistics/view/chart_horizontal_lines_view.cpp + statistics/view/chart_horizontal_lines_view.h statistics/view/chart_view_factory.cpp statistics/view/chart_view_factory.h statistics/view/linear_chart_view.cpp diff --git a/Telegram/SourceFiles/statistics/chart_widget.cpp b/Telegram/SourceFiles/statistics/chart_widget.cpp index 86f94a9d5..2a4c2f017 100644 --- a/Telegram/SourceFiles/statistics/chart_widget.cpp +++ b/Telegram/SourceFiles/statistics/chart_widget.cpp @@ -37,38 +37,6 @@ inline float64 InterpolationRatio(float64 from, float64 to, float64 result) { return (result - from) / (to - from); }; -void PaintHorizontalLines( - QPainter &p, - const ChartHorizontalLinesData &horizontalLine, - const QRect &r) { - const auto alpha = p.opacity(); - p.setOpacity(horizontalLine.alpha); - for (const auto &line : horizontalLine.lines) { - const auto lineRect = QRect( - 0, - r.y() + r.height() * line.relativeValue, - r.x() + r.width(), - st::lineWidth); - p.fillRect(lineRect, st::windowSubTextFg); - } - p.setOpacity(alpha); -} - -void PaintCaptionsToHorizontalLines( - QPainter &p, - const ChartHorizontalLinesData &horizontalLine, - const QRect &r) { - const auto alpha = p.opacity(); - p.setOpacity(horizontalLine.alpha); - p.setFont(st::statisticsDetailsBottomCaptionStyle.font); - p.setPen(st::windowSubTextFg); - const auto offset = r.y() - st::statisticsChartHorizontalLineCaptionSkip; - for (const auto &line : horizontalLine.lines) { - p.drawText(0, offset + r.height() * line.relativeValue, line.caption); - } - p.setOpacity(alpha); -} - void PaintBottomLine( QPainter &p, const std::vector &dates, @@ -653,7 +621,7 @@ void ChartWidget::ChartAnimationController::restartBottomLineAlpha() { void ChartWidget::ChartAnimationController::tick( crl::time now, - std::vector &horizontalLines, + ChartHorizontalLinesView &horizontalLinesView, std::vector &dateLines, const std::unique_ptr &chartView) { if (!_animation.animating()) { @@ -725,7 +693,6 @@ void ChartWidget::ChartAnimationController::tick( && footerMinFinished && footerMaxFinished && chartView->isFinished()) { - const auto &lines = horizontalLines.back().lines; if ((_finalHeightLimits.min == _animationValueHeightMin.to()) && _finalHeightLimits.max == _animationValueHeightMax.to()) { _animation.stop(); @@ -755,11 +722,9 @@ void ChartWidget::ChartAnimationController::tick( _dtHeight.current.max, anim::easeInCubic); - for (auto &horizontalLine : horizontalLines) { - horizontalLine.computeRelative( - _animationValueHeightMax.current(), - _animationValueHeightMin.current()); - } + horizontalLinesView.computeRelative( + _animationValueHeightMax.current(), + _animationValueHeightMin.current()); } if (!footerMinFinished) { _animationValueFooterHeightMin.update( @@ -776,22 +741,7 @@ void ChartWidget::ChartAnimationController::tick( _animationValueHeightAlpha.update( _dtHeight.currentAlpha, anim::easeInCubic); - const auto value = _animationValueHeightAlpha.current(); - - for (auto &horizontalLine : horizontalLines) { - horizontalLine.alpha = horizontalLine.fixedAlpha * (1. - value); - } - horizontalLines.back().alpha = value; - if (value == 1.) { - while (horizontalLines.size() > 1) { - const auto startIt = begin(horizontalLines); - if (!startIt->alpha) { - horizontalLines.erase(startIt); - } else { - break; - } - } - } + horizontalLinesView.setAlpha(_animationValueHeightAlpha.current()); } if (!bottomLineAlphaFinished) { @@ -948,7 +898,7 @@ void ChartWidget::setupChartArea() { _animationController.tick( now, - _horizontalLines, + _horizontalLinesView, _bottomLine.dates, _chartView); @@ -956,9 +906,7 @@ void ChartWidget::setupChartArea() { p.fillRect(r, st::boxBg); - for (auto &horizontalLine : _horizontalLines) { - PaintHorizontalLines(p, horizontalLine, chartRect); - } + _horizontalLinesView.paintHorizontalLines(p, chartRect); if (_chartData) { // p.setRenderHint( @@ -976,9 +924,7 @@ void ChartWidget::setupChartArea() { false); } - for (auto &horizontalLine : _horizontalLines) { - PaintCaptionsToHorizontalLines(p, horizontalLine, chartRect); - } + _horizontalLinesView.paintCaptionsToHorizontalLines(p, chartRect); { const auto bottom = r - QMargins{ 0, rect::bottom(chartRect), 0, 0 }; @@ -1124,7 +1070,9 @@ void ChartWidget::setupFooter() { _animationController.addHorizontalLineRequests( ) | rpl::start_with_next([=] { - addHorizontalLine(_animationController.finalHeightLimits(), true); + _horizontalLinesView.add( + _animationController.finalHeightLimits(), + true); _animationController.start(); }, _footer->lifetime()); @@ -1149,7 +1097,9 @@ void ChartWidget::setupFooter() { return; } _lastHeightLimitsChanged = now; - addHorizontalLine(_animationController.finalHeightLimits(), true); + _horizontalLinesView.add( + _animationController.finalHeightLimits(), + true); }, _footer->lifetime()); } @@ -1280,6 +1230,7 @@ void ChartWidget::setChartData( _chartData = std::move(chartData); _chartView = CreateChartView(type); + _horizontalLinesView.setChartData(_chartData, type); setupDetails(); setupFilterButtons(); @@ -1293,7 +1244,7 @@ void ChartWidget::setChartData( updateHeader(); updateBottomDates(); _animationController.finish(); - addHorizontalLine(_animationController.finalHeightLimits(), false); + _horizontalLinesView.add(_animationController.finalHeightLimits(), false); RpWidget::showChildren(); _chartArea->update(); @@ -1357,23 +1308,6 @@ void ChartWidget::setZoomedChartData( zoomOutButton->moveToLeft(0, 0); } -void ChartWidget::addHorizontalLine(Limits newHeight, bool animated) { - const auto newLinesData = ChartHorizontalLinesData( - newHeight.max, - newHeight.min, - true); - if (!animated) { - _horizontalLines.clear(); - } - for (auto &horizontalLine : _horizontalLines) { - horizontalLine.fixedAlpha = horizontalLine.alpha; - } - _horizontalLines.push_back(newLinesData); - if (!animated) { - _horizontalLines.back().alpha = 1.; - } -} - rpl::producer ChartWidget::zoomRequests() { _zoomEnabled = true; setupDetails(); diff --git a/Telegram/SourceFiles/statistics/chart_widget.h b/Telegram/SourceFiles/statistics/chart_widget.h index 56d858b4f..ef0446c2d 100644 --- a/Telegram/SourceFiles/statistics/chart_widget.h +++ b/Telegram/SourceFiles/statistics/chart_widget.h @@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "data/data_statistics.h" -#include "statistics/chart_horizontal_lines_data.h" +#include "statistics/view/chart_horizontal_lines_view.h" #include "statistics/statistics_common.h" #include "ui/effects/animation_value.h" #include "ui/effects/animations.h" @@ -68,7 +68,7 @@ private: void restartBottomLineAlpha(); void tick( crl::time now, - std::vector &horizontalLines, + ChartHorizontalLinesView &horizontalLinesView, std::vector &dateLines, const std::unique_ptr &AbstractChartView); @@ -162,7 +162,7 @@ private: ChartAnimationController _animationController; crl::time _lastHeightLimitsChanged = 0; - std::vector _horizontalLines; + ChartHorizontalLinesView _horizontalLinesView; bool _zoomEnabled = false; rpl::event_stream _zoomRequests; diff --git a/Telegram/SourceFiles/statistics/view/chart_horizontal_lines_view.cpp b/Telegram/SourceFiles/statistics/view/chart_horizontal_lines_view.cpp new file mode 100644 index 000000000..d52e6aa05 --- /dev/null +++ b/Telegram/SourceFiles/statistics/view/chart_horizontal_lines_view.cpp @@ -0,0 +1,106 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "statistics/view/chart_horizontal_lines_view.h" + +#include "data/data_statistics.h" +#include "statistics/statistics_common.h" +#include "styles/style_statistics.h" + +namespace Statistic { + +ChartHorizontalLinesView::ChartHorizontalLinesView() = default; + +void ChartHorizontalLinesView::setChartData( + const Data::StatisticalChart &chartData, + ChartViewType type) { + _isDouble = (type == ChartViewType::DoubleLinear); + if (_isDouble && (chartData.lines.size() == 2)) { + _leftColor = chartData.lines.front().color; + _rightColor = chartData.lines.back().color; + } +} + +void ChartHorizontalLinesView::paintHorizontalLines( + QPainter &p, + const QRect &r) { + for (auto &horizontalLine : _horizontalLines) { + const auto alpha = p.opacity(); + p.setOpacity(horizontalLine.alpha); + for (const auto &line : horizontalLine.lines) { + const auto lineRect = QRect( + 0, + r.y() + r.height() * line.relativeValue, + r.x() + r.width(), + st::lineWidth); + p.fillRect(lineRect, st::windowSubTextFg); + } + p.setOpacity(alpha); + } +} + +void ChartHorizontalLinesView::paintCaptionsToHorizontalLines( + QPainter &p, + const QRect &r) { + for (auto &horizontalLine : _horizontalLines) { + const auto alpha = p.opacity(); + p.setOpacity(horizontalLine.alpha); + p.setFont(st::statisticsDetailsBottomCaptionStyle.font); + p.setPen(st::windowSubTextFg); + const auto offset = r.y() + - st::statisticsChartHorizontalLineCaptionSkip; + for (const auto &line : horizontalLine.lines) { + const auto y = offset + r.height() * line.relativeValue; + p.drawText(0, y, line.caption); + } + p.setOpacity(alpha); + } +} + +void ChartHorizontalLinesView::computeRelative( + int newMaxHeight, + int newMinHeight) { + for (auto &horizontalLine : _horizontalLines) { + horizontalLine.computeRelative(newMaxHeight, newMinHeight); + } +} + +void ChartHorizontalLinesView::setAlpha(float64 value) { + for (auto &horizontalLine : _horizontalLines) { + horizontalLine.alpha = horizontalLine.fixedAlpha * (1. - value); + } + _horizontalLines.back().alpha = value; + if (value == 1.) { + while (_horizontalLines.size() > 1) { + const auto startIt = begin(_horizontalLines); + if (!startIt->alpha) { + _horizontalLines.erase(startIt); + } else { + break; + } + } + } +} + +void ChartHorizontalLinesView::add(Limits newHeight, bool animated) { + const auto newLinesData = ChartHorizontalLinesData( + newHeight.max, + newHeight.min, + true); + if (!animated) { + _horizontalLines.clear(); + } + for (auto &horizontalLine : _horizontalLines) { + horizontalLine.fixedAlpha = horizontalLine.alpha; + } + _horizontalLines.push_back(newLinesData); + if (!animated) { + _horizontalLines.back().alpha = 1.; + } +} + +} // namespace Statistic diff --git a/Telegram/SourceFiles/statistics/view/chart_horizontal_lines_view.h b/Telegram/SourceFiles/statistics/view/chart_horizontal_lines_view.h new file mode 100644 index 000000000..f8ad7b419 --- /dev/null +++ b/Telegram/SourceFiles/statistics/view/chart_horizontal_lines_view.h @@ -0,0 +1,46 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "statistics/chart_horizontal_lines_data.h" + +namespace Data { +struct StatisticalChart; +} // namespace Data + +namespace Statistic { + +enum class ChartViewType; +struct Limits; + +struct ChartHorizontalLinesView final { +public: + ChartHorizontalLinesView(); + + void setChartData( + const Data::StatisticalChart &chartData, + ChartViewType type); + + void paintHorizontalLines(QPainter &p, const QRect &r); + + void paintCaptionsToHorizontalLines(QPainter &p, const QRect &r); + + void computeRelative(int newMaxHeight, int newMinHeight); + void setAlpha(float64 value); + void add(Limits newHeight, bool animated); + +private: + bool _isDouble = false; + QColor _leftColor; + QColor _rightColor; + + std::vector _horizontalLines; + +}; + +} // namespace Statistic