1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 #define EFL_UI_FOCUS_OBJECT_PROTECTED
5
6
7 #include <Elementary.h>
8 #include "elm_priv.h"
9 #include "efl_ui_focus_graph.h"
10
11 typedef enum {
12 Q_TOP = 1, Q_RIGHT = 2, Q_LEFT = 4, Q_BOTTOM = 8, Q_LAST = 16
13 } Quadrant;
14
15 Quadrant q_helper[] = {Q_TOP, Q_RIGHT, Q_LEFT, Q_BOTTOM};
16
17 static inline Efl_Ui_Focus_Object*
_convert(Efl_Ui_Focus_Graph_Context * ctx,Opaque_Graph_Member * member)18 _convert(Efl_Ui_Focus_Graph_Context *ctx, Opaque_Graph_Member *member)
19 {
20 return *((Efl_Ui_Focus_Object**)(((char*) member) + ctx->offset_focusable));
21 }
22
23 static inline unsigned int
_distance(Eina_Rect o,Eina_Rect r2,Quadrant q)24 _distance(Eina_Rect o, Eina_Rect r2, Quadrant q)
25 {
26 int res = INT_MAX;
27 if (q == Q_TOP)
28 res = o.y - eina_rectangle_max_y(&r2.rect);
29 else if (q == Q_LEFT)
30 res = o.x - eina_rectangle_max_x(&r2.rect);
31 else if (q == Q_BOTTOM)
32 res = r2.y - eina_rectangle_max_y(&o.rect);
33 else if (q == Q_RIGHT)
34 res = r2.x - eina_rectangle_max_x(&o.rect);
35
36 return res;
37 }
38
39 static inline Efl_Ui_Focus_Graph_Calc_Direction_Result*
_result_get(Quadrant q,Efl_Ui_Focus_Graph_Calc_Result * result)40 _result_get(Quadrant q, Efl_Ui_Focus_Graph_Calc_Result *result)
41 {
42 if (q == Q_TOP) return &result->top;
43 else if (q == Q_LEFT) return &result->left;
44 else if (q == Q_BOTTOM) return &result->bottom;
45 else if (q == Q_RIGHT) return &result->right;
46 else return NULL;
47 }
48
49 /*
50
51 _quadrant_get return in which quadrant the elem is placed, oriented at origin
52
53 All this is based on three levels
54
55 lvl1:
56 | |
57 | Top |
58 _____|_____|_____
59 | |
60 left |clean|right
61 _____|_____|_____
62 | |
63 | Bot |
64 | |
65 lvl3:
66 \ /
67 \ Top /
68 \ _____ /
69 | |
70 left |clean|right
71 |_____|
72 / \
73 / Bot \
74 / \
75
76 lvl3:
77 | |
78 L & T| Top | R & T
79 _____|_____|_____
80 | |
81 left |clean|right
82 _____|_____|_____
83 | |
84 L & B| Bot | R & B
85 | |
86
87
88 */
89
90 static inline void
_quadrant_get(Eina_Rect origin,Eina_Rect elem,Quadrant * lvl2,Quadrant * lvl1,Quadrant * lvl3)91 _quadrant_get(Eina_Rect origin, Eina_Rect elem, Quadrant *lvl2, Quadrant *lvl1, Quadrant *lvl3)
92 {
93 int dis = 0;
94
95 *lvl1 = 0;
96 *lvl2 = 0;
97 *lvl3 = 0;
98
99 if (eina_rectangle_max_y(&elem.rect) <= origin.y)
100 {
101 dis = origin.y - elem.y;
102
103 *lvl3 |= Q_TOP;
104
105 if (eina_spans_intersect(origin.x - dis, 2*dis + origin.w, elem.x, elem.w))
106 *lvl2 |= Q_TOP;
107 if (eina_spans_intersect(origin.x, origin.w, elem.x, elem.w))
108 *lvl1 |= Q_TOP;
109 }
110 if (elem.y >= eina_rectangle_max_y(&origin.rect))
111 {
112 dis = eina_rectangle_max_y(&elem.rect) - origin.y;
113
114 *lvl3 |= Q_BOTTOM;
115
116 if (eina_spans_intersect(origin.x - dis, 2*dis + origin.w, elem.x, elem.w))
117 *lvl2 |= Q_BOTTOM;
118 if (eina_spans_intersect(origin.x, origin.w, elem.x, elem.w))
119 *lvl1 |= Q_BOTTOM;
120 }
121 if (elem.x >= eina_rectangle_max_x(&origin.rect))
122 {
123 dis = eina_rectangle_max_x(&elem.rect) - origin.x;
124
125 *lvl3 |= Q_RIGHT;
126
127 if (eina_spans_intersect(origin.y - dis, 2*dis + origin.h, elem.y, elem.h))
128 *lvl2 |= Q_RIGHT;
129 if (eina_spans_intersect(origin.y, origin.h, elem.y, elem.h))
130 *lvl1 |= Q_RIGHT;
131 }
132 if (eina_rectangle_max_x(&elem.rect) <= origin.x)
133 {
134 dis = origin.x - elem.x;
135
136 *lvl3 |= Q_LEFT;
137
138 if (eina_spans_intersect(origin.y - dis, 2*dis + origin.h, elem.y, elem.h))
139 *lvl2 |= Q_LEFT;
140 if (eina_spans_intersect(origin.y, origin.h, elem.y, elem.h))
141 *lvl1 |= Q_LEFT;
142 }
143
144 }
145
146 void
efl_ui_focus_graph_calc(Efl_Ui_Focus_Graph_Context * ctx,Eina_Iterator * nodes,Opaque_Graph_Member * origin_obj,Efl_Ui_Focus_Graph_Calc_Result * result)147 efl_ui_focus_graph_calc(Efl_Ui_Focus_Graph_Context *ctx, Eina_Iterator *nodes, Opaque_Graph_Member *origin_obj, Efl_Ui_Focus_Graph_Calc_Result *result)
148 {
149 Opaque_Graph_Member *elem_obj;
150 Eina_Rect origin, elem;
151
152 for (int i = 0; i < 4; ++i)
153 {
154 Efl_Ui_Focus_Graph_Calc_Direction_Result *res;
155
156 res = _result_get(q_helper[i], result);
157
158 res->distance = INT_MAX;
159 res->lvl = INT_MAX;
160 res->relation = NULL;
161 }
162
163 origin = efl_ui_focus_object_focus_geometry_get(_convert(ctx, origin_obj));
164
165 //printf("=========> CALCING %p %s\n", _convert(ctx, origin_obj), efl_class_name_get(_convert(ctx, origin_obj)));
166
167 EINA_ITERATOR_FOREACH(nodes, elem_obj)
168 {
169 Efl_Ui_Focus_Graph_Calc_Direction_Result *res;
170 unsigned int distance;
171 Quadrant lvl3, lvl2, lvl1;
172
173 if (elem_obj == origin_obj) continue;
174
175 elem = efl_ui_focus_object_focus_geometry_get(_convert(ctx, elem_obj));
176
177 if (eina_rectangle_intersection(&origin.rect, &elem.rect)) continue;
178
179 _quadrant_get(origin, elem, &lvl2, &lvl1, &lvl3);
180
181 for (int i = 0; i < 4; ++i)
182 {
183 if (q_helper[i] & lvl3)
184 {
185 int lvl;
186 res = _result_get(q_helper[i], result);
187 EINA_SAFETY_ON_NULL_GOTO(res, cont);
188
189 distance = _distance(origin, elem, q_helper[i]);
190
191 if (q_helper[i] & lvl1)
192 lvl = 1;
193 else if (q_helper[i] & lvl2)
194 lvl = 2;
195 else //if (q_helper[i] & lvl3)
196 lvl = 3;
197
198 if (lvl < res->lvl)
199 {
200 res->relation = eina_list_free(res->relation);
201 res->relation = eina_list_append(res->relation, elem_obj);
202 res->distance = distance;
203 res->lvl = lvl;
204 //printf("=========> %p:%d LVL_DROP %d \t %d \t %p %s\n", res, i, distance, lvl, origin_obj, efl_class_name_get(_convert(ctx, elem_obj)));
205 }
206 else if (lvl == res->lvl && res->distance > distance)
207 {
208 res->relation = eina_list_free(res->relation);
209 res->relation = eina_list_append(res->relation, elem_obj);
210 res->distance = distance;
211 //printf("=========> %p:%d DIST_DROP %d \t %d \t %p %s\n", res, i, distance, lvl, origin_obj, efl_class_name_get(_convert(ctx, elem_obj)));
212
213 }
214 else if (lvl == res->lvl && res->distance >= distance)
215 {
216 res->relation = eina_list_append(res->relation, elem_obj);
217 //printf("=========> %p:%d DIST_ADD %d \t %d \t %p %s\n", res, i, distance, lvl, origin_obj, efl_class_name_get(_convert(ctx, elem_obj)));
218 }
219 }
220 }
221
222 continue;
223 cont:
224 continue;
225 }
226 eina_iterator_free(nodes);
227 }
228