瀏覽代碼

Merge pull request #12962 from SaracenOne/gui_focus_next_prev

Add manual overrides for focus_next and focus_previous
Juan Linietsky 7 年之前
父節點
當前提交
0e04316214
共有 3 個文件被更改,包括 108 次插入3 次删除
  1. 34 2
      doc/classes/Control.xml
  2. 67 1
      scene/gui/control.cpp
  3. 7 0
      scene/gui/control.h

+ 34 - 2
doc/classes/Control.xml

@@ -228,7 +228,14 @@
 			<argument index="0" name="margin" type="int" enum="Margin">
 			</argument>
 			<description>
-				Return the forced neighbour for moving the input focus to. When pressing TAB or directional/joypad directions focus is moved to the next control in that direction. However, the neighbour to move to can be forced with this function.
+				Return the forced neighbour for moving the input focus to. When pressing directional/joypad directions, focus is moved to the next control in that direction. However, the neighbour to move to can be forced with this function.
+			</description>
+		</method>
+		<method name="get_focus_next" qualifiers="const">
+			<return type="NodePath">
+			</return>
+			<description>
+				Return the 'focus_next' for moving input focus to. When pressing TAB, focus is moved to the next control in the tree. However, the control to move to can be forced with this function.
 			</description>
 		</method>
 		<method name="get_focus_owner" qualifiers="const">
@@ -238,6 +245,13 @@
 				Return which control is owning the keyboard focus, or null if no one.
 			</description>
 		</method>
+		<method name="get_focus_previous" qualifiers="const">
+			<return type="NodePath">
+			</return>
+			<description>
+				Return the 'focus_previous' for moving input focus to. When pressing Shift+TAB focus is moved to the previous control in the tree. However, the control to move to can be forced with this function.
+			</description>
+		</method>
 		<method name="get_font" qualifiers="const">
 			<return type="Font">
 			</return>
@@ -676,7 +690,25 @@
 			<argument index="1" name="neighbour" type="NodePath">
 			</argument>
 			<description>
-				Force a neighbour for moving the input focus to. When pressing TAB or directional/joypad directions focus is moved to the next control in that direction. However, the neighbour to move to can be forced with this function.
+				Force a neighbour for moving the input focus to. When pressing directional/joypad directions, focus is moved to the next control in that direction. However, the neighbour to move to can be forced with this function.
+			</description>
+		</method>
+		<method name="set_focus_next">
+			<return type="void">
+			</return>
+			<argument index="0" name="next" type="NodePath">
+			</argument>
+			<description>
+				Force the 'focus_next' for moving input focus to. When pressing TAB, focus is moved to the next control in the tree. However, the control to move to can be forced with this function.
+			</description>
+		</method>
+		<method name="set_focus_previous">
+			<return type="void">
+			</return>
+			<argument index="0" name="previous" type="NodePath">
+			</argument>
+			<description>
+				Force the 'focus_previous' for moving input focus to. When pressing Shift+TAB, focus is moved to the previous control in the tree. However, the control to move to can be forced with this function.
 			</description>
 		</method>
 		<method name="set_global_position">

+ 67 - 1
scene/gui/control.cpp

