StylePainter.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. #include <LibDraw/Painter.h>
  2. #include <LibDraw/StylePainter.h>
  3. void StylePainter::paint_tab_button(Painter& painter, const Rect& rect, bool active, bool hovered, bool enabled)
  4. {
  5. Color base_color = SystemColor::Button;
  6. Color highlight_color2 = SystemColor::ThreedHighlight;
  7. Color shadow_color1 = SystemColor::ThreedShadow1;
  8. Color shadow_color2 = SystemColor::ThreedShadow2;
  9. if (hovered && enabled && !active)
  10. base_color = StylePainter::hover_highlight_color();
  11. PainterStateSaver saver(painter);
  12. painter.translate(rect.location());
  13. // Base
  14. painter.fill_rect({ 1, 1, rect.width() - 2, rect.height() - 1 }, base_color);
  15. // Top line
  16. painter.draw_line({ 2, 0 }, { rect.width() - 3, 0 }, highlight_color2);
  17. // Left side
  18. painter.draw_line({ 0, 2 }, { 0, rect.height() - 1 }, highlight_color2);
  19. painter.set_pixel({ 1, 1 }, highlight_color2);
  20. // Right side
  21. painter.draw_line({
  22. rect.width() - 1,
  23. 2,
  24. },
  25. { rect.width() - 1, rect.height() - 1 }, shadow_color2);
  26. painter.draw_line({
  27. rect.width() - 2,
  28. 2,
  29. },
  30. { rect.width() - 2, rect.height() - 1 }, shadow_color1);
  31. painter.set_pixel({
  32. rect.width() - 2,
  33. 1,
  34. },
  35. shadow_color2);
  36. }
  37. static void paint_button_new(Painter& painter, const Rect& rect, bool pressed, bool checked, bool hovered, bool enabled)
  38. {
  39. Color button_color = SystemColor::Button;
  40. Color highlight_color2 = SystemColor::ThreedHighlight;
  41. Color shadow_color1 = SystemColor::ThreedShadow1;
  42. Color shadow_color2 = SystemColor::ThreedShadow2;
  43. if (checked && enabled) {
  44. if (hovered)
  45. button_color = SystemColor::HoverHighlight;
  46. else
  47. button_color = SystemColor::Button;
  48. } else if (hovered && enabled)
  49. button_color = StylePainter::hover_highlight_color();
  50. PainterStateSaver saver(painter);
  51. painter.translate(rect.location());
  52. if (pressed || checked) {
  53. // Base
  54. painter.fill_rect({ 1, 1, rect.width() - 2, rect.height() - 2 }, button_color);
  55. painter.draw_rect({ {}, rect.size() }, shadow_color2);
  56. // Sunken shadow
  57. painter.draw_line({ 1, 1 }, { rect.width() - 2, 1 }, shadow_color1);
  58. painter.draw_line({ 1, 2 }, { 1, rect.height() - 2 }, shadow_color1);
  59. } else {
  60. // Base
  61. painter.fill_rect({ 1, 1, rect.width() - 3, rect.height() - 3 }, button_color);
  62. // Outer highlight
  63. painter.draw_line({ 0, 0 }, { rect.width() - 2, 0 }, highlight_color2);
  64. painter.draw_line({ 0, 1 }, { 0, rect.height() - 2 }, highlight_color2);
  65. // Outer shadow
  66. painter.draw_line({ 0, rect.height() - 1 }, { rect.width() - 1, rect.height() - 1 }, shadow_color2);
  67. painter.draw_line({ rect.width() - 1, 0 }, { rect.width() - 1, rect.height() - 2 }, shadow_color2);
  68. // Inner shadow
  69. painter.draw_line({ 1, rect.height() - 2 }, { rect.width() - 2, rect.height() - 2 }, shadow_color1);
  70. painter.draw_line({ rect.width() - 2, 1 }, { rect.width() - 2, rect.height() - 3 }, shadow_color1);
  71. }
  72. }
  73. void StylePainter::paint_button(Painter& painter, const Rect& rect, ButtonStyle button_style, bool pressed, bool hovered, bool checked, bool enabled)
  74. {
  75. if (button_style == ButtonStyle::Normal)
  76. return paint_button_new(painter, rect, pressed, checked, hovered, enabled);
  77. Color button_color = SystemColor::Button;
  78. Color highlight_color = Color::White;
  79. Color shadow_color = Color(96, 96, 96);
  80. if (button_style == ButtonStyle::CoolBar && !enabled)
  81. return;
  82. PainterStateSaver saver(painter);
  83. painter.translate(rect.location());
  84. if (pressed || checked) {
  85. // Base
  86. painter.fill_rect({ 1, 1, rect.width() - 2, rect.height() - 2 }, button_color);
  87. // Sunken shadow
  88. painter.draw_line({ 1, 1 }, { rect.width() - 2, 1 }, shadow_color);
  89. painter.draw_line({ 1, 2 }, { 1, rect.height() - 2 }, shadow_color);
  90. // Bottom highlight
  91. painter.draw_line({ rect.width() - 2, 1 }, { rect.width() - 2, rect.height() - 3 }, highlight_color);
  92. painter.draw_line({ 1, rect.height() - 2 }, { rect.width() - 2, rect.height() - 2 }, highlight_color);
  93. } else if (button_style == ButtonStyle::CoolBar && hovered) {
  94. // Base
  95. painter.fill_rect({ 1, 1, rect.width() - 2, rect.height() - 2 }, button_color);
  96. // White highlight
  97. painter.draw_line({ 1, 1 }, { rect.width() - 2, 1 }, highlight_color);
  98. painter.draw_line({ 1, 2 }, { 1, rect.height() - 2 }, highlight_color);
  99. // Gray shadow
  100. painter.draw_line({ rect.width() - 2, 1 }, { rect.width() - 2, rect.height() - 3 }, shadow_color);
  101. painter.draw_line({ 1, rect.height() - 2 }, { rect.width() - 2, rect.height() - 2 }, shadow_color);
  102. }
  103. }
  104. void StylePainter::paint_surface(Painter& painter, const Rect& rect, bool paint_vertical_lines, bool paint_top_line)
  105. {
  106. painter.fill_rect({ rect.x(), rect.y() + 1, rect.width(), rect.height() - 2 }, SystemColor::Button);
  107. painter.draw_line(rect.top_left(), rect.top_right(), paint_top_line ? SystemColor::ThreedHighlight : SystemColor::Button);
  108. painter.draw_line(rect.bottom_left(), rect.bottom_right(), SystemColor::ThreedShadow1);
  109. if (paint_vertical_lines) {
  110. painter.draw_line(rect.top_left().translated(0, 1), rect.bottom_left().translated(0, -1), SystemColor::ThreedHighlight);
  111. painter.draw_line(rect.top_right(), rect.bottom_right().translated(0, -1), SystemColor::ThreedShadow1);
  112. }
  113. }
  114. void StylePainter::paint_frame(Painter& painter, const Rect& rect, FrameShape shape, FrameShadow shadow, int thickness, bool skip_vertical_lines)
  115. {
  116. Color top_left_color;
  117. Color bottom_right_color;
  118. Color dark_shade = SystemColor::ThreedShadow1;
  119. Color light_shade = SystemColor::ThreedHighlight;
  120. if (shape == FrameShape::Container && thickness >= 2) {
  121. if (shadow == FrameShadow::Raised) {
  122. dark_shade = SystemColor::ThreedShadow2;
  123. }
  124. }
  125. if (shadow == FrameShadow::Raised) {
  126. top_left_color = light_shade;
  127. bottom_right_color = dark_shade;
  128. } else if (shadow == FrameShadow::Sunken) {
  129. top_left_color = dark_shade;
  130. bottom_right_color = light_shade;
  131. } else if (shadow == FrameShadow::Plain) {
  132. top_left_color = dark_shade;
  133. bottom_right_color = dark_shade;
  134. }
  135. if (thickness >= 1) {
  136. painter.draw_line(rect.top_left(), rect.top_right(), top_left_color);
  137. painter.draw_line(rect.bottom_left(), rect.bottom_right(), bottom_right_color);
  138. if (shape != FrameShape::Panel || !skip_vertical_lines) {
  139. painter.draw_line(rect.top_left().translated(0, 1), rect.bottom_left().translated(0, -1), top_left_color);
  140. painter.draw_line(rect.top_right(), rect.bottom_right().translated(0, -1), bottom_right_color);
  141. }
  142. }
  143. if (shape == FrameShape::Container && thickness >= 2) {
  144. Color top_left_color;
  145. Color bottom_right_color;
  146. Color dark_shade = SystemColor::ThreedShadow2;
  147. Color light_shade = SystemColor::Button;
  148. if (shadow == FrameShadow::Raised) {
  149. dark_shade = SystemColor::ThreedShadow1;
  150. top_left_color = light_shade;
  151. bottom_right_color = dark_shade;
  152. } else if (shadow == FrameShadow::Sunken) {
  153. top_left_color = dark_shade;
  154. bottom_right_color = light_shade;
  155. } else if (shadow == FrameShadow::Plain) {
  156. top_left_color = dark_shade;
  157. bottom_right_color = dark_shade;
  158. }
  159. Rect inner_container_frame_rect = rect.shrunken(2, 2);
  160. painter.draw_line(inner_container_frame_rect.top_left(), inner_container_frame_rect.top_right(), top_left_color);
  161. painter.draw_line(inner_container_frame_rect.bottom_left(), inner_container_frame_rect.bottom_right(), bottom_right_color);
  162. painter.draw_line(inner_container_frame_rect.top_left().translated(0, 1), inner_container_frame_rect.bottom_left().translated(0, -1), top_left_color);
  163. painter.draw_line(inner_container_frame_rect.top_right(), inner_container_frame_rect.bottom_right().translated(0, -1), bottom_right_color);
  164. }
  165. if (shape == FrameShape::Box && thickness >= 2) {
  166. swap(top_left_color, bottom_right_color);
  167. Rect inner_rect = rect.shrunken(2, 2);
  168. painter.draw_line(inner_rect.top_left(), inner_rect.top_right(), top_left_color);
  169. painter.draw_line(inner_rect.bottom_left(), inner_rect.bottom_right(), bottom_right_color);
  170. painter.draw_line(inner_rect.top_left().translated(0, 1), inner_rect.bottom_left().translated(0, -1), top_left_color);
  171. painter.draw_line(inner_rect.top_right(), inner_rect.bottom_right().translated(0, -1), bottom_right_color);
  172. }
  173. }
  174. void StylePainter::paint_window_frame(Painter& painter, const Rect& rect)
  175. {
  176. Color base_color = SystemColor::Button;
  177. Color dark_shade = SystemColor::ThreedShadow2;
  178. Color mid_shade = SystemColor::ThreedShadow1;
  179. Color light_shade = SystemColor::ThreedHighlight;
  180. painter.draw_line(rect.top_left(), rect.top_right(), base_color);
  181. painter.draw_line(rect.top_left().translated(0, 1), rect.bottom_left(), base_color);
  182. painter.draw_line(rect.top_left().translated(1, 1), rect.top_right().translated(-1, 1), light_shade);
  183. painter.draw_line(rect.top_left().translated(1, 1), rect.bottom_left().translated(1, -1), light_shade);
  184. painter.draw_line(rect.top_left().translated(2, 2), rect.top_right().translated(-2, 2), base_color);
  185. painter.draw_line(rect.top_left().translated(2, 2), rect.bottom_left().translated(2, -2), base_color);
  186. painter.draw_line(rect.top_right(), rect.bottom_right(), dark_shade);
  187. painter.draw_line(rect.top_right().translated(-1, 1), rect.bottom_right().translated(-1, -1), mid_shade);
  188. painter.draw_line(rect.top_right().translated(-2, 2), rect.bottom_right().translated(-2, -2), base_color);
  189. painter.draw_line(rect.bottom_left(), rect.bottom_right(), dark_shade);
  190. painter.draw_line(rect.bottom_left().translated(1, -1), rect.bottom_right().translated(-1, -1), mid_shade);
  191. painter.draw_line(rect.bottom_left().translated(2, -2), rect.bottom_right().translated(-2, -2), base_color);
  192. }
  193. void StylePainter::paint_progress_bar(Painter& painter, const Rect& rect, int min, int max, int value, const StringView& text)
  194. {
  195. // First we fill the entire widget with the gradient. This incurs a bit of
  196. // overdraw but ensures a consistent look throughout the progression.
  197. Color start_color(110, 34, 9);
  198. Color end_color(244, 202, 158);
  199. painter.fill_rect_with_gradient(rect, start_color, end_color);
  200. if (!text.is_null()) {
  201. painter.draw_text(rect.translated(1, 1), text, TextAlignment::Center, Color::Black);
  202. painter.draw_text(rect, text, TextAlignment::Center, Color::White);
  203. }
  204. float range_size = max - min;
  205. float progress = (value - min) / range_size;
  206. // Then we carve out a hole in the remaining part of the widget.
  207. // We draw the text a third time, clipped and inverse, for sharp contrast.
  208. float progress_width = progress * rect.width();
  209. Rect hole_rect { (int)progress_width, 0, (int)(rect.width() - progress_width), rect.height() };
  210. hole_rect.move_by(rect.location());
  211. PainterStateSaver saver(painter);
  212. painter.fill_rect(hole_rect, Color::White);
  213. painter.add_clip_rect(hole_rect);
  214. if (!text.is_null())
  215. painter.draw_text(rect.translated(0, 0), text, TextAlignment::Center, Color::Black);
  216. }