cross_line.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #include "ui/effects/cross_line.h"
  8. #include "ui/painter.h"
  9. namespace Ui {
  10. namespace {
  11. [[nodiscard]] float64 StrokeWidth(
  12. const style::CrossLineAnimation &st) noexcept {
  13. return float64(st.stroke)
  14. / (st.strokeDenominator ? st.strokeDenominator : 1);
  15. }
  16. } // namespace
  17. CrossLineAnimation::CrossLineAnimation(
  18. const style::CrossLineAnimation &st,
  19. bool reversed,
  20. float angle)
  21. : _st(st)
  22. , _reversed(reversed)
  23. , _transparentPen(
  24. Qt::transparent,
  25. StrokeWidth(st),
  26. Qt::SolidLine,
  27. Qt::RoundCap)
  28. , _strokePen(st.fg, StrokeWidth(st), Qt::SolidLine, Qt::RoundCap)
  29. , _line(st.startPosition, st.endPosition) {
  30. _line.setAngle(angle);
  31. }
  32. void CrossLineAnimation::paint(
  33. QPainter &p,
  34. QPoint position,
  35. float64 progress,
  36. std::optional<QColor> colorOverride) {
  37. paint(p, position.x(), position.y(), progress, colorOverride);
  38. }
  39. void CrossLineAnimation::paint(
  40. QPainter &p,
  41. int left,
  42. int top,
  43. float64 progress,
  44. std::optional<QColor> colorOverride) {
  45. if (progress == 0.) {
  46. if (colorOverride) {
  47. _st.icon.paint(p, left, top, _st.icon.width(), *colorOverride);
  48. } else {
  49. _st.icon.paint(p, left, top, _st.icon.width());
  50. }
  51. } else if (progress == 1.) {
  52. auto &complete = colorOverride
  53. ? _completeCrossOverride
  54. : _completeCross;
  55. if (complete.isNull()) {
  56. fillFrame(progress, colorOverride);
  57. complete = _frame;
  58. }
  59. p.drawImage(left, top, complete);
  60. } else {
  61. fillFrame(progress, colorOverride);
  62. p.drawImage(left, top, _frame);
  63. }
  64. }
  65. void CrossLineAnimation::fillFrame(
  66. float64 progress,
  67. std::optional<QColor> colorOverride) {
  68. const auto ratio = style::DevicePixelRatio();
  69. if (_frame.isNull()) {
  70. _frame = QImage(
  71. _st.icon.size() * ratio,
  72. QImage::Format_ARGB32_Premultiplied);
  73. _frame.setDevicePixelRatio(ratio);
  74. }
  75. _frame.fill(Qt::transparent);
  76. auto topLine = _line;
  77. topLine.setLength(topLine.length() * progress);
  78. auto bottomLine = topLine.translated(0, _strokePen.widthF() + 1);
  79. auto q = QPainter(&_frame);
  80. PainterHighQualityEnabler hq(q);
  81. const auto colorize = ((colorOverride && colorOverride->alpha() != 255)
  82. || (!colorOverride && _st.fg->c.alpha() != 255));
  83. const auto color = colorize
  84. ? QColor(255, 255, 255)
  85. : colorOverride;
  86. if (color) {
  87. _st.icon.paint(q, 0, 0, _st.icon.width(), *color);
  88. } else {
  89. _st.icon.paint(q, 0, 0, _st.icon.width());
  90. }
  91. if (color) {
  92. auto pen = _strokePen;
  93. pen.setColor(*color);
  94. q.setPen(pen);
  95. } else {
  96. q.setPen(_strokePen);
  97. }
  98. q.drawLine(_reversed ? topLine : bottomLine);
  99. q.setCompositionMode(QPainter::CompositionMode_Source);
  100. q.setPen(_transparentPen);
  101. q.drawLine(_reversed ? bottomLine : topLine);
  102. q.end();
  103. if (colorize) {
  104. style::colorizeImage(
  105. _frame,
  106. colorOverride.value_or(_st.fg->c),
  107. &_frame);
  108. }
  109. }
  110. void CrossLineAnimation::invalidate() {
  111. _completeCross = QImage();
  112. _completeCrossOverride = QImage();
  113. _strokePen = QPen(_st.fg, StrokeWidth(_st), Qt::SolidLine, Qt::RoundCap);
  114. }
  115. } // namespace Ui