@@ -1847,6 +1847,25 @@ Control *Control::find_next_valid_focus() const {
 
 	while (true) {
 
+		// If the focus property is manually overwritten, attempt to use it.
+
+		if (!data.focus_next.is_empty()) {
+			Node *n = get_node(data.focus_next);
+			if (n) {
+				from = Object::cast_to<Control>(n);
+
+				if (!from) {
+
+					ERR_EXPLAIN("Next focus node is not a control: " + n->get_name());
+					ERR_FAIL_V(NULL);
+				}
+			} else {
+				return NULL;
+			}
+			if (from->is_visible() && from->get_focus_mode() != FOCUS_NONE)
+				return from;
+		}
+
 		// find next child
 
 		Control *next_child = NULL;
@@ -1926,6 +1945,25 @@ Control *Control::find_prev_valid_focus() const {
 
 	while (true) {
 
+		// If the focus property is manually overwritten, attempt to use it.
+
+		if (!data.focus_prev.is_empty()) {
+			Node *n = get_node(data.focus_prev);
+			if (n) {
+				from = Object::cast_to<Control>(n);
+
+				if (!from) {
+
+					ERR_EXPLAIN("Prev focus node is not a control: " + n->get_name());
+					ERR_FAIL_V(NULL);
+				}
+			} else {
+				return NULL;
+			}
+			if (from->is_visible() && from->get_focus_mode() != FOCUS_NONE)
+				return from;
+		}
+
 		// find prev child
 
 		Control *prev_child = NULL;
@@ -2157,6 +2195,26 @@ NodePath Control::get_focus_neighbour(Margin p_margin) const {
 	return data.focus_neighbour[p_margin];
 }
 
+void Control::set_focus_next(const NodePath &p_next) {
+
+	data.focus_next = p_next;
+}
+
+NodePath Control::get_focus_next() const {
+
+	return data.focus_next;
+}
+
+void Control::set_focus_previous(const NodePath &p_prev) {
+
+	data.focus_prev = p_prev;
+}
+
+NodePath Control::get_focus_previous() const {
+
+	return data.focus_prev;
+}
+
 #define MAX_NEIGHBOUR_SEARCH_COUNT 512
 
 Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
@@ -2172,7 +2230,7 @@ Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
 
 			if (!c) {
 
-				ERR_EXPLAIN("Next focus node is not a control: " + n->get_name());
+				ERR_EXPLAIN("Neighbour focus node is not a control: " + n->get_name());
 				ERR_FAIL_V(NULL);
 			}
 		} else {
@@ -2677,6 +2735,12 @@ void Control::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_focus_neighbour", "margin", "neighbour"), &Control::set_focus_neighbour);
 	ClassDB::bind_method(D_METHOD("get_focus_neighbour", "margin"), &Control::get_focus_neighbour);
 
+	ClassDB::bind_method(D_METHOD("set_focus_next", "next"), &Control::set_focus_next);
+	ClassDB::bind_method(D_METHOD("get_focus_next"), &Control::get_focus_next);
+
+	ClassDB::bind_method(D_METHOD("set_focus_previous", "previous"), &Control::set_focus_previous);
+	ClassDB::bind_method(D_METHOD("get_focus_previous"), &Control::get_focus_previous);
+
 	ClassDB::bind_method(D_METHOD("force_drag", "data", "preview"), &Control::force_drag);
 
 	ClassDB::bind_method(D_METHOD("set_mouse_filter", "filter"), &Control::set_mouse_filter);
@@ -2737,6 +2801,8 @@ void Control::_bind_methods() {
 	ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_top"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_TOP);
 	ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_right"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_RIGHT);
 	ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_bottom"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_BOTTOM);
+	ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "focus_next"), "set_focus_next", "get_focus_next");
+	ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "focus_previous"), "set_focus_previous", "get_focus_previous");
 
 	ADD_GROUP("Mouse", "mouse_");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_filter", PROPERTY_HINT_ENUM, "Stop,Pass,Ignore"), "set_mouse_filter", "get_mouse_filter");

+ 7 - 0
scene/gui/control.h

@@ -191,6 +191,8 @@ private:
 		ObjectID modal_prev_focus_owner;
 
 		NodePath focus_neighbour[4];
+		NodePath focus_next;
+		NodePath focus_prev;
 
 		HashMap<StringName, Ref<Texture>, StringNameHasher> icon_override;
 		HashMap<StringName, Ref<Shader>, StringNameHasher> shader_override;
@@ -374,6 +376,11 @@ public:
 	void set_focus_neighbour(Margin p_margin, const NodePath &p_neighbour);
 	NodePath get_focus_neighbour(Margin p_margin) const;
 
+	void set_focus_next(const NodePath &p_next);
+	NodePath get_focus_next() const;
+	void set_focus_previous(const NodePath &p_prev);
+	NodePath get_focus_previous() const;
+
 	Control *get_focus_owner() const;
 
 	void set_mouse_filter(MouseFilter p_filter);