ValueSlider.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*
  2. * Copyright (c) 2021, Marcus Nilsson <brainbomb@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibGUI/BoxLayout.h>
  7. #include <LibGUI/Painter.h>
  8. #include <LibGUI/TextBox.h>
  9. #include <LibGUI/ValueSlider.h>
  10. #include <LibGfx/FontDatabase.h>
  11. #include <LibGfx/Palette.h>
  12. #include <LibGfx/StylePainter.h>
  13. REGISTER_WIDGET(GUI, ValueSlider)
  14. namespace GUI {
  15. ValueSlider::ValueSlider(Gfx::Orientation orientation, String suffix)
  16. : AbstractSlider(orientation)
  17. , m_suffix(move(suffix))
  18. {
  19. //FIXME: Implement vertical mode
  20. VERIFY(orientation == Orientation::Horizontal);
  21. set_fixed_height(20);
  22. m_textbox = add<GUI::TextBox>();
  23. m_textbox->set_relative_rect({ 0, 0, 34, 20 });
  24. m_textbox->set_font_fixed_width(true);
  25. m_textbox->set_font_size(8);
  26. m_textbox->on_change = [&]() {
  27. String value = m_textbox->text();
  28. if (value.ends_with(m_suffix, AK::CaseSensitivity::CaseInsensitive))
  29. value = value.substring_view(0, value.length() - m_suffix.length());
  30. auto integer_value = value.to_int();
  31. if (integer_value.has_value())
  32. AbstractSlider::set_value(integer_value.value());
  33. };
  34. m_textbox->on_return_pressed = [&]() {
  35. m_textbox->on_change();
  36. m_textbox->set_text(formatted_value());
  37. };
  38. m_textbox->on_up_pressed = [&]() {
  39. if (value() < max())
  40. AbstractSlider::increase_slider_by(1);
  41. m_textbox->set_text(formatted_value());
  42. };
  43. m_textbox->on_down_pressed = [&]() {
  44. if (value() > min())
  45. AbstractSlider::decrease_slider_by(1);
  46. m_textbox->set_text(formatted_value());
  47. };
  48. m_textbox->on_focusout = [&]() {
  49. m_textbox->on_return_pressed();
  50. };
  51. m_textbox->on_escape_pressed = [&]() {
  52. m_textbox->clear_selection();
  53. m_textbox->set_text(formatted_value());
  54. parent_widget()->set_focus(true);
  55. };
  56. }
  57. ValueSlider::~ValueSlider()
  58. {
  59. }
  60. String ValueSlider::formatted_value() const
  61. {
  62. return String::formatted("{:2}{}", value(), m_suffix);
  63. }
  64. void ValueSlider::paint_event(PaintEvent& event)
  65. {
  66. GUI::Painter painter(*this);
  67. painter.add_clip_rect(event.rect());
  68. if (is_enabled())
  69. painter.fill_rect_with_gradient(m_orientation, bar_rect(), palette().active_window_border1(), palette().active_window_border2());
  70. else
  71. painter.fill_rect_with_gradient(m_orientation, bar_rect(), palette().inactive_window_border1(), palette().inactive_window_border2());
  72. auto unfilled_rect = bar_rect();
  73. unfilled_rect.set_left(knob_rect().right());
  74. painter.fill_rect(unfilled_rect, palette().base());
  75. Gfx::StylePainter::paint_frame(painter, bar_rect(), palette(), Gfx::FrameShape::Container, Gfx::FrameShadow::Sunken, 2);
  76. Gfx::StylePainter::paint_button(painter, knob_rect(), palette(), Gfx::ButtonStyle::Normal, false, m_hovered);
  77. auto paint_knurl = [&](int x, int y) {
  78. painter.set_pixel(x, y, palette().threed_shadow1());
  79. painter.set_pixel(x + 1, y, palette().threed_shadow1());
  80. painter.set_pixel(x, y + 1, palette().threed_shadow1());
  81. painter.set_pixel(x + 1, y + 1, palette().threed_highlight());
  82. };
  83. auto knurl_rect = knob_rect().shrunken(4, 8);
  84. if (m_knob_style == KnobStyle::Wide) {
  85. for (int i = 0; i < 4; ++i) {
  86. paint_knurl(knurl_rect.x(), knurl_rect.y() + (i * 3));
  87. paint_knurl(knurl_rect.x() + 3, knurl_rect.y() + (i * 3));
  88. paint_knurl(knurl_rect.x() + 6, knurl_rect.y() + (i * 3));
  89. }
  90. } else {
  91. for (int i = 0; i < 4; ++i)
  92. paint_knurl(knurl_rect.x(), knurl_rect.y() + (i * 3));
  93. }
  94. }
  95. Gfx::IntRect ValueSlider::bar_rect() const
  96. {
  97. auto bar_rect = rect();
  98. bar_rect.set_width(rect().width() - m_textbox->width());
  99. bar_rect.set_x(m_textbox->width());
  100. return bar_rect;
  101. }
  102. Gfx::IntRect ValueSlider::knob_rect() const
  103. {
  104. int knob_thickness = m_knob_style == KnobStyle::Wide ? 13 : 7;
  105. Gfx::IntRect knob_rect = bar_rect();
  106. knob_rect.set_width(knob_thickness);
  107. int knob_offset = (int)((float)bar_rect().left() + (float)(value() - min()) / (float)(max() - min()) * (float)(bar_rect().width() - knob_thickness));
  108. knob_rect.set_left(knob_offset);
  109. knob_rect.center_vertically_within(bar_rect());
  110. return knob_rect;
  111. }
  112. int ValueSlider::value_at(const Gfx::IntPoint& position) const
  113. {
  114. if (position.x() < bar_rect().left())
  115. return min();
  116. if (position.x() > bar_rect().right())
  117. return max();
  118. float relative_offset = (float)(position.x() - bar_rect().left()) / (float)bar_rect().width();
  119. return (int)(relative_offset * (float)max());
  120. }
  121. void ValueSlider::set_value(int value, AllowCallback allow_callback)
  122. {
  123. AbstractSlider::set_value(value, allow_callback);
  124. m_textbox->set_text(formatted_value());
  125. }
  126. void ValueSlider::leave_event(Core::Event&)
  127. {
  128. if (!m_hovered)
  129. return;
  130. m_hovered = false;
  131. update(knob_rect());
  132. }
  133. void ValueSlider::mousewheel_event(MouseEvent& event)
  134. {
  135. if (event.wheel_delta_y() < 0)
  136. increase_slider_by(1);
  137. else
  138. decrease_slider_by(1);
  139. }
  140. void ValueSlider::mousemove_event(MouseEvent& event)
  141. {
  142. bool is_hovered = knob_rect().contains(event.position());
  143. if (is_hovered != m_hovered) {
  144. m_hovered = is_hovered;
  145. update(knob_rect());
  146. }
  147. if (!m_dragging)
  148. return;
  149. set_value(value_at(event.position()));
  150. }
  151. void ValueSlider::mousedown_event(MouseEvent& event)
  152. {
  153. if (event.button() != MouseButton::Primary)
  154. return;
  155. m_textbox->set_focus(true);
  156. if (bar_rect().contains(event.position())) {
  157. m_dragging = true;
  158. set_value(value_at(event.position()));
  159. }
  160. }
  161. void ValueSlider::mouseup_event(MouseEvent& event)
  162. {
  163. if (event.button() != MouseButton::Primary)
  164. return;
  165. m_dragging = false;
  166. }
  167. }