diff --git a/Telegram/SourceFiles/statistics/point_details_widget.cpp b/Telegram/SourceFiles/statistics/point_details_widget.cpp index cb2c27f86a..1e28f7a455 100644 --- a/Telegram/SourceFiles/statistics/point_details_widget.cpp +++ b/Telegram/SourceFiles/statistics/point_details_widget.cpp @@ -32,6 +32,57 @@ namespace { } // namespace +void PaintDetails( + QPainter &p, + const Data::StatisticalChart::Line &line, + int absoluteValue, + const QRect &rect) { + auto name = Ui::Text::String( + st::statisticsDetailsPopupStyle, + line.name); + auto value = Ui::Text::String( + st::statisticsDetailsPopupStyle, + QString("%L1").arg(absoluteValue)); + const auto nameWidth = name.maxWidth(); + const auto valueWidth = value.maxWidth(); + + const auto width = valueWidth + + rect::m::sum::h(st::statisticsDetailsPopupMargins) + + rect::m::sum::h(st::statisticsDetailsPopupPadding) + + st::statisticsDetailsPopupPadding.left() // Between strings. + + nameWidth; + + const auto height = st::statisticsDetailsPopupStyle.font->height + + rect::m::sum::v(st::statisticsDetailsPopupMargins) + + rect::m::sum::v(st::statisticsDetailsPopupPadding); + + const auto fullRect = QRect( + rect.x() + rect.width() - width, + rect.y(), + width, + height); + + const auto innerRect = fullRect - st::statisticsDetailsPopupPadding; + const auto textRect = innerRect - st::statisticsDetailsPopupMargins; + + Ui::Shadow::paint(p, innerRect, rect.width(), st::boxRoundShadow); + Ui::FillRoundRect(p, innerRect, st::boxBg, Ui::BoxCorners); + + const auto lineY = textRect.y(); + const auto valueContext = Ui::Text::PaintContext{ + .position = QPoint(rect::right(textRect) - valueWidth, lineY), + }; + const auto nameContext = Ui::Text::PaintContext{ + .position = QPoint(textRect.x(), lineY), + .outerWidth = textRect.width() - valueWidth, + .availableWidth = textRect.width(), + }; + p.setPen(st::boxTextFg); + name.draw(p, nameContext); + p.setPen(line.color); + value.draw(p, valueContext); +} + PointDetailsWidget::PointDetailsWidget( not_null parent, const Data::StatisticalChart &chartData, diff --git a/Telegram/SourceFiles/statistics/point_details_widget.h b/Telegram/SourceFiles/statistics/point_details_widget.h index 232cc6382e..81253a4d9d 100644 --- a/Telegram/SourceFiles/statistics/point_details_widget.h +++ b/Telegram/SourceFiles/statistics/point_details_widget.h @@ -12,6 +12,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Statistic { +void PaintDetails( + QPainter &p, + const Data::StatisticalChart::Line &line, + int absoluteValue, + const QRect &rect); + class PointDetailsWidget : public Ui::RippleButton { public: PointDetailsWidget( diff --git a/Telegram/SourceFiles/statistics/view/stack_linear_chart_view.cpp b/Telegram/SourceFiles/statistics/view/stack_linear_chart_view.cpp index 4306af9bf8..d844b20dc0 100644 --- a/Telegram/SourceFiles/statistics/view/stack_linear_chart_view.cpp +++ b/Telegram/SourceFiles/statistics/view/stack_linear_chart_view.cpp @@ -7,8 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "statistics/view/stack_linear_chart_view.h" -#include "ui/effects/animation_value_f.h" #include "data/data_statistics.h" +#include "statistics/point_details_widget.h" +#include "ui/effects/animation_value_f.h" #include "ui/painter.h" #include "ui/rect.h" #include "styles/style_statistics.h" @@ -429,27 +430,43 @@ void StackLinearChartView::paintZoomed(QPainter &p, const PaintContext &c) { center + QPointF(side, side)); auto hq = PainterHighQualityEnabler(p); + auto selectedLineIndex = -1; for (auto k = 0; k < c.chartData.lines.size(); k++) { const auto previous = k ? _cachedTransition.lines[k - 1].angle : -180; const auto now = _cachedTransition.lines[k].angle; - p.setBrush(c.chartData.lines[k].color); + const auto &line = c.chartData.lines[k]; + p.setBrush(line.color); p.setPen(Qt::NoPen); const auto textAngle = (previous + kPieAngleOffset) + (now - previous) / 2.; - const auto partOffset = _piePartController.offset( - c.chartData.lines[k].id, - textAngle); + const auto partOffset = _piePartController.offset(line.id, textAngle); p.translate(partOffset); p.drawPie( rectF, -(previous + kPieAngleOffset) * 16, -(now - previous) * 16); p.translate(-partOffset); + if (_piePartController.selected() == line.id) { + selectedLineIndex = k; + } } paintPieText(p, c); + + if (selectedLineIndex >= 0) { + const auto &[localStart, localEnd] = _lastPaintedXIndices; + const auto &line = c.chartData.lines[selectedLineIndex]; + auto sum = 0; + for (auto i = localStart; i <= localEnd; i++) { + sum += line.y[i]; + } + sum *= alpha(line.id); + if (sum > 0) { + PaintDetails(p, line, sum, c.rect); + } + } } void StackLinearChartView::paintPieText(QPainter &p, const PaintContext &c) { @@ -552,6 +569,10 @@ QPointF StackLinearChartView::PiePartController::offset( return { std::cos(radians) * offset, std::sin(radians) * offset }; } +auto StackLinearChartView::PiePartController::selected() const -> LineId { + return _selected; +} + void StackLinearChartView::handleMouseMove( const Data::StatisticalChart &chartData, const QPoint ¢er, @@ -570,7 +591,10 @@ void StackLinearChartView::handleMouseMove( : -180; const auto now = _cachedTransition.lines[k].angle; if (angle > previous && angle <= now) { - if (_piePartController.set(chartData.lines[k].id)) { + const auto id = p.isNull() + ? -1 + : chartData.lines[k].id; + if (_piePartController.set(id)) { if (!_piePartAnimation.animating()) { _piePartAnimation.start(); } diff --git a/Telegram/SourceFiles/statistics/view/stack_linear_chart_view.h b/Telegram/SourceFiles/statistics/view/stack_linear_chart_view.h index ca2c9ce366..2a63029a25 100644 --- a/Telegram/SourceFiles/statistics/view/stack_linear_chart_view.h +++ b/Telegram/SourceFiles/statistics/view/stack_linear_chart_view.h @@ -128,6 +128,7 @@ private: bool set(LineId id); [[nodiscard]] float64 progress(LineId id); [[nodiscard]] QPointF offset(LineId id, float64 angle); + [[nodiscard]] LineId selected() const; private: void update(LineId id);