#ifdef HAVE_CONFIG_H # include "elementary_config.h" #endif #define EFL_UI_FOCUS_OBJECT_PROTECTED #include #include "elm_priv.h" #include "efl_ui_focus_graph.h" typedef enum { Q_TOP = 1, Q_RIGHT = 2, Q_LEFT = 4, Q_BOTTOM = 8, Q_LAST = 16 } Quadrant; Quadrant q_helper[] = {Q_TOP, Q_RIGHT, Q_LEFT, Q_BOTTOM}; static inline Efl_Ui_Focus_Object* _convert(Efl_Ui_Focus_Graph_Context *ctx, Opaque_Graph_Member *member) { return *((Efl_Ui_Focus_Object**)(((char*) member) + ctx->offset_focusable)); } static inline unsigned int _distance(Eina_Rect o, Eina_Rect r2, Quadrant q) { int res = INT_MAX; if (q == Q_TOP) res = o.y - eina_rectangle_max_y(&r2.rect); else if (q == Q_LEFT) res = o.x - eina_rectangle_max_x(&r2.rect); else if (q == Q_BOTTOM) res = r2.y - eina_rectangle_max_y(&o.rect); else if (q == Q_RIGHT) res = r2.x - eina_rectangle_max_x(&o.rect); return res; } static inline Efl_Ui_Focus_Graph_Calc_Direction_Result* _result_get(Quadrant q, Efl_Ui_Focus_Graph_Calc_Result *result) { if (q == Q_TOP) return &result->top; else if (q == Q_LEFT) return &result->left; else if (q == Q_BOTTOM) return &result->bottom; else if (q == Q_RIGHT) return &result->right; else return NULL; } /* _quadrant_get return in which quadrant the elem is placed, oriented at origin All this is based on three levels lvl1: | | | Top | _____|_____|_____ | | left |clean|right _____|_____|_____ | | | Bot | | | lvl3: \ / \ Top / \ _____ / | | left |clean|right |_____| / \ / Bot \ / \ lvl3: | | L & T| Top | R & T _____|_____|_____ | | left |clean|right _____|_____|_____ | | L & B| Bot | R & B | | */ static inline void _quadrant_get(Eina_Rect origin, Eina_Rect elem, Quadrant *lvl2, Quadrant *lvl1, Quadrant *lvl3) { int dis = 0; *lvl1 = 0; *lvl2 = 0; *lvl3 = 0; if (eina_rectangle_max_y(&elem.rect) <= origin.y) { dis = origin.y - elem.y; *lvl3 |= Q_TOP; if (eina_spans_intersect(origin.x - dis, 2*dis + origin.w, elem.x, elem.w)) *lvl2 |= Q_TOP; if (eina_spans_intersect(origin.x, origin.w, elem.x, elem.w)) *lvl1 |= Q_TOP; } if (elem.y >= eina_rectangle_max_y(&origin.rect)) { dis = eina_rectangle_max_y(&elem.rect) - origin.y; *lvl3 |= Q_BOTTOM; if (eina_spans_intersect(origin.x - dis, 2*dis + origin.w, elem.x, elem.w)) *lvl2 |= Q_BOTTOM; if (eina_spans_intersect(origin.x, origin.w, elem.x, elem.w)) *lvl1 |= Q_BOTTOM; } if (elem.x >= eina_rectangle_max_x(&origin.rect)) { dis = eina_rectangle_max_x(&elem.rect) - origin.x; *lvl3 |= Q_RIGHT; if (eina_spans_intersect(origin.y - dis, 2*dis + origin.h, elem.y, elem.h)) *lvl2 |= Q_RIGHT; if (eina_spans_intersect(origin.y, origin.h, elem.y, elem.h)) *lvl1 |= Q_RIGHT; } if (eina_rectangle_max_x(&elem.rect) <= origin.x) { dis = origin.x - elem.x; *lvl3 |= Q_LEFT; if (eina_spans_intersect(origin.y - dis, 2*dis + origin.h, elem.y, elem.h)) *lvl2 |= Q_LEFT; if (eina_spans_intersect(origin.y, origin.h, elem.y, elem.h)) *lvl1 |= Q_LEFT; } } 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) { Opaque_Graph_Member *elem_obj; Eina_Rect origin, elem; for (int i = 0; i < 4; ++i) { Efl_Ui_Focus_Graph_Calc_Direction_Result *res; res = _result_get(q_helper[i], result); res->distance = INT_MAX; res->lvl = INT_MAX; res->relation = NULL; } origin = efl_ui_focus_object_focus_geometry_get(_convert(ctx, origin_obj)); //printf("=========> CALCING %p %s\n", _convert(ctx, origin_obj), efl_class_name_get(_convert(ctx, origin_obj))); EINA_ITERATOR_FOREACH(nodes, elem_obj) { Efl_Ui_Focus_Graph_Calc_Direction_Result *res; unsigned int distance; Quadrant lvl3, lvl2, lvl1; if (elem_obj == origin_obj) continue; elem = efl_ui_focus_object_focus_geometry_get(_convert(ctx, elem_obj)); if (eina_rectangle_intersection(&origin.rect, &elem.rect)) continue; _quadrant_get(origin, elem, &lvl2, &lvl1, &lvl3); for (int i = 0; i < 4; ++i) { if (q_helper[i] & lvl3) { int lvl; res = _result_get(q_helper[i], result); EINA_SAFETY_ON_NULL_GOTO(res, cont); distance = _distance(origin, elem, q_helper[i]); if (q_helper[i] & lvl1) lvl = 1; else if (q_helper[i] & lvl2) lvl = 2; else //if (q_helper[i] & lvl3) lvl = 3; if (lvl < res->lvl) { res->relation = eina_list_free(res->relation); res->relation = eina_list_append(res->relation, elem_obj); res->distance = distance; res->lvl = lvl; //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))); } else if (lvl == res->lvl && res->distance > distance) { res->relation = eina_list_free(res->relation); res->relation = eina_list_append(res->relation, elem_obj); res->distance = distance; //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))); } else if (lvl == res->lvl && res->distance >= distance) { res->relation = eina_list_append(res->relation, elem_obj); //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))); } } } continue; cont: continue; } eina_iterator_free(nodes); }