228 lines
6.3 KiB
C
228 lines
6.3 KiB
C
#ifdef HAVE_CONFIG_H
|
|
# include "elementary_config.h"
|
|
#endif
|
|
#define EFL_UI_FOCUS_OBJECT_PROTECTED
|
|
|
|
|
|
#include <Elementary.h>
|
|
#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);
|
|
}
|