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;