elm: introduce efl_ui_focus_layer

what it does is described in the mixin

this commit refactors inwin hover popup ctxpopup to use that behaviour.
Since it should do exactly that.
This commit is contained in:
Marcel Hollerbach 2017-09-25 18:07:54 +02:00
parent ac18f7fe04
commit 6ba107b899
12 changed files with 117 additions and 274 deletions

View File

@ -147,6 +147,8 @@ elm_public_eolian_files = \
# Private classes (not exposed or shipped)
elm_private_eolian_files = \
lib/elementary/efl_ui_internal_text_interactive.eo \
lib/elementary/efl_ui_focus_layer.eo \
lib/elementary/efl_ui_win_part.eo \
tests/elementary/focus_test.eo \
tests/elementary/focus_test_sub_main.eo \
$(NULL)
@ -700,6 +702,7 @@ lib_elementary_libelementary_la_SOURCES = \
lib/elementary/efl_ui_focus_object.c \
lib/elementary/efl_ui_focus_manager_root_focus.c \
lib/elementary/efl_ui_textpath.c \
lib/elementary/efl_ui_focus_layer.c \
$(NULL)

View File

@ -0,0 +1,90 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#include <Elementary.h>
#include "elm_priv.h"
#include "efl_ui_focus_layer.eo.h"
#define MY_CLASS EFL_UI_FOCUS_LAYER_MIXIN
typedef struct {
Efl_Ui_Focus_Manager *registered_manager;
Eina_Bool registered;
Efl_Ui_Focus_Manager *manager;
} Efl_Ui_Focus_Layer_Data;
EOLIAN static Efl_Ui_Focus_Manager*
_efl_ui_focus_layer_elm_widget_focus_manager_create(Eo *obj, Efl_Ui_Focus_Layer_Data *pd EINA_UNUSED, Efl_Ui_Focus_Object *root)
{
return efl_add(EFL_UI_FOCUS_MANAGER_ROOT_FOCUS_CLASS, obj, efl_ui_focus_manager_root_set(efl_added, root));
}
EOLIAN static void
_efl_ui_focus_layer_efl_gfx_visible_set(Eo *obj, Efl_Ui_Focus_Layer_Data *pd, Eina_Bool v)
{
efl_gfx_visible_set(efl_super(obj, MY_CLASS), v);
if (v && !pd->registered)
{
pd->registered_manager = elm_widget_top_get(obj);
efl_ui_focus_manager_redirect_set(pd->registered_manager, obj);
efl_ui_focus_manager_focus_set(pd->manager, obj);
pd->registered = EINA_TRUE;
}
else if (!v && pd->registered)
{
efl_ui_focus_manager_redirect_set(pd->registered_manager, NULL);
pd->registered = EINA_FALSE;
}
}
EOLIAN static Efl_Ui_Focus_Object*
_efl_ui_focus_layer_efl_ui_focus_manager_move(Eo *obj, Efl_Ui_Focus_Layer_Data *pd, Efl_Ui_Focus_Direction direction)
{
Eo *ret = efl_ui_focus_manager_move(pd->manager, direction);
if (ret)
return ret;
if ((direction == EFL_UI_FOCUS_DIRECTION_PREV) || (direction == EFL_UI_FOCUS_DIRECTION_NEXT))
efl_ui_focus_manager_focus_set(pd->manager, obj);
return efl_ui_focus_manager_focus_get(obj);
}
EOLIAN static void
_efl_ui_focus_layer_efl_object_destructor(Eo *obj, Efl_Ui_Focus_Layer_Data *pd)
{
if (pd->registered)
{
efl_ui_focus_manager_redirect_set(pd->registered_manager, NULL);
pd->registered = EINA_FALSE;
}
efl_destructor(efl_super(obj, MY_CLASS));
}
EOLIAN static Efl_Ui_Focus_Manager*
_efl_ui_focus_layer_efl_ui_focus_user_manager_get(Eo *obj, Efl_Ui_Focus_Layer_Data *pd)
{
return elm_widget_top_get(obj);
}
EOLIAN static Eina_Bool
_efl_ui_focus_layer_elm_widget_focus_state_apply(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Layer_Data *pd EINA_UNUSED, Elm_Widget_Focus_State current_state EINA_UNUSED, Elm_Widget_Focus_State *configured_state EINA_UNUSED, Elm_Widget *redirect EINA_UNUSED)
{
return EINA_FALSE;
}
EOLIAN static Efl_Object*
_efl_ui_focus_layer_efl_object_constructor(Eo *obj, Efl_Ui_Focus_Layer_Data *pd)
{
pd->manager = elm_obj_widget_focus_manager_create(obj, obj);
efl_composite_attach(obj, pd->manager);
return efl_constructor(efl_super(obj, MY_CLASS));
}
#include "efl_ui_focus_layer.eo.c"

