GScrollBar.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. #include <LibGUI/GScrollBar.h>
  2. #include <LibGUI/GStyle.h>
  3. #include <SharedGraphics/GraphicsBitmap.h>
  4. #include <SharedGraphics/Painter.h>
  5. static const char* s_up_arrow_bitmap_data = {
  6. " "
  7. " # "
  8. " ### "
  9. " ##### "
  10. " ####### "
  11. " ### "
  12. " ### "
  13. " ### "
  14. " "
  15. };
  16. static const char* s_down_arrow_bitmap_data = {
  17. " "
  18. " ### "
  19. " ### "
  20. " ### "
  21. " ####### "
  22. " ##### "
  23. " ### "
  24. " # "
  25. " "
  26. };
  27. static const char* s_left_arrow_bitmap_data = {
  28. " "
  29. " # "
  30. " ## "
  31. " ###### "
  32. " ####### "
  33. " ###### "
  34. " ## "
  35. " # "
  36. " "
  37. };
  38. static const char* s_right_arrow_bitmap_data = {
  39. " "
  40. " # "
  41. " ## "
  42. " ###### "
  43. " ####### "
  44. " ###### "
  45. " ## "
  46. " # "
  47. " "
  48. };
  49. static CharacterBitmap* s_up_arrow_bitmap;
  50. static CharacterBitmap* s_down_arrow_bitmap;
  51. static CharacterBitmap* s_left_arrow_bitmap;
  52. static CharacterBitmap* s_right_arrow_bitmap;
  53. GScrollBar::GScrollBar(Orientation orientation, GWidget* parent)
  54. : GWidget(parent)
  55. , m_orientation(orientation)
  56. {
  57. if (!s_up_arrow_bitmap)
  58. s_up_arrow_bitmap = CharacterBitmap::create_from_ascii(s_up_arrow_bitmap_data, 9, 9).leak_ref();
  59. if (!s_down_arrow_bitmap)
  60. s_down_arrow_bitmap = CharacterBitmap::create_from_ascii(s_down_arrow_bitmap_data, 9, 9).leak_ref();
  61. if (!s_left_arrow_bitmap)
  62. s_left_arrow_bitmap = CharacterBitmap::create_from_ascii(s_left_arrow_bitmap_data, 9, 9).leak_ref();
  63. if (!s_right_arrow_bitmap)
  64. s_right_arrow_bitmap = CharacterBitmap::create_from_ascii(s_right_arrow_bitmap_data, 9, 9).leak_ref();
  65. if (m_orientation == Orientation::Vertical) {
  66. set_preferred_size({ 15, 0 });
  67. } else {
  68. set_preferred_size({ 0, 15 });
  69. }
  70. }
  71. GScrollBar::~GScrollBar()
  72. {
  73. }
  74. void GScrollBar::set_range(int min, int max)
  75. {
  76. ASSERT(min <= max);
  77. if (m_min == min && m_max == max)
  78. return;
  79. m_min = min;
  80. m_max = max;
  81. int old_value = m_value;
  82. if (m_value < m_min)
  83. m_value = m_min;
  84. if (m_value > m_max)
  85. m_value = m_max;
  86. if (on_change && m_value != old_value)
  87. on_change(m_value);
  88. update();
  89. }
  90. void GScrollBar::set_value(int value)
  91. {
  92. if (value < m_min)
  93. value = m_min;
  94. if (value > m_max)
  95. value = m_max;
  96. if (value == m_value)
  97. return;
  98. m_value = value;
  99. if (on_change)
  100. on_change(value);
  101. update();
  102. }
  103. Rect GScrollBar::up_button_rect() const
  104. {
  105. return { 0, 0, button_size(), button_size() };
  106. }
  107. Rect GScrollBar::down_button_rect() const
  108. {
  109. if (orientation() == Orientation::Vertical)
  110. return { 0, height() - button_size(), button_size(), button_size() };
  111. else
  112. return { width() - button_size(), 0, button_size(), button_size() };
  113. }
  114. Rect GScrollBar::upper_gutter_rect() const
  115. {
  116. if (orientation() == Orientation::Vertical)
  117. return { 0, button_size(), button_size(), scrubber_rect().top() - button_size() };
  118. else
  119. return { button_size(), 0, scrubber_rect().x() - button_size(), button_size() };
  120. }
  121. Rect GScrollBar::lower_gutter_rect() const
  122. {
  123. auto scrubber_rect = this->scrubber_rect();
  124. if (orientation() == Orientation::Vertical)
  125. return { 0, scrubber_rect.bottom() + 1, button_size(), height() - button_size() - scrubber_rect.bottom() - 1};
  126. else
  127. return { scrubber_rect.right() + 1, 0, width() - button_size() - scrubber_rect.right() - 1, button_size() };
  128. }
  129. int GScrollBar::scrubbable_range_in_pixels() const
  130. {
  131. if (orientation() == Orientation::Vertical)
  132. return height() - button_size() * 3;
  133. else
  134. return width() - button_size() * 3;
  135. }
  136. bool GScrollBar::has_scrubber() const
  137. {
  138. return m_max != m_min;
  139. }
  140. Rect GScrollBar::scrubber_rect() const
  141. {
  142. if (!has_scrubber())
  143. return { };
  144. float x_or_y;
  145. if (m_value == m_min)
  146. x_or_y = button_size();
  147. else if (m_value == m_max)
  148. x_or_y = (orientation() == Orientation::Vertical ? height() : width()) - (button_size() * 2);
  149. else {
  150. float range_size = m_max - m_min;
  151. float available = scrubbable_range_in_pixels();
  152. float step = available / range_size;
  153. x_or_y = (button_size() + (step * m_value));
  154. }
  155. if (orientation() == Orientation::Vertical)
  156. return { 0, (int)x_or_y, button_size(), button_size() };
  157. else
  158. return { (int)x_or_y, 0, button_size(), button_size() };
  159. }
  160. void GScrollBar::paint_event(GPaintEvent&)
  161. {
  162. Painter painter(*this);
  163. painter.fill_rect(rect(), Color(164, 164, 164));
  164. GStyle::the().paint_button(painter, up_button_rect(), false);
  165. painter.draw_bitmap(up_button_rect().location().translated(3, 3), orientation() == Orientation::Vertical ? *s_up_arrow_bitmap : *s_left_arrow_bitmap, has_scrubber() ? Color::Black : Color::MidGray);
  166. GStyle::the().paint_button(painter, down_button_rect(), false);
  167. painter.draw_bitmap(down_button_rect().location().translated(3, 3), orientation() == Orientation::Vertical ? *s_down_arrow_bitmap : *s_right_arrow_bitmap, has_scrubber() ? Color::Black : Color::MidGray);
  168. if (has_scrubber())
  169. GStyle::the().paint_button(painter, scrubber_rect(), m_scrubbing);
  170. }
  171. void GScrollBar::mousedown_event(GMouseEvent& event)
  172. {
  173. if (event.button() != GMouseButton::Left)
  174. return;
  175. if (up_button_rect().contains(event.position())) {
  176. set_value(value() - m_step);
  177. return;
  178. }
  179. if (down_button_rect().contains(event.position())) {
  180. set_value(value() + m_step);
  181. return;
  182. }
  183. if (has_scrubber() && upper_gutter_rect().contains(event.position())) {
  184. set_value(value() - m_big_step);
  185. return;
  186. }
  187. if (has_scrubber() && lower_gutter_rect().contains(event.position())) {
  188. set_value(value() + m_big_step);
  189. return;
  190. }
  191. if (has_scrubber() && scrubber_rect().contains(event.position())) {
  192. m_scrubbing = true;
  193. m_scrub_start_value = value();
  194. m_scrub_origin = event.position();
  195. set_global_cursor_tracking(true);
  196. update();
  197. return;
  198. }
  199. }
  200. void GScrollBar::mouseup_event(GMouseEvent& event)
  201. {
  202. if (event.button() != GMouseButton::Left)
  203. return;
  204. if (!m_scrubbing)
  205. return;
  206. m_scrubbing = false;
  207. set_global_cursor_tracking(false);
  208. update();
  209. }
  210. void GScrollBar::mousemove_event(GMouseEvent& event)
  211. {
  212. if (!m_scrubbing)
  213. return;
  214. float delta = orientation() == Orientation::Vertical ? (event.y() - m_scrub_origin.y()) : (event.x() - m_scrub_origin.x());
  215. float scrubbable_range = scrubbable_range_in_pixels();
  216. float value_steps_per_scrubbed_pixel = (m_max - m_min) / scrubbable_range;
  217. float new_value = m_scrub_start_value + (value_steps_per_scrubbed_pixel * delta);
  218. set_value(new_value);
  219. }