GScrollBar.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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 CharacterBitmap* s_up_arrow_bitmap;
  28. static CharacterBitmap* s_down_arrow_bitmap;
  29. GScrollBar::GScrollBar(Orientation orientation, GWidget* parent)
  30. : GWidget(parent)
  31. , m_orientation(orientation)
  32. {
  33. if (!s_up_arrow_bitmap)
  34. s_up_arrow_bitmap = CharacterBitmap::create_from_ascii(s_up_arrow_bitmap_data, 9, 9).leak_ref();
  35. if (!s_down_arrow_bitmap)
  36. s_down_arrow_bitmap = CharacterBitmap::create_from_ascii(s_down_arrow_bitmap_data, 9, 9).leak_ref();
  37. if (m_orientation == Orientation::Vertical) {
  38. set_preferred_size({ 15, 0 });
  39. } else {
  40. set_preferred_size({ 0, 15 });
  41. }
  42. }
  43. GScrollBar::~GScrollBar()
  44. {
  45. }
  46. void GScrollBar::set_range(int min, int max)
  47. {
  48. ASSERT(min <= max);
  49. if (m_min == min && m_max == max)
  50. return;
  51. m_min = min;
  52. m_max = max;
  53. int old_value = m_value;
  54. if (m_value < m_min)
  55. m_value = m_min;
  56. if (m_value > m_max)
  57. m_value = m_max;
  58. if (on_change && m_value != old_value)
  59. on_change(m_value);
  60. update();
  61. }
  62. void GScrollBar::set_value(int value)
  63. {
  64. if (value < m_min)
  65. value = m_min;
  66. if (value > m_max)
  67. value = m_max;
  68. if (value == m_value)
  69. return;
  70. m_value = value;
  71. if (on_change)
  72. on_change(value);
  73. update();
  74. }
  75. Rect GScrollBar::up_button_rect() const
  76. {
  77. return { 0, 0, button_size(), button_size() };
  78. }
  79. Rect GScrollBar::down_button_rect() const
  80. {
  81. return { 0, height() - button_size(), button_size(), button_size() };
  82. }
  83. Rect GScrollBar::upper_gutter_rect() const
  84. {
  85. return { 0, button_size(), button_size(), scrubber_rect().top() - button_size() };
  86. }
  87. Rect GScrollBar::lower_gutter_rect() const
  88. {
  89. auto scrubber_rect = this->scrubber_rect();
  90. return { 0, scrubber_rect.bottom(), button_size(), height() - button_size() - scrubber_rect.bottom() };
  91. }
  92. int GScrollBar::scrubbable_range_in_pixels() const
  93. {
  94. return height() - button_size() * 3;
  95. }
  96. bool GScrollBar::has_scrubber() const
  97. {
  98. return m_max != m_min;
  99. }
  100. Rect GScrollBar::scrubber_rect() const
  101. {
  102. int range_size = m_max - m_min;
  103. if (range_size == 0)
  104. return { 0, button_size(), button_size(), height() - button_size() * 2 };
  105. float available_y = scrubbable_range_in_pixels();
  106. float y_step = available_y / range_size;
  107. float y = button_size() + (y_step * m_value);
  108. return { 0, (int)y, button_size(), button_size() };
  109. }
  110. void GScrollBar::paint_event(GPaintEvent&)
  111. {
  112. Painter painter(*this);
  113. painter.fill_rect(rect(), Color(164, 164, 164));
  114. GStyle::the().paint_button(painter, up_button_rect(), false);
  115. painter.draw_bitmap(up_button_rect().location().translated(3, 3), *s_up_arrow_bitmap, has_scrubber() ? Color::Black : Color::MidGray);
  116. GStyle::the().paint_button(painter, down_button_rect(), false);
  117. painter.draw_bitmap(down_button_rect().location().translated(3, 3), *s_down_arrow_bitmap, has_scrubber() ? Color::Black : Color::MidGray);
  118. if (has_scrubber())
  119. GStyle::the().paint_button(painter, scrubber_rect(), m_scrubbing);
  120. }
  121. void GScrollBar::mousedown_event(GMouseEvent& event)
  122. {
  123. if (event.button() != GMouseButton::Left)
  124. return;
  125. if (up_button_rect().contains(event.position())) {
  126. set_value(value() - m_step);
  127. return;
  128. }
  129. if (down_button_rect().contains(event.position())) {
  130. set_value(value() + m_step);
  131. return;
  132. }
  133. if (upper_gutter_rect().contains(event.position())) {
  134. set_value(value() - m_big_step);
  135. return;
  136. }
  137. if (lower_gutter_rect().contains(event.position())) {
  138. set_value(value() + m_big_step);
  139. return;
  140. }
  141. if (has_scrubber() && scrubber_rect().contains(event.position())) {
  142. m_scrubbing = true;
  143. m_scrub_start_value = value();
  144. m_scrub_origin = event.position();
  145. set_global_cursor_tracking(true);
  146. update();
  147. return;
  148. }
  149. }
  150. void GScrollBar::mouseup_event(GMouseEvent& event)
  151. {
  152. if (event.button() != GMouseButton::Left)
  153. return;
  154. if (!m_scrubbing)
  155. return;
  156. m_scrubbing = false;
  157. set_global_cursor_tracking(false);
  158. update();
  159. }
  160. void GScrollBar::mousemove_event(GMouseEvent& event)
  161. {
  162. if (!m_scrubbing)
  163. return;
  164. float delta = event.y() - m_scrub_origin.y();
  165. float scrubbable_range = scrubbable_range_in_pixels();
  166. float value_steps_per_scrubbed_pixel = (m_max - m_min) / scrubbable_range;
  167. float new_value = m_scrub_start_value + (value_steps_per_scrubbed_pixel * delta);
  168. set_value(new_value);
  169. }