efl/src/lib/elementary/elm_dayselector.c

645 lines
18 KiB
C

#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#define EFL_ACCESS_OBJECT_PROTECTED
#define EFL_UI_L10N_PROTECTED
#define EFL_PART_PROTECTED
#include <Elementary.h>
#include "elm_priv.h"
#include "elm_widget_dayselector.h"
#include "elm_widget_container.h"
#include "elm_dayselector_part.eo.h"
#include "elm_part_helper.h"
#define MY_CLASS ELM_DAYSELECTOR_CLASS
#define MY_CLASS_NAME "Elm_Dayselector"
#define MY_CLASS_NAME_LEGACY "elm_dayselector"
/* signals to edc */
#define ITEM_TYPE_WEEKDAY_DEFAULT "elm,type,weekday,default"
#define ITEM_TYPE_WEEKDAY_STYLE1 "elm,type,weekday,style1"
#define ITEM_TYPE_WEEKEND_DEFAULT "elm,type,weekend,default"
#define ITEM_TYPE_WEEKEND_STYLE1 "elm,type,weekend,style1"
#define ITEM_POS_LEFT "elm,pos,check,left"
#define ITEM_POS_RIGHT "elm,pos,check,right"
#define ITEM_POS_MIDDLE "elm,pos,check,middle"
static const char SIG_CHANGED[] = "dayselector,changed";
static const Evas_Smart_Cb_Description _smart_callbacks[] = {
{SIG_CHANGED, ""},
{SIG_WIDGET_LANG_CHANGED, ""}, /**< handled by elm_widget */
{SIG_WIDGET_ACCESS_CHANGED, ""}, /**< handled by elm_widget */
{NULL, NULL}
};
static void
_dayselector_resize(void *data,
Evas *e EINA_UNUSED,
Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
elm_layout_sizing_eval(data);
}
EOLIAN static void
_elm_dayselector_efl_ui_l10n_translation_update(Eo *obj EINA_UNUSED, Elm_Dayselector_Data *sd)
{
time_t t;
Eina_List *l;
char buf[1024];
struct tm time_daysel;
Elm_Dayselector_Item_Data *it;
if (sd->weekdays_names_set)
return;
t = time(NULL);
localtime_r(&t, &time_daysel);
EINA_LIST_FOREACH(sd->items, l, it)
{
time_daysel.tm_wday = it->day;
strftime(buf, sizeof(buf), "%a", &time_daysel);
elm_object_text_set(VIEW(it), buf);
}
efl_ui_l10n_translation_update(efl_super(obj, MY_CLASS));
}
static void
_update_items(Evas_Object *obj)
{
Eina_List *l;
Eina_Bool rtl;
unsigned int last_day;
Elm_Dayselector_Item_Data *it;
ELM_DAYSELECTOR_DATA_GET(obj, sd);
last_day = sd->week_start + ELM_DAYSELECTOR_MAX - 1;
if (last_day >= ELM_DAYSELECTOR_MAX)
last_day = last_day % ELM_DAYSELECTOR_MAX;
rtl = efl_ui_mirrored_get(obj);
EINA_LIST_FOREACH(sd->items, l, it)
{
elm_object_signal_emit(VIEW(it), it->day_style, ""); // XXX: compat
elm_object_signal_emit(VIEW(it), it->day_style, "elm");
if (it->day == sd->week_start)
{
if (rtl) elm_object_signal_emit(VIEW(it), ITEM_POS_RIGHT, "elm");
else elm_object_signal_emit(VIEW(it), ITEM_POS_LEFT, "elm");
}
else if (it->day == last_day)
{
if (rtl) elm_object_signal_emit(VIEW(it), ITEM_POS_LEFT, "elm");
else elm_object_signal_emit(VIEW(it), ITEM_POS_RIGHT, "elm");
}
else
elm_object_signal_emit(VIEW(it), ITEM_POS_MIDDLE, "elm");
}
}
static inline unsigned int
_item_location_get(Elm_Dayselector_Data *sd,
Elm_Dayselector_Item_Data *it)
{
return (ELM_DAYSELECTOR_MAX - sd->week_start + it->day) %
ELM_DAYSELECTOR_MAX;
}
EOLIAN static Eina_Error
_elm_dayselector_efl_ui_widget_theme_apply(Eo *obj, Elm_Dayselector_Data *sd)
{
Eina_Error int_ret = EFL_UI_THEME_APPLY_ERROR_GENERIC;
Eina_List *l;
char buf[1024];
Elm_Dayselector_Item_Data *it;
int_ret = efl_ui_widget_theme_apply(efl_super(obj, MY_CLASS));
if (int_ret == EFL_UI_THEME_APPLY_ERROR_GENERIC) return int_ret;
EINA_LIST_FOREACH(sd->items, l, it)
{
snprintf
(buf, sizeof(buf), "dayselector/%s", elm_object_style_get(obj));
elm_object_style_set(VIEW(it), buf);
/* XXX kept for legacy compatibility, remove eventually */
snprintf
(buf, sizeof(buf), "day%d,visible", _item_location_get(sd, it));
elm_layout_signal_emit(obj, buf, "elm");
/* XXX */
snprintf
(buf, sizeof(buf), "elm,day%d,visible", _item_location_get(sd, it));
elm_layout_signal_emit(obj, buf, "elm");
}
_update_items(obj);
elm_layout_sizing_eval(obj);
return int_ret;
}
static void
_item_del_cb(void *data,
Evas *e EINA_UNUSED,
Evas_Object *obj,
void *event_info EINA_UNUSED)
{
Eina_List *l;
char buf[1024];
Elm_Dayselector_Item_Data *it;
ELM_DAYSELECTOR_DATA_GET(data, sd);
EINA_LIST_FOREACH(sd->items, l, it)
{
if (obj == VIEW(it))
{
sd->items = eina_list_remove(sd->items, it);
eina_stringshare_del(it->day_style);
/* XXX kept for legacy compatibility, remove eventually */
snprintf(buf, sizeof(buf), "day%d,default",
_item_location_get(sd, it));
elm_layout_signal_emit(obj, buf, "elm");
/* XXX */
snprintf(buf, sizeof(buf), "elm,day%d,default",
_item_location_get(sd, it));
elm_layout_signal_emit(obj, buf, "elm");
// The object is already being deleted, there is no point in calling efl_del on it nore setting it to NULL.
elm_layout_sizing_eval(obj);
break;
}
}
}
static void
_item_signal_emit_cb(void *data,
Evas_Object *obj EINA_UNUSED,
const char *emission,
const char *source EINA_UNUSED)
{
Elm_Dayselector_Item_Data *it = data;
eina_stringshare_replace(&it->day_style, emission);
}
static void
_item_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Elm_Dayselector_Item_Data *it = data;
evas_object_smart_callback_call(WIDGET(it), "changed", event_info);
}
static Elm_Dayselector_Item_Data *
_item_find(const Evas_Object *obj,
Elm_Dayselector_Day day)
{
Eina_List *l;
Elm_Dayselector_Item_Data *it;
ELM_DAYSELECTOR_DATA_GET(obj, sd);
EINA_LIST_FOREACH(sd->items, l, it)
if (day == it->day) return it;
return NULL;
}
static Eina_Bool
_elm_dayselector_content_set(Eo *obj, Elm_Dayselector_Data *sd, const char *item, Evas_Object *content)
{
Eina_Bool int_ret = EINA_FALSE;
int day;
char buf[1024];
Elm_Dayselector_Item_Data *it = NULL;
EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(content, EFL_UI_CHECK_CLASS), EINA_FALSE);
if (!item) return EINA_FALSE;
day = atoi(item + (strlen(item) - 1));
if (day < 0 || day > ELM_DAYSELECTOR_MAX) return EINA_FALSE;
it = _item_find(obj, day);
if (it)
{
snprintf(buf, sizeof(buf), "elm.swallow.day%d", _item_location_get(sd, it));
int_ret = efl_content_set(efl_part(efl_super(obj, MY_CLASS), buf), content);
if (!int_ret)
{
/* XXX kept for legacy compatibility, remove eventually */
snprintf(buf, sizeof(buf), "day%d", _item_location_get(sd, it));
int_ret = efl_content_set(efl_part(efl_super(obj, MY_CLASS), buf), content);
/* XXX */
}
if (!int_ret) return EINA_FALSE;
if (!content) return EINA_TRUE; /* item deletion already handled */
evas_object_del(VIEW(it));
VIEW_SET(it, content);
}
else
{
Eo *eo_it = efl_add(ELM_DAYSELECTOR_ITEM_CLASS, obj);
it = efl_data_scope_get(eo_it, ELM_DAYSELECTOR_ITEM_CLASS);
it->day = day;
snprintf(buf, sizeof(buf), "elm.swallow.day%d", _item_location_get(sd, it));
int_ret = efl_content_set(efl_part(efl_super(obj, MY_CLASS), buf), content);
if (!int_ret)
{
/* XXX kept for legacy compatibility, remove eventually */
snprintf(buf, sizeof(buf), "day%d", _item_location_get(sd, it));
int_ret = efl_content_set(efl_part(efl_super(obj, MY_CLASS), buf), content);
/* XXX */
}
if (!int_ret)
{
efl_del(eo_it);
return EINA_FALSE;
}
sd->items = eina_list_append(sd->items, it);
VIEW_SET(it, content);
}
snprintf(buf, sizeof(buf), "elm,day%d,visible", _item_location_get(sd, it));
elm_layout_signal_emit(obj, buf, "elm");
/* XXX kept for legacy compatibility, remove eventually */
snprintf(buf, sizeof(buf), "day%d,visible", _item_location_get(sd, it));
elm_layout_signal_emit(obj, buf, "elm");
evas_object_smart_callback_add(VIEW(it), "changed", _item_clicked_cb, it);
evas_object_event_callback_add
(VIEW(it), EVAS_CALLBACK_DEL, _item_del_cb, obj);
elm_object_signal_callback_add
(VIEW(it), ITEM_TYPE_WEEKDAY_DEFAULT, "*", _item_signal_emit_cb, it);
elm_object_signal_callback_add
(VIEW(it), ITEM_TYPE_WEEKDAY_STYLE1, "*", _item_signal_emit_cb, it);
elm_object_signal_callback_add
(VIEW(it), ITEM_TYPE_WEEKEND_DEFAULT, "*", _item_signal_emit_cb, it);
elm_object_signal_callback_add
(VIEW(it), ITEM_TYPE_WEEKEND_STYLE1, "*", _item_signal_emit_cb, it);
elm_layout_sizing_eval(obj);
_update_items(obj);
return EINA_TRUE;
}
EOLIAN static Eo *
_elm_dayselector_item_efl_object_constructor(Eo *eo_item, Elm_Dayselector_Item_Data *item)
{
eo_item = efl_constructor(efl_super(eo_item, ELM_DAYSELECTOR_ITEM_CLASS));
item->base = efl_data_scope_get(eo_item, ELM_WIDGET_ITEM_CLASS);
return eo_item;
}
static Evas_Object*
_elm_dayselector_content_unset(Eo *obj, Elm_Dayselector_Data *sd, const char *item)
{
int day;
char buf[1024];
Evas_Object *content;
Elm_Dayselector_Item_Data *it = NULL;
day = atoi(item + (strlen(item) - 1));
if (day < 0 || day > ELM_DAYSELECTOR_MAX) return NULL;
it = _item_find(obj, day);
if (!it) return NULL;
content = efl_content_unset(efl_part(efl_super(obj, MY_CLASS), buf));
if (!content) return NULL;
sd->items = eina_list_remove(sd->items, it);
evas_object_smart_callback_del_full(content, "changed", _item_clicked_cb, it);
evas_object_event_callback_del(content, EVAS_CALLBACK_DEL, _item_del_cb);
elm_object_signal_callback_del
(content, ITEM_TYPE_WEEKDAY_DEFAULT, "*", _item_signal_emit_cb);
elm_object_signal_callback_del
(content, ITEM_TYPE_WEEKDAY_STYLE1, "*", _item_signal_emit_cb);
elm_object_signal_callback_del
(content, ITEM_TYPE_WEEKEND_DEFAULT, "*", _item_signal_emit_cb);
elm_object_signal_callback_del
(content, ITEM_TYPE_WEEKEND_STYLE1, "*", _item_signal_emit_cb);
snprintf(buf, sizeof(buf), "elm,day%d,default", _item_location_get(sd, it));
elm_layout_signal_emit(obj, buf, "elm");
/* XXX kept for legacy compatibility, remove eventually */
snprintf(buf, sizeof(buf), "day%d,default", _item_location_get(sd, it));
elm_layout_signal_emit(obj, buf, "elm");
efl_del(EO_OBJ(it));
elm_layout_sizing_eval(obj);
return content;
}
static void
_items_style_set(Evas_Object *obj)
{
Eina_List *l;
Elm_Dayselector_Item_Data *it;
unsigned int weekend_last;
ELM_DAYSELECTOR_DATA_GET(obj, sd);
weekend_last = sd->weekend_start + sd->weekend_len - 1;
if (weekend_last >= ELM_DAYSELECTOR_MAX)
weekend_last = weekend_last % ELM_DAYSELECTOR_MAX;
EINA_LIST_FOREACH(sd->items, l, it)
{
if (weekend_last >= sd->weekend_start)
{
if ((it->day >= sd->weekend_start) && (it->day <= weekend_last))
eina_stringshare_replace(&it->day_style,
ITEM_TYPE_WEEKEND_DEFAULT);
else
eina_stringshare_replace(&it->day_style,
ITEM_TYPE_WEEKDAY_DEFAULT);
}
else
{
if ((it->day >= sd->weekend_start) || (it->day <= weekend_last))
eina_stringshare_replace(&it->day_style,
ITEM_TYPE_WEEKEND_DEFAULT);
else
eina_stringshare_replace(&it->day_style,
ITEM_TYPE_WEEKDAY_DEFAULT);
}
}
}
static void
_items_create(Evas_Object *obj)
{
time_t t;
char buf[1024];
unsigned int idx;
struct tm time_daysel;
t = time(NULL);
localtime_r(&t, &time_daysel);
for (idx = 0; idx < ELM_DAYSELECTOR_MAX; idx++)
{
Evas_Object *chk;
chk = elm_check_add(obj);
elm_object_style_set(chk, "dayselector/default");
time_daysel.tm_wday = idx;
strftime(buf, sizeof(buf), "%a", &time_daysel);
elm_object_text_set(chk, buf);
snprintf(buf, sizeof(buf), "elm.swallow.day%u", idx);
if (!elm_layout_content_set(obj, buf, chk))
{
snprintf(buf, sizeof(buf), "day%u", idx);
elm_layout_content_set(obj, buf, chk);
}
// XXX: ACCESS
_elm_access_text_set(_elm_access_info_get(chk),
ELM_ACCESS_TYPE, E_("day selector item"));
}
_items_style_set(obj);
_update_items(obj);
}
EOLIAN static void
_elm_dayselector_efl_canvas_group_group_add(Eo *obj, Elm_Dayselector_Data *priv)
{
efl_canvas_group_add(efl_super(obj, MY_CLASS));
if (!elm_layout_theme_set(obj, "dayselector", "base",
elm_widget_style_get(obj)))
CRI("Failed to set layout!");
priv->week_start = _elm_config->week_start;
priv->weekend_start = _elm_config->weekend_start;
priv->weekend_len = _elm_config->weekend_len;
efl_ui_layout_finger_size_multiplier_set(obj, ELM_DAYSELECTOR_MAX, 1);
_items_create(obj);
evas_object_event_callback_add
(obj, EVAS_CALLBACK_RESIZE, _dayselector_resize, obj);
elm_layout_sizing_eval(obj);
}
EOLIAN static void
_elm_dayselector_efl_canvas_group_group_del(Eo *obj, Elm_Dayselector_Data *sd)
{
Elm_Dayselector_Item_Data *it;
EINA_LIST_FREE(sd->items, it)
{
sd->items = eina_list_remove(sd->items, it);
eina_stringshare_del(it->day_style);
// No need to efl_del the object as they have been created by efl_add and are dead by now.
}
/* handles freeing sd */
efl_canvas_group_del(efl_super(obj, MY_CLASS));
}
EAPI Evas_Object *
elm_dayselector_add(Evas_Object *parent)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
return elm_legacy_add(MY_CLASS, parent);
}
EOLIAN static Eo *
_elm_dayselector_efl_object_constructor(Eo *obj, Elm_Dayselector_Data *_pd EINA_UNUSED)
{
obj = efl_constructor(efl_super(obj, MY_CLASS));
efl_canvas_object_type_set(obj, MY_CLASS_NAME_LEGACY);
evas_object_smart_callbacks_descriptions_set(obj, _smart_callbacks);
efl_access_object_role_set(obj, EFL_ACCESS_ROLE_PANEL);
return obj;
}
EOLIAN static void
_elm_dayselector_day_selected_set(Eo *obj, Elm_Dayselector_Data *_pd EINA_UNUSED, Elm_Dayselector_Day day, Eina_Bool selected)
{
Elm_Dayselector_Item_Data *it = _item_find(obj, day);
if (!it)
{
ERR("Failed to find item");
return;
}
elm_check_state_set(VIEW(it), selected);
}
EOLIAN static Eina_Bool
_elm_dayselector_day_selected_get(const Eo *obj, Elm_Dayselector_Data *_pd EINA_UNUSED, Elm_Dayselector_Day day)
{
Elm_Dayselector_Item_Data *it = _item_find(obj, day);
if (!it)
{
ERR("Failed to find item");
return EINA_FALSE;
}
return elm_check_state_get(VIEW(it));
}
EOLIAN static void
_elm_dayselector_week_start_set(Eo *obj, Elm_Dayselector_Data *sd, Elm_Dayselector_Day day)
{
ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
Eina_List *l;
char buf[1024];
Elm_Dayselector_Item_Data *it;
/* just shuffling items, so swalling them directly */
sd->week_start = day;
EINA_LIST_FOREACH(sd->items, l, it)
{
snprintf(buf, sizeof(buf), "elm.swallow.day%d", _item_location_get(sd, it));
if (!edje_object_part_swallow(wd->resize_obj, buf, VIEW(it)))
{
snprintf(buf, sizeof(buf), "day%d", _item_location_get(sd, it));
edje_object_part_swallow(wd->resize_obj, buf, VIEW(it));
}
}
_update_items(obj);
}
EOLIAN static Elm_Dayselector_Day
_elm_dayselector_week_start_get(const Eo *obj EINA_UNUSED, Elm_Dayselector_Data *sd)
{
return sd->week_start;
}
EOLIAN static void
_elm_dayselector_weekend_start_set(Eo *obj, Elm_Dayselector_Data *sd, Elm_Dayselector_Day day)
{
sd->weekend_start = day;
_items_style_set(obj);
_update_items(obj);
}
EOLIAN static Elm_Dayselector_Day
_elm_dayselector_weekend_start_get(const Eo *obj EINA_UNUSED, Elm_Dayselector_Data *sd)
{
return sd->weekend_start;
}
EOLIAN static void
_elm_dayselector_weekend_length_set(Eo *obj, Elm_Dayselector_Data *sd, unsigned int length)
{
sd->weekend_len = length;
_items_style_set(obj);
_update_items(obj);
}
EOLIAN static unsigned int
_elm_dayselector_weekend_length_get(const Eo *obj EINA_UNUSED, Elm_Dayselector_Data *sd)
{
return sd->weekend_len;
}
EOLIAN static void
_elm_dayselector_weekdays_names_set(Eo *obj, Elm_Dayselector_Data *sd, const char **weekdays)
{
int idx;
time_t now;
struct tm time_daysel;
Elm_Dayselector_Item_Data *it;
char buf[1024];
if (weekdays)
sd->weekdays_names_set = EINA_TRUE;
else
{
now = time(NULL);
localtime_r(&now, &time_daysel);
sd->weekdays_names_set = EINA_FALSE;
}
for (idx = 0; idx < ELM_DAYSELECTOR_MAX; idx++)
{
it = _item_find(obj, idx);
if (!it) continue;
if (sd->weekdays_names_set)
elm_object_text_set(VIEW(it), weekdays[idx]);
else
{
time_daysel.tm_wday = idx;
strftime(buf, sizeof(buf), "%a", &time_daysel);
elm_object_text_set(VIEW(it), buf);
}
}
}
EOLIAN static Eina_List *
_elm_dayselector_weekdays_names_get(const Eo *obj, Elm_Dayselector_Data *sd EINA_UNUSED)
{
int idx;
const char *weekday;
Elm_Dayselector_Item_Data *it;
Eina_List *weekdays = NULL;
for (idx = 0; idx < ELM_DAYSELECTOR_MAX; idx++)
{
it = _item_find(obj, idx);
if (!it) continue ;
weekday = elm_object_text_get(VIEW(it));
weekdays = eina_list_append(weekdays, eina_stringshare_add(weekday));
}
return weekdays;
}
static void
_elm_dayselector_class_constructor(Efl_Class *klass)
{
evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
}
/* Efl.Part begin */
ELM_PART_OVERRIDE(elm_dayselector, ELM_DAYSELECTOR, Elm_Dayselector_Data)
ELM_PART_OVERRIDE_CONTENT_SET(elm_dayselector, ELM_DAYSELECTOR, Elm_Dayselector_Data)
ELM_PART_OVERRIDE_CONTENT_UNSET(elm_dayselector, ELM_DAYSELECTOR, Elm_Dayselector_Data)
#include "elm_dayselector_part.eo.c"
/* Efl.Part end */
/* Internal EO APIs and hidden overrides */
#define ELM_DAYSELECTOR_EXTRA_OPS \
EFL_CANVAS_GROUP_ADD_DEL_OPS(elm_dayselector)
#include "elm_dayselector_eo.c"
#include "elm_dayselector_item_eo.c"