
Previously SpinBox did not update on return or changes to the editor. The widget had to lose focus or be manually incremented. This lets the editor update on return and now always displays the most recent clamped value. set_value_from_current_text() will also be useful to programmatically set SpinBox within layouts whose default buttons consume return key presses.
130 lines
4.2 KiB
C++
130 lines
4.2 KiB
C++
/*
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
|
* Copyright (c) 2022, the SerenityOS developers.
|
|
* Copyright (c) 2022, Timothy Slater <tslater2006@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibGUI/Button.h>
|
|
#include <LibGUI/SpinBox.h>
|
|
#include <LibGUI/TextBox.h>
|
|
|
|
REGISTER_WIDGET(GUI, SpinBox)
|
|
|
|
namespace GUI {
|
|
|
|
SpinBox::SpinBox()
|
|
{
|
|
set_min_size({ 40, 22 });
|
|
set_preferred_size({ SpecialDimension::OpportunisticGrow, 22 });
|
|
m_editor = add<TextBox>();
|
|
m_editor->set_text("0"sv);
|
|
m_editor->on_change = [this, weak_this = make_weak_ptr()] {
|
|
if (!weak_this)
|
|
return;
|
|
|
|
auto value = m_editor->text().to_uint();
|
|
if (!value.has_value() && m_editor->text().length() > 0)
|
|
m_editor->do_delete();
|
|
};
|
|
m_editor->on_focusout = [this] {
|
|
set_value_from_current_text();
|
|
};
|
|
m_editor->on_up_pressed = [this] {
|
|
set_value(m_value + 1);
|
|
};
|
|
m_editor->on_down_pressed = [this] {
|
|
set_value(m_value - 1);
|
|
};
|
|
m_editor->on_return_pressed = [this] {
|
|
set_value_from_current_text();
|
|
if (on_return_pressed)
|
|
on_return_pressed();
|
|
};
|
|
|
|
m_increment_button = add<Button>();
|
|
m_increment_button->set_button_style(Gfx::ButtonStyle::ThickCap);
|
|
m_increment_button->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/upward-triangle.png"sv).release_value_but_fixme_should_propagate_errors());
|
|
m_increment_button->set_focus_policy(GUI::FocusPolicy::NoFocus);
|
|
m_increment_button->on_click = [this](auto) { set_value(m_value + 1); };
|
|
m_increment_button->set_auto_repeat_interval(150);
|
|
m_decrement_button = add<Button>();
|
|
m_decrement_button->set_button_style(Gfx::ButtonStyle::ThickCap);
|
|
m_decrement_button->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/downward-triangle.png"sv).release_value_but_fixme_should_propagate_errors());
|
|
m_decrement_button->set_focus_policy(GUI::FocusPolicy::NoFocus);
|
|
m_decrement_button->on_click = [this](auto) { set_value(m_value - 1); };
|
|
m_decrement_button->set_auto_repeat_interval(150);
|
|
|
|
REGISTER_INT_PROPERTY("min", min, set_min);
|
|
REGISTER_INT_PROPERTY("max", max, set_max);
|
|
}
|
|
|
|
void SpinBox::set_value(int value, AllowCallback allow_callback)
|
|
{
|
|
value = clamp(value, m_min, m_max);
|
|
m_editor->set_text(DeprecatedString::number(value));
|
|
if (m_value == value)
|
|
return;
|
|
m_value = value;
|
|
|
|
m_increment_button->set_enabled(m_value < m_max);
|
|
m_decrement_button->set_enabled(m_value > m_min);
|
|
|
|
update();
|
|
if (on_change && allow_callback == AllowCallback::Yes)
|
|
on_change(value);
|
|
}
|
|
|
|
void SpinBox::set_value_from_current_text()
|
|
{
|
|
auto value = m_editor->text().to_int();
|
|
if (value.has_value())
|
|
set_value(value.value());
|
|
else
|
|
set_value(min());
|
|
}
|
|
|
|
void SpinBox::set_range(int min, int max, AllowCallback allow_callback)
|
|
{
|
|
VERIFY(min <= max);
|
|
if (m_min == min && m_max == max)
|
|
return;
|
|
|
|
m_min = min;
|
|
m_max = max;
|
|
|
|
int old_value = m_value;
|
|
m_value = clamp(m_value, m_min, m_max);
|
|
if (m_value != old_value) {
|
|
m_editor->set_text(DeprecatedString::number(m_value));
|
|
if (on_change && allow_callback == AllowCallback::Yes)
|
|
on_change(m_value);
|
|
}
|
|
|
|
m_increment_button->set_enabled(m_value < m_max);
|
|
m_decrement_button->set_enabled(m_value > m_min);
|
|
|
|
update();
|
|
}
|
|
|
|
void SpinBox::mousewheel_event(MouseEvent& event)
|
|
{
|
|
auto wheel_delta = event.wheel_delta_y() / abs(event.wheel_delta_y());
|
|
if (event.modifiers() == KeyModifier::Mod_Ctrl)
|
|
wheel_delta *= 6;
|
|
set_value(m_value - wheel_delta);
|
|
event.accept();
|
|
}
|
|
|
|
void SpinBox::resize_event(ResizeEvent& event)
|
|
{
|
|
int frame_thickness = m_editor->frame_thickness();
|
|
int button_height = (event.size().height() / 2) - frame_thickness;
|
|
int button_width = 15;
|
|
m_increment_button->set_relative_rect(width() - button_width - frame_thickness, frame_thickness, button_width, button_height);
|
|
m_decrement_button->set_relative_rect(width() - button_width - frame_thickness, frame_thickness + button_height, button_width, button_height);
|
|
m_editor->set_relative_rect(0, 0, width(), height());
|
|
}
|
|
|
|
}
|