diff --git a/doc/classes/ScrollBar.xml b/doc/classes/ScrollBar.xml index d0dd69408e99..7615fd25efca 100644 --- a/doc/classes/ScrollBar.xml +++ b/doc/classes/ScrollBar.xml @@ -8,10 +8,23 @@ + + + + + Returns [code]true[/code] if the target [ScrollContainer] is sharing its corresponding internal [ScrollBar] with this [ScrollBar] according to the orientation of this [ScrollBar]. + [b]Note:[/b] Share will only be attempted if both nodes are valid and in the tree. + See [method Range.share]. + + + Overrides the step used when clicking increment and decrement buttons or when using arrow keys when the [ScrollBar] is focused. + + The [NodePath] of the target [ScrollContainer] that the [ScrollBar] tries to watch. See [method is_watching]. + diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index f387f91a8b27..f7ac13fb78bb 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -33,6 +33,7 @@ #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/string/print_string.h" +#include "scene/gui/scroll_container.h" #include "scene/main/window.h" bool ScrollBar::focus_by_default = false; @@ -305,6 +306,8 @@ void ScrollBar::_notification(int p_what) { drag_node->connect("gui_input", callable_mp(this, &ScrollBar::_drag_node_input)); drag_node->connect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit), varray(), CONNECT_ONESHOT); } + + _try_watch(); } break; case NOTIFICATION_EXIT_TREE: { @@ -314,6 +317,8 @@ void ScrollBar::_notification(int p_what) { } drag_node = nullptr; + + watching = false; } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { @@ -500,6 +505,41 @@ Size2 ScrollBar::get_minimum_size() const { return minsize; } +void ScrollBar::_try_watch() { + if (watch_target_path.is_empty()) { + return; + } + + ScrollContainer *watch_target = Object::cast_to(get_node(watch_target_path)); + if (watch_target) { + ScrollBar *watch_target_bar = orientation == HORIZONTAL ? Object::cast_to(watch_target->get_h_scroll_bar()) : Object::cast_to(watch_target->get_v_scroll_bar()); + if (watch_target_bar && watch_target_bar != this) { + watch_target_bar->share(this); + watching = true; + } + } +} + +void ScrollBar::set_watch_target_path(const NodePath p_path) { + if (watch_target_path == p_path) { + return; + } + watch_target_path = p_path; + watching = false; + + if (is_inside_tree()) { + _try_watch(); + } +} + +NodePath ScrollBar::get_watch_target_path() const { + return watch_target_path; +} + +bool ScrollBar::is_watching() const { + return watching && has_node(watch_target_path); +} + void ScrollBar::set_custom_step(float p_custom_step) { custom_step = p_custom_step; } @@ -617,12 +657,17 @@ bool ScrollBar::is_smooth_scroll_enabled() const { } void ScrollBar::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_watch_target_path", "path"), &ScrollBar::set_watch_target_path); + ClassDB::bind_method(D_METHOD("get_watch_target_path"), &ScrollBar::get_watch_target_path); + ClassDB::bind_method(D_METHOD("is_watching"), &ScrollBar::is_watching); + ClassDB::bind_method(D_METHOD("set_custom_step", "step"), &ScrollBar::set_custom_step); ClassDB::bind_method(D_METHOD("get_custom_step"), &ScrollBar::get_custom_step); ADD_SIGNAL(MethodInfo("scrolling")); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_step", PROPERTY_HINT_RANGE, "-1,4096,suffix:px"), "set_custom_step", "get_custom_step"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "watch_target_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "ScrollContainer"), "set_watch_target_path", "get_watch_target_path"); } ScrollBar::ScrollBar(Orientation p_orientation) { diff --git a/scene/gui/scroll_bar.h b/scene/gui/scroll_bar.h index 1823f86a67a7..e42554906abb 100644 --- a/scene/gui/scroll_bar.h +++ b/scene/gui/scroll_bar.h @@ -45,6 +45,9 @@ class ScrollBar : public Range { static bool focus_by_default; + NodePath watch_target_path; + bool watching = false; + Orientation orientation; Size2 size; float custom_step = -1.0; @@ -89,6 +92,8 @@ class ScrollBar : public Range { void _drag_node_exit(); void _drag_node_input(const Ref &p_input); + void _try_watch(); + virtual void gui_input(const Ref &p_event) override; protected: @@ -97,6 +102,10 @@ class ScrollBar : public Range { static void _bind_methods(); public: + void set_watch_target_path(const NodePath p_path); + NodePath get_watch_target_path() const; + bool is_watching() const; + void set_custom_step(float p_custom_step); float get_custom_step() const;