From 81406ff1f4bcc194f21d46cc1e1dc0f4595927ed Mon Sep 17 00:00:00 2001 From: LuoZhihao Date: Mon, 9 Jun 2025 18:57:24 +0800 Subject: [PATCH] Spinbox: Fix incorrect step and decimal text when using custom arrow step --- scene/gui/range.cpp | 15 +++++++-------- scene/gui/range.h | 1 + scene/gui/spin_box.cpp | 32 +++++++++++++------------------- scene/gui/spin_box.h | 1 - 4 files changed, 21 insertions(+), 28 deletions(-) diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index dce927093f1..552de917b34 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -135,8 +135,12 @@ void Range::set_value(double p_val) { } void Range::_set_value_no_signal(double p_val) { - if (shared->step > 0) { - p_val = Math::round((p_val - shared->min) / shared->step) * shared->step + shared->min; + shared->val = _calc_value(p_val, shared->step); +} + +double Range::_calc_value(double p_val, double p_step) const { + if (p_step > 0) { + p_val = Math::round((p_val - shared->min) / p_step) * p_step + shared->min; } if (_rounded_values) { @@ -150,12 +154,7 @@ void Range::_set_value_no_signal(double p_val) { if (!shared->allow_lesser && p_val < shared->min) { p_val = shared->min; } - - if (shared->val == p_val) { - return; - } - - shared->val = p_val; + return p_val; } void Range::set_value_no_signal(double p_val) { diff --git a/scene/gui/range.h b/scene/gui/range.h index 92ae94b0e8a..7ebda8ded0f 100644 --- a/scene/gui/range.h +++ b/scene/gui/range.h @@ -62,6 +62,7 @@ class Range : public Control { void _set_value_no_signal(double p_val); protected: + double _calc_value(double p_val, double p_step) const; virtual void _value_changed(double p_value); void _notify_shared_value_changed() { shared->emit_value_changed(); } void _notification(int p_what); diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 9a0c86502ea..12e02594ea6 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -86,9 +86,6 @@ Size2 SpinBox::get_minimum_size() const { void SpinBox::_update_text(bool p_only_update_if_value_changed) { double step = get_step(); - if (use_custom_arrow_step && custom_arrow_step != 0.0) { - step = custom_arrow_step; - } String value = String::num(get_value(), Math::range_step_decimals(step)); if (is_localizing_numeral_system()) { value = TS->format_number(value); @@ -195,13 +192,14 @@ void SpinBox::_line_edit_input(const Ref &p_event) { void SpinBox::_range_click_timeout() { if (!drag.enabled && Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) { - bool up = get_local_mouse_position().y < (get_size().height / 2); - double step = get_step(); - // Arrow button is being pressed, so we also need to set the step to the same value as custom_arrow_step if its not 0. + bool mouse_on_up_button = get_local_mouse_position().y < (get_size().height / 2); + // Arrow button is being pressed. Snap the value to next step. double temp_step = get_custom_arrow_step() != 0.0 ? get_custom_arrow_step() : get_step(); - _set_step_no_signal(temp_step); - set_value(get_value() + (up ? temp_step : -temp_step)); - _set_step_no_signal(step); + double new_value = _calc_value(get_value(), temp_step); + if ((mouse_on_up_button && new_value <= get_value() + CMP_EPSILON) || (!mouse_on_up_button && new_value >= get_value() - CMP_EPSILON)) { + new_value = _calc_value(get_value() + (mouse_on_up_button ? temp_step : -temp_step), temp_step); + } + set_value(new_value); use_custom_arrow_step = true; if (range_click_timer->is_one_shot()) { @@ -264,11 +262,13 @@ void SpinBox::gui_input(const Ref &p_event) { line_edit->grab_focus(); if (mouse_on_up_button || mouse_on_down_button) { - // Arrow button is being pressed, so step is being changed temporarily. + // Arrow button is being pressed. Snap the value to next step. double temp_step = get_custom_arrow_step() != 0.0 ? get_custom_arrow_step() : get_step(); - _set_step_no_signal(temp_step); - set_value(get_value() + (mouse_on_up_button ? temp_step : -temp_step)); - _set_step_no_signal(step); + double new_value = _calc_value(get_value(), temp_step); + if ((mouse_on_up_button && new_value <= get_value() + CMP_EPSILON) || (!mouse_on_up_button && new_value >= get_value() - CMP_EPSILON)) { + new_value = _calc_value(get_value() + (mouse_on_up_button ? temp_step : -temp_step), temp_step); + } + set_value(new_value); use_custom_arrow_step = true; } state_cache.up_button_pressed = mouse_on_up_button; @@ -616,12 +616,6 @@ void SpinBox::_update_buttons_state_for_current_value() { } } -void SpinBox::_set_step_no_signal(double p_step) { - set_block_signals(true); - set_step(p_step); - set_block_signals(false); -} - void SpinBox::_validate_property(PropertyInfo &p_property) const { if (p_property.name == "exp_edit") { p_property.usage = PROPERTY_USAGE_NONE; diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h index 37f839b2003..46393fb1844 100644 --- a/scene/gui/spin_box.h +++ b/scene/gui/spin_box.h @@ -144,7 +144,6 @@ class SpinBox : public Range { void _mouse_exited(); void _update_buttons_state_for_current_value(); - void _set_step_no_signal(double p_step); protected: virtual void gui_input(const Ref &p_event) override;