summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorMarcel Hollerbach <marcel-hollerbach@t-online.de>2017-07-05 12:48:52 +0200
committerMarcel Hollerbach <marcel-hollerbach@t-online.de>2017-08-10 20:55:50 +0200
commitd4cd85aa55c15fdc088c27aaf46c745c9000b514 (patch)
tree3f865d0160faefee8f83918537f2e9f2ccd1ea37 /src/lib
parent348a7084aff3db9ba8f009309c34b9a39a56129e (diff)
efl_ui_focus_manager: split this of tinto a class and a interface
it turns out to be very handy to have a interface for the moving and border elements, that is unconnected to the way of how widgets are registering themself. This for example enables us to get a simple focus manager that just redirects the call into a internal 2 dimensional data struct
Diffstat (limited to '')
-rw-r--r--src/lib/elementary/Elementary.h1
-rw-r--r--src/lib/elementary/efl_ui_focus_manager.c1452
-rw-r--r--src/lib/elementary/efl_ui_focus_manager.eo88
-rw-r--r--src/lib/elementary/efl_ui_focus_manager_calc.c1459
-rw-r--r--src/lib/elementary/efl_ui_focus_manager_calc.eo107
-rw-r--r--src/lib/elementary/efl_ui_focus_manager_root_focus.c12
-rw-r--r--src/lib/elementary/efl_ui_focus_manager_root_focus.eo6
-rw-r--r--src/lib/elementary/efl_ui_focus_manager_sub.c6
-rw-r--r--src/lib/elementary/efl_ui_focus_manager_sub.eo2
-rw-r--r--src/lib/elementary/efl_ui_win.c2
-rw-r--r--src/lib/elementary/elc_fileselector.c2
-rw-r--r--src/lib/elementary/elm_box.c2
-rw-r--r--src/lib/elementary/elm_gengrid.c10
-rw-r--r--src/lib/elementary/elm_grid.c2
-rw-r--r--src/lib/elementary/elm_hover.c2
-rw-r--r--src/lib/elementary/elm_menu.c2
-rw-r--r--src/lib/elementary/elm_scroller.c2
-rw-r--r--src/lib/elementary/elm_table.c2
-rw-r--r--src/lib/elementary/elm_toolbar.c10
-rw-r--r--src/lib/elementary/elm_widget.c12
20 files changed, 1605 insertions, 1576 deletions
diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h
index 829a622bcf..766d854028 100644
--- a/src/lib/elementary/Elementary.h
+++ b/src/lib/elementary/Elementary.h
@@ -146,6 +146,7 @@ EAPI extern Elm_Version *elm_version;
146#if defined (EFL_EO_API_SUPPORT) && defined (EFL_BETA_API_SUPPORT) 146#if defined (EFL_EO_API_SUPPORT) && defined (EFL_BETA_API_SUPPORT)
147# include "efl_ui_focus_object.eo.h" 147# include "efl_ui_focus_object.eo.h"
148# include "efl_ui_focus_manager.eo.h" 148# include "efl_ui_focus_manager.eo.h"
149# include "efl_ui_focus_manager_calc.eo.h"
149# include "efl_ui_focus_manager_sub.eo.h" 150# include "efl_ui_focus_manager_sub.eo.h"
150# include "efl_ui_focus_manager_root_focus.eo.h" 151# include "efl_ui_focus_manager_root_focus.eo.h"
151# include "efl_ui_focus_user.eo.h" 152# include "efl_ui_focus_user.eo.h"
diff --git a/src/lib/elementary/efl_ui_focus_manager.c b/src/lib/elementary/efl_ui_focus_manager.c
index 9ebb7ba94d..09db7da090 100644
--- a/src/lib/elementary/efl_ui_focus_manager.c
+++ b/src/lib/elementary/efl_ui_focus_manager.c
@@ -5,1456 +5,4 @@
5#include <Elementary.h> 5#include <Elementary.h>
6#include "elm_priv.h" 6#include "elm_priv.h"
7 7
8#define MY_CLASS EFL_UI_FOCUS_MANAGER_CLASS
9#define FOCUS_DATA(obj) Efl_Ui_Focus_Manager_Data *pd = efl_data_scope_get(obj, MY_CLASS);
10
11#define DIM_EFL_UI_FOCUS_DIRECTION(dim,neg) dim*2+neg
12#define NODE_DIRECTIONS_COUNT 4
13
14#define DIRECTION_CHECK(dir) (dir >= 0 && dir < EFL_UI_FOCUS_DIRECTION_LAST)
15
16//#define CALC_DEBUG
17#define DEBUG_TUPLE(obj) efl_name_get(obj), efl_class_name_get(obj)
18
19static int _focus_log_domain = -1;
20
21#define F_CRI(...) EINA_LOG_DOM_CRIT(_focus_log_domain, __VA_ARGS__)
22#define F_ERR(...) EINA_LOG_DOM_ERR(_focus_log_domain, __VA_ARGS__)
23#define F_WRN(...) EINA_LOG_DOM_WARN(_focus_log_domain, __VA_ARGS__)
24#define F_INF(...) EINA_LOG_DOM_INFO(_focus_log_domain, __VA_ARGS__)
25#define F_DBG(...) EINA_LOG_DOM_DBG(_focus_log_domain, __VA_ARGS__)
26
27typedef struct {
28 Eina_Bool positive;
29 Efl_Ui_Focus_Object *anchor;
30} Anchor;
31
32typedef enum {
33 DIMENSION_X = 0,
34 DIMENSION_Y = 1,
35} Dimension;
36
37typedef struct _Border Border;
38typedef struct _Node Node;
39
40struct _Border {
41 Eina_List *partners;
42};
43
44typedef enum {
45 NODE_TYPE_NORMAL = 0,
46 NODE_TYPE_ONLY_LOGICAL = 2,
47} Node_Type;
48
49struct _Node{
50 Node_Type type; //type of the node
51
52 Efl_Ui_Focus_Object *focusable;
53 Efl_Ui_Focus_Manager *manager;
54 Efl_Ui_Focus_Manager *redirect_manager;
55
56 struct _Tree_Node{
57 Node *parent; //the parent of the tree
58 Eina_List *children; //this saves the original set of elements
59 Eina_List *safed_order;
60 }tree;
61
62 struct _Graph_Node {
63 Border directions[NODE_DIRECTIONS_COUNT];
64 } graph;
65};
66
67#define T(n) (n->tree)
68#define G(n) (n->graph)
69
70typedef struct {
71 Eina_List *focus_stack;
72 Eina_Hash *node_hash;
73 Efl_Ui_Focus_Manager *redirect;
74 Eina_List *dirty;
75
76 Node *root;
77} Efl_Ui_Focus_Manager_Data;
78
79static Efl_Ui_Focus_Direction
80_complement(Efl_Ui_Focus_Direction dir)
81{
82 #define COMP(a,b) \
83 if (dir == a) return b; \
84 if (dir == b) return a;
85
86 COMP(EFL_UI_FOCUS_DIRECTION_RIGHT, EFL_UI_FOCUS_DIRECTION_LEFT)
87 COMP(EFL_UI_FOCUS_DIRECTION_UP, EFL_UI_FOCUS_DIRECTION_DOWN)
88 COMP(EFL_UI_FOCUS_DIRECTION_PREV, EFL_UI_FOCUS_DIRECTION_NEXT)
89
90 #undef COMP
91
92 return EFL_UI_FOCUS_DIRECTION_LAST;
93}
94
95/*
96 * Set this new list of partners to the border.
97 * All old partners will be deleted
98 */
99static void
100border_partners_set(Node *node, Efl_Ui_Focus_Direction direction, Eina_List *list)
101{
102 Node *partner;
103 Eina_List *lnode;
104 Border *border = &G(node).directions[direction];
105
106 EINA_LIST_FREE(border->partners, partner)
107 {
108 Border *comp_border = &G(partner).directions[_complement(direction)];
109
110 comp_border->partners = eina_list_remove(comp_border->partners, node);
111 }
112
113 border->partners = list;
114
115 EINA_LIST_FOREACH(border->partners, lnode, partner)
116 {
117 Border *comp_border = &G(partner).directions[_complement(direction)];
118
119 comp_border->partners = eina_list_append(comp_border->partners, node);
120 }
121}
122
123/**
124 * Create a new node
125 */
126static Node*
127node_new(Efl_Ui_Focus_Object *focusable, Efl_Ui_Focus_Manager *manager)
128{
129 Node *node;
130
131 node = calloc(1, sizeof(Node));
132
133 node->focusable = focusable;
134 node->manager = manager;
135
136 return node;
137}
138
139/**
140 * Looks up given focus object from the focus manager.
141 *
142 * @returns node found, or NULL if focusable was not found in the manager.
143 */
144static Node*
145node_get(Efl_Ui_Focus_Manager *obj, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Object *focusable)
146{
147 Node *ret;
148
149 ret = eina_hash_find(pd->node_hash, &focusable);
150
151 if (ret) return ret;
152
153 ERR("Focusable %p (%s) not registered in manager %p", focusable, efl_class_name_get(focusable), obj);
154
155 return NULL;
156}
157
158/**
159 * Free a node item and unlink this item from all direction
160 */
161static void
162node_item_free(Node *item)
163{
164 Node *n;
165 Eina_List *l;
166 //free the graph items
167 for(int i = 0;i < NODE_DIRECTIONS_COUNT; i++)
168 {
169 border_partners_set(item, i, NULL);
170 }
171
172 //free the tree items
173 if (!item->tree.parent && item->tree.children)
174 {
175 ERR("Freeing the root with children is going to break the logical tree!");
176 }
177
178 if (item->tree.parent && item->tree.children)
179 {
180 Node *parent;
181
182 parent = item->tree.parent;
183 //reparent everything into the next layer
184 EINA_LIST_FOREACH(item->tree.children, l, n)
185 {
186 n->tree.parent = item->tree.parent;
187 }
188 parent->tree.children = eina_list_merge(parent->tree.children , item->tree.children);
189 }
190
191 if (item->tree.parent)
192 {
193 Node *parent;
194
195 parent = item->tree.parent;
196 T(parent).children = eina_list_remove(T(parent).children, item);
197 }
198
199 //free the safed order
200 ELM_SAFE_FREE(T(item).safed_order, eina_list_free);
201
202 free(item);
203}
204
205
206//CALCULATING STUFF
207
208static inline int
209_distance(Eina_Rectangle node, Eina_Rectangle op, Dimension dim)
210{
211 int min, max, point;
212 int v1, v2;
213
214 if (dim == DIMENSION_X)
215 {
216 min = op.x;
217 max = eina_rectangle_max_x(&op);
218 point = node.x + node.w/2;
219 }
220 else
221 {
222 min = op.y;
223 max = eina_rectangle_max_y(&op);
224 point = node.y + node.h/2;
225 }
226
227 v1 = min - point;
228 v2 = max - point;
229
230 if (abs(v1) < abs(v2))
231 return v1;
232 else
233 return v2;
234}
235
236static inline void
237_calculate_node(Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Object *node, Dimension dim, Eina_List **pos, Eina_List **neg)
238{
239 Eina_Rectangle rect = EINA_RECTANGLE_INIT;
240 Efl_Ui_Focus_Object *op;
241 int dim_min, dim_max;
242 Eina_Iterator *nodes;
243 int cur_pos_min = 0, cur_neg_min = 0;
244 Node *n;
245
246 nodes = eina_hash_iterator_data_new(pd->node_hash);
247 rect = efl_ui_focus_object_focus_geometry_get(node);
248
249 *pos = NULL;
250 *neg = NULL;
251
252 if (dim == DIMENSION_X)
253 {
254 dim_min = rect.y;
255 dim_max = rect.y + rect.h;
256 }
257 else
258 {
259 dim_min = rect.x;
260 dim_max = rect.x + rect.w;
261 }
262
263 EINA_ITERATOR_FOREACH(nodes, n)
264 {
265 Eina_Rectangle op_rect = EINA_RECTANGLE_INIT;
266 int min, max;
267
268 op = n->focusable;
269 if (op == node) continue;
270
271 if (n->type == NODE_TYPE_ONLY_LOGICAL) continue;
272
273 op_rect = efl_ui_focus_object_focus_geometry_get(op);
274
275 if (dim == DIMENSION_X)
276 {
277 min = op_rect.y;
278 max = eina_rectangle_max_y(&op_rect);
279 }
280 else
281 {
282 min = op_rect.x;
283 max = eina_rectangle_max_x(&op_rect);
284 }
285
286
287 /* The only way the calculation does make sense is if the two number
288 * lines are not disconnected.
289 * If they are connected one point of the 4 lies between the min and max of the other line
290 */
291 if (!((min <= max && max <= dim_min && dim_min <= dim_max) ||
292 (dim_min <= dim_max && dim_max <= min && min <= max)) &&
293 !eina_rectangle_intersection(&op_rect, &rect))
294 {
295 //this thing hits horizontal
296 int tmp_dis;
297
298 tmp_dis = _distance(rect, op_rect, dim);
299
300 if (tmp_dis < 0)
301 {
302 if (tmp_dis == cur_neg_min)
303 {
304 //add it
305 *neg = eina_list_append(*neg, op);
306 }
307 else if (tmp_dis > cur_neg_min
308 || cur_neg_min == 0) //init case
309 {
310 //nuke the old and add
311#ifdef CALC_DEBUG
312 printf("CORRECTION FOR %s-%s\n found anchor %s-%s in distance %d\n (%d,%d,%d,%d)\n (%d,%d,%d,%d)\n\n", DEBUG_TUPLE(node), DEBUG_TUPLE(op),
313 tmp_dis,
314 op_rect.x, op_rect.y, op_rect.w, op_rect.h,
315 rect.x, rect.y, rect.w, rect.h);
316#endif
317 *neg = eina_list_free(*neg);
318 *neg = eina_list_append(NULL, op);
319 cur_neg_min = tmp_dis;
320 }
321 }
322 else
323 {
324 if (tmp_dis == cur_pos_min)
325 {
326 //add it
327 *pos = eina_list_append(*pos, op);
328 }
329 else if (tmp_dis < cur_pos_min
330 || cur_pos_min == 0) //init case
331 {
332 //nuke the old and add
333#ifdef CALC_DEBUG
334 printf("CORRECTION FOR %s-%s\n found anchor %s-%s in distance %d\n (%d,%d,%d,%d)\n (%d,%d,%d,%d)\n\n", DEBUG_TUPLE(node), DEBUG_TUPLE(op),
335 tmp_dis,
336 op_rect.x, op_rect.y, op_rect.w, op_rect.h,
337 rect.x, rect.y, rect.w, rect.h);
338#endif
339 *pos = eina_list_free(*pos);
340 *pos = eina_list_append(NULL, op);
341 cur_pos_min = tmp_dis;
342 }
343 }
344
345
346#if 0
347 printf("(%d,%d,%d,%d)%s vs(%d,%d,%d,%d)%s\n", rect.x, rect.y, rect.w, rect.h, elm_widget_part_text_get(node, NULL), op_rect.x, op_rect.y, op_rect.w, op_rect.h, elm_widget_part_text_get(op, NULL));
348 printf("(%d,%d,%d,%d)\n", min, max, dim_min, dim_max);
349 printf("Candidate %d\n", tmp_dis);
350 if (anchor->anchor == NULL || abs(tmp_dis) < abs(distance)) //init case
351 {
352 distance = tmp_dis;
353 anchor->positive = tmp_dis > 0 ? EINA_FALSE : EINA_TRUE;
354 anchor->anchor = op;
355 //Helper for debugging wrong calculations
356
357 }
358#endif
359 }
360
361 }
362 eina_iterator_free(nodes);
363 nodes = NULL;
364}
365
366#ifdef CALC_DEBUG
367static void
368_debug_node(Node *node)
369{
370 Eina_List *tmp = NULL;
371
372 if (!node) return;
373
374 printf("NODE %s-%s\n", DEBUG_TUPLE(node->focusable));
375
376#define DIR_LIST(dir) G(node).directions[dir].partners
377
378#define DIR_OUT(dir)\
379 tmp = DIR_LIST(dir); \
380 { \
381 Eina_List *list_node; \
382 Node *partner; \
383 printf("-"#dir"-> ("); \
384 EINA_LIST_FOREACH(tmp, list_node, partner) \
385 printf("%s-%s,", DEBUG_TUPLE(partner->focusable)); \
386 printf(")\n"); \
387 }
388
389 DIR_OUT(EFL_UI_FOCUS_DIRECTION_RIGHT)
390 DIR_OUT(EFL_UI_FOCUS_DIRECTION_LEFT)
391 DIR_OUT(EFL_UI_FOCUS_DIRECTION_UP)
392 DIR_OUT(EFL_UI_FOCUS_DIRECTION_DOWN)
393
394}
395#endif
396
397static void
398convert_border_set(Efl_Ui_Focus_Manager *obj, Efl_Ui_Focus_Manager_Data *pd, Node *node, Eina_List *focusable_list, Efl_Ui_Focus_Direction dir)
399{
400 Eina_List *partners = NULL;
401 Efl_Ui_Focus_Object *fobj;
402
403 EINA_LIST_FREE(focusable_list, fobj)
404 {
405 Node *entry;
406
407 entry = node_get(obj, pd, fobj);
408 if (!entry)
409 {
410 CRI("Found a obj in graph without node-entry!");
411 return;
412 }
413 partners = eina_list_append(partners, entry);
414 }
415
416 border_partners_set(node, dir, partners);
417}
418
419static void
420dirty_flush_node(Efl_Ui_Focus_Manager *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Data *pd, Node *node)
421{
422 Eina_List *x_partners_pos, *x_partners_neg;
423 Eina_List *y_partners_pos, *y_partners_neg;
424
425 _calculate_node(pd, node->focusable, DIMENSION_X, &x_partners_pos, &x_partners_neg);
426 _calculate_node(pd, node->focusable, DIMENSION_Y, &y_partners_pos, &y_partners_neg);
427
428 convert_border_set(obj, pd, node, x_partners_pos, EFL_UI_FOCUS_DIRECTION_RIGHT);
429 convert_border_set(obj, pd, node, x_partners_neg, EFL_UI_FOCUS_DIRECTION_LEFT);
430 convert_border_set(obj, pd, node, y_partners_neg, EFL_UI_FOCUS_DIRECTION_UP);
431 convert_border_set(obj, pd, node, y_partners_pos, EFL_UI_FOCUS_DIRECTION_DOWN);
432
433#ifdef CALC_DEBUG
434 _debug_node(node);
435#endif
436}
437
438static void
439dirty_flush(Efl_Ui_Focus_Manager *obj, Efl_Ui_Focus_Manager_Data *pd, Node *node)
440{
441 if (!eina_list_data_find(pd->dirty, node)) return;
442
443 efl_event_callback_call(obj, EFL_UI_FOCUS_MANAGER_EVENT_FLUSH_PRE, NULL);
444
445 pd->dirty = eina_list_remove(pd->dirty, node);
446
447 dirty_flush_node(obj, pd, node);
448}
449
450static void
451dirty_flush_all(Efl_Ui_Focus_Manager *obj, Efl_Ui_Focus_Manager_Data *pd)
452{
453 Node *node;
454
455 efl_event_callback_call(obj, EFL_UI_FOCUS_MANAGER_EVENT_FLUSH_PRE, NULL);
456
457 EINA_LIST_FREE(pd->dirty, node)
458 {
459 dirty_flush_node(obj, pd, node);
460 }
461}
462
463static void
464dirty_add(Eo *obj, Efl_Ui_Focus_Manager_Data *pd, Node *dirty)
465{
466 if (dirty->type == NODE_TYPE_ONLY_LOGICAL)
467 {
468 ERR("Only not only logical nodes can be marked dirty");
469 return;
470 }
471
472 //if (eina_list_data_find(pd->dirty, dirty)) return;
473 pd->dirty = eina_list_remove(pd->dirty, dirty);
474 pd->dirty = eina_list_append(pd->dirty, dirty);
475
476 efl_event_callback_call(obj, EFL_UI_FOCUS_MANAGER_EVENT_COORDS_DIRTY, NULL);
477}
478
479
480static void
481_node_new_geometery_cb(void *data, const Efl_Event *event)
482{
483 Node *node;
484 FOCUS_DATA(data)
485
486 node = node_get(data, pd, event->object);
487 if (!node)
488 return;
489
490 dirty_add(data, pd, node);
491
492 return;
493}
494
495EFL_CALLBACKS_ARRAY_DEFINE(focusable_node,
496 {EFL_GFX_EVENT_RESIZE, _node_new_geometery_cb},
497 {EFL_GFX_EVENT_MOVE, _node_new_geometery_cb},
498);
499
500//=============================
501
502static Node*
503_register(Eo *obj, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Object *child, Node *parent)
504{
505 Node *node;
506 if (!!eina_hash_find(pd->node_hash, &child))
507 {
508 ERR("Child %p is already registered in the graph", child);
509 return NULL;
510 }
511
512 node = node_new(child, obj);
513 eina_hash_add(pd->node_hash, &child, node);
514
515 //add the parent
516 if (parent)
517 {
518 T(node).parent = parent;
519 T(parent).children = eina_list_append(T(parent).children, node);
520 }
521
522 return node;
523}
524EOLIAN static Eina_Bool
525_efl_ui_focus_manager_register_logical(Eo *obj, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Object *child, Efl_Ui_Focus_Object *parent, Efl_Ui_Focus_Manager *redirect)
526{
527 Node *node = NULL;
528 Node *pnode = NULL;
529
530 EINA_SAFETY_ON_NULL_RETURN_VAL(child, EINA_FALSE);
531 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, EINA_FALSE);
532
533 if (redirect)
534 EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(redirect, MY_CLASS), EINA_FALSE);
535
536 F_DBG("Manager: %p register %p %p %p", obj, child, parent, redirect);
537
538 pnode = node_get(obj, pd, parent);
539 if (!pnode) return EINA_FALSE;
540
541 node = _register(obj, pd, child, pnode);
542 if (!node) return EINA_FALSE;
543
544 node->type = NODE_TYPE_ONLY_LOGICAL;
545 node->redirect_manager = redirect;
546
547 //set again
548 if (T(pnode).safed_order)
549 {
550 Eina_List *tmp;
551
552 tmp = eina_list_clone(T(pnode).safed_order);
553 efl_ui_focus_manager_update_order(obj, parent, tmp);
554 }
555
556 return EINA_TRUE;
557}
558
559
560EOLIAN static Eina_Bool
561_efl_ui_focus_manager_register(Eo *obj, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Object *child, Efl_Ui_Focus_Object *parent, Efl_Ui_Focus_Manager *redirect)
562{
563 Node *node = NULL;
564 Node *pnode = NULL;
565
566 EINA_SAFETY_ON_NULL_RETURN_VAL(child, EINA_FALSE);
567 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, EINA_FALSE);
568
569 if (redirect)
570 EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(redirect, MY_CLASS), EINA_FALSE);
571
572 F_DBG("Manager: %p register %p %p %p", obj, child, parent, redirect);
573
574 pnode = node_get(obj, pd, parent);
575 if (!pnode) return EINA_FALSE;
576
577 node = _register(obj, pd, child, pnode);
578 if (!node) return EINA_FALSE;
579
580 //listen to changes
581 efl_event_callback_array_add(child, focusable_node(), obj);
582
583 node->type = NODE_TYPE_NORMAL;
584 node->redirect_manager = redirect;
585
586 //mark dirty
587 dirty_add(obj, pd, node);
588
589 //set again
590 if (T(pnode).safed_order)
591 {
592 Eina_List *tmp;
593
594 tmp = eina_list_clone(T(pnode).safed_order);
595 efl_ui_focus_manager_update_order(obj, parent, tmp);
596 }
597
598 return EINA_TRUE;
599}
600
601EOLIAN static Eina_Bool
602_efl_ui_focus_manager_update_redirect(Eo *obj, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Object *child, Efl_Ui_Focus_Manager *redirect)
603{
604 Node *node = node_get(obj, pd, child);
605 if (!node) return EINA_FALSE;
606
607 if (redirect)
608 EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(redirect, MY_CLASS), EINA_FALSE);
609
610 node->redirect_manager = redirect;
611
612 return EINA_TRUE;
613}
614
615EOLIAN static Eina_Bool
616_efl_ui_focus_manager_update_parent(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Object *child, Efl_Ui_Focus_Object *parent_obj)
617{
618 Node *node;
619 Node *parent;
620
621 EINA_SAFETY_ON_NULL_RETURN_VAL(parent_obj, EINA_FALSE);
622 EINA_SAFETY_ON_NULL_RETURN_VAL(child, EINA_FALSE);
623
624 node = node_get(obj, pd, child);
625 parent = node_get(obj, pd, parent_obj);
626
627 if (!node || !parent) return EINA_FALSE;
628
629 if (T(node).parent)
630 {
631 Node *old_parent;
632
633 old_parent = T(node).parent;
634
635 T(old_parent).children = eina_list_remove(T(old_parent).children, node);
636 }
637
638 T(node).parent = parent;
639
640 if (T(node).parent)
641 {
642 T(parent).children = eina_list_append(T(parent).children, node);
643 }
644
645 return EINA_TRUE;
646}
647
648static Eina_List*
649_set_a_without_b(Eina_List *a, Eina_List *b)
650{
651 Eina_List *a_out = NULL, *node;
652 void *data;
653
654 a_out = eina_list_clone(a);
655
656 EINA_LIST_FOREACH(b, node, data)
657 {
658 a_out = eina_list_remove(a_out, data);
659 }
660
661 return a_out;
662}
663
664static Eina_Bool
665_equal_set(Eina_List *none_nodes, Eina_List *nodes)
666{
667 Eina_List *n;
668 Node *node;
669
670 if (eina_list_count(nodes) != eina_list_count(none_nodes)) return EINA_FALSE;
671
672 EINA_LIST_FOREACH(nodes, n, node)
673 {
674 if (!eina_list_data_find(none_nodes, node))
675 return EINA_FALSE;
676 }
677
678 return EINA_TRUE;
679}
680
681EOLIAN static void
682_efl_ui_focus_manager_update_order(Eo *obj, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Object *parent, Eina_List *order)
683{
684 Node *pnode;
685 Efl_Ui_Focus_Object *o;
686 Eina_List *node_order = NULL, *not_ordered, *trash, *node_order_clean, *n;
687
688 F_DBG("Manager_update_order on %p %p", obj, parent);
689
690 pnode = node_get(obj, pd, parent);
691 if (!pnode)
692 return;
693
694 ELM_SAFE_FREE(T(pnode).safed_order, eina_list_free);
695 T(pnode).safed_order = order;
696
697 //get all nodes from the subset
698 EINA_LIST_FOREACH(order, n, o)
699 {
700 Node *tmp;
701
702 tmp = eina_hash_find(pd->node_hash, &o);
703
704 if (!tmp) continue;
705
706 node_order = eina_list_append(node_order, tmp);
707 }
708
709 not_ordered = _set_a_without_b(T(pnode).children, node_order);
710 trash = _set_a_without_b(node_order, T(pnode).children);
711 node_order_clean = _set_a_without_b(node_order, trash);
712
713 eina_list_free(node_order);
714 eina_list_free(trash);
715
716 eina_list_free(T(pnode).children);
717 T(pnode).children = eina_list_merge(node_order_clean, not_ordered);
718
719 return;
720}
721
722EOLIAN static Eina_Bool
723_efl_ui_focus_manager_update_children(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Object *parent, Eina_List *order)
724{
725 Node *pnode;
726 Efl_Ui_Focus_Object *o;
727 Eina_Bool fail = EINA_FALSE;
728 Eina_List *node_order = NULL;
729
730 pnode = node_get(obj, pd, parent);
731 if (!pnode)
732 return EINA_FALSE;
733
734 //get all nodes from the subset
735 EINA_LIST_FREE(order, o)
736 {
737 Node *tmp;
738
739 tmp = node_get(obj, pd, o);
740 if (!tmp)
741 fail = EINA_TRUE;
742 node_order = eina_list_append(node_order, tmp);
743 }
744
745 if (fail)
746 {
747 eina_list_free(node_order);
748 return EINA_FALSE;
749 }
750
751 if (!_equal_set(node_order, T(pnode).children))
752 {
753 ERR("Set of children is not equal");
754 return EINA_FALSE;
755 }
756
757 eina_list_free(T(pnode).children);
758 T(pnode).children = node_order;
759
760 return EINA_TRUE;
761}
762
763EOLIAN static void
764_efl_ui_focus_manager_unregister(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Object *child)
765{
766 Node *node;
767
768 node = eina_hash_find(pd->node_hash, &child);
769
770 if (!node) return;
771
772 F_DBG("Manager: %p unregister %p", obj, child);
773
774
775 //remove the object from the stack if it hasn't done that until now
776 //after this it's not at the top anymore
777 //elm_widget_focus_set(node->focusable, EINA_FALSE);
778 //delete again from the list, for the case it was not at the top
779 pd->focus_stack = eina_list_remove(pd->focus_stack, node);
780
781 //add all neighbors of the node to the dirty list
782 for(int i = 0; i < 4; i++)
783 {
784 Node *partner;
785 Eina_List *n;
786
787 EINA_LIST_FOREACH(node->graph.directions[i].partners, n, partner)
788 {
789 dirty_add(obj, pd, partner);
790 }
791 }
792
793 //remove from the dirty parts
794 pd->dirty = eina_list_remove(pd->dirty, node);
795
796 eina_hash_del_by_key(pd->node_hash, &child);
797}
798
799EOLIAN static void
800_efl_ui_focus_manager_redirect_set(Eo *obj, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Manager *redirect)
801{
802 Efl_Ui_Focus_Manager *old_manager;
803
804 if (pd->redirect == redirect) return;
805
806 F_DBG("Manager: %p setting redirect from %p to %p", obj, pd->redirect, redirect);
807
808 if (pd->redirect)
809 efl_wref_del(pd->redirect, &pd->redirect);
810
811 old_manager = pd->redirect;
812 pd->redirect = redirect;
813
814 if (pd->redirect)
815 efl_wref_add(pd->redirect, &pd->redirect);
816
817 efl_event_callback_call(obj, EFL_UI_FOCUS_MANAGER_EVENT_REDIRECT_CHANGED , old_manager);
818}
819
820EOLIAN static Efl_Ui_Focus_Manager *
821_efl_ui_focus_manager_redirect_get(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Data *pd)
822{
823 return pd->redirect;
824}
825
826static void
827_free_node(void *data)
828{
829 Node *node = data;
830 FOCUS_DATA(node->manager);
831
832 efl_event_callback_array_del(node->focusable, focusable_node(), node->manager);
833
834 if (pd->root != data)
835 {
836 node_item_free(node);
837 }
838}
839
840EOLIAN static Efl_Object *
841_efl_ui_focus_manager_efl_object_constructor(Eo *obj, Efl_Ui_Focus_Manager_Data *pd)
842{
843 pd->node_hash = eina_hash_pointer_new(_free_node);
844 return efl_constructor(efl_super(obj, MY_CLASS));
845}
846
847EOLIAN static Efl_Object *
848_efl_ui_focus_manager_efl_object_provider_find(Eo *obj, Efl_Ui_Focus_Manager_Data *pd EINA_UNUSED, const Efl_Object *klass)
849{
850 if (klass == MY_CLASS)
851 return obj;
852
853 return efl_provider_find(efl_super(obj, MY_CLASS), klass);
854}
855
856EOLIAN static void
857_efl_ui_focus_manager_efl_object_destructor(Eo *obj, Efl_Ui_Focus_Manager_Data *pd)
858{
859 eina_list_free(pd->focus_stack);
860 eina_list_free(pd->dirty);
861
862 eina_hash_free(pd->node_hash);
863
864 efl_ui_focus_manager_redirect_set(obj, NULL);
865
866 if (pd->root)
867 node_item_free(pd->root);
868 pd->root = NULL;
869
870 efl_destructor(efl_super(obj, MY_CLASS));
871}
872
873typedef struct {
874 Eina_Iterator iterator;
875 Eina_Iterator *real_iterator;
876 Efl_Ui_Focus_Manager *object;
877} Border_Elements_Iterator;
878
879static Eina_Bool
880_iterator_next(Border_Elements_Iterator *it, void **data)
881{
882 Node *node;
883
884 EINA_ITERATOR_FOREACH(it->real_iterator, node)
885 {
886 for(int i = 0 ;i < NODE_DIRECTIONS_COUNT; i++)
887 {
888 if (node->type != NODE_TYPE_ONLY_LOGICAL &&
889 !node->graph.directions[i].partners)
890 {
891 *data = node->focusable;
892 return EINA_TRUE;
893 }
894 }
895 }
896 return EINA_FALSE;
897}
898
899static Eo *
900_iterator_get_container(Border_Elements_Iterator *it)
901{
902 return it->object;
903}
904
905static void
906_iterator_free(Border_Elements_Iterator *it)
907{
908 eina_iterator_free(it->real_iterator);
909 free(it);
910}
911
912EOLIAN static Eina_Iterator*
913_efl_ui_focus_manager_border_elements_get(Eo *obj, Efl_Ui_Focus_Manager_Data *pd)
914{
915 Border_Elements_Iterator *it;
916
917 dirty_flush_all(obj, pd);
918
919 it = calloc(1, sizeof(Border_Elements_Iterator));
920
921 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
922
923 it->real_iterator = eina_hash_iterator_data_new(pd->node_hash);
924 it->iterator.version = EINA_ITERATOR_VERSION;
925 it->iterator.next = FUNC_ITERATOR_NEXT(_iterator_next);
926 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_iterator_get_container);
927 it->iterator.free = FUNC_ITERATOR_FREE(_iterator_free);
928 it->object = obj;
929
930 return (Eina_Iterator*) it;
931}
932
933static Node*
934_no_history_element(Eina_Hash *node_hash)
935{
936 //nothing is selected yet, just try to use the first element in the iterator
937 Eina_Iterator *iter;
938 Node *upper;
939
940 iter = eina_hash_iterator_data_new(node_hash);
941
942 EINA_ITERATOR_FOREACH(iter, upper)
943 {
944 if (upper->type == NODE_TYPE_NORMAL)
945 break;
946 }
947
948 eina_iterator_free(iter);
949
950 if (upper->type != NODE_TYPE_NORMAL)
951 return NULL;
952
953 return upper;
954}
955
956static void
957_get_middle(Evas_Object *obj, Eina_Vector2 *elem)
958{
959 Eina_Rectangle geom;
960
961 geom = efl_ui_focus_object_focus_geometry_get(obj);
962 elem->x = geom.x + geom.w/2;
963 elem->y = geom.y + geom.h/2;
964}
965
966static Node*
967_coords_movement(Efl_Ui_Focus_Manager_Data *pd, Node *upper, Efl_Ui_Focus_Direction direction)
968{
969 Node *candidate;
970 Eina_List *node_list;
971
972 //we are searching which of the partners is lower to the history
973 EINA_LIST_REVERSE_FOREACH(pd->focus_stack, node_list, candidate)
974 {
975 if (eina_list_data_find(G(upper).directions[direction].partners, candidate))
976 {
977 //this is the next accessable part
978 return candidate;
979 }
980 }
981
982 //if we haven't found anything in the history, use the widget with the smallest distance
983 {
984 Eina_List *lst = G(upper).directions[direction].partners;
985 Eina_List *n;
986 Node *node, *min = NULL;
987 Eina_Vector2 elem, other;
988 float min_distance = 0.0;
989
990
991 _get_middle(upper->focusable, &elem);
992
993 EINA_LIST_FOREACH(lst, n, node)
994 {
995 _get_middle(node->focusable, &other);
996 float tmp = eina_vector2_distance_get(&other, &elem);
997 if (!min || tmp < min_distance)
998 {
999 min = node;
1000 min_distance = tmp;
1001 }
1002 }
1003 candidate = min;
1004 }
1005 return candidate;
1006}
1007
1008
1009static Node*
1010_prev_item(Node *node)
1011{
1012 Node *parent;
1013 Eina_List *lnode;
1014
1015 parent = T(node).parent;
1016 lnode = eina_list_data_find_list(T(parent).children, node);
1017 lnode = eina_list_prev(lnode);
1018
1019 if (lnode)
1020 return eina_list_data_get(lnode);
1021 return NULL;
1022}
1023
1024static Node*
1025_next(Node *node)
1026{
1027 Node *n;
1028
1029 //Case 1 we are having children
1030 //But only enter the children if it does NOT have a redirect manager
1031 if (T(node).children && !node->redirect_manager)
1032 {
1033 return eina_list_data_get(T(node).children);
1034 }
1035
1036 //case 2 we are the root and we don't have children, return ourself
1037 if (!T(node).parent)
1038 {
1039 return node;
1040 }
1041
1042 //case 3 we are not at the end of the parents list
1043 n = node;
1044 while(T(n).parent)
1045 {
1046 Node *parent;
1047 Eina_List *lnode;
1048
1049 parent = T(n).parent;
1050 lnode = eina_list_data_find_list(T(parent).children, n);
1051 lnode = eina_list_next(lnode);
1052
1053 if (lnode)
1054 {
1055 return eina_list_data_get(lnode);
1056 }
1057
1058 n = parent;
1059 }
1060
1061 //this is then the root again
1062 return NULL;
1063}
1064
1065static Node*
1066_prev(Node *node)
1067{
1068 Node *n = NULL;
1069
1070 //this is the root there is no parent
1071 if (!T(node).parent)
1072 return NULL;
1073
1074 n =_prev_item(node);
1075 //case 1 there is a item in the parent previous to node, which has children
1076 if (n && T(n).children)
1077 {
1078 do
1079 {
1080 n = eina_list_last_data_get(T(n).children);
1081 }
1082 while (T(n).children);
1083
1084 return n;
1085 }
1086
1087 //case 2 there is a item in the parent previous to node, which has no children
1088 if (n)
1089 return n;
1090
1091 //case 3 there is a no item in the parent previous to this one
1092 return T(node).parent;
1093}
1094
1095
1096static Node*
1097_logical_movement(Efl_Ui_Focus_Manager_Data *pd EINA_UNUSED, Node *upper, Efl_Ui_Focus_Direction direction)
1098{
1099 Node* (*deliver)(Node *n);
1100 Node *result;
1101 Eina_List *stack = NULL;
1102
1103 if (direction == EFL_UI_FOCUS_DIRECTION_NEXT)
1104 deliver = _next;
1105 else
1106 deliver = _prev;
1107
1108 //search as long as we have a none logical parent
1109 result = upper;
1110 do
1111 {
1112 //give up, if we have already been here
1113 if (!!eina_list_data_find(stack, result))
1114 {
1115 eina_list_free(stack);
1116 ERR("Warning cycle detected\n");
1117 return NULL;
1118 }
1119
1120 stack = eina_list_append(stack, result);
1121 result = deliver(result);
1122 } while(result && result->type != NODE_TYPE_NORMAL && !result->redirect_manager);
1123
1124 eina_list_free(stack);
1125
1126 return result;
1127}
1128
1129static Efl_Ui_Focus_Object*
1130_request_move(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Direction direction, Node *upper)
1131{
1132 Node *dir = NULL;
1133
1134 if (!upper)
1135 upper = eina_list_last_data_get(pd->focus_stack);
1136
1137 if (!upper)
1138 {
1139 upper = _no_history_element(pd->node_hash);
1140 if (upper)
1141 return upper->focusable;
1142 return NULL;
1143
1144 }
1145
1146 dirty_flush(obj, pd, upper);
1147
1148 if (direction == EFL_UI_FOCUS_DIRECTION_PREV
1149 || direction == EFL_UI_FOCUS_DIRECTION_NEXT)
1150 dir = _logical_movement(pd, upper, direction);
1151 else
1152 dir = _coords_movement(pd, upper, direction);
1153
1154 //return the widget
1155 if (dir)
1156 return dir->focusable;
1157 else
1158 return NULL;
1159}
1160
1161EOLIAN static Efl_Ui_Focus_Object*
1162_efl_ui_focus_manager_request_move(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Direction direction)
1163{
1164 EINA_SAFETY_ON_FALSE_RETURN_VAL(DIRECTION_CHECK(direction), NULL);
1165
1166 if (pd->redirect)
1167 return efl_ui_focus_manager_request_move(pd->redirect, direction);
1168 else
1169 {
1170 Node *upper = NULL;
1171
1172 upper = eina_list_last_data_get(pd->focus_stack);
1173
1174 if (!upper)
1175 {
1176 upper = _no_history_element(pd->node_hash);
1177 if (upper)
1178 return upper->focusable;
1179 return NULL;
1180 }
1181
1182 return _request_move(obj, pd, direction, upper);
1183 }
1184}
1185
1186EOLIAN static void
1187_efl_ui_focus_manager_focus(Eo *obj, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Object *focus)
1188{
1189 Node *node;
1190 Node *old_focus;
1191 Efl_Ui_Focus_Manager *redirect_manager;
1192
1193 EINA_SAFETY_ON_NULL_RETURN(focus);
1194
1195 //if we want to focus the root then just spin to the first normal
1196 if (focus == pd->root->focusable)
1197 {
1198 Node *f = _logical_movement(pd, pd->root, EFL_UI_FOCUS_DIRECTION_NEXT);
1199
1200 if (f)
1201 focus = f->focusable;
1202
1203 if (!focus) return;
1204 }
1205
1206 //check if node is part of this manager object
1207 node = node_get(obj, pd, focus);
1208 if (!node) return;
1209
1210 F_DBG("Manager: %p focusing object %p %s", obj, focus, efl_class_name_get(focus));
1211
1212 if (node->type == NODE_TYPE_ONLY_LOGICAL && !node->redirect_manager && pd->root != node)
1213 {
1214 ERR(" %p is logical, cannot be focused", obj);
1215 return;
1216 }
1217
1218 if (pd->redirect)
1219 {
1220 //first unset the redirect
1221 efl_ui_focus_manager_redirect_set(obj, NULL);
1222 }
1223
1224 redirect_manager = node->redirect_manager;
1225
1226 if (node->type == NODE_TYPE_NORMAL)
1227 {
1228 Eo *focusable;
1229 //check if this is already the focused object
1230 old_focus = eina_list_last_data_get(pd->focus_stack);
1231
1232 //check if this is already at the top
1233 if (old_focus && old_focus->focusable == focus) return;
1234
1235 //remove the object from the list and add it again
1236 pd->focus_stack = eina_list_remove(pd->focus_stack, node);
1237 pd->focus_stack = eina_list_append(pd->focus_stack, node);
1238
1239 //save fields we later need
1240 focusable = node->focusable;
1241
1242 //populate the new change
1243 if (old_focus) efl_ui_focus_object_focus_set(old_focus->focusable, EINA_FALSE);
1244 efl_ui_focus_object_focus_set(node->focusable, EINA_TRUE);
1245 efl_event_callback_call(obj, EFL_UI_FOCUS_MANAGER_EVENT_FOCUSED, focusable);
1246 node = NULL;
1247 }
1248 else if (node->redirect_manager)
1249 {
1250 Efl_Ui_Focus_Object *root;
1251
1252 root = efl_ui_focus_manager_root_get(node->redirect_manager);
1253 efl_ui_focus_manager_focus(node->redirect_manager, root);
1254 }
1255
1256 //now check if this is also a listener object
1257 if (redirect_manager)
1258 {
1259 efl_ui_focus_manager_redirect_set(obj, redirect_manager);
1260 }
1261}
1262
1263EOLIAN static Efl_Ui_Focus_Object*
1264_efl_ui_focus_manager_move(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Direction direction)
1265{
1266 Efl_Ui_Focus_Object *candidate = NULL;
1267
1268 EINA_SAFETY_ON_FALSE_RETURN_VAL(DIRECTION_CHECK(direction), NULL);
1269
1270 if (pd->redirect)
1271 {
1272 Efl_Ui_Focus_Object *old_candidate = NULL;
1273 candidate = efl_ui_focus_manager_move(pd->redirect, direction);
1274 old_candidate = efl_ui_focus_manager_focused(pd->redirect);
1275
1276 if (!candidate)
1277 {
1278 Efl_Ui_Focus_Object *new_candidate = NULL;
1279 Node *n;
1280
1281 //there is no candidate check if we have something for that direction
1282 new_candidate = NULL;
1283 n = eina_hash_find(pd->node_hash, &old_candidate);
1284
1285 if (direction == EFL_UI_FOCUS_DIRECTION_NEXT ||
1286 direction == EFL_UI_FOCUS_DIRECTION_PREV)
1287 {
1288 if (n)
1289 {
1290 n = T(n).parent;
1291 new_candidate = _request_move(obj, pd, direction, n);
1292 efl_ui_focus_manager_focus(obj, new_candidate);
1293 candidate = new_candidate;
1294 }
1295 }
1296 else
1297 {
1298
1299 if (n)
1300 new_candidate = _request_move(obj, pd, direction, n);
1301
1302 if (new_candidate)
1303 {
1304 //redirect does not have smth. but we do have.
1305 efl_ui_focus_manager_focus(obj, new_candidate);
1306 }
1307 candidate = new_candidate;
1308 }
1309
1310 }
1311 }
1312 else
1313 {
1314 candidate = efl_ui_focus_manager_request_move(obj, direction);
1315
1316 if (candidate)
1317 efl_ui_focus_manager_focus(obj, candidate);
1318 }
1319
1320 F_DBG("Manager: %p moved to %p %s in direction %d", obj, candidate, efl_class_name_get(candidate), direction);
1321
1322 return candidate;
1323}
1324
1325EOLIAN static Eina_Bool
1326_efl_ui_focus_manager_root_set(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Object *root)
1327{
1328 Node *node;
1329
1330 if (pd->root)
1331 {
1332 ERR("Root element can only be set once!");
1333 return EINA_FALSE;
1334 }
1335
1336 node = _register(obj, pd, root, NULL);
1337 node->type = NODE_TYPE_ONLY_LOGICAL;
1338
1339 pd->root = node;
1340
1341 return EINA_TRUE;
1342}
1343
1344EOLIAN static Efl_Ui_Focus_Object*
1345_efl_ui_focus_manager_root_get(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Data *pd)
1346{
1347 if (!pd->root) return NULL;
1348
1349 return pd->root->focusable;
1350}
1351
1352EOLIAN static Efl_Object*
1353_efl_ui_focus_manager_efl_object_finalize(Eo *obj, Efl_Ui_Focus_Manager_Data *pd)
1354{
1355 Efl_Object *result;
1356
1357 if (!pd->root)
1358 {
1359 ERR("Constructing failed. No root element set.");
1360 return NULL;
1361 }
1362
1363 result = efl_finalize(efl_super(obj, MY_CLASS));
1364
1365 return result;
1366}
1367
1368static Eina_List*
1369_convert(Eina_List *node_list)
1370{
1371 Eina_List *n, *par = NULL;
1372 Node *node;
1373
1374 EINA_LIST_FOREACH(node_list, n, node)
1375 par = eina_list_append(par, node->focusable);
1376
1377 return par;
1378}
1379
1380EOLIAN static Efl_Ui_Focus_Object*
1381_efl_ui_focus_manager_focused(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Data *pd)
1382{
1383 Node *upper = NULL;
1384
1385 upper = eina_list_last_data_get(pd->focus_stack);
1386
1387 if (!upper)
1388 return NULL;
1389 return upper->focusable;
1390}
1391
1392EOLIAN static Efl_Ui_Focus_Relations*
1393_efl_ui_focus_manager_fetch(Eo *obj, Efl_Ui_Focus_Manager_Data *pd, Efl_Ui_Focus_Object *child)
1394{
1395 Efl_Ui_Focus_Relations *res;
1396 Node *n, *tmp;
1397
1398 n = node_get(obj, pd, child);
1399 if (!n)
1400 return NULL;
1401
1402 res = calloc(1, sizeof(Efl_Ui_Focus_Relations));
1403
1404 dirty_flush(obj, pd, n);
1405
1406#define DIR_CLONE(dir) _convert(G(n).directions[dir].partners);
1407
1408 res->right = DIR_CLONE(EFL_UI_FOCUS_DIRECTION_RIGHT);
1409 res->left = DIR_CLONE(EFL_UI_FOCUS_DIRECTION_LEFT);
1410 res->top = DIR_CLONE(EFL_UI_FOCUS_DIRECTION_UP);
1411 res->down = DIR_CLONE(EFL_UI_FOCUS_DIRECTION_DOWN);
1412 res->next = (tmp = _next(n)) ? tmp->focusable : NULL;
1413 res->prev = (tmp = _prev(n)) ? tmp->focusable : NULL;
1414 switch(n->type)
1415 {
1416 case NODE_TYPE_ONLY_LOGICAL:
1417 res->type = "logical";
1418 break;
1419 case NODE_TYPE_NORMAL:
1420 res->type = "normal";
1421 break;
1422 }
1423 res->parent = T(n).parent->focusable;
1424 res->redirect = n->redirect_manager;
1425#undef DIR_CLONE
1426
1427 return res;
1428}
1429
1430EOLIAN static void
1431_efl_ui_focus_manager_class_constructor(Efl_Class *c EINA_UNUSED)
1432{
1433 _focus_log_domain = eina_log_domain_register("elementary-focus", EINA_COLOR_CYAN);
1434}
1435
1436EOLIAN static void
1437_efl_ui_focus_manager_class_destructor(Efl_Class *c EINA_UNUSED)
1438{
1439 eina_log_domain_unregister(_focus_log_domain);
1440 _focus_log_domain = -1;
1441}
1442
1443EOLIAN static Efl_Ui_Focus_Object*
1444_efl_ui_focus_manager_logical_end(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Data *pd)
1445{
1446 Node *child = pd->root;
1447
1448 EINA_SAFETY_ON_NULL_RETURN_VAL(child, NULL);
1449
1450 //we need to return the most lower right element
1451
1452 while(T(child).children)
1453 child = eina_list_last_data_get(T(child).children);
1454 while (child->type != NODE_TYPE_NORMAL)
1455 child = _prev(child);
1456
1457 return child ? child->focusable : NULL;
1458}
1459
1460#include "efl_ui_focus_manager.eo.c" 8#include "efl_ui_focus_manager.eo.c"
diff --git a/src/lib/elementary/efl_ui_focus_manager.eo b/src/lib/elementary/efl_ui_focus_manager.eo
index 16a939a852..3491f2096f 100644
--- a/src/lib/elementary/efl_ui_focus_manager.eo
+++ b/src/lib/elementary/efl_ui_focus_manager.eo
@@ -29,7 +29,7 @@ struct Efl.Ui.Focus.Relations {
29 redirect : Efl.Ui.Focus.Manager; [[Redirect manager]] 29 redirect : Efl.Ui.Focus.Manager; [[Redirect manager]]
30} 30}
31 31
32class Efl.Ui.Focus.Manager (Efl.Object) { 32interface Efl.Ui.Focus.Manager {
33 [[Calculates the directions of Efl.Ui.Focus.Direction 33 [[Calculates the directions of Efl.Ui.Focus.Direction
34 34
35 Each registered item will get a other registered object into each 35 Each registered item will get a other registered object into each
@@ -59,84 +59,6 @@ class Efl.Ui.Focus.Manager (Efl.Object) {
59 } 59 }
60 return : Efl.Ui.Focus.Object; [[Next object to focus]] 60 return : Efl.Ui.Focus.Object; [[Next object to focus]]
61 } 61 }
62 register {
63 [[Register a new item in the graph.
64
65 $parent can not be $null, it will be used as the parent in the
66 logical tree.
67 $redirect will be set as redirect property on that manager, once
68 $child gets focused.
69 ]]
70 params {
71 child : Efl.Ui.Focus.Object @nonull; [[The object to register]]
72 parent : Efl.Ui.Focus.Object @nonull; [[The parent to use in
73 the logical tree]]
74 redirect : Efl.Ui.Focus.Manager; [[The redirect manager to set
75 once this child is focused can be NULL for no redirect]]
76 }
77 return : bool; [[$true if successful, $false otherwise]]
78 }
79 register_logical {
80 [[Register a new item just for the logical parent.
81
82 The item can never get focus, it just helps to build a tree out
83 of the items that are getting focus.
84 ]]
85 params {
86 child : Efl.Ui.Focus.Object @nonull; [[The object to register]]
87 parent : Efl.Ui.Focus.Object @nonull; [[The parent to use in
88 the logical tree]]
89 redirect : Efl.Ui.Focus.Manager; [[The redirect manager to set
90 once this child is focused can be $null for no redirect]]
91 }
92 return : bool; [[$true if successful, $false otherwise]]
93 }
94 update_redirect {
95 [[Set a new redirect object for the given child.
96
97 Once $child is focused the redirect manager will be set
98 in the redirect property. Set redirect to $null if nothing should happen.
99 ]]
100 params {
101 child : Efl.Ui.Focus.Object @nonull; [[The child to update]]
102 redirect : Efl.Ui.Focus.Manager; [[Once $child got focused this
103 element will be set as redirect]]
104 }
105 return : bool; [[$true if successful, $false otherwise]]
106 }
107 update_parent {
108 [[Set a new logical parent for the given child.]]
109 params {
110 child : Efl.Ui.Focus.Object @nonull; [[The child to update]]
111 parent : Efl.Ui.Focus.Object @nonull; [[The parent which now
112 will be the logical parent of child]]
113 }
114 return : bool; [[$true if successful, $false otherwise]]
115 }
116 update_children {
117 [[Give the list of children a different order.]]
118 params {
119 parent : Efl.Ui.Focus.Object @nonull; [[the parent to update]]
120 children : own(list<Efl.Ui.Focus.Object>); [[the list with the new order]]
121 }
122 return : bool; [[$true if successful, $false otherwise]]
123 }
124 update_order {
125 [[Give the given order to the parent's child.
126
127 Children from the list which are no real children are ignored.
128 ]]
129 params {
130 parent : Efl.Ui.Focus.Object @nonull; [[the parent to update]]
131 children : list<Efl.Ui.Focus.Object>; [[the order of items]]
132 }
133 }
134 unregister {
135 [[Unregister the given item from the focus graph.]]
136 params {
137 child : Efl.Ui.Focus.Object; [[The child to unregister.]]
138 }
139 }
140 focus { 62 focus {
141 [[Make the given object the currently focused object in this manager. 63 [[Make the given object the currently focused object in this manager.
142 64
@@ -212,14 +134,6 @@ class Efl.Ui.Focus.Manager (Efl.Object) {
212 return : Efl.Ui.Focus.Object; [[Last object]] 134 return : Efl.Ui.Focus.Object; [[Last object]]
213 } 135 }
214 } 136 }
215 implements {
216 class.constructor;
217 class.destructor;
218 Efl.Object.constructor;
219 Efl.Object.finalize;
220 Efl.Object.provider_find;
221 Efl.Object.destructor;
222 }
223 events { 137 events {
224 redirect,changed : Efl.Ui.Focus.Manager; [[Emitted when the redirect 138 redirect,changed : Efl.Ui.Focus.Manager; [[Emitted when the redirect
225 object has changed, the old manager is passed as event info]] 139 object has changed, the old manager is passed as event info]]
diff --git a/src/lib/elementary/efl_ui_focus_manager_calc.c b/src/lib/elementary/efl_ui_focus_manager_calc.c
new file mode 100644
index 0000000000..b8c2294629
--- /dev/null
+++ b/src/lib/elementary/efl_ui_focus_manager_calc.c
@@ -0,0 +1,1459 @@
1#ifdef HAVE_CONFIG_H
2# include "elementary_config.h"
3#endif
4
5#include <Elementary.h>
6#include "elm_priv.h"
7
8#define MY_CLASS EFL_UI_FOCUS_MANAGER_CALC_CLASS
9#define FOCUS_DATA(obj) Efl_Ui_Focus_Manager_Calc_Data *pd = efl_data_scope_get(obj, MY_CLASS);
10
11#define DIM_EFL_UI_FOCUS_DIRECTION(dim,neg) dim*2+neg
12#define NODE_DIRECTIONS_COUNT 4
13
14#define DIRECTION_CHECK(dir) (dir >= 0 && dir < EFL_UI_FOCUS_DIRECTION_LAST)
15
16//#define CALC_DEBUG
17#define DEBUG_TUPLE(obj) efl_name_get(obj), efl_class_name_get(obj)
18
19static int _focus_log_domain = -1;
20
21#define F_CRI(...) EINA_LOG_DOM_CRIT(_focus_log_domain, __VA_ARGS__)
22#define F_ERR(...) EINA_LOG_DOM_ERR(_focus_log_domain, __VA_ARGS__)
23#define F_WRN(...) EINA_LOG_DOM_WARN(_focus_log_domain, __VA_ARGS__)
24#define F_INF(...) EINA_LOG_DOM_INFO(_focus_log_domain, __VA_ARGS__)
25#define F_DBG(...) EINA_LOG_DOM_DBG(_focus_log_domain, __VA_ARGS__)
26
27typedef struct {
28 Eina_Bool positive;
29 Efl_Ui_Focus_Object *anchor;
30} Anchor;
31
32typedef enum {
33 DIMENSION_X = 0,
34 DIMENSION_Y = 1,
35} Dimension;
36
37typedef struct _Border Border;
38typedef struct _Node Node;
39
40struct _Border {
41 Eina_List *partners;
42};
43
44typedef enum {
45 NODE_TYPE_NORMAL = 0,
46 NODE_TYPE_ONLY_LOGICAL = 2,
47} Node_Type;
48
49struct _Node{
50 Node_Type type; //type of the node
51
52 Efl_Ui_Focus_Object *focusable;
53 Efl_Ui_Focus_Manager *manager;
54 Efl_Ui_Focus_Manager *redirect_manager;
55
56 struct _Tree_Node{
57 Node *parent; //the parent of the tree
58 Eina_List *children; //this saves the original set of elements
59 Eina_List *safed_order;
60 }tree;
61
62 struct _Graph_Node {
63 Border directions[NODE_DIRECTIONS_COUNT];
64 } graph;
65};
66
67#define T(n) (n->tree)
68#define G(n) (n->graph)
69
70typedef struct {
71 Eina_List *focus_stack;
72 Eina_Hash *node_hash;
73 Efl_Ui_Focus_Manager *redirect;
74 Eina_List *dirty;
75
76 Node *root;
77} Efl_Ui_Focus_Manager_Calc_Data;
78
79static Efl_Ui_Focus_Direction
80_complement(Efl_Ui_Focus_Direction dir)
81{
82 #define COMP(a,b) \
83 if (dir == a) return b; \
84 if (dir == b) return a;
85
86 COMP(EFL_UI_FOCUS_DIRECTION_RIGHT, EFL_UI_FOCUS_DIRECTION_LEFT)
87 COMP(EFL_UI_FOCUS_DIRECTION_UP, EFL_UI_FOCUS_DIRECTION_DOWN)
88 COMP(EFL_UI_FOCUS_DIRECTION_PREV, EFL_UI_FOCUS_DIRECTION_NEXT)
89
90 #undef COMP
91
92 return EFL_UI_FOCUS_DIRECTION_LAST;
93}
94
95/*
96 * Set this new list of partners to the border.
97 * All old partners will be deleted
98 */
99static void
100border_partners_set(Node *node, Efl_Ui_Focus_Direction direction, Eina_List *list)
101{
102 Node *partner;
103 Eina_List *lnode;
104 Border *border = &G(node).directions[direction];
105
106 EINA_LIST_FREE(border->partners, partner)
107 {
108 Border *comp_border = &G(partner).directions[_complement(direction)];
109
110 comp_border->partners = eina_list_remove(comp_border->partners, node);
111 }
112
113 border->partners = list;
114
115 EINA_LIST_FOREACH(border->partners, lnode, partner)
116 {
117 Border *comp_border = &G(partner).directions[_complement(direction)];
118
119 comp_border->partners = eina_list_append(comp_border->partners, node);
120 }
121}
122
123/**
124 * Create a new node
125 */
126static Node*
127node_new(Efl_Ui_Focus_Object *focusable, Efl_Ui_Focus_Manager *manager)
128{
129 Node *node;
130
131 node = calloc(1, sizeof(Node));
132
133 node->focusable = focusable;
134 node->manager = manager;
135
136 return node;
137}
138
139/**
140 * Looks up given focus object from the focus manager.
141 *
142 * @returns node found, or NULL if focusable was not found in the manager.
143 */
144static Node*
145node_get(Efl_Ui_Focus_Manager *obj, Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Object *focusable)
146{
147 Node *ret;
148
149 ret = eina_hash_find(pd->node_hash, &focusable);
150
151 if (ret) return ret;
152
153 ERR("Focusable %p (%s) not registered in manager %p", focusable, efl_class_name_get(focusable), obj);
154
155 return NULL;
156}
157
158/**
159 * Free a node item and unlink this item from all direction
160 */
161static void
162node_item_free(Node *item)
163{
164 Node *n;
165 Eina_List *l;
166 //free the graph items
167 for(int i = 0;i < NODE_DIRECTIONS_COUNT; i++)
168 {
169 border_partners_set(item, i, NULL);
170 }
171
172 //free the tree items
173 if (!item->tree.parent && item->tree.children)
174 {
175 ERR("Freeing the root with children is going to break the logical tree!");
176 }
177
178 if (item->tree.parent && item->tree.children)
179 {
180 Node *parent;
181
182 parent = item->tree.parent;
183 //reparent everything into the next layer
184 EINA_LIST_FOREACH(item->tree.children, l, n)
185 {
186 n->tree.parent = item->tree.parent;
187 }
188 parent->tree.children = eina_list_merge(parent->tree.children , item->tree.children);
189 }
190
191 if (item->tree.parent)
192 {
193 Node *parent;
194
195 parent = item->tree.parent;
196 T(parent).children = eina_list_remove(T(parent).children, item);
197 }
198
199 //free the safed order
200 ELM_SAFE_FREE(T(item).safed_order, eina_list_free);
201
202 free(item);
203}
204
205
206//CALCULATING STUFF
207
208static inline int
209_distance(Eina_Rectangle node, Eina_Rectangle op, Dimension dim)
210{
211 int min, max, point;
212 int v1, v2;
213
214 if (dim == DIMENSION_X)
215 {
216 min = op.x;
217 max = eina_rectangle_max_x(&op);
218 point = node.x + node.w/2;
219 }
220 else
221 {
222 min = op.y;
223 max = eina_rectangle_max_y(&op);
224 point = node.y + node.h/2;
225 }
226
227 v1 = min - point;
228 v2 = max - point;
229
230 if (abs(v1) < abs(v2))
231 return v1;
232 else
233 return v2;
234}
235
236static inline void
237_calculate_node(Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Object *node, Dimension dim, Eina_List **pos, Eina_List **neg)
238{
239 Eina_Rectangle rect = EINA_RECTANGLE_INIT;
240 Efl_Ui_Focus_Object *op;
241 int dim_min, dim_max;
242 Eina_Iterator *nodes;
243 int cur_pos_min = 0, cur_neg_min = 0;
244 Node *n;
245
246 nodes = eina_hash_iterator_data_new(pd->node_hash);
247 rect = efl_ui_focus_object_focus_geometry_get(node);
248
249 *pos = NULL;
250 *neg = NULL;
251
252 if (dim == DIMENSION_X)
253 {
254 dim_min = rect.y;
255 dim_max = rect.y + rect.h;
256 }
257 else
258 {
259 dim_min = rect.x;
260 dim_max = rect.x + rect.w;
261 }
262
263 EINA_ITERATOR_FOREACH(nodes, n)
264 {
265 Eina_Rectangle op_rect = EINA_RECTANGLE_INIT;
266 int min, max;
267
268 op = n->focusable;
269 if (op == node) continue;
270
271 if (n->type == NODE_TYPE_ONLY_LOGICAL) continue;
272
273 op_rect = efl_ui_focus_object_focus_geometry_get(op);
274
275 if (dim == DIMENSION_X)
276 {
277 min = op_rect.y;
278 max = eina_rectangle_max_y(&op_rect);
279 }
280 else
281 {
282 min = op_rect.x;
283 max = eina_rectangle_max_x(&op_rect);
284 }
285
286
287 /* The only way the calculation does make sense is if the two number
288 * lines are not disconnected.
289 * If they are connected one point of the 4 lies between the min and max of the other line
290 */
291 if (!((min <= max && max <= dim_min && dim_min <= dim_max) ||
292 (dim_min <= dim_max && dim_max <= min && min <= max)) &&
293 !eina_rectangle_intersection(&op_rect, &rect))
294 {
295 //this thing hits horizontal
296 int tmp_dis;
297
298 tmp_dis = _distance(rect, op_rect, dim);
299
300 if (tmp_dis < 0)
301 {
302 if (tmp_dis == cur_neg_min)
303 {
304 //add it
305 *neg = eina_list_append(*neg, op);
306 }
307 else if (tmp_dis > cur_neg_min
308 || cur_neg_min == 0) //init case
309 {
310 //nuke the old and add
311#ifdef CALC_DEBUG
312 printf("CORRECTION FOR %s-%s\n found anchor %s-%s in distance %d\n (%d,%d,%d,%d)\n (%d,%d,%d,%d)\n\n", DEBUG_TUPLE(node), DEBUG_TUPLE(op),
313 tmp_dis,
314 op_rect.x, op_rect.y, op_rect.w, op_rect.h,
315 rect.x, rect.y, rect.w, rect.h);
316#endif
317 *neg = eina_list_free(*neg);
318 *neg = eina_list_append(NULL, op);
319 cur_neg_min = tmp_dis;
320 }
321 }
322 else
323 {
324 if (tmp_dis == cur_pos_min)
325 {
326 //add it
327 *pos = eina_list_append(*pos, op);
328 }
329 else if (tmp_dis < cur_pos_min
330 || cur_pos_min == 0) //init case
331 {
332 //nuke the old and add
333#ifdef CALC_DEBUG
334 printf("CORRECTION FOR %s-%s\n found anchor %s-%s in distance %d\n (%d,%d,%d,%d)\n (%d,%d,%d,%d)\n\n", DEBUG_TUPLE(node), DEBUG_TUPLE(op),
335 tmp_dis,
336 op_rect.x, op_rect.y, op_rect.w, op_rect.h,
337 rect.x, rect.y, rect.w, rect.h);
338#endif
339 *pos = eina_list_free(*pos);
340 *pos = eina_list_append(NULL, op);
341 cur_pos_min = tmp_dis;
342 }
343 }
344
345
346#if 0
347 printf("(%d,%d,%d,%d)%s vs(%d,%d,%d,%d)%s\n", rect.x, rect.y, rect.w, rect.h, elm_widget_part_text_get(node, NULL), op_rect.x, op_rect.y, op_rect.w, op_rect.h, elm_widget_part_text_get(op, NULL));
348 printf("(%d,%d,%d,%d)\n", min, max, dim_min, dim_max);
349 printf("Candidate %d\n", tmp_dis);
350 if (anchor->anchor == NULL || abs(tmp_dis) < abs(distance)) //init case
351 {
352 distance = tmp_dis;
353 anchor->positive = tmp_dis > 0 ? EINA_FALSE : EINA_TRUE;
354 anchor->anchor = op;
355 //Helper for debugging wrong calculations
356
357 }
358#endif
359 }
360
361 }
362 eina_iterator_free(nodes);
363 nodes = NULL;
364}
365
366#ifdef CALC_DEBUG
367static void
368_debug_node(Node *node)
369{
370 Eina_List *tmp = NULL;
371
372 if (!node) return;
373
374 printf("NODE %s-%s\n", DEBUG_TUPLE(node->focusable));
375
376#define DIR_LIST(dir) G(node).directions[dir].partners
377
378#define DIR_OUT(dir)\
379 tmp = DIR_LIST(dir); \
380 { \
381 Eina_List *list_node; \
382 Node *partner; \
383 printf("-"#dir"-> ("); \
384 EINA_LIST_FOREACH(tmp, list_node, partner) \
385 printf("%s-%s,", DEBUG_TUPLE(partner->focusable)); \
386 printf(")\n"); \
387 }
388
389 DIR_OUT(EFL_UI_FOCUS_DIRECTION_RIGHT)
390 DIR_OUT(EFL_UI_FOCUS_DIRECTION_LEFT)
391 DIR_OUT(EFL_UI_FOCUS_DIRECTION_UP)
392 DIR_OUT(EFL_UI_FOCUS_DIRECTION_DOWN)
393
394}
395#endif
396
397static void
398convert_border_set(Efl_Ui_Focus_Manager *obj, Efl_Ui_Focus_Manager_Calc_Data *pd, Node *node, Eina_List *focusable_list, Efl_Ui_Focus_Direction dir)
399{
400 Eina_List *partners = NULL;
401 Efl_Ui_Focus_Object *fobj;
402
403 EINA_LIST_FREE(focusable_list, fobj)
404 {
405 Node *entry;
406
407 entry = node_get(obj, pd, fobj);
408 if (!entry)
409 {
410 CRI("Found a obj in graph without node-entry!");
411 return;
412 }
413 partners = eina_list_append(partners, entry);
414 }
415
416 border_partners_set(node, dir, partners);
417}
418
419static void
420dirty_flush_node(Efl_Ui_Focus_Manager *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Calc_Data *pd, Node *node)
421{
422 Eina_List *x_partners_pos, *x_partners_neg;
423 Eina_List *y_partners_pos, *y_partners_neg;
424
425 _calculate_node(pd, node->focusable, DIMENSION_X, &x_partners_pos, &x_partners_neg);
426 _calculate_node(pd, node->focusable, DIMENSION_Y, &y_partners_pos, &y_partners_neg);
427
428 convert_border_set(obj, pd, node, x_partners_pos, EFL_UI_FOCUS_DIRECTION_RIGHT);
429 convert_border_set(obj, pd, node, x_partners_neg, EFL_UI_FOCUS_DIRECTION_LEFT);
430 convert_border_set(obj, pd, node, y_partners_neg, EFL_UI_FOCUS_DIRECTION_UP);
431 convert_border_set(obj, pd, node, y_partners_pos, EFL_UI_FOCUS_DIRECTION_DOWN);
432
433#ifdef CALC_DEBUG
434 _debug_node(node);
435#endif
436}
437
438static void
439dirty_flush(Efl_Ui_Focus_Manager *obj, Efl_Ui_Focus_Manager_Calc_Data *pd, Node *node)
440{
441 if (!eina_list_data_find(pd->dirty, node)) return;
442
443 efl_event_callback_call(obj, EFL_UI_FOCUS_MANAGER_EVENT_FLUSH_PRE, NULL);
444
445 pd->dirty = eina_list_remove(pd->dirty, node);
446
447 dirty_flush_node(obj, pd, node);
448}
449
450static void
451dirty_flush_all(Efl_Ui_Focus_Manager *obj, Efl_Ui_Focus_Manager_Calc_Data *pd)
452{
453 Node *node;
454
455 efl_event_callback_call(obj, EFL_UI_FOCUS_MANAGER_EVENT_FLUSH_PRE, NULL);
456
457 EINA_LIST_FREE(pd->dirty, node)
458 {
459 dirty_flush_node(obj, pd, node);
460 }
461}
462
463static void
464dirty_add(Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd, Node *dirty)
465{
466 if (dirty->type == NODE_TYPE_ONLY_LOGICAL)
467 {
468 ERR("Only not only logical nodes can be marked dirty");
469 return;
470 }
471
472 //if (eina_list_data_find(pd->dirty, dirty)) return;
473 pd->dirty = eina_list_remove(pd->dirty, dirty);
474 pd->dirty = eina_list_append(pd->dirty, dirty);
475
476 efl_event_callback_call(obj, EFL_UI_FOCUS_MANAGER_EVENT_COORDS_DIRTY, NULL);
477}
478
479
480static void
481_node_new_geometery_cb(void *data, const Efl_Event *event)
482{
483 Node *node;
484 FOCUS_DATA(data)
485
486 node = node_get(data, pd, event->object);
487 if (!node)
488 return;
489
490 dirty_add(data, pd, node);
491
492 return;
493}
494
495EFL_CALLBACKS_ARRAY_DEFINE(focusable_node,
496 {EFL_GFX_EVENT_RESIZE, _node_new_geometery_cb},
497 {EFL_GFX_EVENT_MOVE, _node_new_geometery_cb},
498);
499
500//=============================
501
502static Node*
503_register(Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Object *child, Node *parent)
504{
505 Node *node;
506 if (!!eina_hash_find(pd->node_hash, &child))
507 {
508 ERR("Child %p is already registered in the graph", child);
509 return NULL;
510 }
511
512 node = node_new(child, obj);
513 eina_hash_add(pd->node_hash, &child, node);
514
515 //add the parent
516 if (parent)
517 {
518 T(node).parent = parent;
519 T(parent).children = eina_list_append(T(parent).children, node);
520 }
521
522 return node;
523}
524EOLIAN static Eina_Bool
525_efl_ui_focus_manager_calc_register_logical(Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Object *child, Efl_Ui_Focus_Object *parent, Efl_Ui_Focus_Manager *redirect)
526{
527 Node *node = NULL;
528 Node *pnode = NULL;
529
530 EINA_SAFETY_ON_NULL_RETURN_VAL(child, EINA_FALSE);
531 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, EINA_FALSE);
532
533 if (redirect)
534 EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(redirect, MY_CLASS), EINA_FALSE);
535
536 F_DBG("Manager: %p register %p %p %p", obj, child, parent, redirect);
537
538 pnode = node_get(obj, pd, parent);
539 if (!pnode) return EINA_FALSE;
540
541 node = _register(obj, pd, child, pnode);
542 if (!node) return EINA_FALSE;
543
544 node->type = NODE_TYPE_ONLY_LOGICAL;
545 node->redirect_manager = redirect;
546
547 //set again
548 if (T(pnode).safed_order)
549 {
550 Eina_List *tmp;
551
552 tmp = eina_list_clone(T(pnode).safed_order);
553 efl_ui_focus_manager_calc_update_order(obj, parent, tmp);
554 }
555
556 return EINA_TRUE;
557}
558
559
560EOLIAN static Eina_Bool
561_efl_ui_focus_manager_calc_register(Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Object *child, Efl_Ui_Focus_Object *parent, Efl_Ui_Focus_Manager *redirect)
562{
563 Node *node = NULL;
564 Node *pnode = NULL;
565
566 EINA_SAFETY_ON_NULL_RETURN_VAL(child, EINA_FALSE);
567 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, EINA_FALSE);
568
569 if (redirect)
570 EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(redirect, MY_CLASS), EINA_FALSE);
571
572 F_DBG("Manager: %p register %p %p %p", obj, child, parent, redirect);
573
574 pnode = node_get(obj, pd, parent);
575 if (!pnode) return EINA_FALSE;
576
577 node = _register(obj, pd, child, pnode);
578 if (!node) return EINA_FALSE;
579
580 //listen to changes
581 efl_event_callback_array_add(child, focusable_node(), obj);
582
583 node->type = NODE_TYPE_NORMAL;
584 node->redirect_manager = redirect;
585
586 //mark dirty
587 dirty_add(obj, pd, node);
588
589 //set again
590 if (T(pnode).safed_order)
591 {
592 Eina_List *tmp;
593
594 tmp = eina_list_clone(T(pnode).safed_order);
595 efl_ui_focus_manager_calc_update_order(obj, parent, tmp);
596 }
597
598 return EINA_TRUE;
599}
600
601EOLIAN static Eina_Bool
602_efl_ui_focus_manager_calc_update_redirect(Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Object *child, Efl_Ui_Focus_Manager *redirect)
603{
604 Node *node = node_get(obj, pd, child);
605 if (!node) return EINA_FALSE;
606
607 if (redirect)
608 EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(redirect, MY_CLASS), EINA_FALSE);
609
610 node->redirect_manager = redirect;
611
612 return EINA_TRUE;
613}
614
615EOLIAN static Eina_Bool
616_efl_ui_focus_manager_calc_update_parent(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Object *child, Efl_Ui_Focus_Object *parent_obj)
617{
618 Node *node;
619 Node *parent;
620
621 EINA_SAFETY_ON_NULL_RETURN_VAL(parent_obj, EINA_FALSE);
622 EINA_SAFETY_ON_NULL_RETURN_VAL(child, EINA_FALSE);
623
624 node = node_get(obj, pd, child);
625 parent = node_get(obj, pd, parent_obj);
626
627 if (!node || !parent) return EINA_FALSE;
628
629 if (T(node).parent)
630 {
631 Node *old_parent;
632
633 old_parent = T(node).parent;
634
635 T(old_parent).children = eina_list_remove(T(old_parent).children, node);
636 }
637
638 T(node).parent = parent;
639
640 if (T(node).parent)
641 {
642 T(parent).children = eina_list_append(T(parent).children, node);
643 }
644
645 return EINA_TRUE;
646}
647
648static Eina_List*
649_set_a_without_b(Eina_List *a, Eina_List *b)
650{
651 Eina_List *a_out = NULL, *node;
652 void *data;
653
654 a_out = eina_list_clone(a);
655
656 EINA_LIST_FOREACH(b, node, data)
657 {
658 a_out = eina_list_remove(a_out, data);
659 }
660
661 return a_out;
662}
663
664static Eina_Bool
665_equal_set(Eina_List *none_nodes, Eina_List *nodes)
666{
667 Eina_List *n;
668 Node *node;
669
670 if (eina_list_count(nodes) != eina_list_count(none_nodes)) return EINA_FALSE;
671
672 EINA_LIST_FOREACH(nodes, n, node)
673 {
674 if (!eina_list_data_find(none_nodes, node))
675 return EINA_FALSE;
676 }
677
678 return EINA_TRUE;
679}
680
681EOLIAN static void
682_efl_ui_focus_manager_calc_update_order(Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Object *parent, Eina_List *order)
683{
684 Node *pnode;
685 Efl_Ui_Focus_Object *o;
686 Eina_List *node_order = NULL, *not_ordered, *trash, *node_order_clean, *n;
687
688 F_DBG("Manager_update_order on %p %p", obj, parent);
689
690 pnode = node_get(obj, pd, parent);
691 if (!pnode)
692 return;
693
694 ELM_SAFE_FREE(T(pnode).safed_order, eina_list_free);
695 T(pnode).safed_order = order;
696
697 //get all nodes from the subset
698 EINA_LIST_FOREACH(order, n, o)
699 {
700 Node *tmp;
701
702 tmp = eina_hash_find(pd->node_hash, &o);
703
704 if (!tmp) continue;
705
706 node_order = eina_list_append(node_order, tmp);
707 }
708
709 not_ordered = _set_a_without_b(T(pnode).children, node_order);
710 trash = _set_a_without_b(node_order, T(pnode).children);
711 node_order_clean = _set_a_without_b(node_order, trash);
712
713 eina_list_free(node_order);
714 eina_list_free(trash);
715
716 eina_list_free(T(pnode).children);
717 T(pnode).children = eina_list_merge(node_order_clean, not_ordered);
718
719 return;
720}
721
722EOLIAN static Eina_Bool
723_efl_ui_focus_manager_calc_update_children(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Object *parent, Eina_List *order)
724{
725 Node *pnode;
726 Efl_Ui_Focus_Object *o;
727 Eina_Bool fail = EINA_FALSE;
728 Eina_List *node_order = NULL;
729
730 pnode = node_get(obj, pd, parent);
731 if (!pnode)
732 return EINA_FALSE;
733
734 //get all nodes from the subset
735 EINA_LIST_FREE(order, o)
736 {
737 Node *tmp;
738
739 tmp = node_get(obj, pd, o);
740 if (!tmp)
741 fail = EINA_TRUE;
742 node_order = eina_list_append(node_order, tmp);
743 }
744
745 if (fail)
746 {
747 eina_list_free(node_order);
748 return EINA_FALSE;
749 }
750
751 if (!_equal_set(node_order, T(pnode).children))
752 {
753 ERR("Set of children is not equal");
754 return EINA_FALSE;
755 }
756
757 eina_list_free(T(pnode).children);
758 T(pnode).children = node_order;
759
760 return EINA_TRUE;
761}
762
763EOLIAN static void
764_efl_ui_focus_manager_calc_unregister(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Object *child)
765{
766 Node *node;
767
768 node = eina_hash_find(pd->node_hash, &child);
769
770 if (!node) return;
771
772 F_DBG("Manager: %p unregister %p", obj, child);
773
774
775 //remove the object from the stack if it hasn't done that until now
776 //after this it's not at the top anymore
777 //elm_widget_focus_set(node->focusable, EINA_FALSE);
778 //delete again from the list, for the case it was not at the top
779 pd->focus_stack = eina_list_remove(pd->focus_stack, node);
780
781 //add all neighbors of the node to the dirty list
782 for(int i = 0; i < 4; i++)
783 {
784 Node *partner;
785 Eina_List *n;
786
787 EINA_LIST_FOREACH(node->graph.directions[i].partners, n, partner)
788 {
789 dirty_add(obj, pd, partner);
790 }
791 }
792
793 //remove from the dirty parts
794 pd->dirty = eina_list_remove(pd->dirty, node);
795
796 eina_hash_del_by_key(pd->node_hash, &child);
797}
798
799EOLIAN static void
800_efl_ui_focus_manager_calc_efl_ui_focus_manager_redirect_set(Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Manager *redirect)
801{
802 Efl_Ui_Focus_Manager *old_manager;
803
804 if (pd->redirect == redirect) return;
805
806 F_DBG("Manager: %p setting redirect from %p to %p", obj, pd->redirect, redirect);
807
808 if (pd->redirect)
809 efl_wref_del(pd->redirect, &pd->redirect);
810
811 old_manager = pd->redirect;
812 pd->redirect = redirect;
813
814 if (pd->redirect)
815 efl_wref_add(pd->redirect, &pd->redirect);
816
817 efl_event_callback_call(obj, EFL_UI_FOCUS_MANAGER_EVENT_REDIRECT_CHANGED , old_manager);
818}
819
820EOLIAN static Efl_Ui_Focus_Manager *
821_efl_ui_focus_manager_calc_efl_ui_focus_manager_redirect_get(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Calc_Data *pd)
822{
823 return pd->redirect;
824}
825
826static void
827_free_node(void *data)
828{
829 Node *node = data;
830 FOCUS_DATA(node->manager);
831
832 efl_event_callback_array_del(node->focusable, focusable_node(), node->manager);
833
834 if (pd->root != data)
835 {
836 node_item_free(node);
837 }
838}
839
840EOLIAN static Efl_Object *
841_efl_ui_focus_manager_calc_efl_object_constructor(Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd)
842{
843 pd->node_hash = eina_hash_pointer_new(_free_node);
844 return efl_constructor(efl_super(obj, MY_CLASS));
845}
846
847EOLIAN static Efl_Object *
848_efl_ui_focus_manager_calc_efl_object_provider_find(Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd EINA_UNUSED, const Efl_Object *klass)
849{
850 if (klass == MY_CLASS)
851 return obj;
852
853 return efl_provider_find(efl_super(obj, MY_CLASS), klass);
854}
855
856EOLIAN static void
857_efl_ui_focus_manager_calc_efl_object_destructor(Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd)
858{
859 eina_list_free(pd->focus_stack);
860 eina_list_free(pd->dirty);
861
862 eina_hash_free(pd->node_hash);
863
864 efl_ui_focus_manager_redirect_set(obj, NULL);
865
866 if (pd->root)
867 node_item_free(pd->root);
868 pd->root = NULL;
869
870 efl_destructor(efl_super(obj, MY_CLASS));
871}
872
873typedef struct {
874 Eina_Iterator iterator;
875 Eina_Iterator *real_iterator;
876 Efl_Ui_Focus_Manager *object;
877} Border_Elements_Iterator;
878
879static Eina_Bool
880_iterator_next(Border_Elements_Iterator *it, void **data)
881{
882 Node *node;
883
884 EINA_ITERATOR_FOREACH(it->real_iterator, node)
885 {
886 for(int i = 0 ;i < NODE_DIRECTIONS_COUNT; i++)
887 {
888 if (node->type != NODE_TYPE_ONLY_LOGICAL &&
889 !node->graph.directions[i].partners)
890 {
891 *data = node->focusable;
892 return EINA_TRUE;
893 }
894 }
895 }
896 return EINA_FALSE;
897}
898
899static Eo *
900_iterator_get_container(Border_Elements_Iterator *it)
901{
902 return it->object;
903}
904
905static void
906_iterator_free(Border_Elements_Iterator *it)
907{
908 eina_iterator_free(it->real_iterator);
909 free(it);
910}
911
912EOLIAN static Eina_Iterator*
913_efl_ui_focus_manager_calc_efl_ui_focus_manager_border_elements_get(Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd)
914{
915 Border_Elements_Iterator *it;
916
917 dirty_flush_all(obj, pd);
918
919 it = calloc(1, sizeof(Border_Elements_Iterator));
920
921 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
922
923 it->real_iterator = eina_hash_iterator_data_new(pd->node_hash);
924 it->iterator.version = EINA_ITERATOR_VERSION;
925 it->iterator.next = FUNC_ITERATOR_NEXT(_iterator_next);
926 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_iterator_get_container);
927 it->iterator.free = FUNC_ITERATOR_FREE(_iterator_free);
928 it->object = obj;
929
930 return (Eina_Iterator*) it;
931}
932
933static Node*
934_no_history_element(Eina_Hash *node_hash)
935{
936 //nothing is selected yet, just try to use the first element in the iterator
937 Eina_Iterator *iter;
938 Node *upper;
939
940 iter = eina_hash_iterator_data_new(node_hash);
941
942 EINA_ITERATOR_FOREACH(iter, upper)
943 {
944 if (upper->type == NODE_TYPE_NORMAL)
945 break;
946 }
947
948 eina_iterator_free(iter);
949
950 if (upper->type != NODE_TYPE_NORMAL)
951 return NULL;
952
953 return upper;
954}
955
956static void
957_get_middle(Evas_Object *obj, Eina_Vector2 *elem)
958{
959 Eina_Rectangle geom;
960
961 geom = efl_ui_focus_object_focus_geometry_get(obj);
962 elem->x = geom.x + geom.w/2;
963 elem->y = geom.y + geom.h/2;
964}
965
966static Node*
967_coords_movement(Efl_Ui_Focus_Manager_Calc_Data *pd, Node *upper, Efl_Ui_Focus_Direction direction)
968{
969 Node *candidate;
970 Eina_List *node_list;
971
972 //we are searching which of the partners is lower to the history
973 EINA_LIST_REVERSE_FOREACH(pd->focus_stack, node_list, candidate)
974 {
975 if (eina_list_data_find(G(upper).directions[direction].partners, candidate))
976 {
977 //this is the next accessable part
978 return candidate;
979 }
980 }
981
982 //if we haven't found anything in the history, use the widget with the smallest distance
983 {
984 Eina_List *lst = G(upper).directions[direction].partners;
985 Eina_List *n;
986 Node *node, *min = NULL;
987 Eina_Vector2 elem, other;
988 float min_distance = 0.0;
989
990
991 _get_middle(upper->focusable, &elem);
992
993 EINA_LIST_FOREACH(lst, n, node)
994 {
995 _get_middle(node->focusable, &other);
996 float tmp = eina_vector2_distance_get(&other, &elem);
997 if (!min || tmp < min_distance)
998 {
999 min = node;
1000 min_distance = tmp;
1001 }
1002 }
1003 candidate = min;
1004 }
1005 return candidate;
1006}
1007
1008
1009static Node*
1010_prev_item(Node *node)
1011{
1012 Node *parent;
1013 Eina_List *lnode;
1014
1015 parent = T(node).parent;
1016 lnode = eina_list_data_find_list(T(parent).children, node);
1017 lnode = eina_list_prev(lnode);
1018
1019 if (lnode)
1020 return eina_list_data_get(lnode);
1021 return NULL;
1022}
1023
1024static Node*
1025_next(Node *node)
1026{
1027 Node *n;
1028
1029 //Case 1 we are having children
1030 //But only enter the children if it does NOT have a redirect manager
1031 if (T(node).children && !node->redirect_manager)
1032 {
1033 return eina_list_data_get(T(node).children);
1034 }
1035
1036 //case 2 we are the root and we don't have children, return ourself
1037 if (!T(node).parent)
1038 {
1039 return node;
1040 }
1041
1042 //case 3 we are not at the end of the parents list
1043 n = node;
1044 while(T(n).parent)
1045 {
1046 Node *parent;
1047 Eina_List *lnode;
1048
1049 parent = T(n).parent;
1050 lnode = eina_list_data_find_list(T(parent).children, n);
1051 lnode = eina_list_next(lnode);
1052
1053 if (lnode)
1054 {
1055 return eina_list_data_get(lnode);
1056 }
1057
1058 n = parent;
1059 }
1060
1061 //this is then the root again
1062 return NULL;
1063}
1064
1065static Node*
1066_prev(Node *node)
1067{
1068 Node *n = NULL;
1069
1070 //this is the root there is no parent
1071 if (!T(node).parent)
1072 return NULL;
1073
1074 n =_prev_item(node);
1075 //case 1 there is a item in the parent previous to node, which has children
1076 if (n && T(n).children)
1077 {
1078 do
1079 {
1080 n = eina_list_last_data_get(T(n).children);
1081 }
1082 while (T(n).children);
1083
1084 return n;
1085 }
1086
1087 //case 2 there is a item in the parent previous to node, which has no children
1088 if (n)
1089 return n;
1090
1091 //case 3 there is a no item in the parent previous to this one
1092 return T(node).parent;
1093}
1094
1095
1096static Node*
1097_logical_movement(Efl_Ui_Focus_Manager_Calc_Data *pd EINA_UNUSED, Node *upper, Efl_Ui_Focus_Direction direction)
1098{
1099 Node* (*deliver)(Node *n);
1100 Node *result;
1101 Eina_List *stack = NULL;
1102
1103 if (direction == EFL_UI_FOCUS_DIRECTION_NEXT)
1104 deliver = _next;
1105 else
1106 deliver = _prev;
1107
1108 //search as long as we have a none logical parent
1109 result = upper;
1110 do
1111 {
1112 //give up, if we have already been here
1113 if (!!eina_list_data_find(stack, result))
1114 {
1115 eina_list_free(stack);
1116 ERR("Warning cycle detected\n");
1117 return NULL;
1118 }
1119
1120 stack = eina_list_append(stack, result);
1121 result = deliver(result);
1122 } while(result && result->type != NODE_TYPE_NORMAL && !result->redirect_manager);
1123
1124 eina_list_free(stack);
1125
1126 return result;
1127}
1128
1129static Efl_Ui_Focus_Object*
1130_request_move(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Direction direction, Node *upper)
1131{
1132 Node *dir = NULL;
1133
1134 if (!upper)
1135 upper = eina_list_last_data_get(pd->focus_stack);
1136
1137 if (!upper)
1138 {
1139 upper = _no_history_element(pd->node_hash);
1140 if (upper)
1141 return upper->focusable;
1142 return NULL;
1143
1144 }
1145
1146 dirty_flush(obj, pd, upper);
1147
1148 if (direction == EFL_UI_FOCUS_DIRECTION_PREV
1149 || direction == EFL_UI_FOCUS_DIRECTION_NEXT)
1150 dir = _logical_movement(pd, upper, direction);
1151 else
1152 dir = _coords_movement(pd, upper, direction);
1153
1154 //return the widget
1155 if (dir)
1156 return dir->focusable;
1157 else
1158 return NULL;
1159}
1160
1161EOLIAN static Efl_Ui_Focus_Object*
1162_efl_ui_focus_manager_calc_efl_ui_focus_manager_request_move(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Direction direction)
1163{
1164 EINA_SAFETY_ON_FALSE_RETURN_VAL(DIRECTION_CHECK(direction), NULL);
1165
1166 if (pd->redirect)
1167 return efl_ui_focus_manager_request_move(pd->redirect, direction);
1168 else
1169 {
1170 Node *upper = NULL;
1171
1172 upper = eina_list_last_data_get(pd->focus_stack);
1173
1174 if (!upper)
1175 {
1176 upper = _no_history_element(pd->node_hash);
1177 if (upper)
1178 return upper->focusable;
1179 return NULL;
1180 }
1181
1182 return _request_move(obj, pd, direction, upper);
1183 }
1184}
1185
1186EOLIAN static void
1187_efl_ui_focus_manager_calc_efl_ui_focus_manager_focus(Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Object *focus)
1188{
1189 Node *node;
1190 Node *old_focus;
1191 Efl_Ui_Focus_Manager *redirect_manager;
1192
1193 EINA_SAFETY_ON_NULL_RETURN(focus);
1194
1195 //if we want to focus the root then just spin to the first normal
1196 if (focus == pd->root->focusable)
1197 {
1198 Node *f = _logical_movement(pd, pd->root, EFL_UI_FOCUS_DIRECTION_NEXT);
1199
1200 if (f)
1201 focus = f->focusable;
1202
1203 if (!focus) return;
1204 }
1205
1206 //check if node is part of this manager object
1207 node = node_get(obj, pd, focus);
1208 if (!node) return;
1209
1210 F_DBG("Manager: %p focusing object %p %s", obj, focus, efl_class_name_get(focus));
1211
1212 if (node->type == NODE_TYPE_ONLY_LOGICAL && !node->redirect_manager && pd->root != node)
1213 {
1214 ERR(" %p is logical, cannot be focused", obj);
1215 return;
1216 }
1217
1218 if (pd->redirect)
1219 {
1220 //first unset the redirect
1221 efl_ui_focus_manager_redirect_set(obj, NULL);
1222 }
1223
1224 redirect_manager = node->redirect_manager;
1225
1226 if (node->type == NODE_TYPE_NORMAL)
1227 {
1228 Eo *focusable;
1229 //check if this is already the focused object
1230 old_focus = eina_list_last_data_get(pd->focus_stack);
1231
1232 //check if this is already at the top
1233 if (old_focus && old_focus->focusable == focus) return;
1234
1235 //remove the object from the list and add it again
1236 pd->focus_stack = eina_list_remove(pd->focus_stack, node);
1237 pd->focus_stack = eina_list_append(pd->focus_stack, node);
1238
1239 //save fields we later need
1240 focusable = node->focusable;
1241
1242 //populate the new change
1243 if (old_focus) efl_ui_focus_object_focus_set(old_focus->focusable, EINA_FALSE);
1244 efl_ui_focus_object_focus_set(node->focusable, EINA_TRUE);
1245 efl_event_callback_call(obj, EFL_UI_FOCUS_MANAGER_EVENT_FOCUSED, focusable);
1246 node = NULL;
1247 }
1248 else if (node->redirect_manager)
1249 {
1250 Efl_Ui_Focus_Object *root;
1251
1252 root = efl_ui_focus_manager_root_get(node->redirect_manager);
1253 efl_ui_focus_manager_focus(node->redirect_manager, root);
1254 }
1255
1256 //now check if this is also a listener object
1257 if (redirect_manager)
1258 {
1259 efl_ui_focus_manager_redirect_set(obj, redirect_manager);
1260 }
1261}
1262
1263EOLIAN static Efl_Ui_Focus_Object*
1264_efl_ui_focus_manager_calc_efl_ui_focus_manager_move(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Direction direction)
1265{
1266 Efl_Ui_Focus_Object *candidate = NULL;
1267
1268 EINA_SAFETY_ON_FALSE_RETURN_VAL(DIRECTION_CHECK(direction), NULL);
1269
1270 if (pd->redirect)
1271 {
1272 Efl_Ui_Focus_Object *old_candidate = NULL;
1273 candidate = efl_ui_focus_manager_move(pd->redirect, direction);
1274 old_candidate = efl_ui_focus_manager_focused(pd->redirect);
1275
1276 if (!candidate)
1277 {
1278 Efl_Ui_Focus_Object *new_candidate = NULL;
1279 Node *n;
1280
1281 //there is no candidate check if we have something for that direction
1282 new_candidate = NULL;
1283 n = eina_hash_find(pd->node_hash, &old_candidate);
1284
1285 if (direction == EFL_UI_FOCUS_DIRECTION_NEXT ||
1286 direction == EFL_UI_FOCUS_DIRECTION_PREV)
1287 {
1288 if (n)
1289 {
1290 n = T(n).parent;
1291 new_candidate = _request_move(obj, pd, direction, n);
1292 efl_ui_focus_manager_focus(obj, new_candidate);
1293 candidate = new_candidate;
1294 }
1295 }
1296 else
1297 {
1298
1299 if (n)
1300 new_candidate = _request_move(obj, pd, direction, n);
1301
1302 if (new_candidate)
1303 {
1304 //redirect does not have smth. but we do have.
1305 efl_ui_focus_manager_focus(obj, new_candidate);
1306 }
1307 candidate = new_candidate;
1308 }
1309
1310 }
1311 }
1312 else
1313 {
1314 candidate = efl_ui_focus_manager_request_move(obj, direction);
1315
1316 if (candidate)
1317 efl_ui_focus_manager_focus(obj, candidate);
1318 }
1319
1320 F_DBG("Manager: %p moved to %p %s in direction %d", obj, candidate, efl_class_name_get(candidate), direction);
1321
1322 return candidate;
1323}
1324
1325EOLIAN static Eina_Bool
1326_efl_ui_focus_manager_calc_efl_ui_focus_manager_root_set(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Object *root)
1327{
1328 Node *node;
1329
1330 if (pd->root)
1331 {
1332 ERR("Root element can only be set once!");
1333 return EINA_FALSE;
1334 }
1335
1336 node = _register(obj, pd, root, NULL);
1337 node->type = NODE_TYPE_ONLY_LOGICAL;
1338
1339 pd->root = node;
1340
1341 return EINA_TRUE;
1342}
1343
1344EOLIAN static Efl_Ui_Focus_Object*
1345_efl_ui_focus_manager_calc_efl_ui_focus_manager_root_get(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Calc_Data *pd)
1346{
1347 if (!pd->root) return NULL;
1348
1349 return pd->root->focusable;
1350}
1351
1352EOLIAN static Efl_Object*
1353_efl_ui_focus_manager_calc_efl_object_finalize(Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd)
1354{
1355 Efl_Object *result;
1356
1357 if (!pd->root)
1358 {
1359 ERR("Constructing failed. No root element set.");
1360 return NULL;
1361 }
1362
1363 result = efl_finalize(efl_super(obj, MY_CLASS));
1364
1365 return result;
1366}
1367
1368static Eina_List*
1369_convert(Eina_List *node_list)
1370{
1371 Eina_List *n, *par = NULL;
1372 Node *node;
1373
1374 EINA_LIST_FOREACH(node_list, n, node)
1375 par = eina_list_append(par, node->focusable);
1376
1377 return par;
1378}
1379
1380EOLIAN static Efl_Ui_Focus_Object*
1381_efl_ui_focus_manager_calc_efl_ui_focus_manager_focused(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Calc_Data *pd)
1382{
1383 Node *upper = NULL;
1384
1385 upper = eina_list_last_data_get(pd->focus_stack);
1386
1387 if (!upper)
1388 return NULL;
1389 return upper->focusable;
1390}
1391
1392EOLIAN static Efl_Ui_Focus_Relations*
1393_efl_ui_focus_manager_calc_efl_ui_focus_manager_fetch(Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Object *child)
1394{
1395 Efl_Ui_Focus_Relations *res;
1396 Node *n, *tmp;
1397
1398 n = node_get(obj, pd, child);
1399 if (!n)
1400 return NULL;
1401
1402 res = calloc(1, sizeof(Efl_Ui_Focus_Relations));
1403
1404 dirty_flush(obj, pd, n);
1405
1406#define DIR_CLONE(dir) _convert(G(n).directions[dir].partners);
1407
1408 res->right = DIR_CLONE(EFL_UI_FOCUS_DIRECTION_RIGHT);
1409 res->left = DIR_CLONE(EFL_UI_FOCUS_DIRECTION_LEFT);
1410 res->top = DIR_CLONE(EFL_UI_FOCUS_DIRECTION_UP);
1411 res->down = DIR_CLONE(EFL_UI_FOCUS_DIRECTION_DOWN);
1412 res->next = (tmp = _next(n)) ? tmp->focusable : NULL;
1413 res->prev = (tmp = _prev(n)) ? tmp->focusable : NULL;
1414 switch(n->type)
1415 {
1416 case NODE_TYPE_ONLY_LOGICAL:
1417 res->type = "logical";
1418 break;
1419 case NODE_TYPE_NORMAL:
1420 res->type = "normal";
1421 break;
1422 }
1423 res->parent = T(n).parent->focusable;
1424 res->redirect = n->redirect_manager;
1425#undef DIR_CLONE
1426
1427 return res;
1428}
1429
1430EOLIAN static void
1431_efl_ui_focus_manager_calc_class_constructor(Efl_Class *c EINA_UNUSED)
1432{
1433 _focus_log_domain = eina_log_domain_register("elementary-focus", EINA_COLOR_CYAN);
1434}
1435
1436EOLIAN static void
1437_efl_ui_focus_manager_calc_class_destructor(Efl_Class *c EINA_UNUSED)
1438{
1439 eina_log_domain_unregister(_focus_log_domain);
1440 _focus_log_domain = -1;
1441}
1442
1443EOLIAN static Efl_Ui_Focus_Object*
1444_efl_ui_focus_manager_calc_efl_ui_focus_manager_logical_end(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Manager_Calc_Data *pd)
1445{
1446 Node *child = pd->root;
1447
1448 EINA_SAFETY_ON_NULL_RETURN_VAL(child, NULL);
1449
1450 //we need to return the most lower right element
1451
1452 while(T(child).children)
1453 child = eina_list_last_data_get(T(child).children);
1454 while (child->type != NODE_TYPE_NORMAL)
1455 child = _prev(child);
1456
1457 return child ? child->focusable : NULL;
1458}
1459#include "efl_ui_focus_manager_calc.eo.c"
diff --git a/src/lib/elementary/efl_ui_focus_manager_calc.eo b/src/lib/elementary/efl_ui_focus_manager_calc.eo
new file mode 100644
index 0000000000..5817506590
--- /dev/null
+++ b/src/lib/elementary/efl_ui_focus_manager_calc.eo
@@ -0,0 +1,107 @@
1class Efl.Ui.Focus.Manager.Calc (Efl.Object, Efl.Ui.Focus.Manager) {
2 [[Calculates the directions of Efl.Ui.Focus.Direction
3
4 Each registered item will get a other registered object into each
5 direction, you can get those items for the currently focused item if
6 you call request move.
7
8 @since 1.20
9 ]]
10 methods {
11 register {
12 [[Register a new item in the graph.
13
14 $parent can not be $null, it will be used as the parent in the
15 logical tree.
16 $redirect will be set as redirect property on that manager, once
17 $child gets focused.
18 ]]
19 params {
20 child : Efl.Ui.Focus.Object @nonull; [[The object to register]]
21 parent : Efl.Ui.Focus.Object @nonull; [[The parent to use in
22 the logical tree]]
23 redirect : Efl.Ui.Focus.Manager; [[The redirect manager to set
24 once this child is focused can be NULL for no redirect]]
25 }
26 return : bool; [[$true if successful, $false otherwise]]
27 }
28 register_logical {
29 [[Register a new item just for the logical parent.
30
31 The item can never get focus, it just helps to build a tree out
32 of the items that are getting focus.
33 ]]
34 params {
35 child : Efl.Ui.Focus.Object @nonull; [[The object to register]]
36 parent : Efl.Ui.Focus.Object @nonull; [[The parent to use in
37 the logical tree]]
38 redirect : Efl.Ui.Focus.Manager; [[The redirect manager to set
39 once this child is focused can be $null for no redirect]]
40 }
41 return : bool; [[$true if successful, $false otherwise]]
42 }
43 update_redirect {
44 [[Set a new redirect object for the given child.
45
46 Once $child is focused the redirect manager will be set
47 in the redirect property. Set redirect to $null if nothing should happen.
48 ]]
49 params {
50 child : Efl.Ui.Focus.Object @nonull; [[The child to update]]
51 redirect : Efl.Ui.Focus.Manager; [[Once $child got focused this
52 element will be set as redirect]]
53 }
54 return : bool; [[$true if successful, $false otherwise]]
55 }
56 update_parent {
57 [[Set a new logical parent for the given child.]]
58 params {
59 child : Efl.Ui.Focus.Object @nonull; [[The child to update]]
60 parent : Efl.Ui.Focus.Object @nonull; [[The parent which now
61 will be the logical parent of child]]
62 }
63 return : bool; [[$true if successful, $false otherwise]]
64 }
65 update_children {
66 [[Give the list of children a different order.]]
67 params {
68 parent : Efl.Ui.Focus.Object @nonull; [[the parent to update]]
69 children : own(list<Efl.Ui.Focus.Object>); [[the list with the new order]]
70 }
71 return : bool; [[$true if successful, $false otherwise]]
72 }
73 update_order {
74 [[Give the given order to the parent's child.
75
76 Children from the list which are no real children are ignored.
77 ]]
78 params {
79 parent : Efl.Ui.Focus.Object @nonull; [[the parent to update]]
80 children : list<Efl.Ui.Focus.Object>; [[the order of items]]
81 }
82 }
83 unregister {
84 [[Unregister the given item from the focus graph.]]
85 params {
86 child : Efl.Ui.Focus.Object; [[The child to unregister.]]
87 }
88 }
89 }
90 implements {
91 class.constructor;
92 class.destructor;
93 Efl.Ui.Focus.Manager.move;
94 Efl.Ui.Focus.Manager.request_move;
95 Efl.Ui.Focus.Manager.focus;
96 Efl.Ui.Focus.Manager.focused;
97 Efl.Ui.Focus.Manager.redirect {set; get;}
98 Efl.Ui.Focus.Manager.border_elements {get;}
99 Efl.Ui.Focus.Manager.root {set; get;}
100 Efl.Ui.Focus.Manager.fetch;
101 Efl.Ui.Focus.Manager.logical_end;
102 Efl.Object.constructor;
103 Efl.Object.finalize;
104 Efl.Object.provider_find;
105 Efl.Object.destructor;
106 }
107}
diff --git a/src/lib/elementary/efl_ui_focus_manager_root_focus.c b/src/lib/elementary/efl_ui_focus_manager_root_focus.c
index fcfbd9047c..056e7e0503 100644
--- a/src/lib/elementary/efl_ui_focus_manager_root_focus.c
+++ b/src/lib/elementary/efl_ui_focus_manager_root_focus.c
@@ -29,20 +29,20 @@ _state_eval(Eo *obj, Efl_Ui_Focus_Manager_Root_Focus_Data *pd)
29{ 29{
30 if (!pd->none_logicals && pd->rect_registered) 30 if (!pd->none_logicals && pd->rect_registered)
31 { 31 {
32 efl_ui_focus_manager_unregister(obj, pd->rect); 32 efl_ui_focus_manager_calc_unregister(obj, pd->rect);
33 pd->rect_registered = EINA_FALSE; 33 pd->rect_registered = EINA_FALSE;
34 } 34 }
35 else if (pd->none_logicals && !pd->rect_registered) 35 else if (pd->none_logicals && !pd->rect_registered)
36 { 36 {
37 efl_ui_focus_manager_register(obj, pd->rect, pd->root, NULL); 37 efl_ui_focus_manager_calc_register(obj, pd->rect, pd->root, NULL);
38 pd->rect_registered = EINA_TRUE; 38 pd->rect_registered = EINA_TRUE;
39 } 39 }
40} 40}
41 41
42EOLIAN static Eina_Bool 42EOLIAN static Eina_Bool
43_efl_ui_focus_manager_root_focus_efl_ui_focus_manager_register(Eo *obj, Efl_Ui_Focus_Manager_Root_Focus_Data *pd, Efl_Ui_Focus_Object *child, Efl_Ui_Focus_Object *parent, Efl_Ui_Focus_Manager *redirect) 43_efl_ui_focus_manager_root_focus_efl_ui_focus_manager_calc_register(Eo *obj, Efl_Ui_Focus_Manager_Root_Focus_Data *pd, Efl_Ui_Focus_Object *child, Efl_Ui_Focus_Object *parent, Efl_Ui_Focus_Manager *redirect)
44{ 44{
45 if (efl_ui_focus_manager_register(efl_super(obj, MY_CLASS), child, parent, redirect)) 45 if (efl_ui_focus_manager_calc_register(efl_super(obj, MY_CLASS), child, parent, redirect))
46 { 46 {
47 pd->none_logicals = eina_list_append(pd->none_logicals, child); 47 pd->none_logicals = eina_list_append(pd->none_logicals, child);
48 return EINA_TRUE; 48 return EINA_TRUE;
@@ -53,9 +53,9 @@ _efl_ui_focus_manager_root_focus_efl_ui_focus_manager_register(Eo *obj, Efl_Ui_F
53} 53}
54 54
55EOLIAN static void 55EOLIAN static void
56_efl_ui_focus_manager_root_focus_efl_ui_focus_manager_unregister(Eo *obj, Efl_Ui_Focus_Manager_Root_Focus_Data *pd, Efl_Ui_Focus_Object *child) 56_efl_ui_focus_manager_root_focus_efl_ui_focus_manager_calc_unregister(Eo *obj, Efl_Ui_Focus_Manager_Root_Focus_Data *pd, Efl_Ui_Focus_Object *child)
57{ 57{
58 efl_ui_focus_manager_unregister(efl_super(obj, MY_CLASS), child); 58 efl_ui_focus_manager_calc_unregister(efl_super(obj, MY_CLASS), child);
59 59
60 pd->none_logicals = eina_list_remove(pd->none_logicals, child); 60 pd->none_logicals = eina_list_remove(pd->none_logicals, child);
61 61
diff --git a/src/lib/elementary/efl_ui_focus_manager_root_focus.eo b/src/lib/elementary/efl_ui_focus_manager_root_focus.eo
index 3a3dd46ff8..0865b42cec 100644
--- a/src/lib/elementary/efl_ui_focus_manager_root_focus.eo
+++ b/src/lib/elementary/efl_ui_focus_manager_root_focus.eo
@@ -1,8 +1,8 @@
1class Efl.Ui.Focus.Manager.Root_Focus(Efl.Ui.Focus.Manager) { 1class Efl.Ui.Focus.Manager.Root_Focus(Efl.Ui.Focus.Manager.Calc) {
2 [[ This class ensures that the root is at least focusable, if nothing else is focusable]] 2 [[ This class ensures that the root is at least focusable, if nothing else is focusable]]
3 implements { 3 implements {
4 Efl.Ui.Focus.Manager.register; 4 Efl.Ui.Focus.Manager.Calc.register;
5 Efl.Ui.Focus.Manager.unregister; 5 Efl.Ui.Focus.Manager.Calc.unregister;
6 Efl.Ui.Focus.Manager.focus; 6 Efl.Ui.Focus.Manager.focus;
7 Efl.Ui.Focus.Manager.focused; 7 Efl.Ui.Focus.Manager.focused;
8 Efl.Ui.Focus.Manager.fetch; 8 Efl.Ui.Focus.Manager.fetch;
diff --git a/src/lib/elementary/efl_ui_focus_manager_sub.c b/src/lib/elementary/efl_ui_focus_manager_sub.c
index c7a167892f..7826b22041 100644
--- a/src/lib/elementary/efl_ui_focus_manager_sub.c
+++ b/src/lib/elementary/efl_ui_focus_manager_sub.c
@@ -51,14 +51,14 @@ _focus_changed(void *data, const Efl_Event *event)
51static void 51static void
52_register(Efl_Ui_Focus_Manager *obj, Efl_Ui_Focus_Manager *par_m, Efl_Ui_Focus_Object *node, Efl_Ui_Focus_Object *logical) 52_register(Efl_Ui_Focus_Manager *obj, Efl_Ui_Focus_Manager *par_m, Efl_Ui_Focus_Object *node, Efl_Ui_Focus_Object *logical)
53{ 53{
54 efl_ui_focus_manager_register(par_m, node, logical, obj); 54 efl_ui_focus_manager_calc_register(par_m, node, logical, obj);
55 efl_event_callback_add(node, EFL_UI_FOCUS_OBJECT_EVENT_FOCUS_CHANGED, _focus_changed, obj); 55 efl_event_callback_add(node, EFL_UI_FOCUS_OBJECT_EVENT_FOCUS_CHANGED, _focus_changed, obj);
56} 56}
57 57
58static void 58static void
59_unregister(Efl_Ui_Focus_Manager *obj, Efl_Ui_Focus_Manager *par_m, Efl_Ui_Focus_Object *node) 59_unregister(Efl_Ui_Focus_Manager *obj, Efl_Ui_Focus_Manager *par_m, Efl_Ui_Focus_Object *node)
60{ 60{
61 efl_ui_focus_manager_unregister(par_m, node); 61 efl_ui_focus_manager_calc_unregister(par_m, node);
62 efl_event_callback_del(node, EFL_UI_FOCUS_OBJECT_EVENT_FOCUS_CHANGED, _focus_changed, obj); 62 efl_event_callback_del(node, EFL_UI_FOCUS_OBJECT_EVENT_FOCUS_CHANGED, _focus_changed, obj);
63} 63}
64 64
@@ -170,7 +170,7 @@ _logical_manager_change(void *data EINA_UNUSED, const Efl_Event *ev)
170 EINA_LIST_FOREACH(pd->current_border, n, b) 170 EINA_LIST_FOREACH(pd->current_border, n, b)
171 { 171 {
172 if (b == ev->object) continue; 172 if (b == ev->object) continue;
173 efl_ui_focus_manager_update_parent(manager, b, ev->info); 173 efl_ui_focus_manager_calc_update_parent(manager, b, ev->info);
174 } 174 }
175} 175}
176 176
diff --git a/src/lib/elementary/efl_ui_focus_manager_sub.eo b/src/lib/elementary/efl_ui_focus_manager_sub.eo
index 3c1903bc37..148a399c68 100644
--- a/src/lib/elementary/efl_ui_focus_manager_sub.eo
+++ b/src/lib/elementary/efl_ui_focus_manager_sub.eo
@@ -1,4 +1,4 @@
1class Efl.Ui.Focus.Manager.Sub (Efl.Ui.Focus.Manager, Efl.Object) 1class Efl.Ui.Focus.Manager.Sub (Efl.Ui.Focus.Manager.Calc, Efl.Object)
2{ 2{
3 [[A class that automatically registeres its border elements in the parent manager 3 [[A class that automatically registeres its border elements in the parent manager
4 4
diff --git a/src/lib/elementary/efl_ui_win.c b/src/lib/elementary/efl_ui_win.c
index 96f27cc535..9947f46635 100644
--- a/src/lib/elementary/efl_ui_win.c
+++ b/src/lib/elementary/efl_ui_win.c
@@ -5338,7 +5338,7 @@ _efl_ui_win_elm_widget_focus_manager_factory(Eo *obj EINA_UNUSED, Efl_Ui_Win_Dat
5338{ 5338{
5339 Efl_Ui_Focus_Manager *manager; 5339 Efl_Ui_Focus_Manager *manager;
5340 5340
5341 manager = efl_add(EFL_UI_FOCUS_MANAGER_CLASS, obj, 5341 manager = efl_add(EFL_UI_FOCUS_MANAGER_CALC_CLASS, obj,
5342 efl_ui_focus_manager_root_set(efl_added, root) 5342 efl_ui_focus_manager_root_set(efl_added, root)
5343 ); 5343 );
5344 5344
diff --git a/src/lib/elementary/elc_fileselector.c b/src/lib/elementary/elc_fileselector.c
index 7ecadc659a..efa644b8f0 100644
--- a/src/lib/elementary/elc_fileselector.c
+++ b/src/lib/elementary/elc_fileselector.c
@@ -113,7 +113,7 @@ _focus_chain_update(Eo *obj, Elm_Fileselector_Data *pd)
113 113
114#undef A 114#undef A
115 115
116 efl_ui_focus_manager_update_order(efl_ui_focus_user_manager_get(obj), obj, tmp); 116 efl_ui_focus_manager_calc_update_order(efl_ui_focus_user_manager_get(obj), obj, tmp);
117} 117}
118 118
119static void 119static void
diff --git a/src/lib/elementary/elm_box.c b/src/lib/elementary/elm_box.c
index 9f8cc47838..cda4c9eac4 100644
--- a/src/lib/elementary/elm_box.c
+++ b/src/lib/elementary/elm_box.c
@@ -28,7 +28,7 @@ _focus_order_flush(Eo *obj, Elm_Box_Data *pd EINA_UNUSED)
28 Elm_Widget_Smart_Data *wpd = efl_data_scope_get(obj, ELM_WIDGET_CLASS); 28 Elm_Widget_Smart_Data *wpd = efl_data_scope_get(obj, ELM_WIDGET_CLASS);
29 Eina_List *order = evas_object_box_children_get(wpd->resize_obj); 29 Eina_List *order = evas_object_box_children_get(wpd->resize_obj);
30 30
31 efl_ui_focus_manager_update_order(wpd->focus.manager, obj, order); 31 efl_ui_focus_manager_calc_update_order(wpd->focus.manager, obj, order);
32} 32}
33 33
34static void * 34static void *
diff --git a/src/lib/elementary/elm_gengrid.c b/src/lib/elementary/elm_gengrid.c
index 3808a60969..15ff80535b 100644
--- a/src/lib/elementary/elm_gengrid.c
+++ b/src/lib/elementary/elm_gengrid.c
@@ -2693,7 +2693,7 @@ _anim_end(Elm_Gengrid_Data *sd)
2693 { 2693 {
2694 sd->items = eina_inlist_remove(sd->items, EINA_INLIST_GET(sd->reorder.it1)); 2694 sd->items = eina_inlist_remove(sd->items, EINA_INLIST_GET(sd->reorder.it1));
2695 sd->items = eina_inlist_remove(sd->items, EINA_INLIST_GET(sd->reorder.it2)); 2695 sd->items = eina_inlist_remove(sd->items, EINA_INLIST_GET(sd->reorder.it2));
2696 2696
2697 if (it1_prev) 2697 if (it1_prev)
2698 { 2698 {
2699 tmp = eina_inlist_find(sd->items, EINA_INLIST_GET(it1_prev)); 2699 tmp = eina_inlist_find(sd->items, EINA_INLIST_GET(it1_prev));
@@ -2702,7 +2702,7 @@ _anim_end(Elm_Gengrid_Data *sd)
2702 } 2702 }
2703 else 2703 else
2704 sd->items = eina_inlist_prepend(sd->items, EINA_INLIST_GET(sd->reorder.it2)); 2704 sd->items = eina_inlist_prepend(sd->items, EINA_INLIST_GET(sd->reorder.it2));
2705 2705
2706 if (it2_prev) 2706 if (it2_prev)
2707 { 2707 {
2708 tmp = eina_inlist_find(sd->items, EINA_INLIST_GET(it2_prev)); 2708 tmp = eina_inlist_find(sd->items, EINA_INLIST_GET(it2_prev));
@@ -2726,16 +2726,16 @@ _anim_end(Elm_Gengrid_Data *sd)
2726 { 2726 {
2727 sd->items = eina_inlist_remove(sd->items, EINA_INLIST_GET(sd->reorder.it1)); 2727 sd->items = eina_inlist_remove(sd->items, EINA_INLIST_GET(sd->reorder.it1));
2728 sd->items = eina_inlist_remove(sd->items, EINA_INLIST_GET(sd->reorder.it2)); 2728 sd->items = eina_inlist_remove(sd->items, EINA_INLIST_GET(sd->reorder.it2));
2729 2729
2730 if (it1_prev) 2730 if (it1_prev)
2731 { 2731 {
2732 tmp = eina_inlist_find(sd->items, EINA_INLIST_GET(it1_prev)); 2732 tmp = eina_inlist_find(sd->items, EINA_INLIST_GET(it1_prev));
2733 sd->items = eina_inlist_append_relative(sd->items, EINA_INLIST_GET(sd->reorder.it2), 2733 sd->items = eina_inlist_append_relative(sd->items, EINA_INLIST_GET(sd->reorder.it2),
2734 tmp); 2734 tmp);
2735 } 2735 }
2736 else 2736 else
2737 sd->items = eina_inlist_prepend(sd->items, EINA_INLIST_GET(sd->reorder.it2)); 2737 sd->items = eina_inlist_prepend(sd->items, EINA_INLIST_GET(sd->reorder.it2));
2738 2738
2739 if (it2_prev) 2739 if (it2_prev)
2740 { 2740 {
2741 tmp = eina_inlist_find(sd->items, EINA_INLIST_GET(it2_prev)); 2741 tmp = eina_inlist_find(sd->items, EINA_INLIST_GET(it2_prev));
diff --git a/src/lib/elementary/elm_grid.c b/src/lib/elementary/elm_grid.c
index fcccfb06c4..a1886f6008 100644
--- a/src/lib/elementary/elm_grid.c
+++ b/src/lib/elementary/elm_grid.c
@@ -19,7 +19,7 @@ _focus_order_flush(Eo *obj)
19 Elm_Widget_Smart_Data *wpd = efl_data_scope_get(obj, ELM_WIDGET_CLASS); 19 Elm_Widget_Smart_Data *wpd = efl_data_scope_get(obj, ELM_WIDGET_CLASS);
20 Eina_List *order = evas_object_grid_children_get(wpd->resize_obj); 20 Eina_List *order = evas_object_grid_children_get(wpd->resize_obj);
21 21
22 efl_ui_focus_manager_update_order(wpd->focus.manager, obj, order); 22 efl_ui_focus_manager_calc_update_order(wpd->focus.manager, obj, order);
23} 23}
24 24
25 25
diff --git a/src/lib/elementary/elm_hover.c b/src/lib/elementary/elm_hover.c
index 322f33f9df..ccec32ecee 100644
--- a/src/lib/elementary/elm_hover.c
+++ b/src/lib/elementary/elm_hover.c
@@ -703,7 +703,7 @@ _elm_hover_elm_widget_focus_manager_factory(Eo *obj EINA_UNUSED, Elm_Hover_Data
703{ 703{
704 Efl_Ui_Focus_Manager *manager; 704 Efl_Ui_Focus_Manager *manager;
705 705
706 manager = efl_add(EFL_UI_FOCUS_MANAGER_CLASS, obj, 706 manager = efl_add(EFL_UI_FOCUS_MANAGER_CALC_CLASS, obj,
707 efl_ui_focus_manager_root_set(efl_added, root) 707 efl_ui_focus_manager_root_set(efl_added, root)
708 ); 708 );
709 709
diff --git a/src/lib/elementary/elm_menu.c b/src/lib/elementary/elm_menu.c
index a4baf34b8f..069f71dc5b 100644
--- a/src/lib/elementary/elm_menu.c
+++ b/src/lib/elementary/elm_menu.c
@@ -806,7 +806,7 @@ _elm_menu_elm_widget_focus_manager_factory(Eo *obj EINA_UNUSED, Elm_Menu_Data *p
806{ 806{
807 Efl_Ui_Focus_Manager *manager; 807 Efl_Ui_Focus_Manager *manager;
808 808
809 manager = efl_add(EFL_UI_FOCUS_MANAGER_CLASS, obj, 809 manager = efl_add(EFL_UI_FOCUS_MANAGER_CALC_CLASS, obj,
810 efl_ui_focus_manager_root_set(efl_added, root) 810 efl_ui_focus_manager_root_set(efl_added, root)
811 ); 811 );
812 812
diff --git a/src/lib/elementary/elm_scroller.c b/src/lib/elementary/elm_scroller.c
index d0225616aa..ac85d6c66e 100644
--- a/src/lib/elementary/elm_scroller.c
+++ b/src/lib/elementary/elm_scroller.c
@@ -1453,7 +1453,7 @@ _elm_scroller_elm_widget_focus_register(Eo *obj, Elm_Scroller_Data *pd EINA_UNUS
1453{ 1453{
1454 //undepended from logical or not we always reigster as full with ourself as redirect 1454 //undepended from logical or not we always reigster as full with ourself as redirect
1455 *logical_flag = EINA_TRUE; 1455 *logical_flag = EINA_TRUE;
1456 return efl_ui_focus_manager_register_logical(manager, obj, logical, obj); 1456 return efl_ui_focus_manager_calc_register_logical(manager, obj, logical, obj);
1457} 1457}
1458 1458
1459 1459
diff --git a/src/lib/elementary/elm_table.c b/src/lib/elementary/elm_table.c
index c3720e11a9..7c54b94e1a 100644
--- a/src/lib/elementary/elm_table.c
+++ b/src/lib/elementary/elm_table.c
@@ -20,7 +20,7 @@ _focus_order_flush(Eo *obj)
20 Elm_Widget_Smart_Data *wpd = efl_data_scope_get(obj, ELM_WIDGET_CLASS); 20 Elm_Widget_Smart_Data *wpd = efl_data_scope_get(obj, ELM_WIDGET_CLASS);
21 Eina_List *order = evas_object_table_children_get(wpd->resize_obj); 21 Eina_List *order = evas_object_table_children_get(wpd->resize_obj);
22 22
23 efl_ui_focus_manager_update_order(wpd->focus.manager, obj, order); 23 efl_ui_focus_manager_calc_update_order(wpd->focus.manager, obj, order);
24} 24}
25 25
26EOLIAN static Eina_Bool 26EOLIAN static Eina_Bool
diff --git a/src/lib/elementary/elm_toolbar.c b/src/lib/elementary/elm_toolbar.c
index f01d888be7..ef75fc165f 100644
--- a/src/lib/elementary/elm_toolbar.c
+++ b/src/lib/elementary/elm_toolbar.c
@@ -87,12 +87,12 @@ _item_focus_eval(Elm_Toolbar_Item_Data *pd)
87 87
88 if (want) 88 if (want)
89 { 89 {
90 efl_ui_focus_manager_register(manager, EO_OBJ(pd), widget, NULL); 90 efl_ui_focus_manager_calc_register(manager, EO_OBJ(pd), widget, NULL);
91 pd->registered = manager; 91 pd->registered = manager;
92 } 92 }
93 else 93 else
94 { 94 {
95 efl_ui_focus_manager_unregister(manager, EO_OBJ(pd)); 95 efl_ui_focus_manager_calc_unregister(manager, EO_OBJ(pd));
96 pd->registered = NULL; 96 pd->registered = NULL;
97 } 97 }
98 98
@@ -118,7 +118,7 @@ _item_focus_eval_all(Elm_Toolbar *obj, Elm_Toolbar_Data *pd)
118 order = eina_list_append(order, EO_OBJ(pd->more_item)); 118 order = eina_list_append(order, EO_OBJ(pd->more_item));
119 } 119 }
120 120
121 efl_ui_focus_manager_update_order(wpd->focus.manager, obj, order); 121 efl_ui_focus_manager_calc_update_order(wpd->focus.manager, obj, order);
122} 122}
123 123
124static int 124static int
@@ -2381,7 +2381,7 @@ _elm_toolbar_item_efl_object_destructor(Eo *eo_item, Elm_Toolbar_Item_Data *item
2381 2381
2382 if (item->registered) 2382 if (item->registered)
2383 { 2383 {
2384 efl_ui_focus_manager_unregister(item->registered, eo_item); 2384 efl_ui_focus_manager_calc_unregister(item->registered, eo_item);
2385 item->registered = NULL; 2385 item->registered = NULL;
2386 } 2386 }
2387 2387
@@ -3092,7 +3092,7 @@ EOLIAN static Eina_Bool
3092_elm_toolbar_elm_widget_focus_register(Eo *obj, Elm_Toolbar_Data *pd EINA_UNUSED, Efl_Ui_Focus_Manager *manager, Efl_Ui_Focus_Object *logical, Eina_Bool *logical_flag) 3092_elm_toolbar_elm_widget_focus_register(Eo *obj, Elm_Toolbar_Data *pd EINA_UNUSED, Efl_Ui_Focus_Manager *manager, Efl_Ui_Focus_Object *logical, Eina_Bool *logical_flag)
3093{ 3093{
3094 *logical_flag = EINA_TRUE; 3094 *logical_flag = EINA_TRUE;
3095 return efl_ui_focus_manager_register_logical(manager, obj, logical, NULL); 3095 return efl_ui_focus_manager_calc_register_logical(manager, obj, logical, NULL);
3096} 3096}
3097 3097
3098EOLIAN static Eo * 3098EOLIAN static Eo *
diff --git a/src/lib/elementary/elm_widget.c b/src/lib/elementary/elm_widget.c
index b0b515cd15..cb14afcc70 100644
--- a/src/lib/elementary/elm_widget.c
+++ b/src/lib/elementary/elm_widget.c
@@ -246,7 +246,7 @@ _focus_manager_eval(Eo *obj, Elm_Widget_Smart_Data *pd)
246 Efl_Ui_Focus_Manager *new = NULL, *old = NULL; 246 Efl_Ui_Focus_Manager *new = NULL, *old = NULL;
247 247
248 parent = elm_widget_parent_get(obj); 248 parent = elm_widget_parent_get(obj);
249 if (efl_isa(parent, EFL_UI_FOCUS_MANAGER_CLASS)) 249 if (efl_isa(parent, EFL_UI_FOCUS_MANAGER_INTERFACE))
250 { 250 {
251 new = parent; 251 new = parent;
252 } 252 }
@@ -280,9 +280,9 @@ _elm_widget_focus_register(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED,
280{ 280{
281 281
282 if (!*logical_flag) 282 if (!*logical_flag)
283 return efl_ui_focus_manager_register(manager, obj, logical, NULL); 283 return efl_ui_focus_manager_calc_register(manager, obj, logical, NULL);
284 else 284 else
285 return efl_ui_focus_manager_register_logical(manager, obj, logical, NULL); 285 return efl_ui_focus_manager_calc_register_logical(manager, obj, logical, NULL);
286} 286}
287 287
288 288
@@ -329,7 +329,7 @@ _focus_state_eval(Eo *obj, Elm_Widget_Smart_Data *pd)
329 (pd->focus.manager && should && want_full == pd->focus.logical) 329 (pd->focus.manager && should && want_full == pd->focus.logical)
330 ) 330 )
331 { 331 {
332 efl_ui_focus_manager_unregister(pd->focus.manager, obj); 332 efl_ui_focus_manager_calc_unregister(pd->focus.manager, obj);
333 pd->focus.manager = NULL; 333 pd->focus.manager = NULL;
334 pd->focus.parent = NULL; 334 pd->focus.parent = NULL;
335 } 335 }
@@ -355,7 +355,7 @@ _focus_state_eval(Eo *obj, Elm_Widget_Smart_Data *pd)
355 } 355 }
356 else if (!should && pd->focus.manager) 356 else if (!should && pd->focus.manager)
357 { 357 {
358 efl_ui_focus_manager_unregister(pd->focus.manager, obj); 358 efl_ui_focus_manager_calc_unregister(pd->focus.manager, obj);
359 pd->focus.manager = NULL; 359 pd->focus.manager = NULL;
360 pd->focus.parent = NULL; 360 pd->focus.parent = NULL;
361 } 361 }
@@ -4127,7 +4127,7 @@ _elm_widget_efl_object_dbg_info_get(Eo *eo_obj, Elm_Widget_Smart_Data *_pd EINA_
4127 } 4127 }
4128 4128
4129 //if thats a focus manager, give useful information like the border elements 4129 //if thats a focus manager, give useful information like the border elements
4130 if (efl_isa(eo_obj, EFL_UI_FOCUS_MANAGER_CLASS)) 4130 if (efl_isa(eo_obj, EFL_UI_FOCUS_MANAGER_INTERFACE))
4131 { 4131 {
4132 Efl_Dbg_Info *border; 4132 Efl_Dbg_Info *border;
4133 4133