elm/calendar: apply focus UI feature.

Summary:
elm_calendar is not subject to current automated focus policies due to internal implementation issues.
(Each date in the calendar is an edje part. )

For the above reasons, I have implemented the focus policy support manually.

Test Plan: elementary_test - calendar sample.

Reviewers: bu5hm4n, woohyun

Subscribers: cedric, jpeg

Differential Revision: https://phab.enlightenment.org/D4421

Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
This commit is contained in:
Woochan Lee 2016-11-28 10:58:57 -08:00 committed by Cedric BAIL
parent 05246782dc
commit 6c04755a92
7 changed files with 378 additions and 7 deletions

View File

@ -727,6 +727,24 @@ group "Elm_Config" struct {
value "action" string: "move";
value "params" string: "down";
}
group "Elm_Config_Binding_Key" struct {
value "context" int: 0;
value "key" string: "Return";
value "action" string: "activate";
value "params" string: "";
}
group "Elm_Config_Binding_Key" struct {
value "context" int: 0;
value "key" string: "KP_Enter";
value "action" string: "activate";
value "params" string: "";
}
group "Elm_Config_Binding_Key" struct {
value "context" int: 0;
value "key" string: "space";
value "action" string: "activate";
value "params" string: "";
}
}
}
group "Elm_Config_Bindings_Widget" struct {

View File

@ -731,6 +731,24 @@ group "Elm_Config" struct {
value "action" string: "move";
value "params" string: "down";
}
group "Elm_Config_Binding_Key" struct {
value "context" int: 0;
value "key" string: "Return";
value "action" string: "activate";
value "params" string: "";
}
group "Elm_Config_Binding_Key" struct {
value "context" int: 0;
value "key" string: "KP_Enter";
value "action" string: "activate";
value "params" string: "";
}
group "Elm_Config_Binding_Key" struct {
value "context" int: 0;
value "key" string: "space";
value "action" string: "activate";
value "params" string: "";
}
}
}
group "Elm_Config_Bindings_Widget" struct {

View File

@ -728,6 +728,24 @@ group "Elm_Config" struct {
value "action" string: "move";
value "params" string: "down";
}
group "Elm_Config_Binding_Key" struct {
value "context" int: 0;
value "key" string: "Return";
value "action" string: "activate";
value "params" string: "";
}
group "Elm_Config_Binding_Key" struct {
value "context" int: 0;
value "key" string: "KP_Enter";
value "action" string: "activate";
value "params" string: "";
}
group "Elm_Config_Binding_Key" struct {
value "context" int: 0;
value "key" string: "space";
value "action" string: "activate";
value "params" string: "";
}
}
}
group "Elm_Config_Bindings_Widget" struct {

View File

@ -200,6 +200,21 @@
visible: 1; \
} \
} \
part { name: "cit_"#_pos".glow"; mouse_events: 0; \
description { state: "default" 0.0; \
rel1.to: "cit_"#_pos".rect"; \
rel2.to: "cit_"#_pos".rect"; \
image.normal: "box_glow.png"; \
image.border: 12 12 12 12; \
image.middle: 0; \
fill.smooth: 0; \
visible: 0; \
} \
description { state: "focused" 0.0; \
inherit: "default" 0.0; \
visible: 1; \
} \
} \
part { name: "cit_"#_pos".text"; type: TEXTBLOCK; mouse_events: 0; \
scale: 1; \
description { state: "default" 0.0; \
@ -279,6 +294,26 @@
target: "cit_"#_pos".pat"; \
target: "cit_"#_pos".selected"; \
} \
program { \
name: "cit_"#_pos".focus_highlighted"; \
signal: "cit_"#_pos",focused"; \
source: "elm"; \
script { \
set_int(item_focus_enabled, 1); \
set_int(last_focused_item, _pos); \
if (get_int(win_focus_enabled) == 1) \
set_state(PART:"cit_"#_pos".glow", "focused", 0.0); \
} \
} \
program { \
name: "cit_"#_pos".focus_unhighlighed"; \
signal: "cit_"#_pos",unfocused"; \
source: "elm"; \
script { \
set_int(item_focus_enabled, 0); \
set_state(PART:"cit_"#_pos".glow", "default", 0.0); \
} \
} \
program { \
name: "cit_"#_pos".is_today"; \
signal: "cit_"#_pos",today"; \
@ -413,9 +448,14 @@ group { name: "elm/calendar/base/default";
images.image: "sym_right_glow_normal.png" COMP;
images.image: "icon_border_remember.png" COMP;
images.image: "outline_glow.png" COMP;
images.image: "box_glow.png" COMP;
images.image: "diagonal_stripes.png" COMP;
data.item: "focus_highlight" "on";
script {
public rtl;
public win_focus_enabled;
public item_focus_enabled;
public last_focused_item;
}
styles {
CIT_STYLES
@ -493,6 +533,28 @@ group { name: "elm/calendar/base/default";
CIT(21) CIT(22) CIT(23) CIT(24) CIT(25) CIT(26) CIT(27)
CIT(28) CIT(29) CIT(30) CIT(31) CIT(32) CIT(33) CIT(34)
CIT(35) CIT(36) CIT(37) CIT(38) CIT(39) CIT(40) CIT(41)
}
programs {
program {
signal: "elm,action,focus_highlight,show";
source: "elm";
script {
set_int(win_focus_enabled, 1);
if (get_int(item_focus_enabled) == 1) {
new value[32];
snprintf(value, 32, "cit_%d,focused", get_int(last_focused_item));
emit(value, "elm");
}
}
}
program {
signal: "elm,action,focus_highlight,hide";
source: "elm";
script {
set_int(win_focus_enabled, 0);
}
}
}
}

View File

@ -125,9 +125,11 @@ _eina_tmpstr_steal(Eina_Tmpstr *s)
#endif
static Eina_Bool _key_action_move(Evas_Object *obj, const char *params);
static Eina_Bool _key_action_activate(Evas_Object *obj, const char *params);
static const Elm_Action key_actions[] = {
{"move", _key_action_move},
{"activate", _key_action_activate},
{NULL, NULL}
};
@ -218,7 +220,7 @@ _select(Evas_Object *obj,
ELM_CALENDAR_DATA_GET(obj, sd);
sd->selected_it = selected;
sd->focused_it = sd->selected_it = selected;
snprintf(emission, sizeof(emission), "cit_%i,selected", selected);
elm_layout_signal_emit(obj, emission, "elm");
}
@ -1275,6 +1277,47 @@ _get_item_day(Evas_Object *obj,
return day;
}
static void
_update_unfocused_it(Evas_Object *obj, int unfocused_it)
{
int day;
char emission[32];
ELM_CALENDAR_DATA_GET(obj, sd);
day = _get_item_day(obj, unfocused_it);
if (!day)
return;
sd->focused_it = -1;
snprintf(emission, sizeof(emission), "cit_%i,unfocused", unfocused_it);
elm_layout_signal_emit(obj, emission, "elm");
}
static Eina_Bool
_update_focused_it(Evas_Object *obj, int focused_it)
{
int day;
char emission[32];
ELM_CALENDAR_DATA_GET(obj, sd);
day = _get_item_day(obj, focused_it);
if (!day)
return EINA_FALSE;
snprintf(emission, sizeof(emission), "cit_%i,unfocused", sd->focused_it);
elm_layout_signal_emit(obj, emission, "elm");
sd->focused_it = focused_it;
snprintf(emission, sizeof(emission), "cit_%i,focused", sd->focused_it);
elm_layout_signal_emit(obj, emission, "elm");
return EINA_TRUE;
}
static void
_update_sel_it(Evas_Object *obj,
int sel_it)
@ -1293,6 +1336,8 @@ _update_sel_it(Evas_Object *obj,
_unselect(obj, sd->selected_it);
if (!sd->selected)
sd->selected = EINA_TRUE;
if (sd->focused_it)
_update_unfocused_it(obj, sd->focused_it);
sd->selected_time.tm_mday = day;
_fix_selected_time(sd);
@ -1348,11 +1393,24 @@ _update_cur_date(void *data)
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_key_action_activate(Evas_Object *obj, const char *params EINA_UNUSED)
{
ELM_CALENDAR_DATA_GET(obj, sd);
_update_sel_it(obj, sd->focused_it);
return EINA_TRUE;
}
static Eina_Bool
_key_action_move(Evas_Object *obj, const char *params)
{
ELM_CALENDAR_DATA_GET(obj, sd);
const char *dir = params;
Eina_Bool ret, double_spinner = EINA_FALSE;
ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
_elm_widget_focus_auto_show(obj);
if (!strcmp(dir, "prior"))
@ -1367,33 +1425,212 @@ _key_action_move(Evas_Object *obj, const char *params)
&& ((sd->select_mode != ELM_CALENDAR_SELECT_MODE_ONDEMAND)
|| (sd->selected)))
{
if (edje_object_part_exists(wd->resize_obj, ELM_CALENDAR_BUTTON_YEAR_RIGHT))
double_spinner = EINA_TRUE;
if (!strcmp(dir, "left"))
{
if ((sd->select_mode != ELM_CALENDAR_SELECT_MODE_ONDEMAND)
|| ((sd->shown_time.tm_year == sd->selected_time.tm_year)
&& (sd->shown_time.tm_mon == sd->selected_time.tm_mon)))
_update_sel_it(obj, sd->selected_it - 1);
{
//Double spinner case.
if (double_spinner)
{
if (elm_object_focus_get(sd->inc_btn_year))
{
elm_object_focus_set(sd->dec_btn_year, EINA_TRUE);
return EINA_TRUE;
}
else if (elm_object_focus_get(sd->dec_btn_year))
{
elm_object_focus_set(sd->inc_btn_month, EINA_TRUE);
return EINA_TRUE;
}
}
//Give focus to dec_btn_month when left key down on the inc_btn_month.
//Leave focus, if key down on dec_btn_month.
if (elm_object_focus_get(sd->inc_btn_month))
{
elm_object_focus_set(sd->dec_btn_month, EINA_TRUE);
return EINA_TRUE;
}
else if (elm_object_focus_get(sd->dec_btn_month)) return EINA_FALSE;
//If key move from the left edge of the calendar,
//Leave the focus policy on window.
if (sd->focused_it % ELM_DAY_LAST == 0)
return EINA_FALSE;
//Focus on the day before the day.
ret = _update_focused_it(obj, sd->focused_it - 1);
if (!ret) return EINA_FALSE;
}
}
else if (!strcmp(dir, "right"))
{
if ((sd->select_mode != ELM_CALENDAR_SELECT_MODE_ONDEMAND)
|| ((sd->shown_time.tm_year == sd->selected_time.tm_year)
&& (sd->shown_time.tm_mon == sd->selected_time.tm_mon)))
_update_sel_it(obj, sd->selected_it + 1);
{
//Double spinner case.
if (double_spinner)
{
if (elm_object_focus_get(sd->inc_btn_year)) return EINA_FALSE;
else if (elm_object_focus_get(sd->dec_btn_year))
{
elm_object_focus_set(sd->inc_btn_year, EINA_TRUE);
return EINA_TRUE;
}
else if (elm_object_focus_get(sd->inc_btn_month))
{
elm_object_focus_set(sd->dec_btn_year, EINA_TRUE);
return EINA_TRUE;
}
}
//Give focus to inc_btn_month when right key down on the dec_btn_month.
if (elm_object_focus_get(sd->dec_btn_month))
{
elm_object_focus_set(sd->inc_btn_month, EINA_TRUE);
return EINA_TRUE;
}
else if (elm_object_focus_get(sd->inc_btn_month)) return EINA_FALSE;
//If key move from the right edge of the calendar,
//Leave the focus policy on window.
if (sd->focused_it % ELM_DAY_LAST == ELM_DAY_LAST - 1)
return EINA_FALSE;
//Focus on the day after the day.
ret = _update_focused_it(obj, sd->focused_it + 1);
if (!ret) return EINA_FALSE;
}
}
else if (!strcmp(dir, "up"))
{
if ((sd->select_mode != ELM_CALENDAR_SELECT_MODE_ONDEMAND)
|| ((sd->shown_time.tm_year == sd->selected_time.tm_year)
&& (sd->shown_time.tm_mon == sd->selected_time.tm_mon)))
_update_sel_it(obj, sd->selected_it - ELM_DAY_LAST);
{
//double spinner case.
if (double_spinner)
{
if (elm_object_focus_get(sd->inc_btn_year))
{
elm_object_focus_set(sd->inc_btn_year, EINA_FALSE);
return EINA_FALSE;
}
else if (elm_object_focus_get(sd->dec_btn_year))
{
elm_object_focus_set(sd->dec_btn_year, EINA_FALSE);
return EINA_FALSE;
}
}
//If the dec_btn_month, or inc_btn_month has focus.
//Focus unset and leave the focus policy on window.
if (elm_object_focus_get(sd->dec_btn_month))
{
elm_object_focus_set(sd->dec_btn_month, EINA_FALSE);
return EINA_FALSE;
}
else if (elm_object_focus_get(sd->inc_btn_month))
{
elm_object_focus_set(sd->inc_btn_month, EINA_FALSE);
return EINA_FALSE;
}
//If the focus item is the first week of month.
if ((sd->focused_it >= 0) && (sd->focused_it < ELM_DAY_LAST))
{
//Give focus to inc_btn_month(right side located button)
//If the focused item is smaller than 4.
//Otherwise, give focus to dec_btn_month.
if (sd->focused_it > (ELM_DAY_LAST / 2))
//Double spinner case.
if (edje_object_part_exists(wd->resize_obj, ELM_CALENDAR_BUTTON_YEAR_RIGHT))
elm_object_focus_set(sd->inc_btn_year, EINA_TRUE);
else
elm_object_focus_set(sd->inc_btn_month, EINA_TRUE);
else
elm_object_focus_set(sd->dec_btn_month, EINA_TRUE);
_update_unfocused_it(obj, sd->focused_it);
return EINA_TRUE;
}
//Focus on the last week day.
ret = _update_focused_it(obj, sd->focused_it - ELM_DAY_LAST);
if (!ret)
{
//If focused day is not available(not belongs to current month)
//Take a focus from item and give the focus to suitable button.
if (sd->focused_it >= ELM_DAY_LAST && sd->focused_it < (ELM_DAY_LAST * 2))
{
if (sd->focused_it > (ELM_DAY_LAST + (ELM_DAY_LAST / 2)))
//Double spinner case.
if (edje_object_part_exists(wd->resize_obj, ELM_CALENDAR_BUTTON_YEAR_RIGHT))
elm_object_focus_set(sd->inc_btn_year, EINA_TRUE);
else
elm_object_focus_set(sd->inc_btn_month, EINA_TRUE);
else
elm_object_focus_set(sd->dec_btn_month, EINA_TRUE);
_update_unfocused_it(obj, sd->focused_it);
return EINA_TRUE;
}
}
}
}
else if (!strcmp(dir, "down"))
{
if ((sd->select_mode != ELM_CALENDAR_SELECT_MODE_ONDEMAND)
|| ((sd->shown_time.tm_year == sd->selected_time.tm_year)
&& (sd->shown_time.tm_mon == sd->selected_time.tm_mon)))
_update_sel_it(obj, sd->selected_it + ELM_DAY_LAST);
{
//double spinner case.
if (double_spinner)
{
if (elm_object_focus_get(sd->inc_btn_year))
{
elm_object_focus_set(sd->inc_btn_year, EINA_FALSE);
evas_object_focus_set(obj, EINA_TRUE);
_update_focused_it(obj, (ELM_DAY_LAST - 1));
return EINA_TRUE;
}
else if (elm_object_focus_get(sd->dec_btn_year))
{
elm_object_focus_set(sd->dec_btn_year, EINA_FALSE);
evas_object_focus_set(obj, EINA_TRUE);
_update_focused_it(obj, sd->first_day_it);
return EINA_TRUE;
}
}
//If the XXX_btn_month has focus.
//Set as false to button focus and give to focus to first item of the calendar.
//Otherwise, Give the focus to last day of first week of calendar.
if (elm_object_focus_get(sd->dec_btn_month))
{
elm_object_focus_set(sd->dec_btn_month, EINA_FALSE);
evas_object_focus_set(obj, EINA_TRUE);
_update_focused_it(obj, sd->first_day_it);
return EINA_TRUE;
}
else if(elm_object_focus_get(sd->inc_btn_month))
{
elm_object_focus_set(sd->inc_btn_month, EINA_FALSE);
evas_object_focus_set(obj, EINA_TRUE);
_update_focused_it(obj, (ELM_DAY_LAST - 1));
return EINA_TRUE;
}
//Focus on the next week day.
ret = _update_focused_it(obj, sd->focused_it + ELM_DAY_LAST);
if (!ret) return EINA_FALSE;
}
}
else return EINA_FALSE;
}
@ -1402,6 +1639,22 @@ _key_action_move(Evas_Object *obj, const char *params)
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_elm_calendar_elm_widget_on_focus(Eo *obj, Elm_Calendar_Data *sd, Elm_Object_Item *item EINA_UNUSED)
{
Eina_Bool int_ret = EINA_FALSE;
int_ret = elm_obj_widget_on_focus(efl_super(obj, MY_CLASS), NULL);
if (!int_ret) return EINA_FALSE;
if (elm_widget_focus_get(obj))
sd->focused_it = sd->selected_it;
else
_update_unfocused_it(obj, sd->focused_it);
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_elm_calendar_elm_widget_event(Eo *obj, Elm_Calendar_Data *sd EINA_UNUSED, Evas_Object *src, Evas_Callback_Type type, void *event_info)
{
@ -1545,7 +1798,7 @@ static Eina_Bool _elm_calendar_smart_focus_next_enable = EINA_FALSE;
EOLIAN static Eina_Bool
_elm_calendar_elm_widget_focus_next_manager_is(Eo *obj EINA_UNUSED, Elm_Calendar_Data *_pd EINA_UNUSED)
{
return EINA_TRUE;
return EINA_FALSE;
}
EOLIAN static Eina_Bool
@ -2080,6 +2333,7 @@ _elm_calendar_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNU
{ "move,right", "move", "right", _key_action_move},
{ "move,up", "move", "up", _key_action_move},
{ "move,down", "move", "down", _key_action_move},
{ "activate", "activate", NULL, _key_action_activate},
{ NULL, NULL, NULL, NULL }
};
return &atspi_actions[0];

View File

@ -419,6 +419,7 @@ class Elm.Calendar (Elm.Layout, Elm.Interface.Atspi_Widget_Action)
Elm.Widget.focus_direction_manager_is;
Elm.Widget.access;
Elm.Widget.focus_next;
Elm.Widget.on_focus;
Elm.Widget.event;
Elm.Layout.sizing_eval;
Elm.Interface.Atspi_Widget_Action.elm_actions.get;

View File

@ -38,7 +38,7 @@ struct _Elm_Calendar_Data
Eina_List *marks;
double interval, first_interval;
int spin_speed;
int today_it, selected_it, first_day_it;
int today_it, selected_it, first_day_it, focused_it;
Ecore_Timer *spin_month, *spin_year, *update_timer;
Elm_Calendar_Format_Cb format_func;
const char *weekdays[ELM_DAY_LAST];