forked from enlightenment/efl
efl_ui_focus_manager_calc: implement better relation calculation
The new calculation mechanism does not only look into the exact directions up,right,down,left of a node, it also now checks the sectors, bound by: x < node.x, x > node.max_x, y < node.y, y > node.max_y. ref T6453
This commit is contained in:
parent
22c7fb86d9
commit
87cc19b94d
|
@ -410,10 +410,77 @@ _calculate_node_stage1(Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Object *
|
|||
|
||||
}
|
||||
|
||||
static inline Eina_Position2D
|
||||
_relative_position_rects(Eina_Rect *a, Eina_Rect *b)
|
||||
{
|
||||
Eina_Position2D a_pos = {a->rect.x + a->rect.w/2, a->rect.y + a->rect.h/2};
|
||||
Eina_Position2D b_pos = {b->rect.x + b->rect.w/2, b->rect.y + b->rect.h/2};
|
||||
|
||||
return (Eina_Position2D){b_pos.x - a_pos.x, b_pos.y - b_pos.y};
|
||||
}
|
||||
|
||||
static inline Eina_Rectangle_Outside
|
||||
_direction_to_outside(Efl_Ui_Focus_Direction direction)
|
||||
{
|
||||
if (direction == EFL_UI_FOCUS_DIRECTION_RIGHT) return EINA_RECTANGLE_OUTSIDE_RIGHT;
|
||||
if (direction == EFL_UI_FOCUS_DIRECTION_LEFT) return EINA_RECTANGLE_OUTSIDE_LEFT;
|
||||
if (direction == EFL_UI_FOCUS_DIRECTION_DOWN) return EINA_RECTANGLE_OUTSIDE_BOTTOM;
|
||||
if (direction == EFL_UI_FOCUS_DIRECTION_UP) return EINA_RECTANGLE_OUTSIDE_TOP;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_calculate_node_stage2(Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Object *node, Eina_Rect rect, Efl_Ui_Focus_Direction direction, Eina_List **lst)
|
||||
{
|
||||
Efl_Ui_Focus_Object *op;
|
||||
Eina_Iterator *nodes;
|
||||
int min_distance = 0;
|
||||
Node *n;
|
||||
|
||||
nodes = eina_hash_iterator_data_new(pd->node_hash);
|
||||
|
||||
EINA_ITERATOR_FOREACH(nodes, n)
|
||||
{
|
||||
Eina_Rectangle_Outside outside, outside_dir;
|
||||
Eina_Position2D pos;
|
||||
int distance;
|
||||
Eina_Rect op_rect;
|
||||
|
||||
op = n->focusable;
|
||||
|
||||
if (op == node) continue;
|
||||
if (n->type == NODE_TYPE_ONLY_LOGICAL) continue;
|
||||
|
||||
op_rect = efl_ui_focus_object_focus_geometry_get(op);
|
||||
outside = eina_rectangle_outside_position(&rect.rect, &op_rect.rect);
|
||||
outside_dir = _direction_to_outside(direction);
|
||||
//calculate relative position of the nodes
|
||||
pos = _relative_position_rects(&rect, &op_rect);
|
||||
//calculate distance
|
||||
distance = sqrt(powerof2(pos.x) + powerof2(pos.y));
|
||||
|
||||
if (outside & outside_dir)
|
||||
{
|
||||
if (min_distance == 0 || min_distance > distance)
|
||||
{
|
||||
min_distance = distance;
|
||||
*lst = eina_list_free(*lst);
|
||||
*lst = eina_list_append(*lst, op);
|
||||
}
|
||||
else if (min_distance == distance)
|
||||
{
|
||||
*lst = eina_list_append(*lst, op);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_calculate_node(Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Object *node, Dimension dim, Eina_List **pos, Eina_List **neg)
|
||||
{
|
||||
Eina_Rect rect;
|
||||
Efl_Ui_Focus_Direction direction;
|
||||
|
||||
rect = efl_ui_focus_object_focus_geometry_get(node);
|
||||
|
||||
|
@ -421,6 +488,25 @@ _calculate_node(Efl_Ui_Focus_Manager_Calc_Data *pd, Efl_Ui_Focus_Object *node, D
|
|||
*neg = NULL;
|
||||
|
||||
_calculate_node_stage1(pd, node, rect, dim, pos, neg);
|
||||
|
||||
if (!*pos)
|
||||
{
|
||||
if (dim == DIMENSION_Y)
|
||||
direction = EFL_UI_FOCUS_DIRECTION_DOWN;
|
||||
else
|
||||
direction = EFL_UI_FOCUS_DIRECTION_RIGHT;
|
||||
_calculate_node_stage2(pd, node, rect, direction, pos);
|
||||
}
|
||||
|
||||
if (!*neg)
|
||||
{
|
||||
if (dim == DIMENSION_Y)
|
||||
direction = EFL_UI_FOCUS_DIRECTION_UP;
|
||||
else
|
||||
direction = EFL_UI_FOCUS_DIRECTION_LEFT;
|
||||
|
||||
_calculate_node_stage2(pd, node, rect, direction, neg);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CALC_DEBUG
|
||||
|
|
|
@ -73,10 +73,10 @@ START_TEST(pos_check)
|
|||
efl_ui_focus_manager_focus_set(m, obj);
|
||||
|
||||
CHECK(middle, east, west, north, south)
|
||||
CHECK(east, NULL, middle, NULL, NULL)
|
||||
CHECK(west, middle, NULL, NULL, NULL)
|
||||
CHECK(north, NULL, NULL, NULL, middle)
|
||||
CHECK(south, NULL, NULL, middle, NULL)
|
||||
CHECK(east, NULL, middle, north, south)
|
||||
CHECK(west, middle, NULL, north, south)
|
||||
CHECK(north, east, west, NULL, middle)
|
||||
CHECK(south, east, west, middle, NULL)
|
||||
|
||||
efl_del(middle);
|
||||
efl_del(south);
|
||||
|
@ -88,6 +88,78 @@ START_TEST(pos_check)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
static Eina_Bool
|
||||
_equal_set(Eina_List *elems, Efl_Ui_Focus_Object *lst[])
|
||||
{
|
||||
unsigned int i = 0;
|
||||
|
||||
for (i = 0; lst[i]; ++i)
|
||||
{
|
||||
Eina_Bool found = EINA_FALSE;
|
||||
Eina_List *n;
|
||||
Efl_Ui_Focus_Object *elem;
|
||||
|
||||
EINA_LIST_FOREACH(elems, n, elem)
|
||||
{
|
||||
if (lst[i] != elem) continue;
|
||||
|
||||
found = EINA_TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) return EINA_FALSE;
|
||||
}
|
||||
|
||||
if (eina_list_count(elems) != i) return EINA_FALSE;
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
START_TEST(pos_check2)
|
||||
{
|
||||
Efl_Ui_Focus_Manager *m;
|
||||
Efl_Ui_Focus_Relations *rel;
|
||||
Efl_Ui_Focus_Object *root, *middle, *north_east, *north_west, *south_east, *south_west;
|
||||
|
||||
elm_init(1, NULL);
|
||||
|
||||
middle = elm_focus_test_object_new("middle", 40, 40, 5, 5);
|
||||
|
||||
north_east = elm_focus_test_object_new("north_east", 60, 20, 5, 5);
|
||||
north_west = elm_focus_test_object_new("north_west", 20, 20, 5, 5);
|
||||
south_east = elm_focus_test_object_new("south_east", 60, 60, 5, 5);
|
||||
south_west = elm_focus_test_object_new("south_west", 20, 60, 5, 5);
|
||||
|
||||
m = elm_focus_test_manager_new(&root);
|
||||
efl_ui_focus_manager_calc_register(m, middle, root, NULL);
|
||||
efl_ui_focus_manager_calc_register(m, north_east, root, NULL);
|
||||
efl_ui_focus_manager_calc_register(m, north_west, root, NULL);
|
||||
efl_ui_focus_manager_calc_register(m, south_east, root, NULL);
|
||||
efl_ui_focus_manager_calc_register(m, south_west, root, NULL);
|
||||
|
||||
rel = efl_ui_focus_manager_fetch(m, middle);
|
||||
|
||||
#define ck_assert_set_eq(set, ...) \
|
||||
{ \
|
||||
Efl_Ui_Focus_Object *tmp[] = { __VA_ARGS__ }; \
|
||||
ck_assert_int_eq(_equal_set(set, tmp), EINA_TRUE); \
|
||||
}
|
||||
|
||||
ck_assert_set_eq(rel->left, north_west, south_west, NULL);
|
||||
ck_assert_set_eq(rel->right, north_east, south_east, NULL);
|
||||
ck_assert_set_eq(rel->top, north_west, north_east, NULL);
|
||||
ck_assert_set_eq(rel->down, south_west, south_east, NULL);
|
||||
|
||||
#undef ck_assert_set_eq
|
||||
|
||||
efl_del(middle);
|
||||
efl_del(north_east);
|
||||
efl_del(north_west);
|
||||
efl_del(south_east);
|
||||
efl_del(south_west);
|
||||
|
||||
elm_shutdown();
|
||||
}
|
||||
END_TEST
|
||||
START_TEST(redirect)
|
||||
{
|
||||
elm_init(1, NULL);
|
||||
|
@ -539,6 +611,7 @@ void elm_test_focus(TCase *tc)
|
|||
tcase_add_test(tc, focus_register_twice);
|
||||
tcase_add_test(tc, focus_unregister_twice);
|
||||
tcase_add_test(tc, pos_check);
|
||||
tcase_add_test(tc, pos_check2);
|
||||
tcase_add_test(tc, redirect);
|
||||
tcase_add_test(tc, border_check);
|
||||
tcase_add_test(tc, finalize_check);
|
||||
|
|
Loading…
Reference in New Issue