diff --git a/Telegram/SourceFiles/statistics/chart_widget.cpp b/Telegram/SourceFiles/statistics/chart_widget.cpp index 422d6f84f..ee99ed772 100644 --- a/Telegram/SourceFiles/statistics/chart_widget.cpp +++ b/Telegram/SourceFiles/statistics/chart_widget.cpp @@ -923,22 +923,24 @@ void ChartWidget::setupChartArea() { p.fillRect(r, st::boxBg); + if (!_chartData) { + return; + } + _horizontalLinesView.paintHorizontalLines(p, chartRect); - if (_chartData) { - // p.setRenderHint( - // QPainter::Antialiasing, - // !_animationController.isFPSSlow() - // || !_animationController.animating()); + const auto context = PaintContext{ + _chartData, + _animationController.currentXIndices(), + _animationController.currentXLimits(), + _animationController.currentHeightLimits(), + chartRect, + false, + }; + + { PainterHighQualityEnabler hp(p); - _chartView->paint( - p, - _chartData, - _animationController.currentXIndices(), - _animationController.currentXLimits(), - _animationController.currentHeightLimits(), - chartRect, - false); + _chartView->paint(p, context); } _horizontalLinesView.paintCaptionsToHorizontalLines(p, chartRect); @@ -960,10 +962,7 @@ void ChartWidget::setupChartArea() { } _chartView->paintSelectedXIndex( p, - _chartData, - _animationController.currentXLimits(), - _animationController.currentHeightLimits(), - chartRect, + context, _details.widget->xIndex(), detailsAlpha); } @@ -1069,19 +1068,18 @@ void ChartWidget::setupFooter() { const QRect &r) { if (_chartData) { p.fillRect(r, st::boxBg); - // p.setRenderHint( - // QPainter::Antialiasing, - // !_animationController.isFPSSlow() - // || !_animationController.animating()); - PainterHighQualityEnabler hp(p); + + auto hp = PainterHighQualityEnabler(p); _chartView->paint( p, - _chartData, - { 0., float64(_chartData.x.size() - 1) }, - fullXLimits, - _animationController.currentFooterHeightLimits(), - r, - true); + PaintContext{ + _chartData, + { 0., float64(_chartData.x.size() - 1) }, + fullXLimits, + _animationController.currentFooterHeightLimits(), + r, + true, + }); } }); diff --git a/Telegram/SourceFiles/statistics/view/abstract_chart_view.h b/Telegram/SourceFiles/statistics/view/abstract_chart_view.h index db347b582..8e1b2326c 100644 --- a/Telegram/SourceFiles/statistics/view/abstract_chart_view.h +++ b/Telegram/SourceFiles/statistics/view/abstract_chart_view.h @@ -15,25 +15,24 @@ namespace Statistic { struct Limits; +struct PaintContext final { + const Data::StatisticalChart &chartData; + const Limits &xIndices; + const Limits &xPercentageLimits; + const Limits &heightLimits; + const QRect ▭ + bool footer = false; +}; + class AbstractChartView { public: virtual ~AbstractChartView() = default; - virtual void paint( - QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xIndices, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, - bool footer) = 0; + virtual void paint(QPainter &p, const PaintContext &c) = 0; virtual void paintSelectedXIndex( QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, + const PaintContext &c, int selectedXIndex, float64 progress) = 0; diff --git a/Telegram/SourceFiles/statistics/view/linear_chart_view.cpp b/Telegram/SourceFiles/statistics/view/linear_chart_view.cpp index 5d005d6c1..15c6cd607 100644 --- a/Telegram/SourceFiles/statistics/view/linear_chart_view.cpp +++ b/Telegram/SourceFiles/statistics/view/linear_chart_view.cpp @@ -26,20 +26,16 @@ float64 Ratio(const LinearChartView::CachedLineRatios &ratios, int id) { void PaintChartLine( QPainter &p, int lineIndex, - const Data::StatisticalChart &chartData, - const Limits &xIndices, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QSize &size, + const PaintContext &c, const LinearChartView::CachedLineRatios &ratios) { - const auto &line = chartData.lines[lineIndex]; + const auto &line = c.chartData.lines[lineIndex]; auto chartPoints = QPolygonF(); - const auto localStart = std::max(0, int(xIndices.min)); + const auto localStart = std::max(0, int(c.xIndices.min)); const auto localEnd = std::min( - int(chartData.xPercentage.size() - 1), - int(xIndices.max)); + int(c.chartData.xPercentage.size() - 1), + int(c.xIndices.max)); const auto ratio = Ratio(ratios, line.id); @@ -47,12 +43,12 @@ void PaintChartLine( if (line.y[i] < 0) { continue; } - const auto xPoint = size.width() - * ((chartData.xPercentage[i] - xPercentageLimits.min) - / (xPercentageLimits.max - xPercentageLimits.min)); - const auto yPercentage = (line.y[i] * ratio - heightLimits.min) - / float64(heightLimits.max - heightLimits.min); - const auto yPoint = (1. - yPercentage) * size.height(); + const auto xPoint = c.rect.width() + * ((c.chartData.xPercentage[i] - c.xPercentageLimits.min) + / (c.xPercentageLimits.max - c.xPercentageLimits.min)); + const auto yPercentage = (line.y[i] * ratio - c.heightLimits.min) + / float64(c.heightLimits.max - c.heightLimits.min); + const auto yPoint = (1. - yPercentage) * c.rect.height(); chartPoints << QPointF(xPoint, yPoint); } p.setPen(QPen(line.color, st::statisticsChartLineWidth)); @@ -68,27 +64,19 @@ LinearChartView::LinearChartView(bool isDouble) LinearChartView::~LinearChartView() = default; -void LinearChartView::paint( - QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xIndices, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, - bool footer) { - +void LinearChartView::paint(QPainter &p, const PaintContext &c) { const auto cacheToken = LinearChartView::CacheToken( - xIndices, - xPercentageLimits, - heightLimits, - rect.size()); + c.xIndices, + c.xPercentageLimits, + c.heightLimits, + c.rect.size()); - const auto imageSize = rect.size() * style::DevicePixelRatio(); + const auto imageSize = c.rect.size() * style::DevicePixelRatio(); const auto cacheScale = 1. / style::DevicePixelRatio(); - auto &caches = (footer ? _footerCaches : _mainCaches); + auto &caches = (c.footer ? _footerCaches : _mainCaches); - for (auto i = 0; i < chartData.lines.size(); i++) { - const auto &line = chartData.lines[i]; + for (auto i = 0; i < c.chartData.lines.size(); i++) { + const auto &line = c.chartData.lines[i]; p.setOpacity(alpha(line.id)); if (!p.opacity()) { continue; @@ -99,7 +87,7 @@ void LinearChartView::paint( const auto isSameToken = (cache.lastToken == cacheToken); if ((isSameToken && cache.hq) || (p.opacity() < 1. && !isEnabled(line.id))) { - p.drawImage(rect.topLeft(), cache.image); + p.drawImage(c.rect.topLeft(), cache.image); continue; } cache.hq = isSameToken; @@ -116,15 +104,7 @@ void LinearChartView::paint( imagePainter.scale(cacheScale, cacheScale); } - PaintChartLine( - imagePainter, - i, - chartData, - xIndices, - xPercentageLimits, - heightLimits, - rect.size(), - _cachedLineRatios); + PaintChartLine(imagePainter, i, c, _cachedLineRatios); } if (!isSameToken) { @@ -133,7 +113,7 @@ void LinearChartView::paint( Qt::IgnoreAspectRatio, Qt::FastTransformation); } - p.drawImage(rect.topLeft(), image); + p.drawImage(c.rect.topLeft(), image); cache.lastToken = cacheToken; cache.image = std::move(image); } @@ -141,10 +121,7 @@ void LinearChartView::paint( void LinearChartView::paintSelectedXIndex( QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, + const PaintContext &c, int selectedXIndex, float64 progress) { if (selectedXIndex < 0) { @@ -156,36 +133,36 @@ void LinearChartView::paintSelectedXIndex( const auto r = st::statisticsDetailsDotRadius; const auto i = selectedXIndex; const auto isSameToken = (_selectedPoints.lastXIndex == selectedXIndex) - && (_selectedPoints.lastHeightLimits.min == heightLimits.min) - && (_selectedPoints.lastHeightLimits.max == heightLimits.max) - && (_selectedPoints.lastXLimits.min == xPercentageLimits.min) - && (_selectedPoints.lastXLimits.max == xPercentageLimits.max); + && (_selectedPoints.lastHeightLimits.min == c.heightLimits.min) + && (_selectedPoints.lastHeightLimits.max == c.heightLimits.max) + && (_selectedPoints.lastXLimits.min == c.xPercentageLimits.min) + && (_selectedPoints.lastXLimits.max == c.xPercentageLimits.max); auto linePainted = false; - for (const auto &line : chartData.lines) { + for (const auto &line : c.chartData.lines) { const auto lineAlpha = alpha(line.id); const auto useCache = isSameToken || (lineAlpha < 1. && !isEnabled(line.id)); if (!useCache) { // Calculate. const auto r = Ratio(_cachedLineRatios, line.id); - const auto xPoint = rect.width() - * ((chartData.xPercentage[i] - xPercentageLimits.min) - / (xPercentageLimits.max - xPercentageLimits.min)); - const auto yPercentage = (line.y[i] * r - heightLimits.min) - / float64(heightLimits.max - heightLimits.min); - const auto yPoint = (1. - yPercentage) * rect.height(); + const auto xPoint = c.rect.width() + * ((c.chartData.xPercentage[i] - c.xPercentageLimits.min) + / (c.xPercentageLimits.max - c.xPercentageLimits.min)); + const auto yPercentage = (line.y[i] * r - c.heightLimits.min) + / float64(c.heightLimits.max - c.heightLimits.min); + const auto yPoint = (1. - yPercentage) * c.rect.height(); _selectedPoints.points[line.id] = QPointF(xPoint, yPoint) - + rect.topLeft(); + + c.rect.topLeft(); } if (!linePainted) { const auto lineRect = QRectF( - rect.x() + c.rect.x() + begin(_selectedPoints.points)->second.x() - (st::lineWidth / 2.), - rect.y(), + c.rect.y(), st::lineWidth, - rect.height()); + c.rect.height()); p.fillRect(lineRect, st::windowSubTextFg); linePainted = true; } @@ -196,8 +173,8 @@ void LinearChartView::paintSelectedXIndex( p.drawEllipse(_selectedPoints.points[line.id], r, r); } _selectedPoints.lastXIndex = selectedXIndex; - _selectedPoints.lastHeightLimits = heightLimits; - _selectedPoints.lastXLimits = xPercentageLimits; + _selectedPoints.lastHeightLimits = c.heightLimits; + _selectedPoints.lastXLimits = c.xPercentageLimits; } int LinearChartView::findXIndexByPosition( diff --git a/Telegram/SourceFiles/statistics/view/linear_chart_view.h b/Telegram/SourceFiles/statistics/view/linear_chart_view.h index 62af443fb..813cabe3a 100644 --- a/Telegram/SourceFiles/statistics/view/linear_chart_view.h +++ b/Telegram/SourceFiles/statistics/view/linear_chart_view.h @@ -25,21 +25,11 @@ public: LinearChartView(bool isDouble); ~LinearChartView() override final; - void paint( - QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xIndices, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, - bool footer) override; + void paint(QPainter &p, const PaintContext &c) override; void paintSelectedXIndex( QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, + const PaintContext &c, int selectedXIndex, float64 progress) override; diff --git a/Telegram/SourceFiles/statistics/view/stack_chart_view.cpp b/Telegram/SourceFiles/statistics/view/stack_chart_view.cpp index 317e10639..708edd1b0 100644 --- a/Telegram/SourceFiles/statistics/view/stack_chart_view.cpp +++ b/Telegram/SourceFiles/statistics/view/stack_chart_view.cpp @@ -23,76 +23,60 @@ StackChartView::StackChartView() = default; StackChartView::~StackChartView() = default; -void StackChartView::paint( - QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xIndices, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, - bool footer) { +void StackChartView::paint(QPainter &p, const PaintContext &c) { constexpr auto kOffset = float64(2); _lastPaintedXIndices = { - float64(std::max(0., xIndices.min - kOffset)), + float64(std::max(0., c.xIndices.min - kOffset)), float64(std::min( - float64(chartData.xPercentage.size() - 1), - xIndices.max + kOffset)), + float64(c.chartData.xPercentage.size() - 1), + c.xIndices.max + kOffset)), }; - StackChartView::paint( - p, - chartData, - xPercentageLimits, - heightLimits, - rect, - footer); + StackChartView::paintChartAndSelected(p, c); } -void StackChartView::paint( +void StackChartView::paintChartAndSelected( QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, - bool footer) { + const PaintContext &c) { const auto &[localStart, localEnd] = _lastPaintedXIndices; const auto &[leftStart, w] = ComputeLeftStartAndStep( - chartData, - xPercentageLimits, - rect, + c.chartData, + c.xPercentageLimits, + c.rect, localStart); const auto opacity = p.opacity(); auto hq = PainterHighQualityEnabler(p); - auto bottoms = std::vector(localEnd - localStart + 1, -rect.y()); + auto bottoms = std::vector( + localEnd - localStart + 1, + -c.rect.y()); auto selectedBottoms = std::vector(); - const auto hasSelectedXIndex = !footer && (_lastSelectedXIndex >= 0); + const auto hasSelectedXIndex = !c.footer && (_lastSelectedXIndex >= 0); if (hasSelectedXIndex) { - selectedBottoms = std::vector(chartData.lines.size(), 0); + selectedBottoms = std::vector(c.chartData.lines.size(), 0); constexpr auto kSelectedAlpha = 0.5; p.setOpacity( anim::interpolateF(1.0, kSelectedAlpha, _lastSelectedXProgress)); } - for (auto i = 0; i < chartData.lines.size(); i++) { - const auto &line = chartData.lines[i]; + for (auto i = 0; i < c.chartData.lines.size(); i++) { + const auto &line = c.chartData.lines[i]; auto path = QPainterPath(); for (auto x = localStart; x <= localEnd; x++) { if (line.y[x] <= 0) { continue; } - const auto xPoint = rect.width() - * ((chartData.xPercentage[x] - xPercentageLimits.min) - / (xPercentageLimits.max - xPercentageLimits.min)); - const auto yPercentage = (line.y[x] - heightLimits.min) - / float64(heightLimits.max - heightLimits.min); - const auto yPoint = yPercentage * rect.height() * alpha(line.id); + const auto yPercentage = (line.y[x] - c.heightLimits.min) + / float64(c.heightLimits.max - c.heightLimits.min); + const auto yPoint = yPercentage + * c.rect.height() + * alpha(line.id); const auto bottomIndex = x - localStart; const auto column = QRectF( leftStart + (x - localStart) * w, - rect.height() - bottoms[bottomIndex] - yPoint, + c.rect.height() - bottoms[bottomIndex] - yPoint, w, yPoint); if (hasSelectedXIndex && (x == _lastSelectedXIndex)) { @@ -110,10 +94,10 @@ void StackChartView::paint( if (selectedBottoms[i] <= 0) { continue; } - const auto &line = chartData.lines[i]; - const auto yPercentage = (line.y[_lastSelectedXIndex] - heightLimits.min) - / float64(heightLimits.max - heightLimits.min); - const auto yPoint = yPercentage * rect.height() * alpha(line.id); + const auto &line = c.chartData.lines[i]; + const auto yPercentage = (line.y[_lastSelectedXIndex] - c.heightLimits.min) + / float64(c.heightLimits.max - c.heightLimits.min); + const auto yPoint = yPercentage * c.rect.height() * alpha(line.id); const auto column = QRectF( leftStart + (_lastSelectedXIndex - localStart) * w, @@ -126,22 +110,13 @@ void StackChartView::paint( void StackChartView::paintSelectedXIndex( QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, + const PaintContext &c, int selectedXIndex, float64 progress) { _lastSelectedXIndex = selectedXIndex; _lastSelectedXProgress = progress; [[maybe_unused]] const auto o = ScopedPainterOpacity(p, progress); - StackChartView::paint( - p, - chartData, - xPercentageLimits, - heightLimits, - rect, - false); + StackChartView::paintChartAndSelected(p, c); } int StackChartView::findXIndexByPosition( diff --git a/Telegram/SourceFiles/statistics/view/stack_chart_view.h b/Telegram/SourceFiles/statistics/view/stack_chart_view.h index 34cc8e0bc..13e2e8b8c 100644 --- a/Telegram/SourceFiles/statistics/view/stack_chart_view.h +++ b/Telegram/SourceFiles/statistics/view/stack_chart_view.h @@ -25,21 +25,11 @@ public: StackChartView(); ~StackChartView() override final; - void paint( - QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xIndices, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, - bool footer) override; + void paint(QPainter &p, const PaintContext &c) override; void paintSelectedXIndex( QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, + const PaintContext &c, int selectedXIndex, float64 progress) override; @@ -62,13 +52,7 @@ public: void update(float64 dt) override; private: - void paint( - QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, - bool footer); + void paintChartAndSelected(QPainter &p, const PaintContext &c); struct { Limits full; diff --git a/Telegram/SourceFiles/statistics/view/stack_linear_chart_view.cpp b/Telegram/SourceFiles/statistics/view/stack_linear_chart_view.cpp index a6a9d861a..553a0b61f 100644 --- a/Telegram/SourceFiles/statistics/view/stack_linear_chart_view.cpp +++ b/Telegram/SourceFiles/statistics/view/stack_linear_chart_view.cpp @@ -48,28 +48,21 @@ StackLinearChartView::StackLinearChartView() = default; StackLinearChartView::~StackLinearChartView() = default; -void StackLinearChartView::paint( - QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xIndices, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, - bool footer) { +void StackLinearChartView::paint(QPainter &p, const PaintContext &c) { constexpr auto kOffset = float64(2); const auto wasXIndices = _lastPaintedXIndices; _lastPaintedXIndices = { - float64(std::max(0., xIndices.min - kOffset)), + float64(std::max(0., c.xIndices.min - kOffset)), float64(std::min( - float64(chartData.xPercentage.size() - 1), - xIndices.max + kOffset)), + float64(c.chartData.xPercentage.size() - 1), + c.xIndices.max + kOffset)), }; if ((wasXIndices.min != _lastPaintedXIndices.min) || (wasXIndices.max != _lastPaintedXIndices.max)) { const auto &[localStart, localEnd] = _lastPaintedXIndices; _cachedTransition.lines = std::vector( - chartData.lines.size(), + c.chartData.lines.size(), Transition::TransitionLine()); for (auto j = 0; j < 2; j++) { @@ -77,7 +70,7 @@ void StackLinearChartView::paint( auto stackOffset = 0; auto sum = 0.; auto drawingLinesCount = 0; - for (const auto &line : chartData.lines) { + for (const auto &line : c.chartData.lines) { if (!isEnabled(line.id)) { continue; } @@ -87,11 +80,11 @@ void StackLinearChartView::paint( } } - for (auto k = 0; k < chartData.lines.size(); k++) { + for (auto k = 0; k < c.chartData.lines.size(); k++) { auto &linePoint = (j ? _cachedTransition.lines[k].end : _cachedTransition.lines[k].start); - const auto &line = chartData.lines[k]; + const auto &line = c.chartData.lines[k]; if (!isEnabled(line.id)) { continue; } @@ -99,22 +92,22 @@ void StackLinearChartView::paint( ? (line.y[i] ? alpha(line.id) : 0) : (sum ? (line.y[i] * alpha(line.id) / sum) : 0); - const auto xPoint = rect.width() - * ((chartData.xPercentage[i] - xPercentageLimits.min) - / (xPercentageLimits.max - xPercentageLimits.min)); - const auto height = yPercentage * rect.height(); - const auto yPoint = rect::bottom(rect) - height - stackOffset; + const auto xPoint = c.rect.width() + * ((c.chartData.xPercentage[i] - c.xPercentageLimits.min) + / (c.xPercentageLimits.max - c.xPercentageLimits.min)); + const auto height = yPercentage * c.rect.height(); + const auto yPoint = rect::bottom(c.rect) - height - stackOffset; linePoint = { xPoint, yPoint }; stackOffset += height; } } auto sums = std::vector(); - sums.reserve(chartData.lines.size()); + sums.reserve(c.chartData.lines.size()); auto totalSum = 0; - for (const auto &line : chartData.lines) { + for (const auto &line : c.chartData.lines) { auto sum = 0; - for (auto i = xIndices.min; i <= xIndices.max; i++) { + for (auto i = c.xIndices.min; i <= c.xIndices.max; i++) { sum += line.y[i]; } sum *= alpha(line.id); @@ -129,43 +122,26 @@ void StackLinearChartView::paint( } } - StackLinearChartView::paint( - p, - chartData, - xPercentageLimits, - heightLimits, - rect, - footer); + StackLinearChartView::paintChartOrZoomAnimation(p, c); } -void StackLinearChartView::paint( +void StackLinearChartView::paintChartOrZoomAnimation( QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, - bool footer) { - const auto context = PaintContext{ - chartData, - xPercentageLimits, - heightLimits, - rect, - footer - }; + const PaintContext &c) { if (_transitionProgress == 1.) { - if (footer) { - return paintZoomedFooter(p, context); + if (c.footer) { + return paintZoomedFooter(p, c); } else { - return paintZoomed(p, context); + return paintZoomed(p, c); } } const auto &[localStart, localEnd] = _lastPaintedXIndices; - _skipPoints = std::vector(chartData.lines.size(), false); + _skipPoints = std::vector(c.chartData.lines.size(), false); auto paths = std::vector( - chartData.lines.size(), + c.chartData.lines.size(), QPainterPath()); - const auto center = QPointF(rect.center()); + const auto center = QPointF(c.rect.center()); const auto rotate = [&](float64 ang, const QPointF &p) { return QTransform() @@ -175,7 +151,7 @@ void StackLinearChartView::paint( .map(p); }; - const auto hasTransitionAnimation = _transitionProgress && !footer; + const auto hasTransitionAnimation = _transitionProgress && !c.footer; auto straightLineProgress = 0.; auto hasEmptyPoint = false; @@ -188,13 +164,13 @@ void StackLinearChartView::paint( 0., 1.); auto rectPath = QPainterPath(); - rectPath.addRect(rect); + rectPath.addRect(c.rect); const auto r = anim::interpolateF( 1., kCircleSizeRatio, _transitionProgress); const auto per = anim::interpolateF(0., 100., _transitionProgress); - const auto side = (rect.width() / 2.) * r; + const auto side = (c.rect.width() / 2.) * r; const auto rectF = QRectF( center - QPointF(side, side), center + QPointF(side, side)); @@ -209,8 +185,8 @@ void StackLinearChartView::paint( auto drawingLinesCount = int(0); - for (auto k = 0; k < chartData.lines.size(); k++) { - const auto &line = chartData.lines[k]; + for (auto k = 0; k < c.chartData.lines.size(); k++) { + const auto &line = c.chartData.lines[k]; if (!isEnabled(line.id)) { continue; } @@ -221,8 +197,8 @@ void StackLinearChartView::paint( lastEnabled = k; } - for (auto k = 0; k < chartData.lines.size(); k++) { - const auto &line = chartData.lines[k]; + for (auto k = 0; k < c.chartData.lines.size(); k++) { + const auto &line = c.chartData.lines[k]; const auto isLastLine = (k == lastEnabled); const auto &transitionLine = _cachedTransition.lines[k]; if (!isEnabled(line.id)) { @@ -237,20 +213,20 @@ void StackLinearChartView::paint( ? float64(y[i] ? lineAlpha : 0.) : float64(sum ? (y[i] * lineAlpha / sum) : 0.); - const auto xPoint = rect.width() - * ((chartData.xPercentage[i] - xPercentageLimits.min) - / (xPercentageLimits.max - xPercentageLimits.min)); + const auto xPoint = c.rect.width() + * ((c.chartData.xPercentage[i] - c.xPercentageLimits.min) + / (c.xPercentageLimits.max - c.xPercentageLimits.min)); if (!yPercentage && isLastLine) { hasEmptyPoint = true; } - const auto height = yPercentage * rect.height(); - const auto yPoint = rect::bottom(rect) - height - stackOffset; + const auto height = yPercentage * c.rect.height(); + const auto yPoint = rect::bottom(c.rect) - height - stackOffset; // startFromY[k] = yPoint; auto angle = 0.; auto resultPoint = QPointF(xPoint, yPoint); - auto pointZero = QPointF(xPoint, rect.y() + rect.height()); + auto pointZero = QPointF(xPoint, c.rect.y() + c.rect.height()); // if (i == localEnd) { // endXPoint = xPoint; // } else if (i == localStart) { @@ -289,11 +265,11 @@ void StackLinearChartView::paint( std::max(pointZero.x(), center.x()), rotate(resultAngle, pointZero).y()); } else { - const auto &xLimits = xPercentageLimits; + const auto &xLimits = c.xPercentageLimits; const auto isNextXPointAfterCenter = false - || center.x() < (rect.width() * ((i == localEnd) + || center.x() < (c.rect.width() * ((i == localEnd) ? 1. - : ((chartData.xPercentage[i + 1] - xLimits.min) + : ((c.chartData.xPercentage[i + 1] - xLimits.min) / (xLimits.max - xLimits.min)))); if (isNextXPointAfterCenter) { pointZero = resultPoint = QPointF() @@ -309,7 +285,7 @@ void StackLinearChartView::paint( } if (i == localStart) { - const auto bottomLeft = QPointF(rect.x(), rect::bottom(rect)); + const auto bottomLeft = QPointF(c.rect.x(), rect::bottom(c.rect)); const auto local = (hasTransitionAnimation && !isLastLine) ? rotate( _transitionProgress * angle @@ -361,10 +337,10 @@ void StackLinearChartView::paint( || (local.y() > center.y() && resultPoint.y() > center.y())); const auto endQuarter = (!ending) - ? QuarterForPoint(rect, resultPoint) + ? QuarterForPoint(c.rect, resultPoint) : kRightTop; const auto startQuarter = (!ending) - ? QuarterForPoint(rect, local) + ? QuarterForPoint(c.rect, local) : (transitionLine.angle == -180.) ? kRightTop : kLeftTop; @@ -372,14 +348,14 @@ void StackLinearChartView::paint( for (auto q = endQuarter; q <= startQuarter; q++) { chartPath.lineTo( (q == kLeftTop || q == kLeftBottom) - ? rect.x() - : rect::right(rect), + ? c.rect.x() + : rect::right(c.rect), (q == kLeftTop || q == kRightTop) - ? rect.y() - : rect::right(rect)); + ? c.rect.y() + : rect::right(c.rect)); } } else { - chartPath.lineTo(rect::right(rect), rect::bottom(rect)); + chartPath.lineTo(rect::right(c.rect), rect::bottom(c.rect)); } } @@ -389,23 +365,23 @@ void StackLinearChartView::paint( auto hq = PainterHighQualityEnabler(p); - p.fillRect(rect, st::boxBg); + p.fillRect(c.rect, st::boxBg); if (!ovalPath.isEmpty()) { p.setClipPath(ovalPath); } - const auto opacity = footer ? (1. - _transitionProgress) : 1.; - for (auto k = int(chartData.lines.size() - 1); k >= 0; k--) { + const auto opacity = c.footer ? (1. - _transitionProgress) : 1.; + for (auto k = int(c.chartData.lines.size() - 1); k >= 0; k--) { if (paths[k].isEmpty()) { continue; } - const auto &line = chartData.lines[k]; + const auto &line = c.chartData.lines[k]; p.setOpacity(alpha(line.id) * opacity); p.setPen(Qt::NoPen); p.fillPath(paths[k], line.color); } p.setOpacity(opacity); - if (!footer) { + if (!c.footer) { constexpr auto kAlphaTextPart = 0.6; const auto progress = std::clamp( (_transitionProgress - kAlphaTextPart) / (1. - kAlphaTextPart), @@ -413,14 +389,14 @@ void StackLinearChartView::paint( 1.); if (progress > 0) { auto o = ScopedPainterOpacity(p, progress); - paintPieText(p, context); + paintPieText(p, c); } } else { - paintZoomedFooter(p, context); + paintZoomedFooter(p, c); } // Fix ugly outline. - if (!footer || !_transitionProgress) { + if (!c.footer || !_transitionProgress) { p.setBrush(Qt::transparent); p.setPen(st::boxBg); p.drawPath(ovalPath); @@ -672,10 +648,7 @@ bool StackLinearChartView::skipSelectedTranslation() const { void StackLinearChartView::paintSelectedXIndex( QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, + const PaintContext &c, int selectedXIndex, float64 progress) { if (selectedXIndex < 0) { @@ -685,39 +658,39 @@ void StackLinearChartView::paintSelectedXIndex( const auto r = st::statisticsDetailsDotRadius; const auto i = selectedXIndex; const auto isSameToken = (_selectedPoints.lastXIndex == selectedXIndex) - && (_selectedPoints.lastHeightLimits.min == heightLimits.min) - && (_selectedPoints.lastHeightLimits.max == heightLimits.max) - && (_selectedPoints.lastXLimits.min == xPercentageLimits.min) - && (_selectedPoints.lastXLimits.max == xPercentageLimits.max); - for (const auto &line : chartData.lines) { + && (_selectedPoints.lastHeightLimits.min == c.heightLimits.min) + && (_selectedPoints.lastHeightLimits.max == c.heightLimits.max) + && (_selectedPoints.lastXLimits.min == c.xPercentageLimits.min) + && (_selectedPoints.lastXLimits.max == c.xPercentageLimits.max); + for (const auto &line : c.chartData.lines) { const auto lineAlpha = alpha(line.id); const auto useCache = isSameToken || (lineAlpha < 1. && !isEnabled(line.id)); if (!useCache) { // Calculate. - const auto xPoint = rect.width() - * ((chartData.xPercentage[i] - xPercentageLimits.min) - / (xPercentageLimits.max - xPercentageLimits.min)); - const auto yPercentage = (line.y[i] - heightLimits.min) - / float64(heightLimits.max - heightLimits.min); + const auto xPoint = c.rect.width() + * ((c.chartData.xPercentage[i] - c.xPercentageLimits.min) + / (c.xPercentageLimits.max - c.xPercentageLimits.min)); + const auto yPercentage = (line.y[i] - c.heightLimits.min) + / float64(c.heightLimits.max - c.heightLimits.min); _selectedPoints.points[line.id] = QPointF(xPoint, 0) - + rect.topLeft(); + + c.rect.topLeft(); } { const auto lineRect = QRectF( - rect.x() + c.rect.x() + begin(_selectedPoints.points)->second.x() - (st::lineWidth / 2.), - rect.y(), + c.rect.y(), st::lineWidth, - rect.height()); + c.rect.height()); p.fillRect(lineRect, st::windowSubTextFg); } } _selectedPoints.lastXIndex = selectedXIndex; - _selectedPoints.lastHeightLimits = heightLimits; - _selectedPoints.lastXLimits = xPercentageLimits; + _selectedPoints.lastHeightLimits = c.heightLimits; + _selectedPoints.lastXLimits = c.xPercentageLimits; } int StackLinearChartView::findXIndexByPosition( diff --git a/Telegram/SourceFiles/statistics/view/stack_linear_chart_view.h b/Telegram/SourceFiles/statistics/view/stack_linear_chart_view.h index efcf04e70..31d9161da 100644 --- a/Telegram/SourceFiles/statistics/view/stack_linear_chart_view.h +++ b/Telegram/SourceFiles/statistics/view/stack_linear_chart_view.h @@ -26,21 +26,11 @@ public: StackLinearChartView(); ~StackLinearChartView() override final; - void paint( - QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xIndices, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, - bool footer) override; + void paint(QPainter &p, const PaintContext &c) override; void paintSelectedXIndex( QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, + const PaintContext &c, int selectedXIndex, float64 progress) override; @@ -69,25 +59,11 @@ public: const QPoint &p); private: - struct PaintContext final { - const Data::StatisticalChart &chartData; - const Limits &xPercentageLimits; - const Limits &heightLimits; - const QRect ▭ - bool footer = false; - }; + void paintChartOrZoomAnimation(QPainter &p, const PaintContext &c); - void paint( - QPainter &p, - const Data::StatisticalChart &chartData, - const Limits &xPercentageLimits, - const Limits &heightLimits, - const QRect &rect, - bool footer); - - void paintZoomed(QPainter &p, const PaintContext &context); - void paintZoomedFooter(QPainter &p, const PaintContext &context); - void paintPieText(QPainter &p, const PaintContext &context); + void paintZoomed(QPainter &p, const PaintContext &c); + void paintZoomedFooter(QPainter &p, const PaintContext &c); + void paintPieText(QPainter &p, const PaintContext &c); [[nodiscard]] bool skipSelectedTranslation() const;