GScrollBar.cpp 4.8 KB

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