forked from enlightenment/efl
elm_interface_scrollable: add support for *jumping* into a scroller
Until recently we have been only registering the border elements of the graph, (so only the elements that don't have a neighboor). However this lead to the situation that a scroller that is scrolled into the middle (so not the x nor the y axis is scrolled to the max), is not accessable. Now, we register all elements that have a neighboor in the outside. The patch in the test suite is required in order to provide the correct geometry to the implementation of efl_ui_focus_manager_sub. Differential Revision: https://phab.enlightenment.org/D7360
This commit is contained in:
parent
c435cdf173
commit
a444ff743f
|
@ -1,4 +1,5 @@
|
|||
import efl_ui;
|
||||
import eina_types;
|
||||
|
||||
struct Efl.Ui.Focus.Relations {
|
||||
[[Structure holding the graph of relations between focussable objects.
|
||||
|
@ -90,6 +91,20 @@ interface Efl.Ui.Focus.Manager {
|
|||
over the border objects.]]
|
||||
}
|
||||
}
|
||||
@property viewport_elements {
|
||||
[[The list of elements which are at the border of the viewport.
|
||||
|
||||
This means one of the relations right,left or down,up are not set.
|
||||
This call flushes all changes. See @Efl.Ui.Focus.Manager.move
|
||||
]]
|
||||
get {}
|
||||
keys {
|
||||
viewport : Eina.Rect;
|
||||
}
|
||||
values {
|
||||
viewport_elements : iterator<Efl.Ui.Focus.Object>;
|
||||
}
|
||||
}
|
||||
@property root {
|
||||
[[Root node for all logical subtrees.
|
||||
|
||||
|
|
|
@ -937,8 +937,74 @@ typedef struct {
|
|||
Eina_Iterator iterator;
|
||||
Eina_Iterator *real_iterator;
|
||||
Efl_Ui_Focus_Manager *object;
|
||||
Eina_Each_Cb filter_cb;
|
||||
Eina_Rect viewport;
|
||||
Eina_Bool use_viewport;
|
||||
} Border_Elements_Iterator;
|
||||
|
||||
static Eina_Bool
|
||||
_border_filter_cb(Node *node, Border_Elements_Iterator *pd EINA_UNUSED)
|
||||
{
|
||||
for(int i = EFL_UI_FOCUS_DIRECTION_UP ;i < EFL_UI_FOCUS_DIRECTION_LAST; i++)
|
||||
{
|
||||
if (!DIRECTION_ACCESS(node, i).one_direction)
|
||||
{
|
||||
return EINA_TRUE;
|
||||
}
|
||||
}
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
eina_rectangle_real_inside(Eina_Rect rect, Eina_Rect geom)
|
||||
{
|
||||
int min_x, max_x, min_y, max_y;
|
||||
|
||||
min_x = geom.rect.x;
|
||||
min_y = geom.rect.y;
|
||||
max_x = eina_rectangle_max_x(&geom.rect);
|
||||
max_y = eina_rectangle_max_y(&geom.rect);
|
||||
|
||||
Eina_Bool inside = eina_rectangle_coords_inside(&rect.rect, min_x, min_y) &&
|
||||
eina_rectangle_coords_inside(&rect.rect, min_x, max_y) &&
|
||||
eina_rectangle_coords_inside(&rect.rect, max_x, min_y) &&
|
||||
eina_rectangle_coords_inside(&rect.rect, max_x, max_y);
|
||||
|
||||
return inside;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_viewport_filter_cb(Node *node, Border_Elements_Iterator *pd)
|
||||
{
|
||||
Node *partner;
|
||||
Eina_Rect geom;
|
||||
|
||||
if (node->type == NODE_TYPE_ONLY_LOGICAL) return EINA_FALSE;
|
||||
|
||||
geom = efl_ui_focus_object_focus_geometry_get(node->focusable);
|
||||
|
||||
if (eina_rectangle_real_inside(pd->viewport, geom))
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
Eina_List *n, *lst = G(node).directions[i].one_direction;
|
||||
|
||||
if (!lst)
|
||||
return EINA_TRUE;
|
||||
|
||||
EINA_LIST_FOREACH(lst, n, partner)
|
||||
{
|
||||
Eina_Rect partner_geom;
|
||||
partner_geom = efl_ui_focus_object_focus_geometry_get(partner->focusable);
|
||||
if (!eina_rectangle_real_inside(pd->viewport, partner_geom))
|
||||
return EINA_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
|
||||
static Eina_Bool
|
||||
_iterator_next(Border_Elements_Iterator *it, void **data)
|
||||
{
|
||||
|
@ -946,17 +1012,21 @@ _iterator_next(Border_Elements_Iterator *it, void **data)
|
|||
|
||||
EINA_ITERATOR_FOREACH(it->real_iterator, node)
|
||||
{
|
||||
Eina_Bool use = EINA_FALSE;
|
||||
if (node->type == NODE_TYPE_ONLY_LOGICAL) continue;
|
||||
|
||||
for(int i = EFL_UI_FOCUS_DIRECTION_UP ;i < EFL_UI_FOCUS_DIRECTION_LAST; i++)
|
||||
if (!it->use_viewport)
|
||||
use = _border_filter_cb(node, it);
|
||||
else
|
||||
use = _viewport_filter_cb(node, it);
|
||||
|
||||
if (use)
|
||||
{
|
||||
if (!DIRECTION_ACCESS(node, i).one_direction)
|
||||
{
|
||||
*data = node->focusable;
|
||||
return EINA_TRUE;
|
||||
}
|
||||
*data = node->focusable;
|
||||
return EINA_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
|
@ -987,8 +1057,8 @@ _prepare_node(Node *root)
|
|||
}
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Iterator*
|
||||
_efl_ui_focus_manager_calc_efl_ui_focus_manager_border_elements_get(const Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd)
|
||||
static Border_Elements_Iterator*
|
||||
_elements_iterator_new(const Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd)
|
||||
{
|
||||
Border_Elements_Iterator *it;
|
||||
|
||||
|
@ -1009,6 +1079,23 @@ _efl_ui_focus_manager_calc_efl_ui_focus_manager_border_elements_get(const Eo *ob
|
|||
it->iterator.free = FUNC_ITERATOR_FREE(_iterator_free);
|
||||
it->object = (Eo *)obj;
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Iterator*
|
||||
_efl_ui_focus_manager_calc_efl_ui_focus_manager_border_elements_get(const Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd)
|
||||
{
|
||||
return (Eina_Iterator*) _elements_iterator_new(obj, pd);
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Iterator*
|
||||
_efl_ui_focus_manager_calc_efl_ui_focus_manager_viewport_elements_get(const Eo *obj, Efl_Ui_Focus_Manager_Calc_Data *pd, Eina_Rect viewport)
|
||||
{
|
||||
Border_Elements_Iterator *it = _elements_iterator_new(obj, pd);
|
||||
|
||||
it->use_viewport = EINA_TRUE;
|
||||
it->viewport = viewport;
|
||||
|
||||
return (Eina_Iterator*) it;
|
||||
}
|
||||
|
||||
|
|
|
@ -95,6 +95,7 @@ class Efl.Ui.Focus.Manager_Calc (Efl.Object, Efl.Ui.Focus.Manager) {
|
|||
Efl.Ui.Focus.Manager.manager_focus {get; set;}
|
||||
Efl.Ui.Focus.Manager.redirect {set; get;}
|
||||
Efl.Ui.Focus.Manager.border_elements {get;}
|
||||
Efl.Ui.Focus.Manager.viewport_elements {get;}
|
||||
Efl.Ui.Focus.Manager.root {set; get;}
|
||||
Efl.Ui.Focus.Manager.request_subchild;
|
||||
Efl.Ui.Focus.Manager.fetch;
|
||||
|
|
|
@ -141,6 +141,15 @@ _efl_ui_focus_manager_root_focus_efl_ui_focus_manager_border_elements_get(const
|
|||
return efl_ui_focus_manager_border_elements_get(efl_super(obj, MY_CLASS));
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Iterator *
|
||||
_efl_ui_focus_manager_root_focus_efl_ui_focus_manager_viewport_elements_get(const Eo *obj, Efl_Ui_Focus_Manager_Root_Focus_Data *pd, Eina_Rect viewport)
|
||||
{
|
||||
if (pd->rect_registered)
|
||||
return eina_list_iterator_new(pd->iterator_list);
|
||||
|
||||
return efl_ui_focus_manager_border_elements_get(efl_super(obj, MY_CLASS));
|
||||
}
|
||||
|
||||
EOLIAN static Efl_Ui_Focus_Object*
|
||||
_efl_ui_focus_manager_root_focus_efl_ui_focus_manager_request_move(Eo *obj, Efl_Ui_Focus_Manager_Root_Focus_Data *pd, Efl_Ui_Focus_Direction direction, Efl_Ui_Focus_Object *child, Eina_Bool logical)
|
||||
{
|
||||
|
|
|
@ -20,6 +20,7 @@ class Efl.Ui.Focus.Manager_Root_Focus(Efl.Ui.Focus.Manager_Calc) {
|
|||
Efl.Ui.Focus.Manager.fetch;
|
||||
Efl.Ui.Focus.Manager.logical_end;
|
||||
Efl.Ui.Focus.Manager.border_elements {get;}
|
||||
Efl.Ui.Focus.Manager.viewport_elements {get;}
|
||||
Efl.Ui.Focus.Manager.request_move;
|
||||
Efl.Ui.Focus.Manager.move;
|
||||
Efl.Object.constructor;
|
||||
|
|
|
@ -53,7 +53,7 @@ _border_flush(Eo *obj, Efl_Ui_Focus_Manager_Sub_Data *pd)
|
|||
|
||||
manager = efl_ui_focus_object_focus_manager_get(obj);
|
||||
logical = obj;
|
||||
borders = efl_ui_focus_manager_border_elements_get(obj);
|
||||
borders = efl_ui_focus_manager_viewport_elements_get(obj, efl_gfx_entity_geometry_get(obj));
|
||||
|
||||
selection = NULL;
|
||||
EINA_ITERATOR_FOREACH(borders, node)
|
||||
|
|
|
@ -103,6 +103,10 @@ _elm_pan_update(Elm_Pan_Smart_Data *psd)
|
|||
efl_ui_focus_manager_dirty_logic_freeze(manager);
|
||||
evas_object_move(psd->content, psd->x - psd->px, psd->y - psd->py);
|
||||
efl_ui_focus_manager_dirty_logic_unfreeze(manager);
|
||||
//XXX: hack, right now there is no api in efl_ui_focus_manager_sub.eo to mark it dirty
|
||||
// If we have moved the content, then emit this event, in order to ensure that the focus_manager_sub
|
||||
// logic tries to fetch the viewport again
|
||||
efl_event_callback_call(manager, EFL_UI_FOCUS_MANAGER_EVENT_COORDS_DIRTY, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1074,6 +1074,38 @@ EFL_START_TEST(test_events_child_focus)
|
|||
}
|
||||
EFL_END_TEST
|
||||
|
||||
|
||||
EFL_START_TEST(viewport_check)
|
||||
{
|
||||
Efl_Ui_Focus_Manager *m;
|
||||
Efl_Ui_Focus_Object *middle, *east, *west, *north, *south, *root;
|
||||
Eina_List *list = NULL;
|
||||
Eina_Iterator *iter;
|
||||
Efl_Ui_Focus_Object *obj;
|
||||
|
||||
elm_focus_test_setup_cross(&middle, &south, &north, &east, &west);
|
||||
|
||||
m = elm_focus_test_manager_new(&root);
|
||||
efl_ui_focus_manager_calc_register(m, middle, root, NULL);
|
||||
efl_ui_focus_manager_calc_register(m, south, root, NULL);
|
||||
efl_ui_focus_manager_calc_register(m, north, root, NULL);
|
||||
efl_ui_focus_manager_calc_register(m, east, root, NULL);
|
||||
efl_ui_focus_manager_calc_register(m, west, root, NULL);
|
||||
|
||||
iter = efl_ui_focus_manager_viewport_elements_get(m, EINA_RECT(80, 0, 100, 100));
|
||||
|
||||
EINA_ITERATOR_FOREACH(iter, obj)
|
||||
{
|
||||
list = eina_list_append(list, obj);
|
||||
}
|
||||
|
||||
eina_iterator_free(iter);
|
||||
|
||||
ck_assert(eina_list_count(list) == 1);
|
||||
ck_assert_ptr_eq(eina_list_data_get(list), east);
|
||||
}
|
||||
EFL_END_TEST
|
||||
|
||||
void elm_test_focus(TCase *tc)
|
||||
{
|
||||
tcase_add_test(tc, focus_register_twice);
|
||||
|
@ -1105,4 +1137,5 @@ void elm_test_focus(TCase *tc)
|
|||
tcase_add_test(tc, test_request_move);
|
||||
tcase_add_test(tc, redirect_unregister_entrypoint);
|
||||
tcase_add_test(tc, test_events_child_focus);
|
||||
tcase_add_test(tc, viewport_check);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,11 @@ typedef struct {
|
|||
|
||||
} Focus_Test_Sub_Main_Data;
|
||||
|
||||
EOLIAN static Eina_Rect
|
||||
_focus_test_sub_main_efl_gfx_entity_geometry_get(const Eo *obj, Focus_Test_Sub_Main_Data *pd)
|
||||
{
|
||||
return EINA_RECT(-10, -10, 40, 40);
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Rect
|
||||
_focus_test_sub_main_efl_ui_focus_object_focus_geometry_get(const Eo *obj EINA_UNUSED, Focus_Test_Sub_Main_Data *pd EINA_UNUSED)
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
class Focus.Test.Sub.Main
|
||||
extends Efl.Object
|
||||
implements Efl.Ui.Focus.Object, Efl.Ui.Focus.Manager_Sub
|
||||
implements Efl.Ui.Focus.Object, Efl.Ui.Focus.Manager_Sub, Efl.Gfx.Entity
|
||||
{
|
||||
implements {
|
||||
Efl.Ui.Focus.Object.focus_manager { get; }
|
||||
Efl.Ui.Focus.Object.focus_parent { get; }
|
||||
Efl.Ui.Focus.Object.focus_geometry { get; }
|
||||
Efl.Gfx.Entity.geometry {get;}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue