GScrollBar.cpp 6.9 KB

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