View File

@ -0,0 +1,17 @@
mixin Efl.Ui.Focus.Layer (Efl.Interface, Elm.Widget, Efl.Gfx, Efl.Ui.Focus.Manager) {
[[This defines the inheriting widget as focus layer
A focus layer is a layer that will, for the time of existance or visibility, be the upper most layer that gets input, and handles all focus related events, its NOT possible to escape this layer with focus movement.
Once the object is hidden or destructed the focus will go back to the mainwindow, where it has been before.
]]
implements {
Elm.Widget.focus_manager_create;
Elm.Widget.focus_state_apply;
Efl.Gfx.visible {set;}
Efl.Ui.Focus.Manager.move;
Efl.Ui.Focus.User.manager { get; }
Efl.Object.constructor;
Efl.Object.destructor;
}
}

View File

@ -38,11 +38,9 @@ static const Evas_Smart_Cb_Description _smart_callbacks[] = {
};
#undef ELM_PRIV_CTXPOPUP_SIGNALS
static Eina_Bool _key_action_move(Evas_Object *obj, const char *params);
static Eina_Bool _key_action_escape(Evas_Object *obj, const char *params);
static const Elm_Action key_actions[] = {
{"move", _key_action_move},
{"escape", _key_action_escape},
{NULL, NULL}
};
@ -61,81 +59,6 @@ _elm_ctxpopup_efl_ui_translatable_translation_update(Eo *obj, Elm_Ctxpopup_Data
efl_ui_translatable_translation_update(efl_super(obj, MY_CLASS));
}
EOLIAN static Eina_Bool
_elm_ctxpopup_elm_widget_focus_next_manager_is(Eo *obj EINA_UNUSED, Elm_Ctxpopup_Data *_pd EINA_UNUSED)
{
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_elm_ctxpopup_elm_widget_focus_direction_manager_is(Eo *obj EINA_UNUSED, Elm_Ctxpopup_Data *_pd EINA_UNUSED)
{
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_elm_ctxpopup_elm_widget_focus_next(Eo *obj EINA_UNUSED, Elm_Ctxpopup_Data *sd, Elm_Focus_Direction dir, Evas_Object **next, Elm_Object_Item **next_item)
{
if (!sd)
return EINA_FALSE;
if (!elm_obj_widget_focus_next_get(sd->box, dir, next, next_item))
{
elm_obj_widget_focused_object_clear(sd->box);
elm_obj_widget_focus_next_get(sd->box, dir, next, next_item);
}
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_elm_ctxpopup_elm_widget_focus_direction(Eo *obj EINA_UNUSED, Elm_Ctxpopup_Data *sd, const Evas_Object *base, double degree, Evas_Object **direction, Elm_Object_Item **direction_item, double *weight)
{
Eina_Bool int_ret;
Eina_List *l = NULL;
void *(*list_data_get)(const Eina_List *list);
if (!sd)
return EINA_FALSE;
list_data_get = eina_list_data_get;
l = eina_list_append(l, sd->box);
int_ret = elm_widget_focus_list_direction_get
(obj, base, l, list_data_get, degree, direction, direction_item, weight);
eina_list_free(l);
return int_ret;
}
static Eina_Bool
_key_action_move(Evas_Object *obj, const char *params)
{
ELM_CTXPOPUP_DATA_GET(obj, sd);
const char *dir = params;
if (!sd->box) return EINA_FALSE;
_elm_widget_focus_auto_show(obj);
if (!strcmp(dir, "previous"))
elm_obj_widget_focus_cycle(sd->box, ELM_FOCUS_PREVIOUS);
else if (!strcmp(dir, "next"))
elm_obj_widget_focus_cycle(sd->box, ELM_FOCUS_NEXT);
else if (!strcmp(dir, "left"))
elm_obj_widget_focus_cycle(sd->box, ELM_FOCUS_LEFT);
else if (!strcmp(dir, "right"))
elm_obj_widget_focus_cycle(sd->box, ELM_FOCUS_RIGHT);
else if (!strcmp(dir, "up"))
elm_obj_widget_focus_cycle(sd->box, ELM_FOCUS_UP);
else if (!strcmp(dir, "down"))
elm_obj_widget_focus_cycle(sd->box, ELM_FOCUS_DOWN);
else return EINA_FALSE;
return EINA_TRUE;
}
static Eina_Bool
_key_action_escape(Evas_Object *obj, const char *params EINA_UNUSED)
{
@ -1608,12 +1531,6 @@ _elm_ctxpopup_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNU
{
static Elm_Atspi_Action atspi_actions[] = {
{ "escape", "escape", NULL, _key_action_escape},
{ "move,previous", "move", "previous", _key_action_move},
{ "move,next", "move", "next", _key_action_move},
{ "move,left", "move", "left", _key_action_move},
{ "move,right", "move", "right", _key_action_move},
{ "move,up", "move", "up", _key_action_move},
{ "move,down", "move", "down", _key_action_move},
{ NULL, NULL, NULL, NULL }
};
return &atspi_actions[0];

View File

@ -45,7 +45,6 @@ static const Evas_Smart_Cb_Description _smart_callbacks[] = {
{NULL, NULL}
};
static Eina_Bool _key_action_move(Evas_Object *obj, const char *params);
static Eina_Bool _key_action_escape(Evas_Object *obj, const char *params);
static void _parent_geom_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED);
static void _block_clicked_cb(void *data, const Efl_Event *event);
@ -54,7 +53,6 @@ static void _timeout_cb(void *data, const Efl_Event *event);
static void _hide_effect_finished_cb(void *data, const Efl_Event *event);
static const Elm_Action key_actions[] = {
{"move", _key_action_move},
{"escape", _key_action_escape},
{NULL, NULL}
};
@ -1394,106 +1392,6 @@ err:
return NULL;
}
EOLIAN static Eina_Bool
_elm_popup_elm_widget_focus_next_manager_is(Eo *obj EINA_UNUSED, Elm_Popup_Data *_pd EINA_UNUSED)
{
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_elm_popup_elm_widget_focus_next(Eo *obj EINA_UNUSED, Elm_Popup_Data *sd, Elm_Focus_Direction dir, Evas_Object **next, Elm_Object_Item **next_item)
{
Evas_Object *ao;
Eina_List *items = NULL;
Eina_Iterator *base_it;
/* access */
if (_elm_config->access_mode)
{
if (sd->title_text)
{
ao = _access_object_get(obj, ACCESS_TITLE_PART);
items = eina_list_append(items, ao);
}
ao = _access_object_get(obj, ACCESS_BODY_PART);
if (ao) items = eina_list_append(items, ao);
}
base_it = efl_content_iterate(sd->main_layout);
EINA_ITERATOR_FOREACH(base_it, ao)
if (ao) items = eina_list_append(items, ao);
eina_iterator_free(base_it);
if (!elm_widget_focus_list_next_get(sd->main_layout, items, eina_list_data_get, dir, next, next_item))
*next = sd->main_layout;
eina_list_free(items);
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_elm_popup_elm_widget_focus_direction_manager_is(Eo *obj EINA_UNUSED, Elm_Popup_Data *_pd EINA_UNUSED)
{
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_elm_popup_elm_widget_focus_direction(Eo *obj EINA_UNUSED, Elm_Popup_Data *sd, const Evas_Object *base, double degree, Evas_Object **direction, Elm_Object_Item **direction_item, double *weight)
{
Evas_Object *ao;
Eina_List *items = NULL;
Eina_Iterator *base_it;
/* access */
if (_elm_config->access_mode)
{
if (sd->title_text)
{
ao = _access_object_get(obj, ACCESS_TITLE_PART);
items = eina_list_append(items, ao);
}
ao = _access_object_get(obj, ACCESS_BODY_PART);
if (ao) items = eina_list_append(items, ao);
}
base_it = efl_content_iterate(sd->main_layout);
EINA_ITERATOR_FOREACH(base_it, ao)
if (ao) items = eina_list_append(items, ao);
eina_iterator_free(base_it);
elm_widget_focus_list_direction_get
(sd->main_layout, base, items, eina_list_data_get, degree, direction, direction_item, weight);
eina_list_free(items);
return EINA_TRUE;
}
static Eina_Bool
_key_action_move(Evas_Object *obj, const char *params)
{
const char *dir = params;
_elm_widget_focus_auto_show(obj);
if (!strcmp(dir, "previous"))
elm_obj_widget_focus_cycle(obj, ELM_FOCUS_PREVIOUS);
else if (!strcmp(dir, "next"))
elm_obj_widget_focus_cycle(obj, ELM_FOCUS_NEXT);
else if (!strcmp(dir, "left"))
elm_obj_widget_focus_cycle(obj, ELM_FOCUS_LEFT);
else if (!strcmp(dir, "right"))
elm_obj_widget_focus_cycle(obj, ELM_FOCUS_RIGHT);
else if (!strcmp(dir, "up"))
elm_obj_widget_focus_cycle(obj, ELM_FOCUS_UP);
else if (!strcmp(dir, "down"))
elm_obj_widget_focus_cycle(obj, ELM_FOCUS_DOWN);
else return EINA_FALSE;
return EINA_TRUE;
}
static Eina_Bool
_key_action_escape(Evas_Object *obj, const char *params EINA_UNUSED)
{

View File

@ -8,7 +8,7 @@ enum Elm.Ctxpopup.Direction
unknown [[Ctxpopup does not determine it's direction yet.]]
}
class Elm.Ctxpopup (Efl.Ui.Layout, Elm.Interface.Atspi_Widget_Action,
class Elm.Ctxpopup (Efl.Ui.Layout, Efl.Ui.Focus.Layer, Elm.Interface.Atspi_Widget_Action,
Efl.Ui.Menu)
{
[[Elementary context popup class]]
@ -202,10 +202,6 @@ class Elm.Ctxpopup (Efl.Ui.Layout, Elm.Interface.Atspi_Widget_Action,
class.constructor;
Efl.Object.constructor;
Elm.Widget.widget_parent { set; }
Elm.Widget.focus_direction;
Elm.Widget.focus_direction_manager_is;
Elm.Widget.focus_next_manager_is;
Elm.Widget.focus_next;
Elm.Widget.on_disabled_update;
Elm.Widget.widget_sub_object_add;
Efl.Ui.Translatable.translation_update;

View File

@ -698,24 +698,6 @@ elm_hover_add(Evas_Object *parent)
return efl_add(MY_CLASS, parent, efl_canvas_object_legacy_ctor(efl_added));
}
EOLIAN static Efl_Ui_Focus_Manager*
_elm_hover_elm_widget_focus_manager_create(Eo *obj EINA_UNUSED, Elm_Hover_Data *pd EINA_UNUSED, Efl_Ui_Focus_Object *root)
{
Efl_Ui_Focus_Manager *manager;
manager = efl_add(EFL_UI_FOCUS_MANAGER_CALC_CLASS, obj,
efl_ui_focus_manager_root_set(efl_added, root)
);
return manager;
}
EOLIAN static Eina_Bool
_elm_hover_elm_widget_focus_state_apply(Eo *obj EINA_UNUSED, Elm_Hover_Data *pd EINA_UNUSED, Elm_Widget_Focus_State current_state EINA_UNUSED, Elm_Widget_Focus_State *configured_state EINA_UNUSED, Elm_Widget *redirect EINA_UNUSED)
{
return EINA_TRUE;
}
EOLIAN static Eo *
_elm_hover_efl_object_constructor(Eo *obj, Elm_Hover_Data *pd)
{

View File

@ -7,7 +7,7 @@ enum Elm.Hover.Axis
both [[ELM_HOVER_AXIS_BOTH -- both.]]
}
class Elm.Hover (Efl.Ui.Layout, Efl.Ui.Clickable, Elm.Interface.Atspi_Widget_Action, Efl.Ui.Focus.Manager)
class Elm.Hover (Efl.Ui.Layout, Efl.Ui.Focus.Layer, Efl.Ui.Clickable, Elm.Interface.Atspi_Widget_Action)
{
[[Elementary hover class]]
legacy_prefix: elm_hover;
@ -68,8 +68,6 @@ class Elm.Hover (Efl.Ui.Layout, Efl.Ui.Clickable, Elm.Interface.Atspi_Widget_Act
Elm.Widget.widget_sub_object_add;
Elm.Widget.widget_parent { get; set; }
Elm.Widget.widget_sub_object_del;
Elm.Widget.focus_manager_create;
Elm.Widget.focus_state_apply;
Elm.Interface.Atspi_Widget_Action.elm_actions { get; }
Efl.Part.part;
}

View File

@ -27,8 +27,7 @@ static const Elm_Layout_Part_Alias_Description _content_aliases[] =
};
typedef struct {
Efl_Ui_Focus_Manager *manager, *registered_manager;
Eina_Bool registered;
} Elm_Inwin_Data;
EOLIAN static void
@ -78,20 +77,6 @@ elm_win_inwin_add(Evas_Object *parent)
return efl_add(MY_CLASS, parent, efl_canvas_object_legacy_ctor(efl_added));
}
EOLIAN static Efl_Ui_Focus_Manager*
_elm_inwin_elm_widget_focus_manager_create(Eo *obj EINA_UNUSED, Elm_Inwin_Data *pd EINA_UNUSED, Efl_Ui_Focus_Object *root)
{
Efl_Ui_Focus_Manager *manager;
manager = efl_add(EFL_UI_FOCUS_MANAGER_ROOT_FOCUS_CLASS, obj,
efl_ui_focus_manager_root_set(efl_added, root)
);
return manager;
}
EOLIAN static Eo *
_elm_inwin_efl_object_constructor(Eo *obj, Elm_Inwin_Data *pd EINA_UNUSED)
{
@ -109,10 +94,6 @@ _elm_inwin_efl_object_constructor(Eo *obj, Elm_Inwin_Data *pd EINA_UNUSED)
efl_canvas_object_type_set(obj, MY_CLASS_NAME_LEGACY);
elm_interface_atspi_accessible_role_set(obj, ELM_ATSPI_ROLE_GLASS_PANE);
pd->manager = elm_obj_widget_focus_manager_create(obj, obj);
efl_composite_attach(obj, pd->manager);
return obj;
}
@ -130,40 +111,6 @@ _elm_inwin_activate(Eo *obj, Elm_Inwin_Data *pd EINA_UNUSED)
elm_object_focus_set(obj, EINA_TRUE);
}
EOLIAN static void
_elm_inwin_efl_gfx_visible_set(Eo *obj, Elm_Inwin_Data *pd, Eina_Bool v)
{
efl_gfx_visible_set(efl_super(obj, MY_CLASS), v);
if (v && !pd->registered)
{
pd->registered_manager = efl_ui_focus_user_manager_get(obj);
efl_ui_focus_manager_redirect_set(pd->registered_manager, obj);
efl_ui_focus_manager_focus_set(pd->manager, obj);
pd->registered = EINA_TRUE;
}
else if (!v && pd->registered)
{
efl_ui_focus_manager_redirect_set(pd->registered_manager, NULL);
pd->registered = EINA_FALSE;
}
}
EOLIAN static Efl_Ui_Focus_Object*
_elm_inwin_efl_ui_focus_manager_move(Eo *obj, Elm_Inwin_Data *pd, Efl_Ui_Focus_Direction direction)
{
Eo *ret = efl_ui_focus_manager_move(pd->manager , direction);
if (ret)
return ret;
if ((direction == EFL_UI_FOCUS_DIRECTION_PREV) || (direction == EFL_UI_FOCUS_DIRECTION_NEXT))
efl_ui_focus_manager_focus_set(pd->manager, obj);
return efl_ui_focus_manager_focus_get(obj);
}
EOLIAN static Eina_Bool
_elm_inwin_efl_container_content_set(Eo *obj, Elm_Inwin_Data *pd EINA_UNUSED, Efl_Gfx *content)
{

View File

@ -1,4 +1,4 @@
class Elm.Inwin (Efl.Ui.Layout, Efl.Ui.Focus.Manager, Efl.Container)
class Elm.Inwin (Efl.Ui.Layout, Efl.Ui.Focus.Layer, Efl.Container)
{
[[Elementary inwin class]]
legacy_prefix: elm_inwin;
@ -22,9 +22,6 @@ class Elm.Inwin (Efl.Ui.Layout, Efl.Ui.Focus.Manager, Efl.Container)
class.constructor;
Efl.Object.constructor;
Elm.Widget.widget_parent { set; }
Elm.Widget.focus_manager_create;
Efl.Gfx.visible { set; }
Efl.Ui.Focus.Manager.move;
Efl.Container.content { get; set; }
Efl.Container.content_unset;
}

View File

@ -23,7 +23,7 @@ enum Elm.Popup.Orient
}
class Elm.Popup (Efl.Ui.Layout, Elm.Interface.Atspi_Widget_Action)
class Elm.Popup (Efl.Ui.Layout, Efl.Ui.Focus.Layer, Elm.Interface.Atspi_Widget_Action)
{
[[Elementary popup class]]
legacy_prefix: elm_popup;
@ -168,12 +168,8 @@ class Elm.Popup (Efl.Ui.Layout, Elm.Interface.Atspi_Widget_Action)
implements {
class.constructor;
Efl.Object.constructor;
Elm.Widget.focus_direction;
Elm.Widget.focus_next_manager_is;
Elm.Widget.theme_apply;
Elm.Widget.focus_direction_manager_is;
Elm.Widget.on_access_update;
Elm.Widget.focus_next;
Elm.Widget.widget_parent { set; }
Efl.Ui.Translatable.translation_update;
Elm.Widget.widget_sub_object_del;

View File

@ -54,6 +54,8 @@
#include "elm_access.eo.h"
#include "elm_code_private.h"
#include "efl_ui_focus_layer.eo.h"
#ifdef HAVE_LANGINFO_H
# include <langinfo.h>
#endif