aboutsummaryrefslogtreecommitdiff
path: root/extension/src/openvic-extension/classes/GUIScrollbar.cpp
diff options
context:
space:
mode:
author hop311 <hop3114@gmail.com>2024-02-24 14:17:07 +0100
committer hop311 <hop3114@gmail.com>2024-02-24 14:17:07 +0100
commit843edde55306e3fbdb5e37ef9b7c09c7b53f50c4 (patch)
tree487fea19d42106c08b60f5bba99bc76485073002 /extension/src/openvic-extension/classes/GUIScrollbar.cpp
parent5d7c6eafe35e2c6e952bc0b3f91d27d760c8e75e (diff)
Added GUIScrollbar and GFXCorneredTileSupportingTexturescrollbar
Diffstat (limited to 'extension/src/openvic-extension/classes/GUIScrollbar.cpp')
-rw-r--r--extension/src/openvic-extension/classes/GUIScrollbar.cpp654
1 files changed, 654 insertions, 0 deletions
diff --git a/extension/src/openvic-extension/classes/GUIScrollbar.cpp b/extension/src/openvic-extension/classes/GUIScrollbar.cpp
new file mode 100644
index 0000000..0f3cde1
--- /dev/null
+++ b/extension/src/openvic-extension/classes/GUIScrollbar.cpp
@@ -0,0 +1,654 @@
+#include "GUIScrollbar.hpp"
+
+#include <godot_cpp/classes/input_event_mouse_button.hpp>
+#include <godot_cpp/classes/input_event_mouse_motion.hpp>
+#include <godot_cpp/variant/utility_functions.hpp>
+
+#include "openvic-extension/utility/ClassBindings.hpp"
+#include "openvic-extension/utility/UITools.hpp"
+#include "openvic-extension/utility/Utilities.hpp"
+
+using namespace OpenVic;
+using namespace godot;
+
+using OpenVic::Utilities::std_to_godot_string;
+using OpenVic::Utilities::std_view_to_godot_string;
+
+/* StringNames cannot be constructed until Godot has called StringName::setup(),
+ * so we must use wrapper functions to delay their initialisation. */
+StringName const& GUIScrollbar::_signal_value_changed() {
+ static const StringName signal_value_changed = "value_changed";
+ return signal_value_changed;
+}
+
+void GUIScrollbar::_bind_methods() {
+ OV_BIND_METHOD(GUIScrollbar::emit_value_changed);
+ OV_BIND_METHOD(GUIScrollbar::reset);
+ OV_BIND_METHOD(GUIScrollbar::clear);
+
+ OV_BIND_METHOD(GUIScrollbar::set_gui_scrollbar_name, { "gui_scene", "gui_scrollbar_name" });
+ OV_BIND_METHOD(GUIScrollbar::get_gui_scrollbar_name);
+
+ OV_BIND_METHOD(GUIScrollbar::get_orientation);
+
+ OV_BIND_METHOD(GUIScrollbar::get_value);
+ OV_BIND_METHOD(GUIScrollbar::get_value_as_ratio);
+ OV_BIND_METHOD(GUIScrollbar::get_min_value);
+ OV_BIND_METHOD(GUIScrollbar::get_max_value);
+ OV_BIND_METHOD(GUIScrollbar::set_value, { "new_value", "signal" }, DEFVAL(true));
+ OV_BIND_METHOD(GUIScrollbar::set_value_as_ratio, { "new_ratio", "signal" }, DEFVAL(true));
+
+ OV_BIND_METHOD(GUIScrollbar::is_range_limited);
+ OV_BIND_METHOD(GUIScrollbar::get_range_limit_min);
+ OV_BIND_METHOD(GUIScrollbar::get_range_limit_max);
+ OV_BIND_METHOD(GUIScrollbar::set_range_limits, { "new_range_limit_min", "new_range_limit_max", "signal" }, DEFVAL(true));
+ OV_BIND_METHOD(GUIScrollbar::set_limits, { "new_min_value", "new_max_value", "signal" }, DEFVAL(true));
+
+ ADD_SIGNAL(MethodInfo(_signal_value_changed(), PropertyInfo(Variant::INT, "value")));
+}
+
+GUIScrollbar::GUIScrollbar() {
+ /* Anything which the constructor might not have default initialised will be set by clear(). */
+ clear();
+}
+
+void GUIScrollbar::_start_button_change(bool shift_pressed, bool control_pressed) {
+ if (shift_pressed) {
+ if (control_pressed) {
+ button_change_value_base = max_value - min_value;
+ } else {
+ button_change_value_base = 10;
+ }
+ } else {
+ if (control_pressed) {
+ button_change_value_base = 100;
+ } else {
+ button_change_value_base = 1;
+ }
+ }
+ if (orientation == HORIZONTAL) {
+ button_change_value_base = -button_change_value_base;
+ }
+ button_change_value = 0;
+ button_change_accelerate_timer = BUTTON_CHANGE_ACCELERATE_DELAY;
+ button_change_timer = BUTTON_CHANGE_DELAY;
+ set_physics_process_internal(true);
+}
+
+void GUIScrollbar::_stop_button_change() {
+ /* This ensures value always changes by at least 1 if less/more is pressed. */
+ if (button_change_value == 0) {
+ button_change_value = button_change_value_base;
+ _update_button_change();
+ }
+ set_physics_process_internal(false);
+}
+
+bool GUIScrollbar::_update_button_change() {
+ if (pressed_less) {
+ set_value(value + button_change_value);
+ } else if (pressed_more) {
+ set_value(value - button_change_value);
+ } else {
+ return false;
+ }
+ return true;
+}
+
+float GUIScrollbar::_value_to_ratio(int32_t val) const {
+ return min_value != max_value
+ ? static_cast<float>(val - min_value) / (max_value - min_value)
+ : 0.0f;
+}
+
+void GUIScrollbar::_calculate_rects() {
+ update_minimum_size();
+
+ const Size2 size = _get_minimum_size();
+
+ if (orientation == HORIZONTAL) {
+ slider_distance = size.width;
+
+ if (less_texture.is_valid()) {
+ less_rect = { {}, less_texture->get_size() };
+
+ slider_distance -= less_rect.size.width;
+ } else {
+ less_rect = {};
+ }
+
+ if (more_texture.is_valid()) {
+ const Size2 more_size = more_texture->get_size();
+
+ more_rect = { { size.width - more_size.width, 0.0f }, more_size };
+
+ slider_distance -= more_rect.size.width;
+ } else {
+ more_rect = {};
+ }
+
+ slider_start = less_rect.size.width;
+
+ if (track_texture.is_valid()) {
+ const real_t track_height = track_texture->get_height();
+
+ track_rect = { { slider_start, 0.0f }, { slider_distance, track_height } };
+ } else {
+ track_rect = {};
+ }
+
+ if (slider_texture.is_valid()) {
+ slider_rect = { {}, slider_texture->get_size() };
+
+ slider_distance -= slider_rect.size.width;
+ } else {
+ slider_rect = {};
+ }
+ } else { /* VERTICAL */
+ slider_distance = size.height;
+
+ if (less_texture.is_valid()) {
+ const Size2 less_size = less_texture->get_size();
+
+ less_rect = { { 0.0f, size.height - less_size.height }, less_size };
+
+ slider_distance -= less_rect.size.height;
+ } else {
+ less_rect = {};
+ }
+
+ if (more_texture.is_valid()) {
+ more_rect = { {}, more_texture->get_size() };
+
+ slider_distance -= more_rect.size.height;
+ } else {
+ more_rect = {};
+ }
+
+ slider_start = more_rect.size.height;
+ const real_t average_button_width = (more_rect.size.width + less_rect.size.width) / 2.0f;
+
+ if (track_texture.is_valid()) {
+ const real_t track_width = track_texture->get_width();
+
+ /* For some reason vertical scrollbar track textures overlap with their more buttons by a single pixel.
+ * They have a row of transparent pixels at the top to account for this, so we must also draw them
+ * one pixel taller to avoid having a gap between the track and the more button. */
+ track_rect = {
+ { (average_button_width - track_width) / 2.0f, slider_start - 1.0f },
+ { track_width, slider_distance + 1.0f }
+ };
+ } else {
+ track_rect = {};
+ }
+
+ if (slider_texture.is_valid()) {
+ const Size2 slider_size = slider_texture->get_size();
+
+ slider_rect = {
+ { (average_button_width - slider_size.width) / 2.0f, 0.0f },
+ slider_size
+ };
+
+ slider_distance -= slider_rect.size.height;
+ } else {
+ slider_rect = {};
+ }
+ }
+
+ if (range_limit_min_texture.is_valid()) {
+ range_limit_min_rect = { {}, range_limit_min_texture->get_size() };
+ } else {
+ range_limit_min_rect = {};
+ }
+
+ if (range_limit_max_texture.is_valid()) {
+ range_limit_max_rect = { {}, range_limit_max_texture->get_size() };
+ } else {
+ range_limit_max_rect = {};
+ }
+}
+
+void GUIScrollbar::_constrain_value() {
+ /* Clamp using range limits, as even when range limiting is disabled the limits will be set to min/max values. */
+ value = std::clamp(value, range_limit_min, range_limit_max);
+
+ slider_rect.position[orientation == HORIZONTAL ? 0 : 1] = slider_start + slider_distance * get_value_as_ratio();
+
+ queue_redraw();
+}
+
+/* _constrain_value() should be called sometime after this. */
+Error GUIScrollbar::_constrain_range_limits() {
+ range_limit_min = std::clamp(range_limit_min, min_value, max_value);
+ range_limit_max = std::clamp(range_limit_max, min_value, max_value);
+
+ Error err = OK;
+ if (range_limit_min > range_limit_max) {
+ UtilityFunctions::push_error(
+ "GUIScrollbar range max ", range_limit_max, " is less than range min ", range_limit_min, " - swapping values."
+ );
+ std::swap(range_limit_min, range_limit_max);
+ err = FAILED;
+ }
+
+ const int axis = orientation == HORIZONTAL ? 0 : 1;
+ range_limit_min_rect.position[axis] = slider_start + slider_distance * _value_to_ratio(range_limit_min);
+ range_limit_max_rect.position[axis] = slider_start + slider_distance * _value_to_ratio(range_limit_max)
+ + slider_rect.size[axis] / 2.0f;
+
+ return err;
+}
+
+/* _constrain_range_limits() should be called sometime after this. */
+Error GUIScrollbar::_constrain_limits() {
+ if (min_value <= max_value) {
+ return OK;
+ } else {
+ UtilityFunctions::push_error(
+ "GUIScrollbar max value ", max_value, " is less than min value ", min_value, " - swapping values."
+ );
+ std::swap(min_value, max_value);
+ return FAILED;
+ }
+}
+
+Vector2 GUIScrollbar::_get_minimum_size() const {
+ if (gui_scrollbar != nullptr) {
+ Size2 size = Utilities::to_godot_fvec2(gui_scrollbar->get_size());
+
+ const int axis = orientation == HORIZONTAL ? 1 : 0;
+ if (less_texture.is_valid()) {
+ size[axis] = std::max(size[axis], less_texture->get_size()[axis]);
+ }
+ if (more_texture.is_valid()) {
+ size[axis] = std::max(size[axis], more_texture->get_size()[axis]);
+ }
+
+ return size;
+ } else {
+ return {};
+ }
+}
+
+void GUIScrollbar::emit_value_changed() {
+ emit_signal(_signal_value_changed(), value);
+}
+
+Error GUIScrollbar::reset() {
+ set_physics_process_internal(false);
+ button_change_accelerate_timer = 0.0;
+ button_change_timer = 0.0;
+ button_change_value_base = 0;
+ button_change_value = 0;
+
+ hover_slider = false;
+ hover_track = false;
+ hover_less = false;
+ hover_more = false;
+ pressed_slider = false;
+ pressed_track = false;
+ pressed_less = false;
+ pressed_more = false;
+
+ value = (max_value - min_value) / 2;
+ range_limit_min = min_value;
+ range_limit_max = max_value;
+
+ const Error err = _constrain_range_limits();
+ _constrain_value();
+ emit_value_changed();
+ return err;
+}
+
+void GUIScrollbar::clear() {
+ gui_scrollbar = nullptr;
+
+ slider_texture.unref();
+ track_texture.unref();
+ less_texture.unref();
+ more_texture.unref();
+
+ slider_rect = {};
+ track_rect = {};
+ less_rect = {};
+ more_rect = {};
+
+ range_limit_min_texture.unref();
+ range_limit_max_texture.unref();
+
+ range_limit_min_rect = {};
+ range_limit_max_rect = {};
+
+ orientation = HORIZONTAL;
+ min_value = 0;
+ max_value = 100;
+ range_limited = false;
+
+ _calculate_rects();
+
+ _constrain_limits();
+ reset();
+}
+
+Error GUIScrollbar::set_gui_scrollbar(GUI::Scrollbar const* new_gui_scrollbar) {
+ if (gui_scrollbar == new_gui_scrollbar) {
+ return OK;
+ }
+ if (new_gui_scrollbar == nullptr) {
+ clear();
+ return OK;
+ }
+
+ bool ret = true;
+
+ gui_scrollbar = new_gui_scrollbar;
+
+ const String gui_scrollbar_name = std_view_to_godot_string(gui_scrollbar->get_name());
+
+ orientation = gui_scrollbar->is_horizontal() ? HORIZONTAL : VERTICAL;
+ range_limited = gui_scrollbar->is_range_limited();
+
+ /* _Element is either GUI::Button or GUI::Icon, both of which have their own
+ * separately defined get_sprite(), hence the need for a template. */
+ const auto set_texture = [&gui_scrollbar_name]<typename _Element>(
+ String const& target, _Element const* element, Ref<GFXSpriteTexture>& texture
+ ) -> bool {
+ ERR_FAIL_NULL_V_MSG(element, false, vformat(
+ "Invalid %s element for GUIScrollbar %s - null!", target, gui_scrollbar_name
+ ));
+ const String element_name = std_view_to_godot_string(element->get_name());
+
+ /* Get Sprite, convert to TextureSprite, use to make a GFXSpriteTexture. */
+ GFX::Sprite const* sprite = element->get_sprite();
+ ERR_FAIL_NULL_V_MSG(sprite, false, vformat(
+ "Invalid %s element %s for GUIScrollbar %s - sprite is null!", target, element_name, gui_scrollbar_name
+ ));
+ GFX::TextureSprite const* texture_sprite = sprite->cast_to<GFX::TextureSprite>();
+ ERR_FAIL_NULL_V_MSG(texture_sprite, false, vformat(
+ "Invalid %s element %s for GUIScrollbar %s - sprite type is %s with base type %s, expected base %s!", target,
+ element_name, gui_scrollbar_name, std_view_to_godot_string(sprite->get_type()),
+ std_view_to_godot_string(sprite->get_base_type()), std_view_to_godot_string(GFX::TextureSprite::get_type_static())
+ ));
+ texture = GFXSpriteTexture::make_gfx_sprite_texture(texture_sprite);
+ ERR_FAIL_NULL_V_MSG(texture, false, vformat(
+ "Failed to make GFXSpriteTexture from %s element %s for GUIScrollbar %s!", target, element_name, gui_scrollbar_name
+ ));
+ if constexpr (std::is_same_v<_Element, GUI::Button>) {
+ using enum GFXButtonStateTexture::ButtonState;
+ for (GFXButtonStateTexture::ButtonState state : { HOVER, PRESSED }) {
+ ERR_FAIL_NULL_V_MSG(texture->get_button_state_texture(state), false, vformat(
+ "Failed to generate %s texture for %s element %s for GUIScrollbar %s!",
+ GFXButtonStateTexture::button_state_to_theme_name(state), target, element_name, gui_scrollbar_name
+ ));
+ }
+ }
+ return true;
+ };
+
+ static const String SLIDER_NAME = "slider";
+ static const String TRACK_NAME = "track";
+ static const String LESS_NAME = "less";
+ static const String MORE_NAME = "more";
+ static const String RANGE_LIMIT_MIN_NAME = "range limit min";
+ static const String RANGE_LIMIT_MAX_NAME = "range limit max";
+
+ ret &= set_texture(SLIDER_NAME, gui_scrollbar->get_slider_button(), slider_texture);
+ ret &= set_texture(TRACK_NAME, gui_scrollbar->get_track_button(), track_texture);
+ ret &= set_texture(LESS_NAME, gui_scrollbar->get_less_button(), less_texture);
+ ret &= set_texture(MORE_NAME, gui_scrollbar->get_more_button(), more_texture);
+ if (range_limited) {
+ ret &= set_texture(RANGE_LIMIT_MIN_NAME, gui_scrollbar->get_range_limit_min_icon(), range_limit_min_texture);
+ ret &= set_texture(RANGE_LIMIT_MAX_NAME, gui_scrollbar->get_range_limit_max_icon(), range_limit_max_texture);
+ } else {
+ range_limit_min_texture.unref();
+ range_limit_max_texture.unref();
+ }
+
+ _calculate_rects();
+
+ fixed_point_t step_size = gui_scrollbar->get_step_size();
+ if (step_size <= 0) {
+ UtilityFunctions::push_error(
+ "Invalid step size ", std_to_godot_string(step_size.to_string()), " for GUIScrollbar ", gui_scrollbar_name,
+ " - not positive! Defaulting to 1."
+ );
+ step_size = 1;
+ ret = false;
+ }
+ min_value = gui_scrollbar->get_min_value() / step_size;
+ max_value = gui_scrollbar->get_max_value() / step_size;
+
+ ret &= _constrain_limits() == OK;
+ ret &= reset() == OK;
+
+ return ERR(ret);
+}
+
+Error GUIScrollbar::set_gui_scrollbar_name(String const& gui_scene, String const& gui_scrollbar_name) {
+ if (gui_scene.is_empty() && gui_scrollbar_name.is_empty()) {
+ return set_gui_scrollbar(nullptr);
+ }
+ ERR_FAIL_COND_V_MSG(gui_scene.is_empty() || gui_scrollbar_name.is_empty(), FAILED, "GUI scene or scrollbar name is empty!");
+
+ GUI::Element const* gui_element = UITools::get_gui_element(gui_scene, gui_scrollbar_name);
+ ERR_FAIL_NULL_V(gui_element, FAILED);
+ GUI::Scrollbar const* new_gui_scrollbar = gui_element->cast_to<GUI::Scrollbar>();
+ ERR_FAIL_NULL_V(new_gui_scrollbar, FAILED);
+ return set_gui_scrollbar(new_gui_scrollbar);
+}
+
+String GUIScrollbar::get_gui_scrollbar_name() const {
+ return gui_scrollbar != nullptr ? std_view_to_godot_string(gui_scrollbar->get_name()) : String {};
+}
+
+void GUIScrollbar::set_value(int32_t new_value, bool signal) {
+ const int32_t old_value = value;
+ value = new_value;
+ _constrain_value();
+ if (signal && value != old_value) {
+ emit_value_changed();
+ }
+}
+
+float GUIScrollbar::get_value_as_ratio() const {
+ return _value_to_ratio(value);
+}
+
+void GUIScrollbar::set_value_as_ratio(float new_ratio, bool signal) {
+ set_value(min_value + (max_value - min_value) * new_ratio, signal);
+}
+
+Error GUIScrollbar::set_range_limits(int32_t new_range_limit_min, int32_t new_range_limit_max, bool signal) {
+ ERR_FAIL_COND_V_MSG(!range_limited, FAILED, "Cannot set range limits of non-range-limited GUIScrollbar!");
+ range_limit_min = new_range_limit_min;
+ range_limit_max = new_range_limit_max;
+ const Error err = _constrain_range_limits();
+ set_value(value, signal);
+ return err;
+}
+
+Error GUIScrollbar::set_limits(int32_t new_min_value, int32_t new_max_value, bool signal) {
+ min_value = new_min_value;
+ max_value = new_max_value;
+ bool ret = _constrain_limits() == OK;
+ ret &= _constrain_range_limits() == OK;
+ set_value(value, signal);
+ return ERR(ret);
+}
+
+void GUIScrollbar::_gui_input(Ref<InputEvent> const& event) {
+ ERR_FAIL_NULL(event);
+
+ Ref<InputEventMouseButton> mb = event;
+
+ if (mb.is_valid()) {
+ if (mb->get_button_index() == MouseButton::MOUSE_BUTTON_LEFT) {
+ if (mb->is_pressed()) {
+ if (less_rect.has_point(mb->get_position())) {
+ pressed_less = true;
+ _start_button_change(mb->is_shift_pressed(), mb->is_ctrl_pressed());
+ } else if (more_rect.has_point(mb->get_position())) {
+ pressed_more = true;
+ _start_button_change(mb->is_shift_pressed(), mb->is_ctrl_pressed());
+ } else if (slider_rect.has_point(mb->get_position())) {
+ pressed_slider = true;
+ } else if (track_rect.has_point(mb->get_position())) {
+ pressed_track = true;
+ const real_t click_pos = mb->get_position()[orientation == HORIZONTAL ? 0 : 1];
+ set_value_as_ratio((click_pos - slider_start) / slider_distance);
+ } else {
+ return;
+ }
+ } else {
+ if (pressed_less) {
+ _stop_button_change();
+ pressed_less = false;
+ } else if (pressed_more) {
+ _stop_button_change();
+ pressed_more = false;
+ } else if (pressed_slider) {
+ pressed_slider = false;
+ } else if (pressed_track) {
+ pressed_track = false;
+ } else {
+ return;
+ }
+ }
+ queue_redraw();
+ }
+ return;
+ }
+
+ Ref<InputEventMouseMotion> mm = event;
+
+ if (mm.is_valid()) {
+ if (pressed_track) {
+ /* Switch to moving the slider if a track click is held and moved. */
+ pressed_track = false;
+ pressed_slider = true;
+ }
+ if (pressed_slider) {
+ const real_t click_pos = mm->get_position()[orientation == HORIZONTAL ? 0 : 1];
+ set_value_as_ratio((click_pos - slider_start) / slider_distance);
+ }
+
+ if (hover_slider != slider_rect.has_point(mm->get_position())) {
+ hover_slider = !hover_slider;
+ queue_redraw();
+ }
+ if (hover_track != track_rect.has_point(mm->get_position())) {
+ hover_track = !hover_track;
+ queue_redraw();
+ }
+ if (hover_less != less_rect.has_point(mm->get_position())) {
+ hover_less = !hover_less;
+ queue_redraw();
+ }
+ if (hover_more != more_rect.has_point(mm->get_position())) {
+ hover_more = !hover_more;
+ queue_redraw();
+ }
+ return;
+ }
+}
+
+void GUIScrollbar::_notification(int what) {
+ switch (what) {
+ case NOTIFICATION_VISIBILITY_CHANGED:
+ case NOTIFICATION_MOUSE_EXIT: {
+ hover_slider = false;
+ hover_track = false;
+ hover_less = false;
+ hover_more = false;
+ queue_redraw();
+ } break;
+
+ /* Pressing (and holding) less and more buttons. */
+ case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
+ const double delta = get_physics_process_delta_time();
+
+ button_change_accelerate_timer -= delta;
+ while (button_change_accelerate_timer <= 0.0) {
+ button_change_accelerate_timer += BUTTON_CHANGE_ACCELERATE_DELAY;
+ button_change_value += button_change_value_base;
+ }
+
+ button_change_timer -= delta;
+ while (button_change_timer <= 0.0) {
+ button_change_timer += BUTTON_CHANGE_DELAY;
+ if (!_update_button_change()) {
+ set_physics_process_internal(false);
+ }
+ }
+ } break;
+
+ case NOTIFICATION_DRAW: {
+ const RID ci = get_canvas_item();
+
+ using enum GFXButtonStateTexture::ButtonState;
+
+ if (less_texture.is_valid()) {
+ Ref<Texture2D> less_state_texture;
+ if (pressed_less) {
+ less_state_texture = less_texture->get_button_state_texture(PRESSED);
+ } else if (hover_less) {
+ less_state_texture = less_texture->get_button_state_texture(HOVER);
+ }
+ if (less_state_texture.is_null()) {
+ less_state_texture = less_texture;
+ }
+ less_state_texture->draw_rect(ci, less_rect, false);
+ }
+
+ if (more_texture.is_valid()) {
+ Ref<Texture2D> more_state_texture;
+ if (pressed_more) {
+ more_state_texture = more_texture->get_button_state_texture(PRESSED);
+ } else if (hover_more) {
+ more_state_texture = more_texture->get_button_state_texture(HOVER);
+ }
+ if (more_state_texture.is_null()) {
+ more_state_texture = more_texture;
+ }
+ more_state_texture->draw_rect(ci, more_rect, false);
+ }
+
+ if (track_texture.is_valid()) {
+ Ref<GFXCorneredTileSupportingTexture> track_state_texture;
+ if (pressed_track) {
+ track_state_texture = track_texture->get_button_state_texture(PRESSED);
+ } else if (hover_track) {
+ track_state_texture = track_texture->get_button_state_texture(HOVER);
+ }
+ if (track_state_texture.is_null()) {
+ track_state_texture = track_texture;
+ }
+ track_state_texture->draw_rect_cornered(ci, track_rect);
+ }
+
+ if (slider_texture.is_valid()) {
+ Ref<Texture2D> slider_state_texture;
+ if (pressed_slider) {
+ slider_state_texture = slider_texture->get_button_state_texture(PRESSED);
+ } else if (hover_slider) {
+ slider_state_texture = slider_texture->get_button_state_texture(HOVER);
+ }
+ if (slider_state_texture.is_null()) {
+ slider_state_texture = slider_texture;
+ }
+ slider_state_texture->draw_rect(ci, slider_rect, false);
+ }
+
+ if (range_limited) {
+ if (range_limit_min != min_value && range_limit_min_texture.is_valid()) {
+ range_limit_min_texture->draw_rect(ci, range_limit_min_rect, false);
+ }
+
+ if (range_limit_max != max_value && range_limit_max_texture.is_valid()) {
+ range_limit_max_texture->draw_rect(ci, range_limit_max_rect, false);
+ }
+ }
+ } break;
+ }
+}