Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * Copyright (c) 2022, the SerenityOS developers.
4 * Copyright (c) 2022, Timothy Slater <tslater2006@gmail.com>
5 *
6 * SPDX-License-Identifier: BSD-2-Clause
7 */
8
9#include <LibGUI/Button.h>
10#include <LibGUI/SpinBox.h>
11#include <LibGUI/TextBox.h>
12
13REGISTER_WIDGET(GUI, SpinBox)
14
15namespace GUI {
16
17SpinBox::SpinBox()
18{
19 set_min_size({ 40, 22 });
20 set_preferred_size({ SpecialDimension::OpportunisticGrow, 22 });
21 m_editor = add<TextBox>();
22 m_editor->set_text("0"sv);
23 m_editor->on_change = [this, weak_this = make_weak_ptr()] {
24 if (!weak_this)
25 return;
26
27 auto value = m_editor->text().to_uint();
28 if (!value.has_value() && m_editor->text().length() > 0)
29 m_editor->do_delete();
30 };
31 m_editor->on_focusout = [this] {
32 auto value = m_editor->text().to_int();
33 if (value.has_value())
34 set_value(value.value());
35 else
36 set_value(min());
37 };
38 m_editor->on_up_pressed = [this] {
39 set_value(m_value + 1);
40 };
41 m_editor->on_down_pressed = [this] {
42 set_value(m_value - 1);
43 };
44 m_editor->on_return_pressed = [this] {
45 if (on_return_pressed)
46 on_return_pressed();
47 };
48
49 m_increment_button = add<Button>();
50 m_increment_button->set_button_style(Gfx::ButtonStyle::ThickCap);
51 m_increment_button->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/upward-triangle.png"sv).release_value_but_fixme_should_propagate_errors());
52 m_increment_button->set_focus_policy(GUI::FocusPolicy::NoFocus);
53 m_increment_button->on_click = [this](auto) { set_value(m_value + 1); };
54 m_increment_button->set_auto_repeat_interval(150);
55 m_decrement_button = add<Button>();
56 m_decrement_button->set_button_style(Gfx::ButtonStyle::ThickCap);
57 m_decrement_button->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/downward-triangle.png"sv).release_value_but_fixme_should_propagate_errors());
58 m_decrement_button->set_focus_policy(GUI::FocusPolicy::NoFocus);
59 m_decrement_button->on_click = [this](auto) { set_value(m_value - 1); };
60 m_decrement_button->set_auto_repeat_interval(150);
61
62 REGISTER_INT_PROPERTY("min", min, set_min);
63 REGISTER_INT_PROPERTY("max", max, set_max);
64}
65
66void SpinBox::set_value(int value, AllowCallback allow_callback)
67{
68 value = clamp(value, m_min, m_max);
69 if (m_value == value)
70 return;
71 m_value = value;
72
73 m_increment_button->set_enabled(m_value < m_max);
74 m_decrement_button->set_enabled(m_value > m_min);
75
76 m_editor->set_text(DeprecatedString::number(value));
77 update();
78 if (on_change && allow_callback == AllowCallback::Yes)
79 on_change(value);
80}
81
82void SpinBox::set_range(int min, int max, AllowCallback allow_callback)
83{
84 VERIFY(min <= max);
85 if (m_min == min && m_max == max)
86 return;
87
88 m_min = min;
89 m_max = max;
90
91 int old_value = m_value;
92 m_value = clamp(m_value, m_min, m_max);
93 if (m_value != old_value) {
94 m_editor->set_text(DeprecatedString::number(m_value));
95 if (on_change && allow_callback == AllowCallback::Yes)
96 on_change(m_value);
97 }
98
99 m_increment_button->set_enabled(m_value < m_max);
100 m_decrement_button->set_enabled(m_value > m_min);
101
102 update();
103}
104
105void SpinBox::mousewheel_event(MouseEvent& event)
106{
107 auto wheel_delta = event.wheel_delta_y() / abs(event.wheel_delta_y());
108 if (event.modifiers() == KeyModifier::Mod_Ctrl)
109 wheel_delta *= 6;
110 set_value(m_value - wheel_delta);
111 event.accept();
112}
113
114void SpinBox::resize_event(ResizeEvent& event)
115{
116 int frame_thickness = m_editor->frame_thickness();
117 int button_height = (event.size().height() / 2) - frame_thickness;
118 int button_width = 15;
119 m_increment_button->set_relative_rect(width() - button_width - frame_thickness, frame_thickness, button_width, button_height);
120 m_decrement_button->set_relative_rect(width() - button_width - frame_thickness, frame_thickness + button_height, button_width, button_height);
121 m_editor->set_relative_rect(0, 0, width(), height());
122}
123
124}