From e4201734df8c835a12b39276692987d6e2f5c267 Mon Sep 17 00:00:00 2001 From: Saracen Date: Thu, 16 Nov 2017 09:45:52 +0000 Subject: [PATCH] Add manual overrides for focus_next and focus_previous on controls similar to what can already be done with focus neighbours. --- doc/classes/Control.xml | 36 ++++++++++++++++++++-- scene/gui/control.cpp | 68 ++++++++++++++++++++++++++++++++++++++++- scene/gui/control.h | 7 +++++ 3 files changed, 108 insertions(+), 3 deletions(-) diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index b5765ac9487..c56b0a15ce9 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -228,7 +228,14 @@ - 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. + + + + + + + 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. @@ -238,6 +245,13 @@ Return which control is owning the keyboard focus, or null if no one. + + + + + 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. + + @@ -676,7 +690,25 @@ - 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. + + + + + + + + + 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. + + + + + + + + + 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. diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index e73ada9f313..3976a2ad48e 100644 --- a/scene/gui/control.cpp +++ b/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(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(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"); diff --git a/scene/gui/control.h b/scene/gui/control.h index 4d0e3934ad5..94c484ca50b 100644 --- a/scene/gui/control.h +++ b/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, StringNameHasher> icon_override; HashMap, 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);