round_rect.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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/round_rect.h"
  8. #include "ui/style/style_core.h"
  9. #include "ui/image/image_prepare.h"
  10. #include "ui/ui_utility.h"
  11. #include <QPainterPath>
  12. namespace Ui {
  13. QPainterPath ComplexRoundedRectPath(
  14. const QRect &rect,
  15. int topLeftRadius,
  16. int topRightRadius,
  17. int bottomLeftRadius,
  18. int bottomRightRadius) {
  19. auto path = QPainterPath();
  20. path.setFillRule(Qt::WindingFill);
  21. const auto cornerPartSize = rect.size() / 4 * 3;
  22. const auto cornerPartOffset = QPoint(
  23. rect.width() - cornerPartSize.width(),
  24. rect.height() - cornerPartSize.height());
  25. path.addRoundedRect(
  26. rect.x(),
  27. rect.y(),
  28. cornerPartSize.width(),
  29. cornerPartSize.height(),
  30. topLeftRadius,
  31. topLeftRadius);
  32. path.addRoundedRect(
  33. rect.x() + cornerPartOffset.x(),
  34. rect.y(),
  35. cornerPartSize.width(),
  36. cornerPartSize.height(),
  37. topRightRadius,
  38. topRightRadius);
  39. path.addRoundedRect(
  40. rect.x(),
  41. rect.y() + cornerPartOffset.y(),
  42. cornerPartSize.width(),
  43. cornerPartSize.height(),
  44. bottomLeftRadius,
  45. bottomLeftRadius);
  46. path.addRoundedRect(
  47. rect.x() + cornerPartOffset.x(),
  48. rect.y() + cornerPartOffset.y(),
  49. cornerPartSize.width(),
  50. cornerPartSize.height(),
  51. bottomRightRadius,
  52. bottomRightRadius);
  53. return path.simplified();
  54. }
  55. void DrawRoundedRect(
  56. QPainter &p,
  57. const QRect &rect,
  58. const QBrush &brush,
  59. const std::array<QImage, 4> &corners,
  60. RectParts parts) {
  61. const auto pixelRatio = style::DevicePixelRatio();
  62. const auto x = rect.x();
  63. const auto y = rect.y();
  64. const auto w = rect.width();
  65. const auto h = rect.height();
  66. const auto cornerWidth = corners[0].width() / pixelRatio;
  67. const auto cornerHeight = corners[0].height() / pixelRatio;
  68. const auto hasLeft = (parts & RectPart::Left) != 0;
  69. const auto hasRight = (parts & RectPart::Right) != 0;
  70. const auto hasTop = (parts & RectPart::Top) != 0;
  71. const auto hasBottom = (parts & RectPart::Bottom) != 0;
  72. if (w < ((hasLeft ? cornerWidth : 0) + (hasRight ? cornerWidth : 0))) {
  73. return;
  74. }
  75. if (h < ((hasTop ? cornerHeight : 0) + (hasBottom ? cornerHeight : 0))) {
  76. return;
  77. }
  78. if (w > 2 * cornerWidth) {
  79. if (hasTop) {
  80. p.fillRect(x + cornerWidth, y, w - 2 * cornerWidth, cornerHeight, brush);
  81. }
  82. if (hasBottom) {
  83. p.fillRect(x + cornerWidth, y + h - cornerHeight, w - 2 * cornerWidth, cornerHeight, brush);
  84. }
  85. }
  86. if (h > 2 * cornerHeight) {
  87. if ((parts & RectPart::NoTopBottom) == RectPart::NoTopBottom) {
  88. p.fillRect(x, y + cornerHeight, w, h - 2 * cornerHeight, brush);
  89. } else {
  90. if (hasLeft) {
  91. p.fillRect(x, y + cornerHeight, cornerWidth, h - 2 * cornerHeight, brush);
  92. }
  93. if ((parts & RectPart::Center) && w > 2 * cornerWidth) {
  94. p.fillRect(x + cornerWidth, y + cornerHeight, w - 2 * cornerWidth, h - 2 * cornerHeight, brush);
  95. }
  96. if (hasRight) {
  97. p.fillRect(x + w - cornerWidth, y + cornerHeight, cornerWidth, h - 2 * cornerHeight, brush);
  98. }
  99. }
  100. }
  101. if (parts & RectPart::TopLeft) {
  102. p.drawImage(x, y, corners[0]);
  103. }
  104. if (parts & RectPart::TopRight) {
  105. p.drawImage(x + w - cornerWidth, y, corners[1]);
  106. }
  107. if (parts & RectPart::BottomLeft) {
  108. p.drawImage(x, y + h - cornerHeight, corners[2]);
  109. }
  110. if (parts & RectPart::BottomRight) {
  111. p.drawImage(x + w - cornerWidth, y + h - cornerHeight, corners[3]);
  112. }
  113. }
  114. RoundRect::RoundRect(
  115. ImageRoundRadius radius,
  116. const style::color &color)
  117. : _color(color)
  118. , _refresh([=] { _corners = Images::PrepareCorners(radius, _color); }) {
  119. _refresh();
  120. style::PaletteChanged(
  121. ) | rpl::start_with_next(_refresh, _lifetime);
  122. }
  123. RoundRect::RoundRect(
  124. int radius,
  125. const style::color &color)
  126. : _color(color)
  127. , _refresh([=] { _corners = Images::PrepareCorners(radius, _color); }) {
  128. _refresh();
  129. style::PaletteChanged(
  130. ) | rpl::start_with_next(_refresh, _lifetime);
  131. }
  132. void RoundRect::setColor(const style::color &color) {
  133. _color = color;
  134. _refresh();
  135. }
  136. const style::color &RoundRect::color() const {
  137. return _color;
  138. }
  139. void RoundRect::paint(
  140. QPainter &p,
  141. const QRect &rect,
  142. RectParts parts) const {
  143. DrawRoundedRect(p, rect, _color, _corners, parts);
  144. }
  145. void RoundRect::paintSomeRounded(
  146. QPainter &p,
  147. const QRect &rect,
  148. RectParts corners) const {
  149. DrawRoundedRect(
  150. p,
  151. rect,
  152. _color,
  153. _corners,
  154. corners | RectPart::Top | RectPart::NoTopBottom | RectPart::Bottom);
  155. const auto pixelRatio = style::DevicePixelRatio();
  156. const auto cornerWidth = _corners[0].width() / pixelRatio;
  157. const auto cornerHeight = _corners[0].height() / pixelRatio;
  158. if (!(corners & RectPart::TopLeft)) {
  159. p.fillRect(rect.x(), rect.y(), cornerWidth, cornerHeight, _color);
  160. }
  161. if (!(corners & RectPart::TopRight)) {
  162. p.fillRect(
  163. rect.x() + rect.width() - cornerWidth,
  164. rect.y(),
  165. cornerWidth,
  166. cornerHeight,
  167. _color);
  168. }
  169. if (!(corners & RectPart::BottomRight)) {
  170. p.fillRect(
  171. rect.x() + rect.width() - cornerWidth,
  172. rect.y() + rect.height() - cornerHeight,
  173. cornerWidth,
  174. cornerHeight,
  175. _color);
  176. }
  177. if (!(corners & RectPart::BottomLeft)) {
  178. p.fillRect(
  179. rect.x(),
  180. rect.y() + rect.height() - cornerHeight,
  181. cornerWidth,
  182. cornerHeight,
  183. _color);
  184. }
  185. }
  186. } // namespace Ui