chart_rulers_view.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "statistics/view/chart_rulers_view.h"
  8. #include "data/data_channel_earn.h" // Data::kEarnMultiplier.
  9. #include "info/channel_statistics/earn/earn_format.h"
  10. #include "lang/lang_keys.h"
  11. #include "statistics/chart_lines_filter_controller.h"
  12. #include "statistics/statistics_common.h"
  13. #include "statistics/statistics_graphics.h"
  14. #include "styles/style_basic.h"
  15. #include "styles/style_statistics.h"
  16. namespace Statistic {
  17. namespace {
  18. [[nodiscard]] QString FormatF(float64 absoluteValue) {
  19. constexpr auto kTooMuch = int(10'000);
  20. return (absoluteValue >= kTooMuch)
  21. ? Lang::FormatCountToShort(absoluteValue).string
  22. : QString::number(absoluteValue);
  23. }
  24. } // namespace
  25. ChartRulersView::ChartRulersView() = default;
  26. void ChartRulersView::setChartData(
  27. const Data::StatisticalChart &chartData,
  28. ChartViewType type,
  29. std::shared_ptr<LinesFilterController> linesFilter) {
  30. _rulers.clear();
  31. _isDouble = (type == ChartViewType::DoubleLinear)
  32. || chartData.currencyRate;
  33. if (chartData.currencyRate) {
  34. _currencyIcon = ChartCurrencyIcon(chartData, {});
  35. _leftCustomCaption = [=](float64 value) {
  36. return FormatF(value / float64(Data::kEarnMultiplier));
  37. };
  38. _rightCustomCaption = [=, rate = chartData.currencyRate](float64 v) {
  39. return Info::ChannelEarn::ToUsd(v, rate, 0);
  40. };
  41. _rightPen = QPen(st::windowSubTextFg);
  42. }
  43. if (_isDouble && (chartData.lines.size() == 2)) {
  44. _linesFilter = std::move(linesFilter);
  45. _leftPen = QPen(chartData.lines.front().color);
  46. _rightPen = QPen(chartData.lines.back().color);
  47. _leftLineId = chartData.lines.front().id;
  48. _rightLineId = chartData.lines.back().id;
  49. const auto firstMax = chartData.lines.front().maxValue;
  50. const auto secondMax = chartData.lines.back().maxValue;
  51. if (firstMax > secondMax) {
  52. _isLeftLineScaled = false;
  53. _scaledLineRatio = firstMax / float64(secondMax);
  54. } else {
  55. _isLeftLineScaled = true;
  56. _scaledLineRatio = secondMax / float64(firstMax);
  57. }
  58. }
  59. }
  60. void ChartRulersView::paintRulers(
  61. QPainter &p,
  62. const QRect &r) {
  63. const auto alpha = p.opacity();
  64. for (auto &ruler : _rulers) {
  65. p.setOpacity(alpha * ruler.alpha * kRulerLineAlpha);
  66. for (const auto &line : ruler.lines) {
  67. const auto lineRect = QRect(
  68. 0,
  69. r.y() + r.height() * line.relativeValue,
  70. r.x() + r.width(),
  71. st::lineWidth);
  72. p.fillRect(lineRect, st::boxTextFg);
  73. }
  74. }
  75. p.setOpacity(alpha);
  76. }
  77. void ChartRulersView::paintCaptionsToRulers(
  78. QPainter &p,
  79. const QRect &r) {
  80. const auto offset = r.y() - st::statisticsChartRulerCaptionSkip;
  81. p.setFont(st::statisticsDetailsBottomCaptionStyle.font);
  82. const auto alpha = p.opacity();
  83. for (auto &ruler : _rulers) {
  84. const auto rulerAlpha = alpha * ruler.alpha;
  85. p.setOpacity(rulerAlpha);
  86. const auto left = _currencyIcon.isNull()
  87. ? 0
  88. : _currencyIcon.width() / style::DevicePixelRatio();
  89. for (const auto &line : ruler.lines) {
  90. const auto y = offset + r.height() * line.relativeValue;
  91. const auto hasLinesFilter = _isDouble && _linesFilter;
  92. if (hasLinesFilter) {
  93. p.setPen(_leftPen);
  94. p.setOpacity(rulerAlpha * _linesFilter->alpha(_leftLineId));
  95. } else {
  96. p.setPen(st::windowSubTextFg);
  97. }
  98. if (!_currencyIcon.isNull()) {
  99. const auto iconTop = y
  100. - _currencyIcon.height() / style::DevicePixelRatio()
  101. + st::statisticsChartRulerCaptionSkip;
  102. p.drawImage(0, iconTop, _currencyIcon);
  103. }
  104. p.drawText(
  105. left,
  106. y,
  107. (!_isDouble)
  108. ? line.caption
  109. : _isLeftLineScaled
  110. ? line.scaledLineCaption
  111. : line.caption);
  112. if (hasLinesFilter || _rightCustomCaption) {
  113. if (_linesFilter) {
  114. p.setOpacity(rulerAlpha * _linesFilter->alpha(_rightLineId));
  115. }
  116. p.setPen(_rightPen);
  117. p.drawText(
  118. r.width() - line.rightCaptionWidth,
  119. y,
  120. _isLeftLineScaled
  121. ? line.caption
  122. : line.scaledLineCaption);
  123. }
  124. }
  125. }
  126. p.setOpacity(alpha);
  127. }
  128. void ChartRulersView::computeRelative(
  129. int newMaxHeight,
  130. int newMinHeight) {
  131. for (auto &ruler : _rulers) {
  132. ruler.computeRelative(newMaxHeight, newMinHeight);
  133. }
  134. }
  135. void ChartRulersView::setAlpha(float64 value) {
  136. for (auto &ruler : _rulers) {
  137. ruler.alpha = ruler.fixedAlpha * (1. - value);
  138. }
  139. _rulers.back().alpha = value;
  140. if (value == 1.) {
  141. while (_rulers.size() > 1) {
  142. const auto startIt = begin(_rulers);
  143. if (!startIt->alpha) {
  144. _rulers.erase(startIt);
  145. } else {
  146. break;
  147. }
  148. }
  149. }
  150. }
  151. void ChartRulersView::add(Limits newHeight, bool animated) {
  152. auto newLinesData = ChartRulersData(
  153. newHeight.max,
  154. newHeight.min,
  155. true,
  156. _isDouble ? _scaledLineRatio : 0.,
  157. _leftCustomCaption,
  158. _rightCustomCaption);
  159. if (_isDouble) {
  160. const auto &font = st::statisticsDetailsBottomCaptionStyle.font;
  161. for (auto &line : newLinesData.lines) {
  162. line.rightCaptionWidth = font->width(_isLeftLineScaled
  163. ? line.caption
  164. : line.scaledLineCaption);
  165. }
  166. }
  167. if (!animated) {
  168. _rulers.clear();
  169. }
  170. for (auto &ruler : _rulers) {
  171. ruler.fixedAlpha = ruler.alpha;
  172. }
  173. _rulers.push_back(newLinesData);
  174. if (!animated) {
  175. _rulers.back().alpha = 1.;
  176. }
  177. }
  178. } // namespace Statistic