diff --git a/doc/classes/SpinBox.xml b/doc/classes/SpinBox.xml index 3e39e9eba947..93ee65b219fb 100644 --- a/doc/classes/SpinBox.xml +++ b/doc/classes/SpinBox.xml @@ -49,6 +49,9 @@ Changes the alignment of the underlying [LineEdit]. + + Controls which side the up and down buttons appear on. [constant BUTTON_ALIGNMENT_DEFAULT] follows the layout direction (right in LTR, left in RTL). [constant BUTTON_ALIGNMENT_LEFT] and [constant BUTTON_ALIGNMENT_RIGHT] override this regardless of layout direction. + If [code]true[/code], the value will be rounded to a multiple of [member custom_arrow_step] when interacting with the arrow buttons. Otherwise, increments the value by [member custom_arrow_step] and then rounds it according to [member Range.step]. @@ -75,6 +78,17 @@ [b]Note:[/b] If set to [code]true[/code], this will interfere with entering mathematical expressions in the [SpinBox]. The [SpinBox] will try to evaluate the expression as you type, which means symbols like a trailing [code]+[/code] are removed immediately by the expression being evaluated. + + + The up and down buttons follow the layout direction: on the right in left-to-right layouts, on the left in right-to-left layouts. + + + The up and down buttons are always placed on the left, regardless of layout direction. + + + The up and down buttons are always placed on the right, regardless of layout direction. + + Down button icon modulation color, when the button is disabled. diff --git a/editor/animation/animation_blend_space_1d_editor.cpp b/editor/animation/animation_blend_space_1d_editor.cpp index b0f7fdd97359..1a33a24b9ec2 100644 --- a/editor/animation/animation_blend_space_1d_editor.cpp +++ b/editor/animation/animation_blend_space_1d_editor.cpp @@ -1080,6 +1080,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { min_value->set_step(STEP_UNIT); min_value->get_line_edit()->set_expand_to_text_length_enabled(true); min_value->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_LEFT); + min_value->set_button_alignment(SpinBox::BUTTON_ALIGNMENT_RIGHT); min_value->set_accessibility_name(TTRC("Min")); max_value = memnew(SpinBox); @@ -1088,6 +1089,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { max_value->set_step(STEP_UNIT); max_value->get_line_edit()->set_expand_to_text_length_enabled(true); max_value->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT); + max_value->set_button_alignment(SpinBox::BUTTON_ALIGNMENT_LEFT); max_value->set_accessibility_name(TTRC("Max")); label_value = memnew(LineEdit); diff --git a/editor/animation/animation_blend_space_2d_editor.cpp b/editor/animation/animation_blend_space_2d_editor.cpp index 1d46aa4eba7b..928711dac038 100644 --- a/editor/animation/animation_blend_space_2d_editor.cpp +++ b/editor/animation/animation_blend_space_2d_editor.cpp @@ -1339,6 +1339,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { max_y_value->set_accessibility_name(TTRC("Max Y")); max_y_value->get_line_edit()->set_expand_to_text_length_enabled(true); max_y_value->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT); + max_y_value->set_button_alignment(SpinBox::BUTTON_ALIGNMENT_LEFT); left_vbox->add_child(max_y_value); left_vbox->add_spacer(); label_y = memnew(LineEdit); @@ -1351,6 +1352,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { min_y_value->set_accessibility_name(TTRC("Min Y")); min_y_value->get_line_edit()->set_expand_to_text_length_enabled(true); min_y_value->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT); + min_y_value->set_button_alignment(SpinBox::BUTTON_ALIGNMENT_LEFT); left_vbox->add_child(min_y_value); max_y_value->set_max(ABS_MAX); @@ -1385,6 +1387,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { min_x_value->set_accessibility_name(TTRC("Min X")); min_x_value->get_line_edit()->set_expand_to_text_length_enabled(true); min_x_value->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_LEFT); + min_x_value->set_button_alignment(SpinBox::BUTTON_ALIGNMENT_RIGHT); bottom_vbox->add_child(min_x_value); bottom_vbox->add_spacer(); label_x = memnew(LineEdit); @@ -1397,6 +1400,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { max_x_value->set_accessibility_name(TTRC("Max X")); max_x_value->get_line_edit()->set_expand_to_text_length_enabled(true); max_x_value->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT); + max_x_value->set_button_alignment(SpinBox::BUTTON_ALIGNMENT_LEFT); bottom_vbox->add_child(max_x_value); max_x_value->set_max(ABS_MAX); diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 9fabf78037da..58254b2cbcef 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -401,23 +401,26 @@ inline void SpinBox::_compute_sizes() { #endif int w = min_width_from_icons != 0 ? MAX(buttons_block_icon_enforced_width, buttons_block_wanted_width) : buttons_block_wanted_width; - if (w != sizing_cache.buttons_block_width) { + if (_are_buttons_on_left()) { + line_edit->set_offset(SIDE_LEFT, w); + line_edit->set_offset(SIDE_RIGHT, 0); + } else { line_edit->set_offset(SIDE_LEFT, 0); line_edit->set_offset(SIDE_RIGHT, -w); - sizing_cache.buttons_block_width = w; } + sizing_cache.buttons_block_width = w; Size2i size = get_size(); sizing_cache.buttons_width = w - theme_cache.field_and_buttons_separation; sizing_cache.buttons_vertical_separation = CLAMP(theme_cache.buttons_vertical_separation, 0, size.height); - sizing_cache.buttons_left = is_layout_rtl() ? 0 : size.width - sizing_cache.buttons_width; + sizing_cache.buttons_left = _are_buttons_on_left() ? 0 : size.width - sizing_cache.buttons_width; sizing_cache.button_up_height = (size.height - sizing_cache.buttons_vertical_separation) / 2; sizing_cache.button_down_height = size.height - sizing_cache.button_up_height - sizing_cache.buttons_vertical_separation; sizing_cache.second_button_top = size.height - sizing_cache.button_down_height; sizing_cache.buttons_separator_top = sizing_cache.button_up_height; - sizing_cache.field_and_buttons_separator_left = is_layout_rtl() ? sizing_cache.buttons_width : size.width - sizing_cache.buttons_block_width; + sizing_cache.field_and_buttons_separator_left = _are_buttons_on_left() ? sizing_cache.buttons_width : size.width - sizing_cache.buttons_block_width; sizing_cache.field_and_buttons_separator_width = theme_cache.field_and_buttons_separation; } @@ -437,6 +440,17 @@ inline int SpinBox::_get_widest_button_icon_width() { return max; } +inline bool SpinBox::_are_buttons_on_left() const { + switch (button_alignment) { + case BUTTON_ALIGNMENT_LEFT: + return true; + case BUTTON_ALIGNMENT_RIGHT: + return false; + default: + return is_layout_rtl(); + } +} + void SpinBox::_notification(int p_what) { switch (p_what) { case NOTIFICATION_DRAW: { @@ -545,6 +559,7 @@ void SpinBox::_notification(int p_what) { } break; case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { + _compute_sizes(); queue_redraw(); } break; } @@ -639,6 +654,19 @@ bool SpinBox::is_custom_arrow_rounding() const { return custom_arrow_round; } +void SpinBox::set_button_alignment(ButtonAlignment p_side) { + if (button_alignment == p_side) { + return; + } + button_alignment = p_side; + _compute_sizes(); + queue_redraw(); +} + +SpinBox::ButtonAlignment SpinBox::get_button_alignment() const { + return button_alignment; +} + void SpinBox::_value_changed(double p_value) { _update_buttons_state_for_current_value(); } @@ -680,6 +708,12 @@ void SpinBox::_bind_methods() { ClassDB::bind_method(D_METHOD("is_select_all_on_focus"), &SpinBox::is_select_all_on_focus); ClassDB::bind_method(D_METHOD("apply"), &SpinBox::apply); ClassDB::bind_method(D_METHOD("get_line_edit"), &SpinBox::get_line_edit); + ClassDB::bind_method(D_METHOD("set_button_alignment", "side"), &SpinBox::set_button_alignment); + ClassDB::bind_method(D_METHOD("get_button_alignment"), &SpinBox::get_button_alignment); + + BIND_ENUM_CONSTANT(BUTTON_ALIGNMENT_DEFAULT); + BIND_ENUM_CONSTANT(BUTTON_ALIGNMENT_LEFT); + BIND_ENUM_CONSTANT(BUTTON_ALIGNMENT_RIGHT); ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_horizontal_alignment", "get_horizontal_alignment"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable"); @@ -689,6 +723,7 @@ void SpinBox::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_arrow_step", PROPERTY_HINT_RANGE, "0,10000,0.0001,or_greater"), "set_custom_arrow_step", "get_custom_arrow_step"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_arrow_round"), "set_custom_arrow_round", "is_custom_arrow_rounding"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "select_all_on_focus"), "set_select_all_on_focus", "is_select_all_on_focus"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "button_alignment", PROPERTY_HINT_ENUM, "Default,Left,Right"), "set_button_alignment", "get_button_alignment"); BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, SpinBox, buttons_vertical_separation); BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, SpinBox, field_and_buttons_separation); diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h index 8a4f7a5cc5a9..ffbe20df7c72 100644 --- a/scene/gui/spin_box.h +++ b/scene/gui/spin_box.h @@ -49,6 +49,14 @@ class SpinBoxLineEdit : public LineEdit { class SpinBox : public Range { GDCLASS(SpinBox, Range); +public: + enum ButtonAlignment { + BUTTON_ALIGNMENT_DEFAULT, + BUTTON_ALIGNMENT_LEFT, + BUTTON_ALIGNMENT_RIGHT, + }; + +private: SpinBoxLineEdit *line_edit = nullptr; bool update_on_text_changed = false; bool accepted = true; @@ -81,6 +89,8 @@ class SpinBox : public Range { double custom_arrow_step = 0.0; bool custom_arrow_round = false; + ButtonAlignment button_alignment = BUTTON_ALIGNMENT_DEFAULT; + void _line_edit_input(const Ref &p_event); struct Drag { @@ -104,6 +114,7 @@ class SpinBox : public Range { inline void _compute_sizes(); inline int _get_widest_button_icon_width(); + inline bool _are_buttons_on_left() const; struct ThemeCache { Ref up_icon; @@ -187,5 +198,10 @@ class SpinBox : public Range { void set_custom_arrow_round(bool p_round); bool is_custom_arrow_rounding() const; + void set_button_alignment(ButtonAlignment p_alignment); + ButtonAlignment get_button_alignment() const; + SpinBox(); }; + +VARIANT_ENUM_CAST(SpinBox::ButtonAlignment);