From a5c70065795dc371e78c24a9b4c30f6071a927c2 Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Mon, 19 Dec 2016 19:26:33 +0100 Subject: [PATCH] efl_ui_focus_manager: handle redirect objects in logical better --- src/lib/elementary/efl_ui_focus_manager.c | 183 ++++++++++++++------- src/lib/elementary/efl_ui_focus_manager.eo | 4 + 2 files changed, 128 insertions(+), 59 deletions(-) diff --git a/src/lib/elementary/efl_ui_focus_manager.c b/src/lib/elementary/efl_ui_focus_manager.c index 82a301cc9f..763f330103 100644 --- a/src/lib/elementary/efl_ui_focus_manager.c +++ b/src/lib/elementary/efl_ui_focus_manager.c @@ -830,11 +830,16 @@ _no_history_element(Eina_Hash *node_hash) iter = eina_hash_iterator_data_new(node_hash); - if (!eina_iterator_next(iter, (void**)&upper)) - return NULL; - else - return upper; + do + { + if (!eina_iterator_next(iter, (void**)&upper)) + return NULL; + } + while (upper->type != NODE_TYPE_NORMAL); + eina_iterator_free(iter); + + return upper; } static Node* @@ -884,33 +889,39 @@ _next(Node *node) Node *n; //Case 1 we are having children - if (T(node).children) - return eina_list_data_get(T(node).children); + //But only enter the children if it does NOT have a redirect manager + if (T(node).children && !node->redirect_manager) + { + return eina_list_data_get(T(node).children); + } //case 2 we are the root and we dont have children, return ourself if (!T(node).parent) - return node; + { + return node; + } //case 3 we are not at the end of the parents list - n = _parent_item(node, EINA_TRUE); - if (n) - return n; - - //case 4 we are at the end of the parents list n = node; while(T(n).parent) { - Node *parent_next; + Node *parent; + Eina_List *lnode; - parent_next = _parent_item(n, EINA_TRUE); + parent = T(n).parent; + lnode = eina_list_data_find_list(T(parent).children, n); + lnode = eina_list_next(lnode); - if (parent_next) - return parent_next; + if (lnode) + { + return eina_list_data_get(lnode); + } - n = T(n).parent; + n = parent; } + //this is then the root again - return n; + return NULL; } static Node* @@ -920,17 +931,7 @@ _prev(Node *node) //this is the root there is no parent if (!T(node).parent) - { - Node *subtree; - - subtree = node; - //search the most down right item - while(T(subtree).children) - { - subtree = eina_list_last_data_get(T(subtree).children); - } - return subtree; - } + return NULL; n =_parent_item(node, EINA_FALSE); //case 1 there is a item in the parent previous to node, which has children @@ -972,12 +973,8 @@ _logical_movement(Efl_Ui_Focus_Manager_Data *pd EINA_UNUSED, Node *upper, Efl_Ui } stack = eina_list_append(stack, result); - result = deliver(result); - } while(result && result->type != NODE_TYPE_NORMAL); - - if (result->type != NODE_TYPE_NORMAL) - abort(); + } while(result && result->type != NODE_TYPE_NORMAL && !result->redirect_manager); eina_list_free(stack); @@ -989,7 +986,8 @@ _request_move(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_D { Node *dir = NULL; - upper = eina_list_last_data_get(pd->focus_stack); + if (!upper) + upper = eina_list_last_data_get(pd->focus_stack); if (!upper) { @@ -1040,6 +1038,23 @@ _efl_ui_focus_manager_request_move(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Dat } } +static Efl_Ui_Focus_Object* +_find_normal_node(Node *n) +{ + Eina_List *l; + Node *n2; + if (n->type == NODE_TYPE_NORMAL) return n->focusable; + + EINA_LIST_FOREACH(T(n).children , l, n2) + { + Efl_Ui_Focus_Object *r; + + r = _find_normal_node(n2); + if (r) return r; + } + return NULL; +} + EOLIAN static void _efl_ui_focus_manager_focus(Eo *obj, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Object *focus) { @@ -1048,13 +1063,19 @@ _efl_ui_focus_manager_focus(Eo *obj, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus EINA_SAFETY_ON_NULL_RETURN(focus); + //if we want to focus the root then just spin to the first normal + if (focus == pd->root->focusable) + { + focus = _find_normal_node(pd->root); + } + //check if node is part of this manager object - node = node_get(pd, focus); + node = node_get(obj, pd, focus); if (!node) return; F_DBG("Manager: %p focusing object %p %s", obj, focus, efl_class_name_get(focus)); - if (node->type == NODE_TYPE_ONLY_LOGICAL) + if (node->type == NODE_TYPE_ONLY_LOGICAL && !node->redirect_manager && pd->root != node) { ERR(" %p is logical, cannot be focused", obj); return; @@ -1066,19 +1087,29 @@ _efl_ui_focus_manager_focus(Eo *obj, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus efl_ui_focus_manager_redirect_set(obj, NULL); } - //check if this is already the focused object - old_focus = eina_list_last_data_get(pd->focus_stack); + if (node->type == NODE_TYPE_NORMAL) + { + //check if this is already the focused object + old_focus = eina_list_last_data_get(pd->focus_stack); - //check if this is already at the top - if (old_focus && old_focus->focusable == focus) return; + //check if this is already at the top + if (old_focus && old_focus->focusable == focus) return; - //remove the object from the list and add it again - pd->focus_stack = eina_list_remove(pd->focus_stack, node); - pd->focus_stack = eina_list_append(pd->focus_stack, node); + //remove the object from the list and add it again + pd->focus_stack = eina_list_remove(pd->focus_stack, node); + pd->focus_stack = eina_list_append(pd->focus_stack, node); - //populate the new change - if (old_focus) efl_ui_focus_object_focus_set(old_focus->focusable, EINA_FALSE); - efl_ui_focus_object_focus_set(node->focusable, EINA_TRUE); + //populate the new change + if (old_focus) efl_ui_focus_object_focus_set(old_focus->focusable, EINA_FALSE); + efl_ui_focus_object_focus_set(node->focusable, EINA_TRUE); + } + else if (node->redirect_manager) + { + Efl_Ui_Focus_Object *root; + + root = efl_ui_focus_manager_root_get(node->redirect_manager); + efl_ui_focus_manager_focus(node->redirect_manager, root); + } //now check if this is also a listener object if (node->redirect_manager) @@ -1098,8 +1129,6 @@ _efl_ui_focus_manager_move(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Data *pd, E EINA_SAFETY_ON_FALSE_RETURN_VAL(DIRECTION_CHECK(direction), NULL); - F_DBG("Manager: %p move to %d", obj, direction); - if (pd->redirect) { Efl_Ui_Focus_Object *old_candidate = NULL; @@ -1115,16 +1144,27 @@ _efl_ui_focus_manager_move(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Data *pd, E new_candidate = NULL; n = eina_hash_find(pd->node_hash, &old_candidate); - if (n) - new_candidate = _request_move(obj, pd, direction, n); - - if (new_candidate) + if (direction == EFL_UI_FOCUS_DIRECTION_NEXT || + direction == EFL_UI_FOCUS_DIRECTION_PREV) { - //redirect does not have smth. but we do have. - efl_ui_focus_manager_focus(obj, new_candidate); + n = T(n).parent; + new_candidate = _request_move(obj, pd, direction, n); + efl_ui_focus_manager_focus(obj, new_candidate); } - } + else + { + if (n) + new_candidate = _request_move(obj, pd, direction, n); + + if (new_candidate) + { + //redirect does not have smth. but we do have. + efl_ui_focus_manager_focus(obj, new_candidate); + } + } + + } } else { @@ -1134,7 +1174,7 @@ _efl_ui_focus_manager_move(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Data *pd, E efl_ui_focus_manager_focus(obj, candidate); } - F_DBG("Manager: %p moved to %s %s", obj, DEBUG_TUPLE(candidate)); + F_DBG("Manager: %p moved to %s %s in direction %d", obj, DEBUG_TUPLE(candidate), direction); return candidate; } @@ -1224,8 +1264,8 @@ _efl_ui_focus_manager_fetch(Eo *obj, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus res->left = DIR_CLONE(EFL_UI_FOCUS_DIRECTION_LEFT); res->top = DIR_CLONE(EFL_UI_FOCUS_DIRECTION_UP); res->down = DIR_CLONE(EFL_UI_FOCUS_DIRECTION_DOWN); - res->next = _next(n)->focusable; - res->prev = _prev(n)->focusable; + res->next = (tmp = _next(n)) ? tmp->focusable : NULL; + res->prev = (tmp = _prev(n)) ? tmp->focusable : NULL; switch(n->type) { case NODE_TYPE_ONLY_LOGICAL: @@ -1255,4 +1295,29 @@ _efl_ui_focus_manager_class_destructor(Efl_Class *c EINA_UNUSED) _focus_log_domain = -1; } +EOLIAN static Efl_Ui_Focus_Object* +_efl_ui_focus_manager_logical_end(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Data *pd) +{ + //we need to return the most lower right element + Node *child = pd->root; + Efl_Ui_Focus_Object *last_normal = NULL; + while(T(child).children) + { + Efl_Ui_Focus_Object *tmp_last_normal; + + tmp_last_normal = _find_normal_node(child); + if (tmp_last_normal) + last_normal = tmp_last_normal; + + child = eina_list_last_data_get(T(child).children); + } + + if (last_normal) + return last_normal; + else + return NULL; + + return NULL; +} + #include "efl_ui_focus_manager.eo.c" \ No newline at end of file diff --git a/src/lib/elementary/efl_ui_focus_manager.eo b/src/lib/elementary/efl_ui_focus_manager.eo index 885b1e652b..fa8b4ed65b 100644 --- a/src/lib/elementary/efl_ui_focus_manager.eo +++ b/src/lib/elementary/efl_ui_focus_manager.eo @@ -159,6 +159,9 @@ class Efl.Ui.Focus.Manager (Efl.Object) { return : own(ptr(Efl.Ui.Focus.Relations)); } + logical_end { + return : Efl.Ui.Focus.Object; + } } implements { class.constructor; @@ -169,6 +172,7 @@ class Efl.Ui.Focus.Manager (Efl.Object) { Efl.Object.destructor; } events { + redirect,changed : Efl.Ui.Focus.Manager; [[Emitted when the redirect object has changed, the old manager is passed as event info]] pre,flush; [[Emitted once the graph calculationg will be performed]] coords,dirty; [[Emitted once the graph is dirty, this means there are potential changes in border_elements you want to know about]] }