Browse Source

Merge pull request #34269 from KoBeWi/scrolling_peeps

Scroll ScrollContainer to focused children
Rémi Verschelde 5 years ago
parent
commit
f8ea390b52

+ 7 - 0
doc/classes/Viewport.xml

@@ -310,6 +310,13 @@
 				Emitted when the size of the viewport is changed, whether by [method set_size_override], resize of window, or some other means.
 				Emitted when the size of the viewport is changed, whether by [method set_size_override], resize of window, or some other means.
 			</description>
 			</description>
 		</signal>
 		</signal>
+		<signal name="gui_focus_changed">
+			<argument index="0" name="control" type="Control">
+			</argument>
+			<description>
+				Emitted when a Control node grabs keyboard focus.
+			</description>
+		</signal>
 	</signals>
 	</signals>
 	<constants>
 	<constants>
 		<constant name="UPDATE_DISABLED" value="0" enum="UpdateMode">
 		<constant name="UPDATE_DISABLED" value="0" enum="UpdateMode">

+ 24 - 0
scene/gui/scroll_container.cpp

@@ -30,6 +30,7 @@
 
 
 #include "scroll_container.h"
 #include "scroll_container.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
+#include "scene/main/viewport.h"
 
 
 bool ScrollContainer::clips_input() const {
 bool ScrollContainer::clips_input() const {
 
 
@@ -232,6 +233,23 @@ void ScrollContainer::_update_scrollbar_position() {
 	v_scroll->raise();
 	v_scroll->raise();
 }
 }
 
 
+void ScrollContainer::_ensure_focused_visible(Control *p_control) {
+
+	if (is_a_parent_of(p_control)) {
+		float right_margin = 0;
+		if (v_scroll->is_visible()) {
+			right_margin += v_scroll->get_size().x;
+		}
+		float bottom_margin = 0;
+		if (h_scroll->is_visible()) {
+			bottom_margin += h_scroll->get_size().y;
+		}
+
+		set_v_scroll(MAX(MIN(p_control->get_begin().y, get_v_scroll()), p_control->get_end().y - get_size().y + bottom_margin));
+		set_h_scroll(MAX(MIN(p_control->get_begin().x, get_h_scroll()), p_control->get_end().x - get_size().x + right_margin));
+	}
+}
+
 void ScrollContainer::_notification(int p_what) {
 void ScrollContainer::_notification(int p_what) {
 
 
 	if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
 	if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
@@ -239,6 +257,11 @@ void ScrollContainer::_notification(int p_what) {
 		call_deferred("_update_scrollbar_position");
 		call_deferred("_update_scrollbar_position");
 	};
 	};
 
 
+	if (p_what == NOTIFICATION_READY) {
+
+		get_viewport()->connect("gui_focus_changed", this, "_ensure_focused_visible");
+	}
+
 	if (p_what == NOTIFICATION_SORT_CHILDREN) {
 	if (p_what == NOTIFICATION_SORT_CHILDREN) {
 
 
 		child_max_size = Size2(0, 0);
 		child_max_size = Size2(0, 0);
@@ -521,6 +544,7 @@ void ScrollContainer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_enable_v_scroll", "enable"), &ScrollContainer::set_enable_v_scroll);
 	ClassDB::bind_method(D_METHOD("set_enable_v_scroll", "enable"), &ScrollContainer::set_enable_v_scroll);
 	ClassDB::bind_method(D_METHOD("is_v_scroll_enabled"), &ScrollContainer::is_v_scroll_enabled);
 	ClassDB::bind_method(D_METHOD("is_v_scroll_enabled"), &ScrollContainer::is_v_scroll_enabled);
 	ClassDB::bind_method(D_METHOD("_update_scrollbar_position"), &ScrollContainer::_update_scrollbar_position);
 	ClassDB::bind_method(D_METHOD("_update_scrollbar_position"), &ScrollContainer::_update_scrollbar_position);
+	ClassDB::bind_method(D_METHOD("_ensure_focused_visible"), &ScrollContainer::_ensure_focused_visible);
 	ClassDB::bind_method(D_METHOD("set_h_scroll", "value"), &ScrollContainer::set_h_scroll);
 	ClassDB::bind_method(D_METHOD("set_h_scroll", "value"), &ScrollContainer::set_h_scroll);
 	ClassDB::bind_method(D_METHOD("get_h_scroll"), &ScrollContainer::get_h_scroll);
 	ClassDB::bind_method(D_METHOD("get_h_scroll"), &ScrollContainer::get_h_scroll);
 	ClassDB::bind_method(D_METHOD("set_v_scroll", "value"), &ScrollContainer::set_v_scroll);
 	ClassDB::bind_method(D_METHOD("set_v_scroll", "value"), &ScrollContainer::set_v_scroll);

+ 1 - 0
scene/gui/scroll_container.h

@@ -75,6 +75,7 @@ protected:
 	static void _bind_methods();
 	static void _bind_methods();
 
 
 	void _update_scrollbar_position();
 	void _update_scrollbar_position();
+	void _ensure_focused_visible(Control *p_node);
 
 
 public:
 public:
 	int get_v_scroll() const;
 	int get_v_scroll() const;

+ 2 - 0
scene/main/viewport.cpp

@@ -2634,6 +2634,7 @@ void Viewport::_gui_control_grab_focus(Control *p_control) {
 		return;
 		return;
 	get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, "_viewports", "_gui_remove_focus");
 	get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, "_viewports", "_gui_remove_focus");
 	gui.key_focus = p_control;
 	gui.key_focus = p_control;
+	emit_signal("gui_focus_changed", p_control);
 	p_control->notification(Control::NOTIFICATION_FOCUS_ENTER);
 	p_control->notification(Control::NOTIFICATION_FOCUS_ENTER);
 	p_control->update();
 	p_control->update();
 }
 }
@@ -3216,6 +3217,7 @@ void Viewport::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_canvas_transform", PROPERTY_HINT_NONE, "", 0), "set_global_canvas_transform", "get_global_canvas_transform");
 	ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_canvas_transform", PROPERTY_HINT_NONE, "", 0), "set_global_canvas_transform", "get_global_canvas_transform");
 
 
 	ADD_SIGNAL(MethodInfo("size_changed"));
 	ADD_SIGNAL(MethodInfo("size_changed"));
+	ADD_SIGNAL(MethodInfo("gui_focus_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
 
 
 	BIND_ENUM_CONSTANT(UPDATE_DISABLED);
 	BIND_ENUM_CONSTANT(UPDATE_DISABLED);
 	BIND_ENUM_CONSTANT(UPDATE_ONCE);
 	BIND_ENUM_CONSTANT(UPDATE_ONCE);