diff --git a/src/lib/elementary/efl_ui_layout.c b/src/lib/elementary/efl_ui_layout.c index ce6a49d88b..e2c7e14384 100644 --- a/src/lib/elementary/efl_ui_layout.c +++ b/src/lib/elementary/efl_ui_layout.c @@ -1,2611 +1,2617 @@ #ifdef HAVE_CONFIG_H # include "elementary_config.h" #endif #define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED #define ELM_LAYOUT_PROTECTED #include #include "elm_priv.h" #include "elm_widget_layout.h" #include "efl_ui_layout_internal_part.eo.h" #include "elm_part_helper.h" #define EDJE_EDIT_IS_UNSTABLE_AND_I_KNOW_ABOUT_IT #include #define MY_CLASS EFL_UI_LAYOUT_CLASS #define MY_CLASS_PFX efl_ui_layout #define MY_CLASS_NAME "Elm_Layout" #define MY_CLASS_NAME_LEGACY "elm_layout" Eo *_efl_ui_layout_pack_proxy_get(Efl_Ui_Layout *obj, Edje_Part_Type type, const char *part); static void _efl_model_properties_changed_cb(void *, const Efl_Event *); static Eina_Bool _efl_ui_layout_part_cursor_unset(Efl_Ui_Layout_Data *sd, const char *part_name); static const char SIG_THEME_CHANGED[] = "theme,changed"; const char SIG_LAYOUT_FOCUSED[] = "focused"; const char SIG_LAYOUT_UNFOCUSED[] = "unfocused"; const char SIGNAL_PREFIX[] = "signal/"; /* smart callbacks coming from elm layout objects: */ static const Evas_Smart_Cb_Description _smart_callbacks[] = { {SIG_THEME_CHANGED, ""}, {SIG_LAYOUT_FOCUSED, ""}, {SIG_LAYOUT_UNFOCUSED, ""}, {SIG_WIDGET_LANG_CHANGED, ""}, /**< handled by elm_widget */ {SIG_WIDGET_ACCESS_CHANGED, ""}, /**< handled by elm_widget */ {NULL, NULL} }; static const Elm_Layout_Part_Alias_Description _text_aliases[] = { {"default", "elm.text"}, {NULL, NULL} }; static const Elm_Layout_Part_Alias_Description _content_aliases[] = { {"default", "elm.swallow.content"}, {NULL, NULL} }; static const char *_efl_ui_layout_swallow_parts[] = { "elm.swallow.icon", "elm.swallow.end", "elm.swallow.background", NULL }; /* these are data operated by layout's class functions internally, and * should not be messed up by inhering classes */ typedef struct _Efl_Ui_Layout_Sub_Object_Data Efl_Ui_Layout_Sub_Object_Data; typedef struct _Efl_Ui_Layout_Sub_Object_Cursor Efl_Ui_Layout_Sub_Object_Cursor; typedef struct _Efl_Ui_Layout_Sub_Iterator Efl_Ui_Layout_Sub_Iterator; struct _Efl_Ui_Layout_Sub_Iterator { Eina_Iterator iterator; Eina_Iterator *real_iterator; Efl_Ui_Layout *object; }; struct _Efl_Ui_Layout_Sub_Object_Data { const char *part; Evas_Object *obj; enum { SWALLOW, BOX_APPEND, BOX_PREPEND, BOX_INSERT_BEFORE, BOX_INSERT_AT, TABLE_PACK, TEXT } type; union { union { const Evas_Object *reference; unsigned int pos; } box; struct { unsigned short col, row, colspan, rowspan; } table; } p; }; struct _Efl_Ui_Layout_Sub_Object_Cursor { Evas_Object *obj; const char *part; const char *cursor; const char *style; Eina_Bool engine_only : 1; }; typedef struct _Efl_Ui_Layout_Sub_Property_Future Efl_Ui_Layout_Sub_Property_Future; struct _Efl_Ui_Layout_Sub_Property_Future { Efl_Ui_Layout_Data *pd; Eina_Array *name_arr; }; static void _on_sub_object_size_hint_change(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { ELM_WIDGET_DATA_GET_OR_RETURN(data, wd); elm_layout_sizing_eval(data); } static void _part_cursor_free(Efl_Ui_Layout_Sub_Object_Cursor *pc) { eina_stringshare_del(pc->part); eina_stringshare_del(pc->style); eina_stringshare_del(pc->cursor); free(pc); } static void _sizing_eval(Evas_Object *obj, Efl_Ui_Layout_Data *sd) { Evas_Coord minh = -1, minw = -1; Evas_Coord rest_w = 0, rest_h = 0; ELM_WIDGET_DATA_GET_OR_RETURN(sd->obj, wd); if (sd->restricted_calc_w) rest_w = wd->w; if (sd->restricted_calc_h) rest_h = wd->h; edje_object_size_min_restricted_calc(wd->resize_obj, &minw, &minh, rest_w, rest_h); evas_object_size_hint_min_set(obj, minw, minh); sd->restricted_calc_w = sd->restricted_calc_h = EINA_FALSE; } /* common content cases for layout objects: icon and text */ static inline void _icon_signal_emit(Efl_Ui_Layout_Data *sd, Efl_Ui_Layout_Sub_Object_Data *sub_d, Eina_Bool visible) { char buf[1024]; const char *type; int i; //FIXME: Don't limit to the icon and end here. // send signals for all contents after elm 2.0 if (sub_d->type != SWALLOW) return; for (i = 0;; i++) { if (!_efl_ui_layout_swallow_parts[i]) return; if (!strcmp(sub_d->part, _efl_ui_layout_swallow_parts[i])) break; } if (!strncmp(sub_d->part, "elm.swallow.", strlen("elm.swallow."))) type = sub_d->part + strlen("elm.swallow."); else type = sub_d->part; snprintf(buf, sizeof(buf), "elm,state,%s,%s", type, visible ? "visible" : "hidden"); ELM_WIDGET_DATA_GET_OR_RETURN(sd->obj, wd); edje_object_signal_emit(wd->resize_obj, buf, "elm"); /* themes might need immediate action here */ edje_object_message_signal_process(wd->resize_obj); } static inline void _text_signal_emit(Efl_Ui_Layout_Data *sd, Efl_Ui_Layout_Sub_Object_Data *sub_d, Eina_Bool visible) { char buf[1024]; const char *type; //FIXME: Don't limit to "elm.text" prefix. //Send signals for all text parts after elm 2.0 if ((sub_d->type != TEXT) || (!((!strcmp("elm.text", sub_d->part)) || (!strncmp("elm.text.", sub_d->part, 9))))) return; ELM_WIDGET_DATA_GET_OR_RETURN(sd->obj, wd); if (!strncmp(sub_d->part, "elm.text.", strlen("elm.text."))) type = sub_d->part + strlen("elm.text."); else type = sub_d->part; snprintf(buf, sizeof(buf), "elm,state,%s,%s", type, visible ? "visible" : "hidden"); edje_object_signal_emit(wd->resize_obj, buf, "elm"); /* TODO: is this right? It was like that, but IMO it should be removed: */ snprintf(buf, sizeof(buf), visible ? "elm,state,text,visible" : "elm,state,text,hidden"); edje_object_signal_emit(wd->resize_obj, buf, "elm"); /* themes might need immediate action here */ edje_object_message_signal_process(wd->resize_obj); } static void _parts_signals_emit(Efl_Ui_Layout_Data *sd) { const Eina_List *l; Efl_Ui_Layout_Sub_Object_Data *sub_d; EINA_LIST_FOREACH(sd->subs, l, sub_d) { _icon_signal_emit(sd, sub_d, EINA_TRUE); _text_signal_emit(sd, sub_d, EINA_TRUE); } } static void _part_cursor_part_apply(const Efl_Ui_Layout_Sub_Object_Cursor *pc) { elm_object_cursor_set(pc->obj, pc->cursor); elm_object_cursor_style_set(pc->obj, pc->style); elm_object_cursor_theme_search_enabled_set(pc->obj, !pc->engine_only); } static void _parts_cursors_apply(Efl_Ui_Layout_Data *sd) { const Eina_List *l; const char *file, *group; Efl_Ui_Layout_Sub_Object_Cursor *pc; ELM_WIDGET_DATA_GET_OR_RETURN(sd->obj, wd); edje_object_file_get(wd->resize_obj, &file, &group); EINA_LIST_FOREACH(sd->parts_cursors, l, pc) { Evas_Object *obj = (Evas_Object *)edje_object_part_object_get (wd->resize_obj, pc->part); if (!obj) { pc->obj = NULL; WRN("no part '%s' in group '%s' of file '%s'. " "Cannot set cursor '%s'", pc->part, group, file, pc->cursor); continue; } else if (evas_object_pass_events_get(obj)) { pc->obj = NULL; WRN("part '%s' in group '%s' of file '%s' has mouse_events: 0. " "Cannot set cursor '%s'", pc->part, group, file, pc->cursor); continue; } pc->obj = obj; _part_cursor_part_apply(pc); } } static void _efl_ui_layout_highlight_in_theme(Evas_Object *obj) { const char *fh; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); fh = edje_object_data_get (wd->resize_obj, "focus_highlight"); if ((fh) && (!strcmp(fh, "on"))) elm_widget_highlight_in_theme_set(obj, EINA_TRUE); else elm_widget_highlight_in_theme_set(obj, EINA_FALSE); fh = edje_object_data_get (wd->resize_obj, "access_highlight"); if ((fh) && (!strcmp(fh, "on"))) elm_widget_access_highlight_in_theme_set(obj, EINA_TRUE); else elm_widget_access_highlight_in_theme_set(obj, EINA_FALSE); } static Eina_Bool _visuals_refresh(Evas_Object *obj, Efl_Ui_Layout_Data *sd) { Eina_Bool ret = EINA_FALSE; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); _parts_signals_emit(sd); _parts_cursors_apply(sd); edje_object_mirrored_set (wd->resize_obj, efl_ui_mirrored_get(obj)); edje_object_scale_set (wd->resize_obj, efl_ui_scale_get(obj) * elm_config_scale_get()); _efl_ui_layout_highlight_in_theme(obj); ret = elm_obj_widget_disable(obj); elm_layout_sizing_eval(obj); return ret; } EOLIAN static Eina_Bool _efl_ui_layout_elm_widget_disable(Eo *obj, Efl_Ui_Layout_Data *_pd EINA_UNUSED) { ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); if (elm_object_disabled_get(obj)) edje_object_signal_emit (wd->resize_obj, "elm,state,disabled", "elm"); else edje_object_signal_emit (wd->resize_obj, "elm,state,enabled", "elm"); return EINA_TRUE; } static Efl_Ui_Theme_Apply _efl_ui_layout_theme_internal(Eo *obj, Efl_Ui_Layout_Data *sd) { Efl_Ui_Theme_Apply ret = EFL_UI_THEME_APPLY_FAILED; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EFL_UI_THEME_APPLY_FAILED); /* function already prints error messages, if any */ if (!sd->file_set) { ret = elm_widget_theme_object_set (obj, wd->resize_obj, sd->klass, sd->group, elm_widget_style_get(obj)); } if (ret) efl_event_callback_legacy_call(obj, EFL_UI_LAYOUT_EVENT_THEME_CHANGED, NULL); if (!_visuals_refresh(obj, sd)) ret = EFL_UI_THEME_APPLY_FAILED; return ret; } EOLIAN static Efl_Ui_Theme_Apply _efl_ui_layout_elm_widget_theme_apply(Eo *obj, Efl_Ui_Layout_Data *sd) { Efl_Ui_Theme_Apply theme_apply = EFL_UI_THEME_APPLY_FAILED; theme_apply = elm_obj_widget_theme_apply(efl_super(obj, MY_CLASS)); if (!theme_apply) return EFL_UI_THEME_APPLY_FAILED; theme_apply &= _efl_ui_layout_theme_internal(obj, sd); return theme_apply; } static void * _efl_ui_layout_list_data_get(const Eina_List *list) { Efl_Ui_Layout_Sub_Object_Data *sub_d = eina_list_data_get(list); return sub_d->obj; } EOLIAN static Eina_Bool _efl_ui_layout_elm_widget_on_focus(Eo *obj, Efl_Ui_Layout_Data *_pd EINA_UNUSED, Elm_Object_Item *item EINA_UNUSED) { ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); if (!elm_widget_can_focus_get(obj)) return EINA_FALSE; if (elm_widget_focus_get(obj)) { elm_layout_signal_emit(obj, "elm,action,focus", "elm"); evas_object_focus_set(wd->resize_obj, EINA_TRUE); efl_event_callback_legacy_call(obj, ELM_WIDGET_EVENT_FOCUSED, NULL); if (_elm_config->atspi_mode && !elm_widget_child_can_focus_get(obj)) elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_FOCUSED, EINA_TRUE); } else { elm_layout_signal_emit(obj, "elm,action,unfocus", "elm"); evas_object_focus_set(wd->resize_obj, EINA_FALSE); efl_event_callback_legacy_call(obj, ELM_WIDGET_EVENT_UNFOCUSED, NULL); if (_elm_config->atspi_mode && !elm_widget_child_can_focus_get(obj)) elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_FOCUSED, EINA_FALSE); } if (efl_isa(wd->resize_obj, EDJE_OBJECT_CLASS)) edje_object_message_signal_process(wd->resize_obj); return EINA_TRUE; } EOLIAN static Eina_Bool _efl_ui_layout_elm_widget_focus_next_manager_is(Eo *obj EINA_UNUSED, Efl_Ui_Layout_Data *_pd EINA_UNUSED) { if (!elm_widget_can_focus_get(obj)) return EINA_TRUE; else return EINA_FALSE; } static int _access_focus_list_sort_cb(const void *data1, const void *data2) { Evas_Coord_Point p1, p2; Evas_Object *obj1, *obj2; obj1 = ((Efl_Ui_Layout_Sub_Object_Data *)data1)->obj; obj2 = ((Efl_Ui_Layout_Sub_Object_Data *)data2)->obj; evas_object_geometry_get(obj1, &p1.x, &p1.y, NULL, NULL); evas_object_geometry_get(obj2, &p2.x, &p2.y, NULL, NULL); if (p1.y == p2.y) { return p1.x - p2.x; } return p1.y - p2.y; } static const Eina_List * _access_focus_list_sort(Eina_List *origin) { Eina_List *l, *temp = NULL; Efl_Ui_Layout_Sub_Object_Data *sub_d; EINA_LIST_FOREACH(origin, l, sub_d) temp = eina_list_sorted_insert(temp, _access_focus_list_sort_cb, sub_d); return temp; } /* WARNING: if you're making a widget *not* supposed to have focusable * child objects, but still inheriting from elm_layout, just set its * focus_next smart function back to NULL */ EOLIAN static Eina_Bool _efl_ui_layout_elm_widget_focus_next(Eo *obj, Efl_Ui_Layout_Data *sd, Elm_Focus_Direction dir, Evas_Object **next, Elm_Object_Item **next_item) { const Eina_List *items; void *(*list_data_get)(const Eina_List *list); if ((items = elm_widget_focus_custom_chain_get(obj))) list_data_get = eina_list_data_get; else { items = sd->subs; list_data_get = _efl_ui_layout_list_data_get; if (!items) return EINA_FALSE; if (_elm_config->access_mode) items = _access_focus_list_sort((Eina_List *)items); } return elm_widget_focus_list_next_get (obj, items, list_data_get, dir, next, next_item); } EOLIAN static Eina_Bool _efl_ui_layout_elm_widget_sub_object_add(Eo *obj, Efl_Ui_Layout_Data *_pd EINA_UNUSED, Evas_Object *sobj) { Eina_Bool int_ret = EINA_FALSE; if (evas_object_data_get(sobj, "elm-parent") == obj) return EINA_TRUE; int_ret = elm_obj_widget_sub_object_add(efl_super(obj, MY_CLASS), sobj); if (!int_ret) return EINA_FALSE; evas_object_event_callback_add (sobj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_sub_object_size_hint_change, obj); return EINA_TRUE; } EOLIAN static Eina_Bool _efl_ui_layout_elm_widget_sub_object_del(Eo *obj, Efl_Ui_Layout_Data *sd, Evas_Object *sobj) { Eina_List *l; Efl_Ui_Layout_Sub_Object_Data *sub_d; Eina_Bool int_ret = EINA_FALSE; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); evas_object_event_callback_del_full (sobj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_sub_object_size_hint_change, obj); int_ret = elm_obj_widget_sub_object_del(efl_super(obj, MY_CLASS), sobj); if (!int_ret) return EINA_FALSE; if (sd->destructed_is) return EINA_TRUE; EINA_LIST_FOREACH(sd->subs, l, sub_d) { if (sub_d->obj != sobj) continue; sd->subs = eina_list_remove_list(sd->subs, l); _icon_signal_emit(sd, sub_d, EINA_FALSE); eina_stringshare_del(sub_d->part); free(sub_d); break; } elm_layout_sizing_eval(obj); return EINA_TRUE; } EOLIAN static Eina_Bool _efl_ui_layout_elm_widget_focus_direction_manager_is(Eo *obj EINA_UNUSED, Efl_Ui_Layout_Data *_pd EINA_UNUSED) { if (!elm_widget_can_focus_get(obj)) return EINA_TRUE; else return EINA_FALSE; } EOLIAN static Eina_Bool _efl_ui_layout_elm_widget_focus_direction(Eo *obj, Efl_Ui_Layout_Data *sd, const Evas_Object *base, double degree, Evas_Object **direction, Elm_Object_Item **direction_item, double *weight) { const Eina_List *items; void *(*list_data_get)(const Eina_List *list); if (!sd->subs) return EINA_FALSE; /* Focus chain (This block is different from elm_win cycle) */ if ((items = elm_widget_focus_custom_chain_get(obj))) list_data_get = eina_list_data_get; else { items = sd->subs; list_data_get = _efl_ui_layout_list_data_get; if (!items) return EINA_FALSE; } return elm_widget_focus_list_direction_get (obj, base, items, list_data_get, degree, direction, direction_item, weight); } static void _edje_signal_callback(void *data, Evas_Object *obj EINA_UNUSED, const char *emission, const char *source) { Edje_Signal_Data *esd = data; esd->func(esd->data, esd->obj, emission, source); } EAPI Eina_Bool _elm_layout_part_aliasing_eval(const Evas_Object *obj, const char **part, Eina_Bool is_text) { const Elm_Layout_Part_Alias_Description *aliases = NULL; if (is_text) aliases = elm_layout_text_aliases_get(obj); else aliases = elm_layout_content_aliases_get(obj); while (aliases && aliases->alias && aliases->real_part) { /* NULL matches the 1st */ if ((!*part) || (!strcmp(*part, aliases->alias))) { *part = aliases->real_part; break; } aliases++; } if (!*part) { ERR("no default content part set for object %p -- " "part must not be NULL", obj); return EINA_FALSE; } /* if no match, part goes on with the same value */ return EINA_TRUE; } static void _eo_unparent_helper(Eo *child, Eo *parent) { if (efl_parent_get(child) == parent) { efl_parent_set(child, evas_object_evas_get(parent)); } } static void _box_reference_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { Efl_Ui_Layout_Sub_Object_Data *sub_d = data; sub_d->p.box.reference = NULL; } static Evas_Object * _sub_box_remove(Evas_Object *obj, Efl_Ui_Layout_Data *sd, Efl_Ui_Layout_Sub_Object_Data *sub_d) { Evas_Object *child = sub_d->obj; /* sub_d will die in * _efl_ui_layout_smart_sub_object_del */ if (sub_d->type == BOX_INSERT_BEFORE) evas_object_event_callback_del_full ((Evas_Object *)sub_d->p.box.reference, EVAS_CALLBACK_DEL, _box_reference_del, sub_d); ELM_WIDGET_DATA_GET_OR_RETURN(sd->obj, wd, NULL); edje_object_part_box_remove (wd->resize_obj, sub_d->part, child); _eo_unparent_helper(child, obj); if (!_elm_widget_sub_object_redirect_to_top(obj, child)) { ERR("could not remove sub object %p from %p", child, obj); return NULL; } return child; } static Eina_Bool _sub_box_is(const Efl_Ui_Layout_Sub_Object_Data *sub_d) { switch (sub_d->type) { case BOX_APPEND: case BOX_PREPEND: case BOX_INSERT_BEFORE: case BOX_INSERT_AT: return EINA_TRUE; default: return EINA_FALSE; } } static Evas_Object * _sub_table_remove(Evas_Object *obj, Efl_Ui_Layout_Data *sd, Efl_Ui_Layout_Sub_Object_Data *sub_d) { Evas_Object *child; ELM_WIDGET_DATA_GET_OR_RETURN(sd->obj, wd, NULL); child = sub_d->obj; /* sub_d will die in _efl_ui_layout_smart_sub_object_del */ edje_object_part_table_unpack (wd->resize_obj, sub_d->part, child); _eo_unparent_helper(child, obj); if (!_elm_widget_sub_object_redirect_to_top(obj, child)) { ERR("could not remove sub object %p from %p", child, obj); return NULL; } return child; } static void _on_size_evaluate_signal(void *data, Evas_Object *obj EINA_UNUSED, const char *emission EINA_UNUSED, const char *source EINA_UNUSED) { elm_layout_sizing_eval(data); } EOLIAN static void _efl_ui_layout_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Layout_Data *_pd EINA_UNUSED) { Evas_Object *edje; elm_widget_sub_object_parent_add(obj); /* has to be there *before* parent's smart_add() */ edje = edje_object_add(evas_object_evas_get(obj)); elm_widget_resize_object_set(obj, edje); efl_canvas_group_add(efl_super(obj, MY_CLASS)); elm_widget_can_focus_set(obj, EINA_FALSE); edje_object_signal_callback_add (edje, "size,eval", "elm", _on_size_evaluate_signal, obj); elm_layout_sizing_eval(obj); } EOLIAN static void _efl_ui_layout_efl_canvas_group_group_del(Eo *obj, Efl_Ui_Layout_Data *sd) { Efl_Ui_Layout_Sub_Object_Data *sub_d; Efl_Ui_Layout_Sub_Object_Cursor *pc; Edje_Signal_Data *esd; Evas_Object *child; Eina_List *l; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); elm_layout_freeze(obj); EINA_LIST_FREE(sd->subs, sub_d) { eina_stringshare_del(sub_d->part); free(sub_d); } EINA_LIST_FREE(sd->parts_cursors, pc) _part_cursor_free(pc); EINA_LIST_FREE(sd->edje_signals, esd) { edje_object_signal_callback_del_full (wd->resize_obj, esd->emission, esd->source, _edje_signal_callback, esd); eina_stringshare_del(esd->emission); eina_stringshare_del(esd->source); free(esd); } if(sd->model) { efl_event_callback_del(sd->model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _efl_model_properties_changed_cb, sd); efl_unref(sd->model); sd->model = NULL; } eina_hash_free(sd->prop_connect); sd->prop_connect = NULL; eina_hash_free(sd->factories); sd->factories = NULL; eina_stringshare_del(sd->klass); eina_stringshare_del(sd->group); /* let's make our Edje object the *last* to be processed, since it * may (smart) parent other sub objects here */ EINA_LIST_FOREACH(wd->subobjs, l, child) { if (child == wd->resize_obj) { wd->subobjs = eina_list_demote_list(wd->subobjs, l); break; } } sd->destructed_is = EINA_TRUE; efl_canvas_group_del(efl_super(obj, MY_CLASS)); } /* rewrite or extend this one on your derived class as to suit your * needs */ EOLIAN static void _efl_ui_layout_efl_canvas_group_group_calculate(Eo *obj, Efl_Ui_Layout_Data *sd) { if (sd->needs_size_calc) { _sizing_eval(obj, sd); sd->needs_size_calc = EINA_FALSE; } } static Efl_Ui_Layout_Sub_Object_Cursor * _parts_cursors_find(Efl_Ui_Layout_Data *sd, const char *part) { const Eina_List *l; Efl_Ui_Layout_Sub_Object_Cursor *pc; EINA_LIST_FOREACH(sd->parts_cursors, l, pc) { if (!strcmp(pc->part, part)) return pc; } return NULL; } /* The public functions down here are meant to operate on whichever * widget inheriting from elm_layout */ EOLIAN static Eina_Bool _efl_ui_layout_efl_file_file_set(Eo *obj, Efl_Ui_Layout_Data *sd, const char *file, const char *group) { Eina_Bool int_ret = EINA_FALSE; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); int_ret = edje_object_file_set(wd->resize_obj, file, group); if (int_ret) { sd->file_set = EINA_TRUE; _visuals_refresh(obj, sd); } else ERR("failed to set edje file '%s', group '%s': %s", file, group, edje_load_error_str (edje_object_load_error_get(wd->resize_obj))); return int_ret; } EOLIAN static void _efl_ui_layout_efl_file_file_get(Eo *obj, Efl_Ui_Layout_Data *sd EINA_UNUSED, const char **file, const char **group) { ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); edje_object_file_get(wd->resize_obj, file, group); } EOLIAN static Eina_Bool _efl_ui_layout_efl_file_mmap_set(Eo *obj, Efl_Ui_Layout_Data *sd, const Eina_File *file, const char *group) { Eina_Bool int_ret = EINA_FALSE; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); int_ret = edje_object_mmap_set(wd->resize_obj, file, group); if (int_ret) { sd->file_set = EINA_TRUE; _visuals_refresh(obj, sd); } else ERR("failed to set edje mmap file %p, group '%s': %s", file, group, edje_load_error_str (edje_object_load_error_get(wd->resize_obj))); return int_ret; } EOLIAN static void _efl_ui_layout_efl_file_mmap_get(Eo *obj, Efl_Ui_Layout_Data *sd EINA_UNUSED, const Eina_File **file, const char **group) { ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); efl_file_mmap_get(wd->resize_obj, file, group); } EOLIAN static Efl_Ui_Theme_Apply _efl_ui_layout_theme_set(Eo *obj, Efl_Ui_Layout_Data *sd, const char *klass, const char *group, const char *style) { ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); + if (!wd->legacy && efl_finalized_get(obj)) + { + ERR("Efl.Ui.Layout.theme can only be set before finalize!"); + return EFL_UI_THEME_APPLY_FAILED; + } + if (sd->file_set) sd->file_set = EINA_FALSE; eina_stringshare_replace(&(sd->klass), klass); eina_stringshare_replace(&(sd->group), group); eina_stringshare_replace(&(wd->style), style); return _efl_ui_layout_theme_internal(obj, sd); } EOLIAN static void _efl_ui_layout_efl_canvas_layout_signal_signal_emit(Eo *obj, Efl_Ui_Layout_Data *_pd EINA_UNUSED, const char *emission, const char *source) { // Don't do anything else than call forward here ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); efl_canvas_layout_signal_emit(wd->resize_obj, emission, source); } EOLIAN static Eina_Bool _efl_ui_layout_efl_canvas_layout_signal_signal_callback_add(Eo *obj, Efl_Ui_Layout_Data *_pd EINA_UNUSED, const char *emission, const char *source, Efl_Signal_Cb func, void *data) { // Don't do anything else than call forward here ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); return efl_canvas_layout_signal_callback_add(wd->resize_obj, emission, source, func, data); } EOLIAN static Eina_Bool _efl_ui_layout_efl_canvas_layout_signal_signal_callback_del(Eo *obj, Efl_Ui_Layout_Data *_pd EINA_UNUSED, const char *emission, const char *source, Edje_Signal_Cb func, void *data) { // Don't do anything else than call forward here ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); return efl_canvas_layout_signal_callback_add(wd->resize_obj, emission, source, func, data); } // TODO: // - message_send // - message_signal_process // and also message handler (not implemented yet as an EO interface!) EAPI Eina_Bool elm_layout_content_set(Evas_Object *obj, const char *swallow, Evas_Object *content) { EFL_UI_LAYOUT_CHECK(obj) EINA_FALSE; if (!swallow) { swallow = elm_widget_default_content_part_get(obj); if (!swallow) return EINA_FALSE; } return efl_content_set(efl_part(obj, swallow), content); } static Eina_Bool _efl_ui_layout_content_set(Eo *obj, Efl_Ui_Layout_Data *sd, const char *part, Evas_Object *content) { Efl_Ui_Layout_Sub_Object_Data *sub_d; const Eina_List *l; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); if (!_elm_layout_part_aliasing_eval(obj, &part, EINA_FALSE)) return EINA_FALSE; EINA_LIST_FOREACH(sd->subs, l, sub_d) { if (sub_d->type == SWALLOW) { if (!strcmp(part, sub_d->part)) { if (content == sub_d->obj) goto end; _eo_unparent_helper(sub_d->obj, obj); evas_object_del(sub_d->obj); break; } /* was previously swallowed at another part -- mimic * edje_object_part_swallow()'s behavior, then */ else if (content == sub_d->obj) { _elm_widget_sub_object_redirect_to_top(obj, content); break; } } } if (content) { if (!elm_widget_sub_object_add(obj, content)) return EINA_FALSE; if (!edje_object_part_swallow (wd->resize_obj, part, content)) { ERR("could not swallow %p into part '%s'", content, part); _elm_widget_sub_object_redirect_to_top(obj, content); return EINA_FALSE; } sub_d = ELM_NEW(Efl_Ui_Layout_Sub_Object_Data); if (!sub_d) { ERR("failed to allocate memory!"); edje_object_part_unswallow(wd->resize_obj, content); _elm_widget_sub_object_redirect_to_top(obj, content); return EINA_FALSE; } sub_d->type = SWALLOW; sub_d->part = eina_stringshare_add(part); sub_d->obj = content; sd->subs = eina_list_append(sd->subs, sub_d); efl_parent_set(content, obj); _icon_signal_emit(sd, sub_d, EINA_TRUE); } elm_layout_sizing_eval(obj); end: return EINA_TRUE; } EAPI Evas_Object * elm_layout_content_get(const Evas_Object *obj, const char *swallow) { EFL_UI_LAYOUT_CHECK(obj) NULL; if (!swallow) { swallow = elm_widget_default_content_part_get(obj); if (!swallow) return NULL; } return efl_content_get(efl_part(obj, swallow)); } static Evas_Object* _efl_ui_layout_content_get(Eo *obj, Efl_Ui_Layout_Data *sd, const char *part) { const Eina_List *l; Efl_Ui_Layout_Sub_Object_Data *sub_d; if (!_elm_layout_part_aliasing_eval(obj, &part, EINA_FALSE)) return NULL; EINA_LIST_FOREACH(sd->subs, l, sub_d) { if ((sub_d->type != TEXT) && !strcmp(part, sub_d->part)) { if (sub_d->type == SWALLOW) return sub_d->obj; } } ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL); return efl_content_get(efl_part(wd->resize_obj, part)); } EAPI Evas_Object * elm_layout_content_unset(Evas_Object *obj, const char *swallow) { EFL_UI_LAYOUT_CHECK(obj) NULL; return efl_content_unset(efl_part(obj, swallow)); } static Evas_Object* _efl_ui_layout_content_unset(Eo *obj, Efl_Ui_Layout_Data *sd, const char *part) { Efl_Ui_Layout_Sub_Object_Data *sub_d; const Eina_List *l; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL); if (!_elm_layout_part_aliasing_eval(obj, &part, EINA_FALSE)) return NULL; EINA_LIST_FOREACH(sd->subs, l, sub_d) { if ((sub_d->type == SWALLOW) && (!strcmp(part, sub_d->part))) { Evas_Object *content; if (!sub_d->obj) return NULL; content = sub_d->obj; /* sub_d will die in * _efl_ui_layout_smart_sub_object_del */ if (!_elm_widget_sub_object_redirect_to_top(obj, content)) { ERR("could not remove sub object %p from %p", content, obj); return NULL; } edje_object_part_unswallow (wd->resize_obj, content); _eo_unparent_helper(content, obj); return content; } } return NULL; } EOLIAN static Eina_Bool _efl_ui_layout_efl_container_content_set(Eo *obj, Efl_Ui_Layout_Data *sd, Evas_Object *content) { return _efl_ui_layout_content_set(obj, sd, NULL, content); } EOLIAN static Evas_Object* _efl_ui_layout_efl_container_content_get(Eo *obj EINA_UNUSED, Efl_Ui_Layout_Data *sd) { return _efl_ui_layout_content_get(obj, sd, NULL); } EOLIAN static Evas_Object* _efl_ui_layout_efl_container_content_unset(Eo *obj, Efl_Ui_Layout_Data *sd) { return _efl_ui_layout_content_unset(obj, sd, NULL); } EOLIAN static Eina_Bool _efl_ui_layout_efl_container_content_remove(Eo *obj, Efl_Ui_Layout_Data *sd EINA_UNUSED, Efl_Gfx *content) { ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); if (!_elm_widget_sub_object_redirect_to_top(obj, content)) { ERR("could not remove sub object %p from %p", content, obj); return EINA_FALSE; } edje_object_part_unswallow(wd->resize_obj, content); _eo_unparent_helper(content, obj); return EINA_TRUE; } /* legacy only - eo is iterator */ EAPI Eina_List * elm_layout_content_swallow_list_get(const Evas_Object *obj) { EFL_UI_LAYOUT_CHECK(obj) NULL; Eina_List *ret = NULL; Efl_Ui_Layout_Sub_Object_Data *sub_d = NULL; Efl_Ui_Layout_Data *sd = efl_data_scope_get(obj, MY_CLASS); Eina_List *l = NULL; EINA_LIST_FOREACH(sd->subs, l, sub_d) { if (sub_d->type == SWALLOW) ret = eina_list_append(ret, sub_d->obj); } return ret; } static Eina_Bool _sub_iterator_next(Efl_Ui_Layout_Sub_Iterator *it, void **data) { Efl_Ui_Layout_Sub_Object_Data *sub; if (!eina_iterator_next(it->real_iterator, (void **)&sub)) return EINA_FALSE; if (data) *data = sub->obj; return EINA_TRUE; } static Efl_Ui_Layout * _sub_iterator_get_container(Efl_Ui_Layout_Sub_Iterator *it) { return it->object; } static void _sub_iterator_free(Efl_Ui_Layout_Sub_Iterator *it) { eina_iterator_free(it->real_iterator); free(it); } static Eina_Iterator * _sub_iterator_create(Eo *eo_obj, Efl_Ui_Layout_Data *sd) { Efl_Ui_Layout_Sub_Iterator *it; it = calloc(1, sizeof(*it)); if (!it) return NULL; EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); it->real_iterator = eina_list_iterator_new(sd->subs); it->iterator.version = EINA_ITERATOR_VERSION; it->iterator.next = FUNC_ITERATOR_NEXT(_sub_iterator_next); it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_sub_iterator_get_container); it->iterator.free = FUNC_ITERATOR_FREE(_sub_iterator_free); it->object = eo_obj; return &it->iterator; } EOLIAN static Eina_Iterator * _efl_ui_layout_efl_container_content_iterate(Eo *eo_obj EINA_UNUSED, Efl_Ui_Layout_Data *sd) { return _sub_iterator_create(eo_obj, sd); } EOLIAN static int _efl_ui_layout_efl_container_content_count(Eo *eo_obj EINA_UNUSED, Efl_Ui_Layout_Data *sd) { return eina_list_count(sd->subs); } EOLIAN static Eina_Bool _efl_ui_layout_text_set(Eo *obj, Efl_Ui_Layout_Data *sd, const char *part, const char *text) { ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); Eina_List *l; Efl_Ui_Layout_Sub_Object_Data *sub_d = NULL; if (!_elm_layout_part_aliasing_eval(obj, &part, EINA_TRUE)) return EINA_FALSE; EINA_LIST_FOREACH(sd->subs, l, sub_d) { if ((sub_d->type == TEXT) && (!strcmp(part, sub_d->part))) { if (!text) { _text_signal_emit(sd, sub_d, EINA_FALSE); eina_stringshare_del(sub_d->part); free(sub_d); edje_object_part_text_escaped_set (wd->resize_obj, part, NULL); sd->subs = eina_list_remove_list(sd->subs, l); return EINA_TRUE; } else break; } } if (!text) return EINA_TRUE; if (!edje_object_part_text_escaped_set (wd->resize_obj, part, text)) return EINA_FALSE; if (!sub_d) { sub_d = ELM_NEW(Efl_Ui_Layout_Sub_Object_Data); if (!sub_d) return EINA_FALSE; sub_d->type = TEXT; sub_d->part = eina_stringshare_add(part); sd->subs = eina_list_append(sd->subs, sub_d); } _text_signal_emit(sd, sub_d, EINA_TRUE); elm_layout_sizing_eval(obj); if (_elm_config->access_mode == ELM_ACCESS_MODE_ON && sd->can_access && !(sub_d->obj)) sub_d->obj = _elm_access_edje_object_part_object_register (obj, elm_layout_edje_get(obj), part); if (sd->model && !sd->view_updated) { Eina_Stringshare *prop = eina_hash_find(sd->prop_connect, sub_d->part); if (prop) { Eina_Value v; eina_value_setup(&v, EINA_VALUE_TYPE_STRING); eina_value_set(&v, text); efl_model_property_set(sd->model, prop, &v); eina_value_flush(&v); } } sd->view_updated = EINA_FALSE; return EINA_TRUE; } EOLIAN static const char* _efl_ui_layout_text_get(Eo *obj, Efl_Ui_Layout_Data *sd EINA_UNUSED, const char *part) { ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL); if (!_elm_layout_part_aliasing_eval(obj, &part, EINA_TRUE)) return NULL; return edje_object_part_text_get(wd->resize_obj, part); } static void _layout_box_subobj_init(Efl_Ui_Layout_Data *sd, Efl_Ui_Layout_Sub_Object_Data *sub_d, const char *part, Evas_Object *child) { sub_d->part = eina_stringshare_add(part); sub_d->obj = child; sd->subs = eina_list_append(sd->subs, sub_d); efl_parent_set(child, sd->obj); } Eina_Bool _efl_ui_layout_box_append(Eo *obj, Efl_Ui_Layout_Data *sd, const char *part, Evas_Object *child) { Efl_Ui_Layout_Sub_Object_Data *sub_d; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); if (!edje_object_part_box_append (wd->resize_obj, part, child)) { ERR("child %p could not be appended to box part '%s'", child, part); return EINA_FALSE; } if (!elm_widget_sub_object_add(obj, child)) { edje_object_part_box_remove (wd->resize_obj, part, child); return EINA_FALSE; } sub_d = ELM_NEW(Efl_Ui_Layout_Sub_Object_Data); if (!sub_d) { ERR("failed to allocate memory!"); _elm_widget_sub_object_redirect_to_top(obj, child); edje_object_part_box_remove(wd->resize_obj, part, child); return EINA_FALSE; } sub_d->type = BOX_APPEND; _layout_box_subobj_init(sd, sub_d, part, child); elm_layout_sizing_eval(obj); return EINA_TRUE; } Eina_Bool _efl_ui_layout_box_prepend(Eo *obj, Efl_Ui_Layout_Data *sd, const char *part, Evas_Object *child) { Efl_Ui_Layout_Sub_Object_Data *sub_d; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); if (!edje_object_part_box_prepend (wd->resize_obj, part, child)) { ERR("child %p could not be prepended to box part '%s'", child, part); return EINA_FALSE; } if (!elm_widget_sub_object_add(obj, child)) { edje_object_part_box_remove (wd->resize_obj, part, child); return EINA_FALSE; } sub_d = ELM_NEW(Efl_Ui_Layout_Sub_Object_Data); if (!sub_d) { ERR("failed to allocate memory!"); _elm_widget_sub_object_redirect_to_top(obj, child); edje_object_part_box_remove(wd->resize_obj, part, child); return EINA_FALSE; } sub_d->type = BOX_PREPEND; _layout_box_subobj_init(sd, sub_d, part, child); elm_layout_sizing_eval(obj); return EINA_TRUE; } Eina_Bool _efl_ui_layout_box_insert_before(Eo *obj, Efl_Ui_Layout_Data *sd, const char *part, Evas_Object *child, const Evas_Object *reference) { Efl_Ui_Layout_Sub_Object_Data *sub_d; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); if (!edje_object_part_box_insert_before (wd->resize_obj, part, child, reference)) { ERR("child %p could not be inserted before %p inf box part '%s'", child, reference, part); return EINA_FALSE; } if (!elm_widget_sub_object_add(obj, child)) { edje_object_part_box_remove (wd->resize_obj, part, child); return EINA_FALSE; } sub_d = ELM_NEW(Efl_Ui_Layout_Sub_Object_Data); if (!sub_d) { ERR("failed to allocate memory!"); _elm_widget_sub_object_redirect_to_top(obj, child); edje_object_part_box_remove(wd->resize_obj, part, child); return EINA_FALSE; } sub_d->type = BOX_INSERT_BEFORE; sub_d->p.box.reference = reference; _layout_box_subobj_init(sd, sub_d, part, child); evas_object_event_callback_add ((Evas_Object *)reference, EVAS_CALLBACK_DEL, _box_reference_del, sub_d); elm_layout_sizing_eval(obj); return EINA_TRUE; } Eina_Bool _efl_ui_layout_box_insert_at(Eo *obj, Efl_Ui_Layout_Data *sd, const char *part, Evas_Object *child, unsigned int pos) { Efl_Ui_Layout_Sub_Object_Data *sub_d; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); if (!edje_object_part_box_insert_at (wd->resize_obj, part, child, pos)) { ERR("child %p could not be inserted at %u to box part '%s'", child, pos, part); return EINA_FALSE; } if (!elm_widget_sub_object_add(obj, child)) { edje_object_part_box_remove (wd->resize_obj, part, child); return EINA_FALSE; } sub_d = ELM_NEW(Efl_Ui_Layout_Sub_Object_Data); if (!sub_d) { ERR("failed to allocate memory!"); _elm_widget_sub_object_redirect_to_top(obj, child); edje_object_part_box_remove(wd->resize_obj, part, child); return EINA_FALSE; } sub_d->type = BOX_INSERT_AT; sub_d->p.box.pos = pos; _layout_box_subobj_init(sd, sub_d, part, child); elm_layout_sizing_eval(obj); return EINA_TRUE; } Evas_Object * _efl_ui_layout_box_remove(Eo *obj, Efl_Ui_Layout_Data *sd, const char *part, Evas_Object *child) { EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(child, NULL); const Eina_List *l; Efl_Ui_Layout_Sub_Object_Data *sub_d; EINA_LIST_FOREACH(sd->subs, l, sub_d) { if (!_sub_box_is(sub_d)) continue; if ((sub_d->obj == child) && (!strcmp(sub_d->part, part))) return _sub_box_remove(obj, sd, sub_d); } return NULL; } Eina_Bool _efl_ui_layout_box_remove_all(Eo *obj, Efl_Ui_Layout_Data *sd, const char *part, Eina_Bool clear) { EINA_SAFETY_ON_NULL_RETURN_VAL(part, EINA_FALSE); ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); Efl_Ui_Layout_Sub_Object_Data *sub_d; Eina_List *lst; lst = eina_list_clone(sd->subs); EINA_LIST_FREE(lst, sub_d) { if (!_sub_box_is(sub_d)) continue; if (!strcmp(sub_d->part, part)) { /* original item's deletion handled at sub-obj-del */ Evas_Object *child = _sub_box_remove(obj, sd, sub_d); if ((clear) && (child)) evas_object_del(child); } } /* eventually something may not be added with elm_layout, delete them * as well */ edje_object_part_box_remove_all (wd->resize_obj, part, clear); return EINA_TRUE; } Eina_Bool _efl_ui_layout_table_pack(Eo *obj, Efl_Ui_Layout_Data *sd, const char *part, Evas_Object *child, unsigned short col, unsigned short row, unsigned short colspan, unsigned short rowspan) { Efl_Ui_Layout_Sub_Object_Data *sub_d; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); if (!edje_object_part_table_pack (wd->resize_obj, part, child, col, row, colspan, rowspan)) { ERR("child %p could not be packed into table part '%s' col=%uh, row=%hu," " colspan=%hu, rowspan=%hu", child, part, col, row, colspan, rowspan); return EINA_FALSE; } if (!elm_widget_sub_object_add(obj, child)) { edje_object_part_table_unpack (wd->resize_obj, part, child); return EINA_FALSE; } sub_d = ELM_NEW(Efl_Ui_Layout_Sub_Object_Data); if (!sub_d) { ERR("failed to allocate memory!"); _elm_widget_sub_object_redirect_to_top(obj, child); edje_object_part_table_unpack(wd->resize_obj, part, child); return EINA_FALSE; } sub_d->type = TABLE_PACK; sub_d->part = eina_stringshare_add(part); sub_d->obj = child; sub_d->p.table.col = col; sub_d->p.table.row = row; sub_d->p.table.colspan = colspan; sub_d->p.table.rowspan = rowspan; sd->subs = eina_list_append(sd->subs, sub_d); efl_parent_set(child, obj); elm_layout_sizing_eval(obj); return EINA_TRUE; } Evas_Object * _efl_ui_layout_table_unpack(Eo *obj, Efl_Ui_Layout_Data *sd, const char *part, Evas_Object *child) { EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(child, NULL); const Eina_List *l; Efl_Ui_Layout_Sub_Object_Data *sub_d; EINA_LIST_FOREACH(sd->subs, l, sub_d) { if (sub_d->type != TABLE_PACK) continue; if ((sub_d->obj == child) && (!strcmp(sub_d->part, part))) { return _sub_table_remove(obj, sd, sub_d); } } return NULL; } Eina_Bool _efl_ui_layout_table_clear(Eo *obj, Efl_Ui_Layout_Data *sd, const char *part, Eina_Bool clear) { EINA_SAFETY_ON_NULL_RETURN_VAL(part, EINA_FALSE); ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); Efl_Ui_Layout_Sub_Object_Data *sub_d; Eina_List *lst; lst = eina_list_clone(sd->subs); EINA_LIST_FREE(lst, sub_d) { if (sub_d->type != TABLE_PACK) continue; if (!strcmp(sub_d->part, part)) { /* original item's deletion handled at sub-obj-del */ Evas_Object *child = _sub_table_remove(obj, sd, sub_d); if ((clear) && (child)) evas_object_del(child); } } /* eventually something may not be added with elm_layout, delete them * as well */ edje_object_part_table_clear(wd->resize_obj, part, clear); return EINA_TRUE; } EAPI Evas_Object* elm_layout_edje_get(const Eo *obj) { EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(obj, MY_CLASS), NULL); ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL); return wd->resize_obj; } EOLIAN static const char * _efl_ui_layout_efl_canvas_layout_group_group_data_get(Eo *obj, Efl_Ui_Layout_Data *_pd EINA_UNUSED, const char *key) { ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL); return efl_canvas_layout_group_data_get(wd->resize_obj, key); } EOLIAN static void _efl_ui_layout_efl_canvas_layout_group_group_size_min_get(Eo *obj, Efl_Ui_Layout_Data *_pd EINA_UNUSED, int *w, int *h) { ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); efl_canvas_layout_group_size_min_get(wd->resize_obj, w, h); } EOLIAN static void _efl_ui_layout_efl_canvas_layout_group_group_size_max_get(Eo *obj, Efl_Ui_Layout_Data *_pd EINA_UNUSED, int *w, int *h) { ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); efl_canvas_layout_group_size_max_get(wd->resize_obj, w, h); } /* layout's sizing evaluation is deferred. evaluation requests are * queued up and only flag the object as 'changed'. when it comes to * Evas's rendering phase, it will be addressed, finally (see * _efl_ui_layout_smart_calculate()). */ static void _elm_layout_sizing_eval(Eo *obj, Efl_Ui_Layout_Data *sd) { if (sd->frozen) return; if (sd->needs_size_calc) return; sd->needs_size_calc = EINA_TRUE; evas_object_smart_changed(obj); } EAPI void elm_layout_sizing_restricted_eval(Eo *obj, Eina_Bool w, Eina_Bool h) { Efl_Ui_Layout_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS); if (!sd) return; sd->restricted_calc_w = !!w; sd->restricted_calc_h = !!h; evas_object_smart_changed(obj); } EOLIAN static int _efl_ui_layout_efl_canvas_layout_calc_calc_freeze(Eo *obj, Efl_Ui_Layout_Data *sd) { ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, 0); if ((sd->frozen)++ != 0) return sd->frozen; edje_object_freeze(wd->resize_obj); return 1; } EOLIAN static int _efl_ui_layout_efl_canvas_layout_calc_calc_thaw(Eo *obj, Efl_Ui_Layout_Data *sd) { ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, 0); if (--(sd->frozen) != 0) return sd->frozen; edje_object_thaw(wd->resize_obj); elm_layout_sizing_eval(obj); return 0; } static Eina_Bool _efl_ui_layout_part_cursor_set(Efl_Ui_Layout_Data *sd, const char *part_name, const char *cursor) { Evas_Object *part_obj; Efl_Ui_Layout_Sub_Object_Cursor *pc; Eo *obj = sd->obj; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE); if (!cursor) return _efl_ui_layout_part_cursor_unset(sd, part_name); part_obj = (Evas_Object *)edje_object_part_object_get (wd->resize_obj, part_name); if (!part_obj) { const char *group, *file; edje_object_file_get(wd->resize_obj, &file, &group); ERR("no part '%s' in group '%s' of file '%s'. Cannot set cursor '%s'", part_name, group, file, cursor); return EINA_FALSE; } if (evas_object_pass_events_get(part_obj)) { const char *group, *file; edje_object_file_get(wd->resize_obj, &file, &group); ERR("part '%s' in group '%s' of file '%s' has mouse_events: 0. " "Cannot set cursor '%s'", part_name, group, file, cursor); return EINA_FALSE; } pc = _parts_cursors_find(sd, part_name); if (pc) eina_stringshare_replace(&pc->cursor, cursor); else { pc = calloc(1, sizeof(*pc)); if (!pc) { ERR("failed to allocate memory!"); return EINA_FALSE; } pc->part = eina_stringshare_add(part_name); pc->cursor = eina_stringshare_add(cursor); pc->style = eina_stringshare_add("default"); sd->parts_cursors = eina_list_append(sd->parts_cursors, pc); } pc->obj = part_obj; elm_object_sub_cursor_set(part_obj, obj, pc->cursor); return EINA_TRUE; } static const char * _efl_ui_layout_part_cursor_get(Efl_Ui_Layout_Data *sd, const char *part_name) { EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, NULL); Efl_Ui_Layout_Sub_Object_Cursor *pc = _parts_cursors_find(sd, part_name); EINA_SAFETY_ON_NULL_RETURN_VAL(pc, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, NULL); return elm_object_cursor_get(pc->obj); } static Eina_Bool _efl_ui_layout_part_cursor_unset(Efl_Ui_Layout_Data *sd, const char *part_name) { EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE); Eina_List *l; Efl_Ui_Layout_Sub_Object_Cursor *pc; EINA_LIST_FOREACH(sd->parts_cursors, l, pc) { if (!strcmp(part_name, pc->part)) { if (pc->obj) elm_object_cursor_unset(pc->obj); _part_cursor_free(pc); sd->parts_cursors = eina_list_remove_list(sd->parts_cursors, l); return EINA_TRUE; } } return EINA_FALSE; } static Eina_Bool _efl_ui_layout_part_cursor_style_set(Efl_Ui_Layout_Data *sd, const char *part_name, const char *style) { EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE); Efl_Ui_Layout_Sub_Object_Cursor *pc = _parts_cursors_find(sd, part_name); EINA_SAFETY_ON_NULL_RETURN_VAL(pc, EINA_FALSE); EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, EINA_FALSE); eina_stringshare_replace(&pc->style, style); elm_object_cursor_style_set(pc->obj, pc->style); return EINA_TRUE; } static const char* _efl_ui_layout_part_cursor_style_get(Efl_Ui_Layout_Data *sd, const char *part_name) { EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, NULL); Efl_Ui_Layout_Sub_Object_Cursor *pc = _parts_cursors_find(sd, part_name); EINA_SAFETY_ON_NULL_RETURN_VAL(pc, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, NULL); return elm_object_cursor_style_get(pc->obj); } static Eina_Bool _efl_ui_layout_part_cursor_engine_only_set(Efl_Ui_Layout_Data *sd, const char *part_name, Eina_Bool engine_only) { EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE); Efl_Ui_Layout_Sub_Object_Cursor *pc = _parts_cursors_find(sd, part_name); EINA_SAFETY_ON_NULL_RETURN_VAL(pc, EINA_FALSE); EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, EINA_FALSE); pc->engine_only = !!engine_only; elm_object_cursor_theme_search_enabled_set(pc->obj, !pc->engine_only); return EINA_TRUE; } static Eina_Bool _efl_ui_layout_part_cursor_engine_only_get(Efl_Ui_Layout_Data *sd, const char *part_name) { EINA_SAFETY_ON_NULL_RETURN_VAL(part_name, EINA_FALSE); Efl_Ui_Layout_Sub_Object_Cursor *pc = _parts_cursors_find(sd, part_name); EINA_SAFETY_ON_NULL_RETURN_VAL(pc, EINA_FALSE); EINA_SAFETY_ON_NULL_RETURN_VAL(pc->obj, EINA_FALSE); return !elm_object_cursor_theme_search_enabled_get(pc->obj); } EAPI Eina_Bool elm_layout_edje_object_can_access_set(Eo *obj, Eina_Bool can_access) { Efl_Ui_Layout_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS); EINA_SAFETY_ON_NULL_RETURN_VAL(sd, EINA_FALSE); sd->can_access = !!can_access; return EINA_TRUE; } EAPI Eina_Bool elm_layout_edje_object_can_access_get(const Eo *obj) { Efl_Ui_Layout_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS); EINA_SAFETY_ON_NULL_RETURN_VAL(sd, EINA_FALSE); return sd->can_access; } EOLIAN static void _efl_ui_layout_efl_object_dbg_info_get(Eo *eo_obj, Efl_Ui_Layout_Data *_pd EINA_UNUSED, Efl_Dbg_Info *root) { efl_dbg_info_get(efl_super(eo_obj, MY_CLASS), root); ELM_WIDGET_DATA_GET_OR_RETURN(eo_obj, wd); if (wd->resize_obj && efl_isa(wd->resize_obj, EDJE_OBJECT_CLASS)) { Efl_Dbg_Info *group = EFL_DBG_INFO_LIST_APPEND(root, MY_CLASS_NAME); const char *file, *edje_group; Evas_Object *edje_obj = wd->resize_obj; Edje_Load_Error error; efl_file_get(edje_obj, &file, &edje_group); EFL_DBG_INFO_APPEND(group, "File", EINA_VALUE_TYPE_STRING, file); EFL_DBG_INFO_APPEND(group, "Group", EINA_VALUE_TYPE_STRING, edje_group); error = edje_object_load_error_get(edje_obj); if (error != EDJE_LOAD_ERROR_NONE) { EFL_DBG_INFO_APPEND(group, "Error", EINA_VALUE_TYPE_STRING, edje_load_error_str(error)); } } } static void _prop_future_error_cb(void* data, Efl_Event const*event EINA_UNUSED) { Efl_Ui_Layout_Sub_Property_Future *sub_pp = data; Eina_Array_Iterator iterator; Eina_Stringshare *name; unsigned int i = 0; EINA_ARRAY_ITER_NEXT(sub_pp->name_arr, i, name, iterator) eina_stringshare_del(name); eina_array_free(sub_pp->name_arr); free(sub_pp); } static void _view_update(Efl_Ui_Layout_Data *pd, const char *name, const char *property) { Eina_Strbuf *buf; if (strncmp(SIGNAL_PREFIX, name, sizeof(SIGNAL_PREFIX) -1) != 0) { elm_layout_text_set(pd->obj, name, property); return; } ELM_WIDGET_DATA_GET_OR_RETURN(pd->obj, wd); buf = eina_strbuf_new(); eina_strbuf_append(buf, name); eina_strbuf_remove(buf, 0, sizeof(SIGNAL_PREFIX)-1); eina_strbuf_replace_all(buf, "%v", property); edje_object_signal_emit(wd->resize_obj, eina_strbuf_string_get(buf), "elm"); eina_strbuf_free(buf); } static void _prop_future_then_cb(void* data, Efl_Event const*event) { Efl_Ui_Layout_Sub_Property_Future *sub_pp = data; Efl_Ui_Layout_Data *pd = sub_pp->pd; Eina_Accessor *value_acc = (Eina_Accessor *)((Efl_Future_Event_Success*)event->info)->value; Eina_Value *value; Eina_Stringshare *name; char *text; unsigned int i = 0; unsigned int acc_i = 0; while (eina_accessor_data_get(value_acc, acc_i, (void **)&value)) { const Eina_Value_Type *vtype = eina_value_type_get(value); name = eina_array_data_get(sub_pp->name_arr, i); pd->view_updated = EINA_TRUE; if (vtype == EINA_VALUE_TYPE_STRING || vtype == EINA_VALUE_TYPE_STRINGSHARE) { eina_value_get(value, &text); _view_update(pd, name, text); } else { text = eina_value_to_string(value); _view_update(pd, name, text); free(text); } eina_stringshare_del(name); ++acc_i; } eina_array_free(sub_pp->name_arr); free(sub_pp); } static void _efl_ui_layout_view_model_update(Efl_Ui_Layout_Data *pd) { Efl_Ui_Layout_Sub_Property_Future *sub_pp; Efl_Future **future_arr, **f, *future_all; Eina_Hash_Tuple *tuple; Eina_Iterator *it_p; int size; if (!pd->prop_connect || !pd->model) return; size = eina_hash_population(pd->prop_connect); if (size == 0) return; future_arr = alloca((size + 1) * sizeof(Efl_Future*)); f = future_arr; sub_pp = ELM_NEW(Efl_Ui_Layout_Sub_Property_Future); sub_pp->pd = pd; sub_pp->name_arr = eina_array_new(size); it_p = eina_hash_iterator_tuple_new(pd->prop_connect); while (eina_iterator_next(it_p, (void **)&tuple)) { *f = efl_model_property_get(pd->model, tuple->data); eina_array_push(sub_pp->name_arr, eina_stringshare_ref(tuple->key)); f++; } eina_iterator_free(it_p); *f = NULL; future_all = efl_future_iterator_all(eina_carray_iterator_new((void**)future_arr)); efl_future_then(future_all, &_prop_future_then_cb, &_prop_future_error_cb, NULL, sub_pp); } static void _efl_model_properties_changed_cb(void *data, const Efl_Event *event) { Efl_Ui_Layout_Data *pd = data; Efl_Model_Property_Event *evt = event->info; Eina_Stringshare *ss_prop; Eina_Hash_Tuple *tuple; Eina_Array *names, *futures; Eina_Iterator *it_p; const char *prop; Eina_Array_Iterator it; unsigned int i; if (!evt->changed_properties || !pd->prop_connect) return; names = eina_array_new(1); futures = eina_array_new(1); EINA_ARRAY_ITER_NEXT(evt->changed_properties, i, prop, it) { ss_prop = eina_stringshare_add(prop); it_p = eina_hash_iterator_tuple_new(pd->prop_connect); while (eina_iterator_next(it_p, (void **)&tuple)) { if (tuple->data == ss_prop) { eina_array_push(names, eina_stringshare_ref(tuple->key)); eina_array_push(futures, efl_model_property_get(pd->model, prop)); } } eina_iterator_free(it_p); eina_stringshare_del(ss_prop); } if (eina_array_count(names)) { Efl_Ui_Layout_Sub_Property_Future *sub_pp; Efl_Future *future_all; sub_pp = ELM_NEW(Efl_Ui_Layout_Sub_Property_Future); sub_pp->pd = pd; sub_pp->name_arr = names; future_all = efl_future_iterator_all(eina_array_iterator_new(futures)); efl_future_then(future_all, &_prop_future_then_cb, &_prop_future_error_cb, NULL, sub_pp); } else eina_array_free(names); eina_array_free(futures); } EOLIAN static void _efl_ui_layout_efl_ui_view_model_set(Eo *obj EINA_UNUSED, Efl_Ui_Layout_Data *pd, Efl_Model *model) { if (pd->model) { efl_event_callback_del(pd->model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _efl_model_properties_changed_cb, pd); efl_unref(pd->model); pd->model = NULL; } if (model) { pd->model = model; efl_ref(pd->model); efl_event_callback_add(pd->model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _efl_model_properties_changed_cb, pd); } else return; if (pd->prop_connect) _efl_ui_layout_view_model_update(pd); if (pd->factories) { Eina_Hash_Tuple *tuple; Eina_Stringshare *name; Efl_Ui_Factory *factory; Efl_Gfx *content; Eina_Iterator *it_p = eina_hash_iterator_tuple_new(pd->factories); while (eina_iterator_next(it_p, (void **)&tuple)) { name = tuple->key; factory = tuple->data; content = elm_layout_content_get(pd->obj, name); if (content && efl_isa(content, EFL_UI_VIEW_INTERFACE)) { efl_ui_view_model_set(content, pd->model); } else { efl_ui_factory_release(factory, content); content = efl_ui_factory_create(factory, pd->model, pd->obj); elm_layout_content_set(pd->obj, name, content); } } eina_iterator_free(it_p); } } EOLIAN static Efl_Model * _efl_ui_layout_efl_ui_view_model_get(Eo *obj EINA_UNUSED, Efl_Ui_Layout_Data *pd) { return pd->model; } EOLIAN static void _efl_ui_layout_efl_ui_model_connect_connect(Eo *obj EINA_UNUSED, Efl_Ui_Layout_Data *pd, const char *name, const char *property) { EINA_SAFETY_ON_NULL_RETURN(name); Eina_Stringshare *ss_name, *ss_prop; if (property == NULL && pd->prop_connect) { ss_name = eina_stringshare_add(name); eina_hash_del(pd->prop_connect, ss_name, NULL); return; } if (!_elm_layout_part_aliasing_eval(obj, &name, EINA_TRUE)) return; ss_name = eina_stringshare_add(name); ss_prop = eina_stringshare_add(property); if (!pd->prop_connect) { pd->prop_connect = eina_hash_stringshared_new(EINA_FREE_CB(eina_stringshare_del)); } eina_stringshare_del(eina_hash_set(pd->prop_connect, ss_name, ss_prop)); if (pd->model) { Efl_Ui_Layout_Sub_Property_Future *sub_pp = ELM_NEW(Efl_Ui_Layout_Sub_Property_Future); Efl_Future *futures[2] = {NULL,}; Efl_Future *future_all = NULL; sub_pp->pd = pd; sub_pp->name_arr = eina_array_new(1); eina_array_push(sub_pp->name_arr, eina_stringshare_ref(ss_name)); futures[0] = efl_model_property_get(pd->model, ss_prop); future_all = efl_future_iterator_all(eina_carray_iterator_new((void**)futures)); efl_future_then(future_all, &_prop_future_then_cb, &_prop_future_error_cb, NULL, sub_pp); } } EOLIAN static void _efl_ui_layout_efl_ui_model_factory_connect_connect(Eo *obj EINA_UNUSED, Efl_Ui_Layout_Data *pd, const char *name, Efl_Ui_Factory *factory) { EINA_SAFETY_ON_NULL_RETURN(name); Eina_Stringshare *ss_name; Efl_Ui_Factory *old_factory; Evas_Object *new_ev, *old_ev; if (!_elm_layout_part_aliasing_eval(obj, &name, EINA_TRUE)) return; ss_name = eina_stringshare_add(name); if (!pd->factories) pd->factories = eina_hash_stringshared_new(EINA_FREE_CB(efl_unref)); new_ev = efl_ui_factory_create(factory, pd->model, obj); EINA_SAFETY_ON_NULL_RETURN(new_ev); old_factory = eina_hash_set(pd->factories, ss_name, efl_ref(factory)); if (old_factory) { old_ev = elm_layout_content_get(obj, name); if (old_ev) efl_ui_factory_release(old_factory, old_ev); efl_unref(old_factory); } elm_layout_content_set(obj, name, new_ev); } EAPI Evas_Object * elm_layout_add(Evas_Object *parent) { EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL); return efl_add(MY_CLASS, parent, efl_canvas_object_legacy_ctor(efl_added)); } EOLIAN static Eo * _efl_ui_layout_efl_object_constructor(Eo *obj, Efl_Ui_Layout_Data *sd) { sd->obj = obj; 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); elm_interface_atspi_accessible_role_set(obj, ELM_ATSPI_ROLE_FILLER); return obj; } EOLIAN static void _efl_ui_layout_class_constructor(Efl_Class *klass) { evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass); } EOLIAN static void _efl_ui_layout_efl_canvas_layout_signal_message_send(Eo *obj, Efl_Ui_Layout_Data *pd EINA_UNUSED, int id, const Eina_Value msg) { ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); efl_canvas_layout_signal_message_send(wd->resize_obj, id, msg); } EOLIAN static void _efl_ui_layout_efl_canvas_layout_signal_signal_process(Eo *obj, Efl_Ui_Layout_Data *pd EINA_UNUSED, Eina_Bool recurse) { ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); efl_canvas_layout_signal_process(wd->resize_obj, recurse); } /* Legacy APIs */ EAPI Eina_Bool elm_layout_file_set(Eo *obj, const char *file, const char *group) { return efl_file_set((Eo *) obj, file, group); } EAPI void elm_layout_file_get(Eo *obj, const char **file, const char **group) { efl_file_get((Eo *) obj, file, group); } EAPI Eina_Bool elm_layout_mmap_set(Eo *obj, const Eina_File *file, const char *group) { return efl_file_mmap_set((Eo *) obj, file, group); } EAPI void elm_layout_mmap_get(Eo *obj, const Eina_File **file, const char **group) { efl_file_mmap_get((Eo *) obj, file, group); } EAPI Eina_Bool elm_layout_box_append(Eo *obj, const char *part, Evas_Object *child) { return efl_pack(efl_part(obj, part), child); } EAPI Eina_Bool elm_layout_box_prepend(Eo *obj, const char *part, Evas_Object *child) { return efl_pack_begin(efl_part(obj, part), child); } EAPI Eina_Bool elm_layout_box_insert_before(Eo *obj, const char *part, Evas_Object *child, const Evas_Object *reference) { return efl_pack_before(efl_part(obj, part), child, reference); } EAPI Eina_Bool elm_layout_box_insert_at(Eo *obj, const char *part, Evas_Object *child, unsigned int pos) { return efl_pack_at(efl_part(obj, part), child, pos); } EAPI Evas_Object * elm_layout_box_remove(Eo *obj, const char *part, Evas_Object *child) { if (!efl_pack_unpack(efl_part(obj, part), child)) return NULL; return child; } EAPI Eina_Bool elm_layout_box_remove_all(Eo *obj, const char *part, Eina_Bool clear) { if (clear) return efl_pack_clear(efl_part(obj, part)); else return efl_pack_unpack_all(efl_part(obj, part)); } EAPI Eina_Bool elm_layout_table_pack(Eo *obj, const char *part, Evas_Object *child, unsigned short col, unsigned short row, unsigned short colspan, unsigned short rowspan) { return efl_pack_grid(efl_part(obj, part), child, col, row, colspan, rowspan); } EAPI Evas_Object * elm_layout_table_unpack(Eo *obj, const char *part, Evas_Object *child) { if (!efl_pack_unpack(efl_part(obj, part), child)) return NULL; return child; } EAPI Eina_Bool elm_layout_table_clear(Eo *obj, const char *part, Eina_Bool clear) { if (clear) return efl_pack_clear(efl_part(obj, part)); else return efl_pack_unpack_all(efl_part(obj, part)); } EAPI Eina_Bool elm_layout_text_set(Eo *obj, const char *part, const char *text) { if (!part) { part = elm_widget_default_text_part_get(obj); if (!part) return EINA_FALSE; } efl_text_set(efl_part(obj, part), text); return EINA_TRUE; } EAPI const char * elm_layout_text_get(const Eo *obj, const char *part) { if (!part) { part = elm_widget_default_text_part_get(obj); if (!part) return NULL; } return efl_text_get(efl_part(obj, part)); } EAPI Eina_Bool elm_layout_part_cursor_engine_only_set(Eo *obj, const char *part, Eina_Bool engine_only) { return efl_ui_cursor_theme_search_enabled_set(efl_part(obj, part), !engine_only); } EAPI Eina_Bool elm_layout_part_cursor_engine_only_get(const Eo *obj, const char *part) { return !efl_ui_cursor_theme_search_enabled_get(efl_part(obj, part)); } EAPI Eina_Bool elm_layout_part_cursor_set(Eo *obj, const char *part, const char *cursor) { return efl_ui_cursor_set(efl_part(obj, part), cursor); } EAPI const char * elm_layout_part_cursor_get(const Eo *obj, const char *part) { return efl_ui_cursor_get(efl_part(obj, part)); } EAPI Eina_Bool elm_layout_part_cursor_style_set(Eo *obj, const char *part, const char *style) { return efl_ui_cursor_style_set(efl_part(obj, part), style); } EAPI const char * elm_layout_part_cursor_style_get(const Eo *obj, const char *part) { return efl_ui_cursor_style_get(efl_part(obj, part)); } EAPI Eina_Bool elm_layout_part_cursor_unset(Eo *obj, const char *part) { return efl_ui_cursor_set(efl_part(obj, part), NULL); } EAPI int elm_layout_freeze(Evas_Object *obj) { return efl_canvas_layout_calc_freeze(obj); } EAPI int elm_layout_thaw(Evas_Object *obj) { return efl_canvas_layout_calc_thaw(obj); } void _elm_layout_signal_callback_add_legacy(Eo *obj, Eo *edje, Eina_List **p_edje_signals, const char *emission, const char *source, Edje_Signal_Cb func, void *data) { Edje_Signal_Data *esd; esd = ELM_NEW(Edje_Signal_Data); if (!esd) return; esd->obj = obj; esd->func = func; esd->emission = eina_stringshare_add(emission); esd->source = eina_stringshare_add(source); esd->data = data; *p_edje_signals = eina_list_append(*p_edje_signals, esd); efl_canvas_layout_signal_callback_add(edje, emission, source, _edje_signal_callback, esd); } EAPI void elm_layout_signal_callback_add(Eo *obj, const char *emission, const char *source, Edje_Signal_Cb func, void *data) { Efl_Ui_Layout_Data *sd; if (!emission || !source) return; if (efl_isa(obj, ELM_ENTRY_CLASS)) { _elm_entry_signal_callback_add_legacy(obj, emission, source, func, data); return; } sd = efl_data_scope_safe_get(obj, MY_CLASS); if (!sd) return; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); _elm_layout_signal_callback_add_legacy(obj, wd->resize_obj, &sd->edje_signals, emission, source, func, data); } void * _elm_layout_signal_callback_del_legacy(Eo *obj EINA_UNUSED, Eo *edje, Eina_List **p_edje_signals, const char *emission, const char *source, Edje_Signal_Cb func) { Edje_Signal_Data *esd = NULL; void *data = NULL; Eina_List *l; if (!emission || !source) return NULL; EINA_LIST_FOREACH(*p_edje_signals, l, esd) { if ((esd->func == func) && (!strcmp(esd->emission, emission)) && (!strcmp(esd->source, source))) { *p_edje_signals = eina_list_remove_list(*p_edje_signals, l); efl_canvas_layout_signal_callback_del(edje, emission, source, _edje_signal_callback, esd); eina_stringshare_del(esd->emission); eina_stringshare_del(esd->source); data = esd->data; free(esd); return data; /* stop at 1st match */ } } return NULL; } EAPI void * elm_layout_signal_callback_del(Eo *obj, const char *emission, const char *source, Edje_Signal_Cb func) { Efl_Ui_Layout_Data *sd; if (!emission || !source) return NULL; if (efl_isa(obj, ELM_ENTRY_CLASS)) return _elm_entry_signal_callback_del_legacy(obj, emission, source, func); sd = efl_data_scope_safe_get(obj, MY_CLASS); if (!sd) return NULL; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL); return _elm_layout_signal_callback_del_legacy(obj, wd->resize_obj, &sd->edje_signals, emission, source, func); } EAPI void elm_layout_signal_emit(Eo *obj, const char *emission, const char *source) { efl_canvas_layout_signal_emit(obj, emission, source); } EAPI const char * elm_layout_data_get(const Evas_Object *obj, const char *key) { return efl_canvas_layout_group_data_get(obj, key); } EAPI Eina_Bool elm_layout_theme_set(Evas_Object *obj, const char *klass, const char *group, const char *style) { Efl_Ui_Theme_Apply ta; ta = efl_ui_layout_theme_set(obj, klass, group, style); return (ta != EFL_UI_THEME_APPLY_FAILED); } /* End of legacy only */ /* Efl.Part implementation */ static EOLIAN Efl_Object * _efl_ui_layout_efl_part_part(const Eo *obj, Efl_Ui_Layout_Data *sd EINA_UNUSED, const char *part) { Edje_Part_Type type; Elm_Part_Data *pd; Eo *proxy; EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL); ELM_WIDGET_DATA_GET_OR_RETURN((Eo *) obj, wd, NULL); // Check part type with edje_edit, as edje_object_part_object_get() // has side effects (it calls recalc, which may be really bad). type = edje_edit_part_type_get(wd->resize_obj, part); if ((type == EDJE_PART_TYPE_BOX) || (type == EDJE_PART_TYPE_TABLE)) return _efl_ui_layout_pack_proxy_get((Eo *) obj, type, part); // Generic parts (text, anything, ...) proxy = efl_add(EFL_UI_LAYOUT_INTERNAL_PART_CLASS, (Eo *) obj); pd = efl_data_scope_get(proxy, EFL_UI_LAYOUT_INTERNAL_PART_CLASS); if (pd) { pd->obj = (Eo *) obj; pd->sd = efl_data_xref(pd->obj, EFL_UI_LAYOUT_CLASS, proxy); pd->part = strdup(part); pd->temp = 1; } return proxy; } static const char * _efl_ui_layout_default_content_part_get(const Eo *obj, Efl_Ui_Layout_Data *sd EINA_UNUSED) { const char *part = NULL; if (!_elm_layout_part_aliasing_eval(obj, &part, EINA_FALSE)) return NULL; return part; } static const char * _efl_ui_layout_default_text_part_get(const Eo *obj, Efl_Ui_Layout_Data *sd EINA_UNUSED) { const char *part = NULL; if (!_elm_layout_part_aliasing_eval(obj, &part, EINA_TRUE)) return NULL; return part; } EOLIAN static Eina_Bool _efl_ui_layout_internal_part_efl_ui_cursor_cursor_set(Eo *obj, Elm_Part_Data *pd, const char *cursor) { ELM_PART_RETURN_VAL(_efl_ui_layout_part_cursor_set(pd->sd, pd->part, cursor)); } EOLIAN static const char * _efl_ui_layout_internal_part_efl_ui_cursor_cursor_get(Eo *obj, Elm_Part_Data *pd) { ELM_PART_RETURN_VAL(_efl_ui_layout_part_cursor_get(pd->sd, pd->part)); } EOLIAN static Eina_Bool _efl_ui_layout_internal_part_efl_ui_cursor_cursor_style_set(Eo *obj, Elm_Part_Data *pd, const char *style) { ELM_PART_RETURN_VAL(_efl_ui_layout_part_cursor_style_set(pd->sd, pd->part, style)); } EOLIAN static const char * _efl_ui_layout_internal_part_efl_ui_cursor_cursor_style_get(Eo *obj, Elm_Part_Data *pd) { ELM_PART_RETURN_VAL(_efl_ui_layout_part_cursor_style_get(pd->sd, pd->part)); } EOLIAN static Eina_Bool _efl_ui_layout_internal_part_efl_ui_cursor_cursor_theme_search_enabled_set(Eo *obj, Elm_Part_Data *pd, Eina_Bool allow) { ELM_PART_RETURN_VAL(_efl_ui_layout_part_cursor_engine_only_set(pd->sd, pd->part, !allow)); } EOLIAN static Eina_Bool _efl_ui_layout_internal_part_efl_ui_cursor_cursor_theme_search_enabled_get(Eo *obj, Elm_Part_Data *pd) { ELM_PART_RETURN_VAL(!_efl_ui_layout_part_cursor_engine_only_get(pd->sd, pd->part)); } ELM_PART_IMPLEMENT_DESTRUCTOR(efl_ui_layout, EFL_UI_LAYOUT, Efl_Ui_Layout_Data, Elm_Part_Data) ELM_PART_IMPLEMENT_CONTENT_SET(efl_ui_layout, EFL_UI_LAYOUT, Efl_Ui_Layout_Data, Elm_Part_Data) ELM_PART_IMPLEMENT_CONTENT_GET(efl_ui_layout, EFL_UI_LAYOUT, Efl_Ui_Layout_Data, Elm_Part_Data) ELM_PART_IMPLEMENT_CONTENT_UNSET(efl_ui_layout, EFL_UI_LAYOUT, Efl_Ui_Layout_Data, Elm_Part_Data) ELM_PART_IMPLEMENT_TEXT_SET(efl_ui_layout, EFL_UI_LAYOUT, Efl_Ui_Layout_Data, Elm_Part_Data) ELM_PART_IMPLEMENT_TEXT_GET(efl_ui_layout, EFL_UI_LAYOUT, Efl_Ui_Layout_Data, Elm_Part_Data) #include "efl_ui_layout_internal_part.eo.c" /* Efl.Part end */ /* Internal EO APIs and hidden overrides */ EAPI EFL_VOID_FUNC_BODY(elm_layout_sizing_eval) EFL_FUNC_BODY_CONST(elm_layout_text_aliases_get, const Elm_Layout_Part_Alias_Description *, NULL) EFL_FUNC_BODY_CONST(elm_layout_content_aliases_get, const Elm_Layout_Part_Alias_Description *, NULL) ELM_LAYOUT_CONTENT_ALIASES_IMPLEMENT(MY_CLASS_PFX) ELM_LAYOUT_TEXT_ALIASES_IMPLEMENT(MY_CLASS_PFX) #define EFL_UI_LAYOUT_EXTRA_OPS \ EFL_CANVAS_GROUP_ADD_DEL_OPS(efl_ui_layout), \ ELM_PART_CONTENT_DEFAULT_OPS(efl_ui_layout), \ ELM_PART_TEXT_DEFAULT_OPS(efl_ui_layout), \ ELM_LAYOUT_CONTENT_ALIASES_OPS(MY_CLASS_PFX), \ ELM_LAYOUT_TEXT_ALIASES_OPS(MY_CLASS_PFX), \ EFL_OBJECT_OP_FUNC(elm_layout_sizing_eval, _elm_layout_sizing_eval), \ EFL_OBJECT_OP_FUNC(efl_dbg_info_get, _efl_ui_layout_efl_object_dbg_info_get) #include "efl_ui_layout.eo.c" diff --git a/src/lib/elementary/elc_combobox.c b/src/lib/elementary/elc_combobox.c index bd745c774d..c8c0d87e2c 100644 --- a/src/lib/elementary/elc_combobox.c +++ b/src/lib/elementary/elc_combobox.c @@ -1,567 +1,568 @@ #ifdef HAVE_CONFIG_H # include "elementary_config.h" #endif #define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED #define ELM_INTERFACE_ATSPI_WIDGET_ACTION_PROTECTED +#define ELM_WIDGET_PROTECTED #include #include "elm_priv.h" #include "elm_widget_combobox.h" #define MY_CLASS ELM_COMBOBOX_CLASS #define MY_CLASS_NAME "Elm_Combobox" #define MY_CLASS_NAME_LEGACY "elm_combobox" static const char SIG_DISMISSED[] = "dismissed"; static const char SIG_EXPANDED[] = "expanded"; static const char SIG_ITEM_SELECTED[] = "item,selected"; static const char SIG_ITEM_PRESSED[] = "item,pressed"; static const char SIG_FILTER_DONE[] = "filter,done"; static const char SIG_CLICKED[] = "clicked"; static const Evas_Smart_Cb_Description _smart_callbacks[] = { {SIG_DISMISSED, ""}, {SIG_EXPANDED, ""}, {SIG_ITEM_SELECTED, ""}, {SIG_ITEM_PRESSED, ""}, {SIG_FILTER_DONE, ""}, {SIG_CLICKED, ""}, /**< handled by parent button class */ {SIG_WIDGET_LANG_CHANGED, ""}, /**< handled by elm_widget */ {SIG_WIDGET_ACCESS_CHANGED, ""}, /**< handled by elm_widget */ {NULL, NULL} }; static void _table_resize(void *data); 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[] = { {"activate", _key_action_activate}, {"move", _key_action_move}, {NULL, NULL} }; EOLIAN static Eina_Bool _elm_combobox_elm_widget_translate(Eo *obj EINA_UNUSED, Elm_Combobox_Data *sd) { elm_obj_widget_translate(efl_super(obj, MY_CLASS)); elm_obj_widget_translate(sd->genlist); elm_obj_widget_translate(sd->entry); if (sd->hover) elm_obj_widget_translate(sd->hover); return EINA_TRUE; } EOLIAN static Efl_Ui_Theme_Apply _elm_combobox_elm_widget_theme_apply(Eo *obj, Elm_Combobox_Data *sd) { const char *style; Efl_Ui_Theme_Apply int_ret = EFL_UI_THEME_APPLY_FAILED; Eina_Bool mirrored; char buf[128]; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EFL_UI_THEME_APPLY_FAILED); style = eina_stringshare_add(elm_widget_style_get(obj)); snprintf(buf, sizeof(buf), "combobox_vertical/%s", style); /* combobox's style has no extra bit for orientation but could have... */ eina_stringshare_replace(&(wd->style), buf); int_ret = elm_obj_widget_theme_apply(efl_super(obj, MY_CLASS)); if (!int_ret) return EFL_UI_THEME_APPLY_FAILED; eina_stringshare_replace(&(wd->style), style); mirrored = efl_ui_mirrored_get(obj); if (sd->hover) { efl_ui_mirrored_set(sd->hover, mirrored); elm_widget_style_set(sd->hover, buf); } efl_ui_mirrored_set(sd->genlist, mirrored); efl_ui_mirrored_set(sd->entry, mirrored); elm_widget_style_set(sd->genlist, buf); elm_widget_style_set(sd->entry, buf); eina_stringshare_del(style); return int_ret; } static void _on_hover_clicked(void *data, const Efl_Event *event) { const char *dismissstr; dismissstr = elm_layout_data_get(event->object, "dismiss"); if (!dismissstr || strcmp(dismissstr, "on")) elm_combobox_hover_end(data); // for backward compatibility } static void _hover_end_finished(void *data, Evas_Object *obj EINA_UNUSED, const char *emission EINA_UNUSED, const char *source EINA_UNUSED) { const char *dismissstr; ELM_COMBOBOX_DATA_GET(data, sd); dismissstr = elm_layout_data_get(sd->hover, "dismiss"); if (dismissstr && !strcmp(dismissstr, "on")) { sd->expanded = EINA_FALSE; evas_object_hide(sd->hover); efl_event_callback_legacy_call(data, ELM_COMBOBOX_EVENT_DISMISSED, NULL); } } static void count_items_genlist(void *data) { ELM_COMBOBOX_DATA_GET(data, sd); Eina_Iterator *filter_iter; int count = 0; Elm_Object_Item *item; filter_iter = elm_genlist_filter_iterator_new(sd->genlist); if (!filter_iter) return; EINA_ITERATOR_FOREACH(filter_iter, item) if (item) count++; sd->count = count; eina_iterator_free(filter_iter); } static void _item_realized(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { _table_resize(data); } static void _table_resize(void *data) { ELM_COMBOBOX_DATA_GET(data, sd); if (sd->count > 0) { int hover_parent_w, hover_parent_h, obj_h, obj_w, obj_y, win_y_offset; int current_height, h; Eina_List *realized; sd->item = elm_genlist_first_item_get(sd->genlist); if (!(realized = elm_genlist_realized_items_get(sd->genlist))) { //nothing realized and wait until at least one item is realized h = 1; evas_object_smart_callback_add(sd->genlist, "realized", _item_realized, data); } else { // take the first, and update according to that evas_object_geometry_get(elm_object_item_track(eina_list_data_get(realized)), NULL, NULL, NULL, &h); } sd->item_height = h; evas_object_geometry_get(sd->entry, NULL, NULL, &obj_w, NULL); evas_object_geometry_get(data, NULL, &obj_y, NULL, &obj_h); evas_object_geometry_get(sd->hover_parent, NULL, NULL, &hover_parent_w, &hover_parent_h); current_height = sd->item_height * sd->count; sd->best_location = elm_hover_best_content_location_get(sd->hover, ELM_HOVER_AXIS_VERTICAL); if (sd->best_location && !strcmp(sd->best_location , "bottom")) win_y_offset = hover_parent_h - obj_y - obj_h; else win_y_offset = obj_y; if (current_height < win_y_offset) evas_object_size_hint_min_set(sd->spacer, obj_w * elm_config_scale_get(), current_height + (2 * elm_config_scale_get())); else evas_object_size_hint_min_set(sd->spacer, obj_w * elm_config_scale_get(), win_y_offset * elm_config_scale_get()); } } static void _activate(Evas_Object *obj) { ELM_COMBOBOX_DATA_GET(obj, sd); if (elm_widget_disabled_get(obj)) return; if (sd->expanded) { elm_combobox_hover_end(obj); return; } sd->expanded = EINA_TRUE; count_items_genlist(obj); if (sd->count <= 0) return; _table_resize(obj); elm_object_part_content_set(sd->hover, sd->best_location, sd->tbl); evas_object_show(sd->genlist); elm_genlist_item_selected_set(sd->item, EINA_TRUE); evas_object_show(sd->hover); efl_event_callback_legacy_call(obj, ELM_COMBOBOX_EVENT_EXPANDED, NULL); } static void _on_item_selected(void *data , Evas_Object *obj EINA_UNUSED, void *event) { ELM_COMBOBOX_DATA_GET(data, sd); elm_object_focus_set(sd->entry, EINA_TRUE); efl_event_callback_legacy_call(data, ELM_COMBOBOX_EVENT_ITEM_SELECTED, event); } static void _on_item_pressed(void *data , Evas_Object *obj EINA_UNUSED, void *event) { efl_event_callback_legacy_call(data, ELM_COMBOBOX_EVENT_ITEM_PRESSED, event); } static void _gl_filter_finished_cb(void *data, const Efl_Event *event) { char buf[1024]; ELM_COMBOBOX_DATA_GET(data, sd); count_items_genlist(data); if (sd->first_filter) { sd->first_filter = EINA_FALSE; return; } efl_event_callback_legacy_call(data, ELM_COMBOBOX_EVENT_FILTER_DONE, event->info); if (sd->count > 0) { if (!sd->expanded) _activate(data); else _table_resize(data); elm_genlist_item_selected_set(sd->item, EINA_TRUE); } else { sd->expanded = EINA_FALSE; elm_layout_signal_emit(sd->hover, "elm,action,hide,no_animate", "elm"); snprintf(buf, sizeof(buf), "elm,action,slot,%s,hide", sd->best_location); elm_layout_signal_emit(sd->hover, buf, "elm"); edje_object_message_signal_process(elm_layout_edje_get(sd->hover)); } } static void _on_aborted(void *data, const Efl_Event *event EINA_UNUSED) { ELM_COMBOBOX_DATA_GET(data, sd); if (sd->expanded) elm_combobox_hover_end(data); } static void _on_changed(void *data, const Efl_Event *event EINA_UNUSED) { efl_event_callback_legacy_call(data, ELM_ENTRY_EVENT_CHANGED, NULL); } static void _on_clicked(void *data, const Efl_Event *event EINA_UNUSED) { elm_combobox_hover_begin(data); } EOLIAN static void _elm_combobox_efl_canvas_group_group_add(Eo *obj, Elm_Combobox_Data *sd EINA_UNUSED) { efl_canvas_group_add(efl_super(obj, MY_CLASS)); elm_widget_sub_object_parent_add(obj); efl_ui_mirrored_automatic_set(obj, EINA_FALSE); efl_event_callback_add(obj, EFL_UI_EVENT_CLICKED, _on_clicked, obj); //What are you doing here? elm_obj_widget_theme_apply(obj); } EOLIAN static void _elm_combobox_efl_canvas_group_group_del(Eo *obj, Elm_Combobox_Data *sd) { sd->hover_parent = NULL; efl_canvas_group_del(efl_super(obj, MY_CLASS)); } EOLIAN static void _elm_combobox_efl_gfx_visible_set(Eo *obj, Elm_Combobox_Data *sd, Eina_Bool vis) { if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_VISIBLE, 0, vis)) return; efl_gfx_visible_set(efl_super(obj, MY_CLASS), vis); if (vis) { if (sd->expanded) evas_object_show(sd->hover); } else { if (sd->hover) evas_object_hide(sd->hover); } } EOLIAN static Eina_Bool _elm_combobox_efl_ui_autorepeat_autorepeat_supported_get(Eo *obj EINA_UNUSED, Elm_Combobox_Data *sd EINA_UNUSED) { return EINA_FALSE; } EAPI Evas_Object * elm_combobox_add(Evas_Object *parent) { EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL); return efl_add(MY_CLASS, parent, efl_canvas_object_legacy_ctor(efl_added)); } EOLIAN static Eo * _elm_combobox_efl_object_constructor(Eo *obj, Elm_Combobox_Data *sd) { Evas_Object *gl; Evas_Object *entry; char buf[128]; obj = efl_constructor(efl_super(obj, MY_CLASS)); sd->first_filter = EINA_TRUE; efl_canvas_object_type_set(obj, MY_CLASS_NAME_LEGACY); evas_object_smart_callbacks_descriptions_set(obj, _smart_callbacks); elm_interface_atspi_accessible_role_set(obj, ELM_ATSPI_ROLE_GLASS_PANE); //hover-parent sd->hover_parent = elm_object_top_widget_get(obj); + snprintf(buf, sizeof(buf), "combobox_vertical/%s", elm_widget_style_get(obj)); + //hover - sd->hover = efl_add(ELM_HOVER_CLASS, sd->hover_parent); + sd->hover = efl_add(ELM_HOVER_CLASS, sd->hover_parent, + elm_obj_widget_style_set(efl_added, buf)); evas_object_layer_set(sd->hover, EVAS_LAYER_MAX); efl_ui_mirrored_automatic_set(sd->hover, EINA_FALSE); elm_hover_target_set(sd->hover, obj); elm_widget_sub_object_add(obj, sd->hover); - snprintf(buf, sizeof(buf), "combobox_vertical/%s", - elm_widget_style_get(obj)); - elm_object_style_set(sd->hover, buf); efl_event_callback_add (sd->hover, EFL_UI_EVENT_CLICKED, _on_hover_clicked, obj); elm_layout_signal_callback_add (sd->hover, "elm,action,hide,finished", "elm", _hover_end_finished, obj); //table sd->tbl = elm_table_add(obj); evas_object_size_hint_weight_set(sd->tbl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(sd->tbl, EVAS_HINT_FILL, EVAS_HINT_FILL); //spacer sd->spacer = evas_object_rectangle_add(evas_object_evas_get(sd->hover_parent)); evas_object_size_hint_weight_set(sd->spacer, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(sd->spacer, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_color_set(sd->spacer, 0, 0, 0, 0); elm_table_pack(sd->tbl, sd->spacer, 0, 0, 1, 1); // This is the genlist object that will take over the genlist call - sd->genlist = gl = efl_add(ELM_GENLIST_CLASS, obj); + sd->genlist = gl = efl_add(ELM_GENLIST_CLASS, obj, + elm_obj_widget_style_set(efl_added, buf)); elm_genlist_filter_set(gl, NULL); efl_ui_mirrored_automatic_set(gl, EINA_FALSE); efl_ui_mirrored_set(gl, efl_ui_mirrored_get(obj)); evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_smart_callback_add(gl, "selected", _on_item_selected, obj); evas_object_smart_callback_add(gl, "pressed", _on_item_pressed, obj); efl_event_callback_add(gl, ELM_GENLIST_EVENT_FILTER_DONE, _gl_filter_finished_cb, obj); elm_genlist_homogeneous_set(gl, EINA_TRUE); elm_genlist_mode_set(gl, ELM_LIST_COMPRESS); elm_table_pack(sd->tbl, gl, 0, 0, 1, 1); - elm_object_style_set(gl, buf); // This is the entry object that will take over the entry call - sd->entry = entry = efl_add(ELM_ENTRY_CLASS, obj); + sd->entry = entry = efl_add(ELM_ENTRY_CLASS, obj, + elm_obj_widget_style_set(efl_added, buf)); efl_ui_mirrored_automatic_set(entry, EINA_FALSE); efl_ui_mirrored_set(entry, efl_ui_mirrored_get(obj)); elm_scroller_policy_set(entry, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF); elm_entry_scrollable_set(entry, EINA_TRUE); elm_entry_single_line_set(entry, EINA_TRUE); efl_event_callback_add(entry, ELM_ENTRY_EVENT_CHANGED_USER, _on_changed, obj); efl_event_callback_add(entry, ELM_ENTRY_EVENT_ABORTED, _on_aborted, obj); evas_object_show(entry); elm_object_part_content_set(obj, "elm.swallow.content", entry); - elm_object_style_set(entry, buf); efl_composite_attach(obj, gl); efl_composite_attach(obj, entry); return obj; } EOLIAN static void _elm_combobox_hover_begin(Eo *obj, Elm_Combobox_Data *sd) { if (!sd->hover) return; elm_object_focus_set(sd->entry, EINA_TRUE); _activate(obj); } EOLIAN static void _elm_combobox_hover_end(Eo *obj, Elm_Combobox_Data *sd) { const char *dismissstr; if (!sd->hover) return; dismissstr = elm_layout_data_get(sd->hover, "dismiss"); if (dismissstr && !strcmp(dismissstr, "on")) elm_hover_dismiss(sd->hover); else { sd->expanded = EINA_FALSE; evas_object_hide(sd->hover); efl_event_callback_legacy_call(obj, ELM_COMBOBOX_EVENT_DISMISSED, NULL); } // for backward compatibility } EOLIAN static Eina_Bool _elm_combobox_expanded_get(Eo *obj EINA_UNUSED, Elm_Combobox_Data *sd) { return sd->expanded; } static Eina_Bool _key_action_move(Evas_Object *obj, const char *params) { ELM_COMBOBOX_DATA_GET(obj, sd); Elm_Object_Item *it = NULL; const char *dir = params; if (!sd->hover) return EINA_FALSE; if (!strcmp(dir, "up")) { it = sd->item; it = elm_genlist_item_prev_get(it); if (!it) sd->item = elm_genlist_last_item_get(sd->genlist); else sd->item = it; elm_genlist_item_selected_set(sd->item, EINA_TRUE); } else if (!strcmp(dir, "down")) { it = sd->item; it = elm_genlist_item_next_get(it); if (!it) sd->item = elm_genlist_first_item_get(sd->genlist); else sd->item = it; elm_genlist_item_selected_set(sd->item, EINA_TRUE); } else return EINA_FALSE; return EINA_TRUE; } static Eina_Bool _key_action_activate(Evas_Object *obj, const char *params EINA_UNUSED) { ELM_COMBOBOX_DATA_GET(obj, sd); if (!sd->expanded) elm_combobox_hover_begin(obj); else { efl_event_callback_legacy_call(sd->genlist, EFL_UI_EVENT_PRESSED, sd->item); elm_entry_cursor_end_set(sd->entry); } return EINA_TRUE; } EOLIAN static Eina_Bool _elm_combobox_elm_widget_widget_event(Eo *obj, Elm_Combobox_Data *sd, Evas_Object *src EINA_UNUSED, Evas_Callback_Type type, void *event_info) { Evas_Event_Key_Down *ev = event_info; if (!sd || !sd->hover) return EINA_FALSE; if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE; if (!_elm_config_key_binding_call(obj, MY_CLASS_NAME, ev, key_actions)) return EINA_FALSE; ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; return EINA_TRUE; } static void _elm_combobox_class_constructor(Efl_Class *klass) { evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass); } EOLIAN const Elm_Atspi_Action * _elm_combobox_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUSED, Elm_Combobox_Data *pd EINA_UNUSED) { static Elm_Atspi_Action atspi_actions[] = { {"activate", "activate", "return", _key_action_activate}, {"move,up", "move", "up", _key_action_move}, {"move,down", "move", "down", _key_action_move}, {NULL, NULL, NULL, NULL} }; return &atspi_actions[0]; } EOLIAN void _elm_combobox_elm_genlist_filter_set(Eo *obj EINA_UNUSED, Elm_Combobox_Data *pd, void *key) { pd->first_filter = EINA_FALSE; elm_obj_genlist_filter_set(pd->genlist, key); } EOLIAN void _elm_combobox_elm_widget_part_text_set(Eo *obj EINA_UNUSED, Elm_Combobox_Data *pd, const char * part, const char *label) { elm_object_part_text_set(pd->entry, part, label); } EOLIAN const char * _elm_combobox_elm_widget_part_text_get(Eo *obj EINA_UNUSED, Elm_Combobox_Data *pd, const char * part) { return elm_object_part_text_get(pd->entry, part); } EOLIAN static void _elm_combobox_efl_gfx_size_set(Eo *obj, Elm_Combobox_Data *pd, Evas_Coord w, Evas_Coord h) { if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, w, h)) return; if (pd->count > 0) _table_resize(obj); efl_gfx_size_set(efl_super(obj, MY_CLASS), w, h); } /* Internal EO APIs and hidden overrides */ #define ELM_COMBOBOX_EXTRA_OPS \ EFL_CANVAS_GROUP_ADD_DEL_OPS(elm_combobox) #include "elm_combobox.eo.c" diff --git a/src/lib/elementary/elm_widget.c b/src/lib/elementary/elm_widget.c index b21436b3b5..b0b515cd15 100644 --- a/src/lib/elementary/elm_widget.c +++ b/src/lib/elementary/elm_widget.c @@ -1,6576 +1,6591 @@ #ifdef HAVE_CONFIG_H # include "elementary_config.h" #endif #define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED #define ELM_INTERFACE_ATSPI_COMPONENT_PROTECTED #define ELM_WIDGET_PROTECTED #define ELM_WIDGET_ITEM_PROTECTED #define EFL_CANVAS_OBJECT_BETA #define EFL_INPUT_EVENT_PROTECTED #include #include "elm_priv.h" #include "elm_widget_container.h" #include "elm_interface_scrollable.h" #include "elm_part_helper.h" /* FIXME: remove this when we don't rely on evas event structs anymore */ #define EFL_INTERNAL_UNSTABLE #include "interfaces/efl_common_internal.h" #define MY_CLASS ELM_WIDGET_CLASS #define MY_CLASS_NAME "Elm_Widget" #define MY_CLASS_NAME_LEGACY "elm_widget" #define ELM_WIDGET_DATA_GET(o, wd) \ Elm_Widget_Smart_Data *wd = efl_data_scope_get(o, MY_CLASS) #define API_ENTRY \ Elm_Widget_Smart_Data *sd = NULL; \ if (!_elm_widget_is(obj) || \ (!(sd = efl_data_scope_get(obj, MY_CLASS)))) #define INTERNAL_ENTRY \ ELM_WIDGET_DATA_GET(obj, sd); \ if (!sd) return #define ELM_WIDGET_FOCUS_GET(obj) \ (efl_isa(obj, ELM_WIDGET_CLASS) && \ ((_elm_access_auto_highlight_get()) ? (elm_widget_highlight_get(obj)) : \ (elm_widget_focus_get(obj)))) const char SIG_WIDGET_FOCUSED[] = "focused"; const char SIG_WIDGET_UNFOCUSED[] = "unfocused"; const char SIG_WIDGET_LANG_CHANGED[] = "language,changed"; const char SIG_WIDGET_ACCESS_CHANGED[] = "access,changed"; typedef struct _Elm_Event_Cb_Data Elm_Event_Cb_Data; typedef struct _Elm_Label_Data Elm_Label_Data; typedef struct _Elm_Translate_String_Data Elm_Translate_String_Data; struct _Elm_Event_Cb_Data { Elm_Event_Cb func; const void *data; }; struct _Elm_Label_Data { const char *part; const char *text; }; struct _Elm_Translate_String_Data { EINA_INLIST; Eina_Stringshare *id; Eina_Stringshare *domain; Eina_Stringshare *string; Eina_Bool preset : 1; }; /* local subsystem globals */ static unsigned int focus_order = 0; static inline Eina_Bool _elm_widget_is(const Evas_Object *obj) { return efl_isa(obj, MY_CLASS); } static inline Eina_Bool _is_focusable(Evas_Object *obj) { API_ENTRY return EINA_FALSE; return sd->can_focus || (sd->child_can_focus); } static inline Eina_Bool _is_focused(Evas_Object *obj) { API_ENTRY return EINA_FALSE; return sd->focused; } static inline Eina_Bool _elm_scrollable_is(const Evas_Object *obj) { INTERNAL_ENTRY EINA_FALSE; return efl_isa(obj, ELM_INTERFACE_SCROLLABLE_MIXIN); } static void elm_widget_disabled_internal(Eo *obj, Eina_Bool disabled); static void _on_sub_obj_del(void *data, const Efl_Event *event); static void _on_sub_obj_hide(void *data, const Efl_Event *event); static void _propagate_event(void *data, const Efl_Event *event); EFL_CALLBACKS_ARRAY_DEFINE(elm_widget_subitems_callbacks, { EFL_EVENT_DEL, _on_sub_obj_del }, { EFL_GFX_EVENT_HIDE, _on_sub_obj_hide }); EFL_CALLBACKS_ARRAY_DEFINE(efl_subitems_callbacks, { EFL_EVENT_DEL, _on_sub_obj_del }); EFL_CALLBACKS_ARRAY_DEFINE(focus_callbacks, { EFL_EVENT_KEY_DOWN, _propagate_event }, { EFL_EVENT_KEY_UP, _propagate_event }, { EFL_EVENT_POINTER_WHEEL, _propagate_event }); static inline void _callbacks_add(Eo *widget, void *data) { if (_elm_widget_is(widget)) { efl_event_callback_array_add(widget, elm_widget_subitems_callbacks(), data); } else { efl_event_callback_array_add(widget, efl_subitems_callbacks(), data); } } static inline void _callbacks_del(Eo *widget, void *data) { if (_elm_widget_is(widget)) { efl_event_callback_array_del(widget, elm_widget_subitems_callbacks(), data); } else { efl_event_callback_array_del(widget, efl_subitems_callbacks(), data); } } void _elm_widget_item_highlight_in_theme(Evas_Object *obj, Elm_Object_Item *eo_it) { const char *str; if (!eo_it) return; if (efl_isa(eo_it, ELM_WIDGET_ITEM_CLASS)) { Elm_Widget_Item_Data *it = efl_data_scope_get(eo_it, ELM_WIDGET_ITEM_CLASS); if (efl_isa(it->view, EFL_UI_LAYOUT_CLASS)) str = edje_object_data_get(elm_layout_edje_get(it->view), "focus_highlight"); else str = edje_object_data_get(it->view, "focus_highlight"); } else str = edje_object_data_get(((Elm_Widget_Item_Data *)eo_it)->view, "focus_highlight"); if ((str) && (!strcmp(str, "on"))) elm_widget_highlight_in_theme_set(obj, EINA_TRUE); else elm_widget_highlight_in_theme_set(obj, EINA_FALSE); } void _elm_widget_focus_highlight_start(const Evas_Object *obj) { Evas_Object *top = elm_widget_top_get(obj); if (top && efl_isa(top, EFL_UI_WIN_CLASS)) _elm_win_focus_highlight_start(top); } Evas_Object * _elm_widget_focus_highlight_object_get(const Evas_Object *obj) { Evas_Object *top = elm_widget_top_get(obj); if (top && efl_isa(top, EFL_UI_WIN_CLASS)) return _elm_win_focus_highlight_object_get(top); return NULL; } EAPI Eina_Bool elm_widget_focus_highlight_enabled_get(const Evas_Object *obj) { const Evas_Object *win = elm_widget_top_get(obj); if (win && efl_isa(win, EFL_UI_WIN_CLASS)) return elm_win_focus_highlight_enabled_get(win); return EINA_FALSE; } static Eina_Bool _tree_unfocusable(Eo *obj) { Elm_Widget *wid = obj; do { ELM_WIDGET_DATA_GET(wid, wid_pd); if (wid_pd->tree_unfocusable) return EINA_TRUE; } while((wid = elm_widget_parent_widget_get(wid))); return EINA_FALSE; } static Eina_Bool _tree_disabled(Eo *obj) { Elm_Widget *wid = obj; do { ELM_WIDGET_DATA_GET(wid, wid_pd); if (wid_pd->disabled) return EINA_TRUE; } while((wid = elm_widget_parent_widget_get(wid))); return EINA_FALSE; } static void _full_eval(Eo *obj, Elm_Widget_Smart_Data *pd); static void _manager_changed_cb(void *data, const Efl_Event *event EINA_UNUSED) { ELM_WIDGET_DATA_GET(data, pd); _full_eval(data, pd); } static Efl_Ui_Focus_Object* _focus_manager_eval(Eo *obj, Elm_Widget_Smart_Data *pd) { Evas_Object *provider = NULL; Evas_Object *parent; Efl_Ui_Focus_Manager *new = NULL, *old = NULL; parent = elm_widget_parent_get(obj); if (efl_isa(parent, EFL_UI_FOCUS_MANAGER_CLASS)) { new = parent; } else { new = efl_ui_focus_user_manager_get(parent); provider = parent; } if (new != pd->manager.manager ) { old = pd->manager.manager; if (pd->manager.provider) efl_event_callback_del(pd->manager.provider, EFL_UI_FOCUS_USER_EVENT_MANAGER_CHANGED, _manager_changed_cb, obj); pd->manager.manager = new; pd->manager.provider = provider; if (pd->manager.provider) efl_event_callback_add(pd->manager.provider, EFL_UI_FOCUS_USER_EVENT_MANAGER_CHANGED, _manager_changed_cb, obj); } return old; } EOLIAN static Eina_Bool _elm_widget_focus_register(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED, Efl_Ui_Focus_Manager *manager, Efl_Ui_Focus_Object *logical, Eina_Bool *logical_flag) { if (!*logical_flag) return efl_ui_focus_manager_register(manager, obj, logical, NULL); else return efl_ui_focus_manager_register_logical(manager, obj, logical, NULL); } static void _focus_state_eval(Eo *obj, Elm_Widget_Smart_Data *pd) { Eina_Bool should = EINA_FALSE; Eina_Bool want_full = EINA_FALSE; Efl_Ui_Focus_Manager *manager = pd->manager.manager; //there are two reasons to be registered, the child count is bigger than 0, or the widget is flagged to be able to handle focus if (pd->can_focus) { should = EINA_TRUE; //can focus can be overridden by the following properties if (_tree_unfocusable(obj)) should = EINA_FALSE; if (_tree_disabled(obj)) should = EINA_FALSE; if (!evas_object_visible_get(obj)) should = EINA_FALSE; if (should) want_full = EINA_TRUE; } if (!should && pd->logical.child_count > 0) { should = EINA_TRUE; if (_tree_unfocusable(obj)) should = EINA_FALSE; if (_tree_disabled(obj)) should = EINA_FALSE; } if ( //check if we have changed the manager (pd->focus.manager != manager && should) || //check if we are already registered but in a different state (pd->focus.manager && should && want_full == pd->focus.logical) ) { efl_ui_focus_manager_unregister(pd->focus.manager, obj); pd->focus.manager = NULL; pd->focus.parent = NULL; } //now register in the manager if (should && !pd->focus.manager) { if (manager && manager != obj) { if (!pd->logical.parent) return; pd->focus.manager = manager; pd->focus.logical = !want_full; pd->focus.parent = pd->logical.parent; if (!elm_obj_widget_focus_register(obj, pd->focus.manager, pd->focus.parent, &pd->focus.logical)) { pd->focus.manager = NULL; pd->focus.parent = NULL; } } } else if (!should && pd->focus.manager) { efl_ui_focus_manager_unregister(pd->focus.manager, obj); pd->focus.manager = NULL; pd->focus.parent = NULL; } } static Efl_Ui_Focus_Object* _logical_parent_eval(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd) { Elm_Widget *parent; parent = pd->parent_obj; if (pd->logical.parent != parent) { Efl_Ui_Focus_Object *old = NULL; //update old logical parent; if (pd->logical.parent) { ELM_WIDGET_DATA_GET(pd->logical.parent, logical_wd); if (!logical_wd) { ERR("Widget parent has the wrong type!"); return NULL; } logical_wd->logical.child_count --; old = pd->logical.parent; if (pd->logical.parent) efl_weak_unref(&pd->logical.parent); pd->logical.parent = NULL; } if (parent) { ELM_WIDGET_DATA_GET(parent, logical_wd); if (!logical_wd) { ERR("Widget parent has the wrong type!"); return NULL; } logical_wd->logical.child_count ++; pd->logical.parent = parent; efl_weak_ref(&pd->logical.parent); } return old; } return NULL; } static void _full_eval(Eo *obj, Elm_Widget_Smart_Data *pd) { Efl_Ui_Focus_Object *old_parent; Efl_Ui_Focus_Object *old_registered_parent, *old_registered_manager; old_parent = _logical_parent_eval(obj, pd); _focus_manager_eval(obj, pd); if (old_parent) { //emit signal and focus eval old and new ELM_WIDGET_DATA_GET(old_parent, old_pd); _focus_state_eval(old_parent, old_pd); } if (pd->logical.parent) { ELM_WIDGET_DATA_GET(pd->logical.parent, new_pd); _focus_state_eval(pd->logical.parent, new_pd); } old_registered_parent = pd->focus.parent; old_registered_manager = pd->focus.manager; _focus_state_eval(obj, pd); if (old_registered_parent != pd->focus.parent) { efl_event_callback_call(obj, EFL_UI_FOCUS_USER_EVENT_LOGICAL_CHANGED, old_registered_parent); } if (old_registered_manager != pd->focus.manager) { efl_event_callback_call(obj, EFL_UI_FOCUS_USER_EVENT_MANAGER_CHANGED, old_registered_manager); } } /** * @internal * * Resets the mirrored mode from the system mirror mode for widgets that are in * automatic mirroring mode. This function does not call elm_widget_theme. * * @param obj The widget. * @param mirrored EINA_TRUE to set mirrored mode. EINA_FALSE to unset. */ static void _elm_widget_mirrored_reload(Evas_Object *obj) { API_ENTRY return; Eina_Bool mirrored = elm_config_mirrored_get(); if (efl_ui_mirrored_automatic_get(obj) && (sd->is_mirrored != mirrored)) { sd->is_mirrored = mirrored; } } EOLIAN static Eina_Bool _elm_widget_on_focus_region(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Coord *x EINA_UNUSED, Evas_Coord *y EINA_UNUSED, Evas_Coord *w EINA_UNUSED, Evas_Coord *h EINA_UNUSED) { DBG("The %s widget does not implement the \"on_focus_region\" function.", efl_class_name_get(efl_class_get(obj))); return EINA_FALSE; } static void _parents_focus(Evas_Object *obj) { for (; obj; obj = elm_widget_parent_get(obj)) { INTERNAL_ENTRY; if (sd->focused) return; sd->focused = 1; } } static void _parents_unfocus(Evas_Object *obj) { for (; obj; obj = elm_widget_parent_get(obj)) { INTERNAL_ENTRY; if (!sd->focused) return; sd->focused = 0; } } static void _on_sub_obj_hide(void *data EINA_UNUSED, const Efl_Event *event) { elm_widget_focus_hide_handle(event->object); } static void _on_sub_obj_del(void *data, const Efl_Event *event) { ELM_WIDGET_DATA_GET_OR_RETURN(data, sd); if (_elm_widget_is(event->object)) { if (_is_focused(event->object)) _parents_unfocus(sd->obj); } if (event->object == sd->resize_obj) { /* already dels sub object */ elm_widget_resize_object_set(sd->obj, NULL); } else if (event->object == sd->hover_obj) { sd->hover_obj = NULL; } else { if (!elm_widget_sub_object_del(sd->obj, event->object)) ERR("failed to remove sub object %p from %p\n", event->object, sd->obj); } } static const Evas_Smart_Cb_Description _smart_callbacks[] = { {SIG_WIDGET_FOCUSED, ""}, {SIG_WIDGET_UNFOCUSED, ""}, {SIG_WIDGET_LANG_CHANGED, ""}, {SIG_WIDGET_ACCESS_CHANGED, ""}, {NULL, NULL} }; static void _obj_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Object *top; ELM_WIDGET_DATA_GET(data, sd); Evas_Event_Mouse_Down *ev = event_info; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; top = elm_widget_top_get(data); if (top && efl_isa(top, EFL_UI_WIN_CLASS)) _elm_win_focus_auto_hide(top); sd->still_in = EINA_TRUE; } static void _obj_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { ELM_WIDGET_DATA_GET(data, sd); Evas_Event_Mouse_Move *ev = event_info; if (!sd->still_in) return; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) sd->still_in = EINA_FALSE; else { Evas_Coord x, y, w, h; evas_object_geometry_get(obj, &x, &y, &w, &h); if (ELM_RECTS_POINT_OUT(x, y, w, h, ev->cur.canvas.x, ev->cur.canvas.y)) sd->still_in = EINA_FALSE; } } static void _obj_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { ELM_WIDGET_DATA_GET(data, sd); Evas_Event_Mouse_Up *ev = event_info; if (sd->still_in && (ev->flags == EVAS_BUTTON_NONE) && (sd->focus_move_policy == ELM_FOCUS_MOVE_POLICY_CLICK)) elm_widget_focus_mouse_up_handle(obj); sd->still_in = EINA_FALSE; } static void _obj_mouse_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { ELM_WIDGET_DATA_GET(data, sd); if (sd->focus_move_policy == ELM_FOCUS_MOVE_POLICY_IN) elm_widget_focus_mouse_up_handle(obj); } EOLIAN static void _elm_widget_efl_canvas_group_group_add(Eo *obj, Elm_Widget_Smart_Data *priv) { priv->obj = obj; priv->mirrored_auto_mode = EINA_TRUE; /* will follow system locale * settings */ priv->focus_move_policy_auto_mode = EINA_TRUE; priv->focus_region_show_mode = ELM_FOCUS_REGION_SHOW_WIDGET; elm_widget_can_focus_set(obj, EINA_TRUE); priv->is_mirrored = elm_config_mirrored_get(); priv->focus_move_policy = _elm_config->focus_move_policy; evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN, _obj_mouse_down, obj); evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE, _obj_mouse_move, obj); evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP, _obj_mouse_up, obj); evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_IN, _obj_mouse_in, obj); } static void _if_focused_revert(Evas_Object *obj, Eina_Bool can_focus_only) { Evas_Object *top; Evas_Object *newest = NULL; unsigned int newest_focus_order = 0; INTERNAL_ENTRY; if (!sd->focused) return; if (!sd->parent_obj) return; top = elm_widget_top_get(sd->parent_obj); if (top) { newest = elm_widget_newest_focus_order_get (top, &newest_focus_order, can_focus_only); if (newest) { if (newest == top) { ELM_WIDGET_DATA_GET(newest, sd2); if (!sd2) return; if (!_is_focused(newest)) elm_widget_focus_steal(newest, NULL); else { if (sd2->resize_obj && _is_focused(sd2->resize_obj)) elm_widget_focused_object_clear(sd2->resize_obj); else { const Eina_List *l; Evas_Object *child; EINA_LIST_FOREACH(sd2->subobjs, l, child) { if (!_elm_widget_is(child)) continue; if (_is_focused(child)) { elm_widget_focused_object_clear(child); break; } } } } evas_object_focus_set(newest, EINA_TRUE); } else { elm_object_focus_set(newest, EINA_FALSE); elm_object_focus_set(newest, EINA_TRUE); } } } } EOLIAN static void _elm_widget_efl_canvas_group_group_del(Eo *obj, Elm_Widget_Smart_Data *sd) { Evas_Object *sobj; Elm_Translate_String_Data *ts; Elm_Event_Cb_Data *ecb; if (sd->hover_obj) { /* detach it from us */ _callbacks_del(sd->hover_obj, obj); sd->hover_obj = NULL; } while (sd->subobjs) { sobj = eina_list_data_get(sd->subobjs); /* let the objects clean-up themselves and get rid of this list */ if (!elm_widget_sub_object_del(obj, sobj)) { ERR("failed to remove sub object %p from %p\n", sobj, obj); sd->subobjs = eina_list_remove_list (sd->subobjs, sd->subobjs); } evas_object_del(sobj); } sd->tooltips = eina_list_free(sd->tooltips); /* should be empty anyway */ sd->cursors = eina_list_free(sd->cursors); /* should be empty anyway */ while (sd->translate_strings) { ts = EINA_INLIST_CONTAINER_GET(sd->translate_strings, Elm_Translate_String_Data); eina_stringshare_del(ts->id); eina_stringshare_del(ts->domain); eina_stringshare_del(ts->string); sd->translate_strings = eina_inlist_remove(sd->translate_strings, sd->translate_strings); free(ts); } EINA_LIST_FREE(sd->event_cb, ecb) free(ecb); eina_stringshare_del(sd->style); if (sd->theme) elm_theme_free(sd->theme); _if_focused_revert(obj, EINA_TRUE); elm_widget_focus_custom_chain_unset(obj); eina_stringshare_del(sd->access_info); eina_stringshare_del(sd->accessible_name); evas_object_smart_data_set(obj, NULL); efl_canvas_group_del(efl_super(obj, MY_CLASS)); } static void _smart_reconfigure(Elm_Widget_Smart_Data *sd) { if (sd->resize_obj) { evas_object_move(sd->resize_obj, sd->x, sd->y); evas_object_resize(sd->resize_obj, sd->w, sd->h); } if (sd->hover_obj) { evas_object_move(sd->hover_obj, sd->x, sd->y); evas_object_resize(sd->hover_obj, sd->w, sd->h); } } EOLIAN static void _elm_widget_efl_gfx_position_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Coord x, Evas_Coord y) { if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_MOVE, 0, x, y)) return; sd->x = x; sd->y = y; _smart_reconfigure(sd); efl_gfx_position_set(efl_super(obj, MY_CLASS), x, y); } EOLIAN static void _elm_widget_efl_gfx_size_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Coord w, Evas_Coord h) { if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, w, h)) return; sd->w = w; sd->h = h; _smart_reconfigure(sd); efl_gfx_size_set(efl_super(obj, MY_CLASS), w, h); } EOLIAN static void _elm_widget_efl_gfx_visible_set(Eo *obj, Elm_Widget_Smart_Data *pd, Eina_Bool vis) { Eina_Iterator *it; Evas_Object *o; if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_VISIBLE, 0, vis)) return; efl_gfx_visible_set(efl_super(obj, MY_CLASS), vis); _full_eval(obj, pd); it = evas_object_smart_iterator_new(obj); EINA_ITERATOR_FOREACH(it, o) { if (evas_object_data_get(o, "_elm_leaveme")) continue; efl_gfx_visible_set(o, vis); } eina_iterator_free(it); if (!_elm_config->atspi_mode || pd->on_destroy) return; if (vis) { elm_interface_atspi_accessible_added(obj); if (_elm_widget_onscreen_is(obj)) elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_SHOWING, EINA_TRUE); } else { elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_SHOWING, EINA_FALSE); } } EOLIAN static void _elm_widget_efl_gfx_color_set(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, int r, int g, int b, int a) { Eina_Iterator *it; Evas_Object *o; if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_COLOR_SET, 0, r, g, b, a)) return; it = evas_object_smart_iterator_new(obj); EINA_ITERATOR_FOREACH(it, o) { if (evas_object_data_get(o, "_elm_leaveme")) continue; evas_object_color_set(o, r, g, b, a); } eina_iterator_free(it); } EOLIAN static void _elm_widget_efl_canvas_object_no_render_set(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool hide) { Eina_Iterator *it; Evas_Object *o; hide = !!hide; if (efl_canvas_object_no_render_get(obj) == hide) return; it = evas_object_smart_iterator_new(obj); EINA_ITERATOR_FOREACH(it, o) { if (evas_object_data_get(o, "_elm_leaveme")) continue; efl_canvas_object_no_render_set(o, hide); } eina_iterator_free(it); // bypass implementation in Efl.Canvas.Group efl_canvas_object_no_render_set(efl_super(obj, EFL_CANVAS_GROUP_CLASS), hide); } EOLIAN static void _elm_widget_efl_canvas_object_is_frame_object_set(Eo *obj, Elm_Widget_Smart_Data *pd, Eina_Bool frame) { Evas_Object *o; Eina_List *li; frame = !!frame; efl_canvas_object_is_frame_object_set(efl_super(obj, MY_CLASS), frame); EINA_LIST_FOREACH(pd->subobjs, li, o) { if (evas_object_data_get(o, "_elm_leaveme")) continue; efl_canvas_object_is_frame_object_set(o, frame); } } EOLIAN static void _elm_widget_efl_canvas_object_clip_set(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Object *clip) { Eina_Iterator *it; Evas_Object *o; if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_CLIP_SET, 0, clip)) return; efl_canvas_object_clip_set(efl_super(obj, MY_CLASS), clip); it = evas_object_smart_iterator_new(obj); EINA_ITERATOR_FOREACH(it, o) { if (evas_object_data_get(o, "_elm_leaveme")) continue; evas_object_clip_set(o, clip); } eina_iterator_free(it); } EOLIAN static void _elm_widget_efl_canvas_group_group_calculate(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED) { /* a NO-OP, on the base */ } EOLIAN static void _elm_widget_efl_canvas_group_group_member_add(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Object *child) { int r, g, b, a; efl_canvas_group_member_add(efl_super(obj, MY_CLASS), child); if (evas_object_data_get(child, "_elm_leaveme")) return; evas_object_color_get(obj, &r, &g, &b, &a); evas_object_color_set(child, r, g, b, a); efl_canvas_object_no_render_set(child, efl_canvas_object_no_render_get(obj)); evas_object_clip_set(child, evas_object_clip_get(obj)); if (evas_object_visible_get(obj)) evas_object_show(child); else evas_object_hide(child); } EOLIAN static void _elm_widget_efl_canvas_group_group_member_del(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Object *child) { if (!evas_object_data_get(child, "_elm_leaveme")) evas_object_clip_unset(child); efl_canvas_group_member_del(efl_super(obj, MY_CLASS), child); } // internal funcs /** * @internal * * Check if the widget has its own focus next function. * * @param obj The widget. * @return focus next function is implemented/unimplemented. * (@c EINA_TRUE = implemented/@c EINA_FALSE = unimplemented.) */ static inline Eina_Bool _elm_widget_focus_chain_manager_is(const Evas_Object *obj) { ELM_WIDGET_CHECK(obj) EINA_FALSE; Eina_Bool manager_is = EINA_FALSE; manager_is = elm_obj_widget_focus_next_manager_is((Eo *)obj); return manager_is; } static inline Eina_Bool _internal_elm_widget_focus_direction_manager_is(const Evas_Object *obj) { ELM_WIDGET_CHECK(obj) EINA_FALSE; Eina_Bool manager_is = EINA_FALSE; manager_is = elm_obj_widget_focus_direction_manager_is((Eo *)obj); return manager_is; } static void _propagate_x_drag_lock(Evas_Object *obj, int dir) { INTERNAL_ENTRY; if (sd->parent_obj) { ELM_WIDGET_DATA_GET(sd->parent_obj, sd2); if (sd2) { sd2->child_drag_x_locked += dir; _propagate_x_drag_lock(sd->parent_obj, dir); } } } static void _propagate_y_drag_lock(Evas_Object *obj, int dir) { INTERNAL_ENTRY; if (sd->parent_obj) { ELM_WIDGET_DATA_GET(sd->parent_obj, sd2); if (sd2) { sd2->child_drag_y_locked += dir; _propagate_y_drag_lock(sd->parent_obj, dir); } } } static void _propagate_event(void *data EINA_UNUSED, const Efl_Event *event) { Eo *obj = event->object; INTERNAL_ENTRY; Evas_Callback_Type type; Evas_Event_Flags *event_flags, prev_flags; union { Evas_Event_Key_Down *down; Evas_Event_Key_Up *up; Evas_Event_Mouse_Wheel *wheel; void *any; } event_info; if ((evas_focus_get(evas_object_evas_get(obj)) != elm_widget_top_get(obj)) && efl_isa(obj, EFL_UI_WIN_CLASS)) return; if (event->desc == EFL_EVENT_KEY_DOWN) { event_info.down = efl_input_legacy_info_get(event->info); EINA_SAFETY_ON_NULL_RETURN(event_info.down); type = EVAS_CALLBACK_KEY_DOWN; event_flags = &event_info.down->event_flags; } else if (event->desc == EFL_EVENT_KEY_UP) { event_info.up = efl_input_legacy_info_get(event->info); EINA_SAFETY_ON_NULL_RETURN(event_info.up); type = EVAS_CALLBACK_KEY_UP; event_flags = &event_info.up->event_flags; } else if (event->desc == EFL_EVENT_POINTER_WHEEL) { event_info.wheel = efl_input_legacy_info_get(event->info); EINA_SAFETY_ON_NULL_RETURN(event_info.wheel); type = EVAS_CALLBACK_MOUSE_WHEEL; event_flags = &event_info.wheel->event_flags; } else return; prev_flags = *event_flags; elm_widget_event_propagate(obj, type, event_info.any, event_flags); if (prev_flags != *event_flags) efl_input_event_flags_set(event->info, *event_flags); } /** * @internal * * If elm_widget_focus_region_get() returns EINA_FALSE, this function will * ignore region show action. */ EOLIAN static void _elm_widget_focus_region_show(const Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED) { Evas_Coord x, y, w, h, ox, oy; Evas_Object *o; o = elm_widget_parent_get(obj); if (!o) return; if (!elm_widget_focus_region_get(obj, &x, &y, &w, &h)) return; evas_object_geometry_get(obj, &ox, &oy, NULL, NULL); while (o) { Evas_Coord px, py; evas_object_geometry_get(o, &px, &py, NULL, NULL); if (_elm_scrollable_is(o) && !elm_widget_disabled_get(o)) { Evas_Coord sx, sy; elm_interface_scrollable_content_region_get(o, &sx, &sy, NULL, NULL); // Get the object's on_focus_region position relative to the scroller. Evas_Coord rx, ry; rx = ox + x - px + sx; ry = oy + y - py + sy; switch (_elm_config->focus_autoscroll_mode) { case ELM_FOCUS_AUTOSCROLL_MODE_SHOW: elm_interface_scrollable_content_region_show(o, rx, ry, w, h); break; case ELM_FOCUS_AUTOSCROLL_MODE_BRING_IN: elm_interface_scrollable_region_bring_in(o, rx, ry, w, h); break; default: break; } elm_widget_focus_region_get(o, &x, &y, &w, &h); evas_object_geometry_get(o, &ox, &oy, NULL, NULL); } else { x += ox - px; y += oy - py; ox = px; oy = py; } o = elm_widget_parent_get(o); } } EOLIAN static Eina_Bool _elm_widget_focus_highlight_style_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, const char *style) { if (eina_stringshare_replace(&sd->focus_highlight_style, style)) return EINA_TRUE; return EINA_FALSE; } EOLIAN static const char* _elm_widget_focus_highlight_style_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->focus_highlight_style; } static void _parent_focus(Evas_Object *obj, Elm_Object_Item *item) { API_ENTRY return; if (sd->focused) return; Evas_Object *o = elm_widget_parent_get(obj); sd->focus_order_on_calc = EINA_TRUE; if (o) _parent_focus(o, item); if (!sd->focus_order_on_calc) return; /* we don't want to override it if by means of any of the callbacks below one gets to calculate our order first. */ focus_order++; sd->focus_order = focus_order; sd->focused = EINA_TRUE; if (sd->top_win_focused) elm_obj_widget_on_focus(obj, item); sd->focus_order_on_calc = EINA_FALSE; if (_elm_config->access_mode == ELM_ACCESS_MODE_ON) _elm_access_highlight_set(obj); } static void _elm_object_focus_chain_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { ELM_WIDGET_DATA_GET(data, sd); sd->focus_chain = eina_list_remove(sd->focus_chain, obj); } EOLIAN static void _elm_widget_widget_parent_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Object *parent EINA_UNUSED) { } EAPI Eina_Bool elm_widget_api_check(int ver) { if (ver != ELM_INTERNAL_API_VERSION) { CRI("Elementary widget api versions do not match"); return EINA_FALSE; } return EINA_TRUE; } EAPI Eina_Bool elm_widget_access(Evas_Object *obj, Eina_Bool is_access) { const Eina_List *l; Evas_Object *child; Eina_Bool ret = EINA_TRUE; API_ENTRY return EINA_FALSE; EINA_LIST_FOREACH(sd->subobjs, l, child) { if (elm_widget_is(child)) ret &= elm_widget_access(child, is_access); } elm_obj_widget_access(obj, is_access); efl_event_callback_legacy_call(obj, ELM_WIDGET_EVENT_ACCESS_CHANGED, NULL); return ret; } EOLIAN static void _elm_widget_access(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool is_access EINA_UNUSED) { } EAPI Efl_Ui_Theme_Apply elm_widget_theme(Evas_Object *obj) { const Eina_List *l; Evas_Object *child; Elm_Tooltip *tt; Elm_Cursor *cur; Efl_Ui_Theme_Apply ret = EFL_UI_THEME_APPLY_SUCCESS; API_ENTRY return EFL_UI_THEME_APPLY_FAILED; EINA_LIST_FOREACH(sd->subobjs, l, child) if (_elm_widget_is(child)) ret &= elm_widget_theme(child); if (sd->hover_obj) ret &= elm_widget_theme(sd->hover_obj); EINA_LIST_FOREACH(sd->tooltips, l, tt) elm_tooltip_theme(tt); EINA_LIST_FOREACH(sd->cursors, l, cur) elm_cursor_theme(cur); Efl_Ui_Theme_Apply ret2 = EFL_UI_THEME_APPLY_FAILED; ret2 = elm_obj_widget_theme_apply(obj); ret &= ret2; return ret; } EAPI void elm_widget_theme_specific(Evas_Object *obj, Elm_Theme *th, Eina_Bool force) { const Eina_List *l; Evas_Object *child; Elm_Tooltip *tt; Elm_Cursor *cur; Elm_Theme *th2, *thdef; API_ENTRY return; thdef = elm_theme_default_get(); if (!th) th = thdef; if (!force) { th2 = sd->theme; if (!th2) th2 = thdef; while (th2) { if (th2 == th) { force = EINA_TRUE; break; } if (th2 == thdef) break; th2 = th2->ref_theme; if (!th2) th2 = thdef; } } if (!force) return; EINA_LIST_FOREACH(sd->subobjs, l, child) { if (elm_widget_is(child)) elm_widget_theme_specific(child, th, force); } if (sd->hover_obj) elm_widget_theme(sd->hover_obj); EINA_LIST_FOREACH(sd->tooltips, l, tt) elm_tooltip_theme(tt); EINA_LIST_FOREACH(sd->cursors, l, cur) elm_cursor_theme(cur); elm_obj_widget_theme_apply(obj); } EOLIAN static Efl_Ui_Theme_Apply _elm_widget_theme_apply(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED) { _elm_widget_mirrored_reload(obj); if (elm_widget_disabled_get(obj)) elm_widget_disabled_internal(obj, elm_widget_disabled_get(obj)); return EFL_UI_THEME_APPLY_SUCCESS; } /** * @internal * * Returns the widget's mirrored mode. * * @param obj The widget. * @return mirrored mode of the object. * **/ EOLIAN static Eina_Bool _elm_widget_efl_ui_base_mirrored_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->is_mirrored; } /** * @internal * * Sets the widget's mirrored mode. * * @param obj The widget. * @param mirrored EINA_TRUE to set mirrored mode. EINA_FALSE to unset. */ EOLIAN static void _elm_widget_efl_ui_base_mirrored_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool mirrored) { mirrored = !!mirrored; if (sd->is_mirrored == mirrored) return; sd->is_mirrored = mirrored; elm_widget_theme(obj); } /** * Returns the widget's mirrored mode setting. * * @param obj The widget. * @return mirrored mode setting of the object. * **/ EOLIAN static Eina_Bool _elm_widget_efl_ui_base_mirrored_automatic_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->mirrored_auto_mode; } /** * @internal * * Sets the widget's mirrored mode setting. * When widget in automatic mode, it follows the system mirrored mode set by * elm_mirrored_set(). * @param obj The widget. * @param automatic EINA_TRUE for auto mirrored mode. EINA_FALSE for manual. */ EOLIAN static void _elm_widget_efl_ui_base_mirrored_automatic_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool automatic) { if (sd->mirrored_auto_mode != automatic) { sd->mirrored_auto_mode = automatic; if (automatic) { efl_ui_mirrored_set(obj, elm_config_mirrored_get()); } } } EOLIAN static void _elm_widget_on_show_region_hook_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, region_hook_func_type func, void *data) { sd->on_show_region = func; sd->on_show_region_data = data; } /* * @internal * * Add myself as a sub object of parent object * * @see elm_widget_sub_object_add() */ EAPI Eina_Bool elm_widget_sub_object_parent_add(Evas_Object *sobj) { Eo *parent = NULL; parent = efl_parent_get(sobj); if (!efl_isa(parent, ELM_WIDGET_CLASS)) { ERR("You passed a wrong parent parameter (%p %s). " "Elementary widget's parent should be an elementary widget.", parent, evas_object_type_get(parent)); return EINA_FALSE; } return elm_obj_widget_sub_object_add(parent, sobj); } /* * @internal * * Add sobj to obj's sub object. * * What does elementary sub object mean? This is unique in elementary, it * handles overall elementary policies between parent and sub objects. * focus, access, deletion, theme, scale, mirror, scrollable child get, * translate, name find, display mode set, orientation set, tree dump * AUTOMATICALLY. * * @see elm_widget_sub_object_parent_add() */ EOLIAN static Eina_Bool _elm_widget_sub_object_add(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *sobj) { Eina_Bool mirrored, pmirrored = efl_ui_mirrored_get(obj); EINA_SAFETY_ON_TRUE_RETURN_VAL(obj == sobj, EINA_FALSE); if (sobj == sd->parent_obj) { /* in this case, sobj must be an elm widget, or something * very wrong is happening */ if (!_elm_widget_is(sobj)) return EINA_FALSE; if (!elm_widget_sub_object_del(sobj, obj)) return EINA_FALSE; WRN("You passed a parent object of obj = %p as the sub object = %p!", obj, sobj); } if (_elm_widget_is(sobj)) { ELM_WIDGET_DATA_GET(sobj, sdc); if (sdc->parent_obj == obj) goto end; if (sdc->parent_obj) { if (!elm_widget_sub_object_del(sdc->parent_obj, sobj)) return EINA_FALSE; } sdc->parent_obj = obj; _full_eval(sobj, sdc); if (!sdc->on_create) elm_obj_widget_orientation_set(sobj, sd->orient_mode); else sdc->orient_mode = sd->orient_mode; if (!sdc->on_create) { if (!sdc->disabled && (elm_widget_disabled_get(obj))) { elm_widget_focus_disabled_handle(sobj); elm_obj_widget_disable(sobj); } } _elm_widget_top_win_focused_set(sobj, sd->top_win_focused); /* update child focusable-ness on self and parents, now that a * focusable child got in */ if (!sd->child_can_focus && (_is_focusable(sobj))) { Elm_Widget_Smart_Data *sdp = sd; sdp->child_can_focus = EINA_TRUE; while (sdp->parent_obj) { sdp = efl_data_scope_get(sdp->parent_obj, MY_CLASS); if (sdp->child_can_focus) break; sdp->child_can_focus = EINA_TRUE; } } } else { void *data = evas_object_data_get(sobj, "elm-parent"); if (data) { if (data == obj) goto end; if (!elm_widget_sub_object_del(data, sobj)) return EINA_FALSE; } } sd->subobjs = eina_list_append(sd->subobjs, sobj); evas_object_data_set(sobj, "elm-parent", obj); _callbacks_add(sobj, obj); if (_elm_widget_is(sobj)) { ELM_WIDGET_DATA_GET(sobj, sdc); /* NOTE: In the following two lines, 'sobj' is correct. Do not change it. * Due to elementary's scale policy, scale and pscale can be different in * some cases. This happens when sobj's previous parent and new parent have * different scale value. * For example, if sobj's previous parent's scale is 5 and new parent's scale * is 2 while sobj's scale is 0. Then 'pscale' is 5 and 'scale' is 2. So we * need to reset sobj's scale to 5. * Note that each widget's scale is 0 by default. */ double scale, pscale = efl_ui_scale_get(sobj); Elm_Theme *th, *pth = elm_widget_theme_get(sobj); scale = efl_ui_scale_get(sobj); th = elm_widget_theme_get(sobj); mirrored = efl_ui_mirrored_get(sobj); if (!sdc->on_create) { if ((scale != pscale) || (th != pth) || (pmirrored != mirrored)) elm_widget_theme(sobj); } if (_is_focused(sobj)) _parents_focus(obj); elm_widget_display_mode_set(sobj, evas_object_size_hint_display_mode_get(obj)); if (_elm_config->atspi_mode && !sd->on_create) { Elm_Interface_Atspi_Accessible *aparent; aparent = elm_interface_atspi_accessible_parent_get(sobj); if (aparent) elm_interface_atspi_accessible_children_changed_added_signal_emit(aparent, sobj); } } end: return EINA_TRUE; } EOLIAN static Eina_Bool _elm_widget_sub_object_del(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *sobj) { Evas_Object *sobj_parent; if (!sobj) return EINA_FALSE; EINA_SAFETY_ON_TRUE_RETURN_VAL(obj == sobj, EINA_FALSE); sobj_parent = evas_object_data_del(sobj, "elm-parent"); if (sobj_parent && sobj_parent != obj) { static int abort_on_warn = -1; ERR("removing sub object %p (%s) from parent %p (%s), " "but elm-parent is different %p (%s)!", sobj, elm_widget_type_get(sobj), obj, elm_widget_type_get(obj), sobj_parent, elm_widget_type_get(sobj_parent)); if (EINA_UNLIKELY(abort_on_warn == -1)) { if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1; else abort_on_warn = 0; } if (abort_on_warn == 1) abort(); return EINA_FALSE; } if (_elm_widget_is(sobj)) { if (_is_focused(sobj)) { elm_widget_tree_unfocusable_set(sobj, EINA_TRUE); elm_widget_tree_unfocusable_set(sobj, EINA_FALSE); } if ((sd->child_can_focus) && (_is_focusable(sobj))) { Evas_Object *parent = obj; /* update child focusable-ness on self and parents, now that a * focusable child is gone */ while (parent) { const Eina_List *l; Evas_Object *subobj; ELM_WIDGET_DATA_GET(parent, sdp); sdp->child_can_focus = EINA_FALSE; EINA_LIST_FOREACH(sdp->subobjs, l, subobj) { if ((subobj != sobj) && (_is_focusable(subobj))) { sdp->child_can_focus = EINA_TRUE; break; } } /* break again, child_can_focus went back to * original value */ if (sdp->child_can_focus) break; parent = sdp->parent_obj; } } if (_elm_config->atspi_mode && !sd->on_destroy) { Elm_Interface_Atspi_Accessible *aparent; aparent = elm_interface_atspi_accessible_parent_get(sobj); if (aparent) elm_interface_atspi_accessible_children_changed_del_signal_emit(aparent, sobj); } ELM_WIDGET_DATA_GET(sobj, sdc); sdc->parent_obj = NULL; _full_eval(sobj, sdc); } if (sd->resize_obj == sobj) sd->resize_obj = NULL; sd->subobjs = eina_list_remove(sd->subobjs, sobj); _callbacks_del(sobj, obj); return EINA_TRUE; } /* protected function - for widget developers only */ EOLIAN static void _elm_widget_resize_object_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eo *sobj) { Evas_Object *parent; if (sd->resize_obj == sobj) return; EINA_SAFETY_ON_TRUE_RETURN(sobj && !efl_isa(sobj, EFL_CANVAS_OBJECT_CLASS)); // orphan previous resize obj if (sd->resize_obj) { evas_object_clip_unset(sd->resize_obj); evas_object_smart_member_del(sd->resize_obj); if (_elm_widget_is(sd->resize_obj)) { if (_is_focused(sd->resize_obj)) _parents_unfocus(obj); } elm_widget_sub_object_del(obj, sd->resize_obj); } sd->resize_obj = sobj; if (!sobj) return; // orphan new resize obj parent = evas_object_data_get(sobj, "elm-parent"); if (parent && parent != obj) { ELM_WIDGET_DATA_GET(parent, sdp); /* should be there, just being paranoid */ if (sdp) { if (sdp->resize_obj == sobj) elm_widget_resize_object_set(parent, NULL); else elm_widget_sub_object_del(parent, sobj); } } elm_widget_sub_object_add(obj, sobj); evas_object_smart_member_add(sobj, obj); _smart_reconfigure(sd); } /* * @internal * * WARNING: the programmer is responsible, in the scenario of * exchanging a hover object, of cleaning the old hover "target" * before */ EOLIAN static void _elm_widget_hover_object_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Object *sobj) { if (sd->hover_obj) { _callbacks_del(sd->hover_obj, obj); } sd->hover_obj = sobj; if (sd->hover_obj) { _callbacks_add(sobj, obj); _smart_reconfigure(sd); } } EOLIAN static void _elm_widget_can_focus_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool can_focus) { can_focus = !!can_focus; if (sd->can_focus == can_focus) return; sd->can_focus = can_focus; if (sd->can_focus) { /* update child_can_focus of parents */ Evas_Object *o = obj; for (;;) { o = elm_widget_parent_get(o); if (!o) break; ELM_WIDGET_DATA_GET(o, sdp); if (!sdp || sdp->child_can_focus) break; sdp->child_can_focus = EINA_TRUE; } efl_event_callback_array_add(obj, focus_callbacks(), NULL); } else { // update child_can_focus of parents */ Evas_Object *parent = elm_widget_parent_get(obj); while (parent) { const Eina_List *l; Evas_Object *subobj; ELM_WIDGET_DATA_GET(parent, sdp); sdp->child_can_focus = EINA_FALSE; EINA_LIST_FOREACH(sdp->subobjs, l, subobj) { if (_is_focusable(subobj)) { sdp->child_can_focus = EINA_TRUE; break; } } /* break again, child_can_focus went back to * original value */ if (sdp->child_can_focus) break; parent = sdp->parent_obj; } efl_event_callback_array_del(obj, focus_callbacks(), NULL); } if (efl_finalized_get(obj)) _full_eval(obj, sd); } EOLIAN static Eina_Bool _elm_widget_can_focus_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->can_focus; } EOLIAN static Eina_Bool _elm_widget_child_can_focus_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->child_can_focus; } static void _full_eval_children(Eo *obj, Elm_Widget_Smart_Data *sd) { Eina_List *l; Eo *child; _full_eval(obj, sd); EINA_LIST_FOREACH(sd->subobjs , l, child) { Elm_Widget_Smart_Data *sd_child; if (!efl_isa(child, ELM_WIDGET_CLASS)) continue; sd_child = efl_data_scope_get(child, ELM_WIDGET_CLASS); _full_eval_children(child, sd_child); } } /** * @internal * * This API makes the widget object and its children to be unfocusable. * * This API can be helpful for an object to be deleted. * When an object will be deleted soon, it and its children may not * want to get focus (by focus reverting or by other focus controls). * Then, just use this API before deleting. * * @param obj The widget root of sub-tree * @param tree_unfocusable If true, set the object sub-tree as unfocusable * * @ingroup Widget */ EOLIAN static void _elm_widget_tree_unfocusable_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool tree_unfocusable) { tree_unfocusable = !!tree_unfocusable; if (sd->tree_unfocusable == tree_unfocusable) return; sd->tree_unfocusable = tree_unfocusable; elm_widget_focus_tree_unfocusable_handle(obj); //focus state eval on all children _full_eval_children(obj, sd); } /** * @internal * * This returns true, if the object sub-tree is unfocusable. * * @param obj The widget root of sub-tree * @return EINA_TRUE if the object sub-tree is unfocusable * * @ingroup Widget */ EOLIAN static Eina_Bool _elm_widget_tree_unfocusable_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->tree_unfocusable; } /** * @internal * * Get the list of focusable child objects. * * This function retruns list of child objects which can get focus. * * @param obj The parent widget * @retrun list of focusable child objects. * * @ingroup Widget */ EOLIAN static Eina_List* _elm_widget_can_focus_child_list_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { const Eina_List *l; Eina_List *child_list = NULL; Evas_Object *child; EINA_LIST_FOREACH(sd->subobjs, l, child) { if (!_elm_widget_is(child)) continue; if ((elm_widget_can_focus_get(child)) && (evas_object_visible_get(child)) && (!elm_widget_disabled_get(child))) child_list = eina_list_append(child_list, child); else { Eina_List *can_focus_list; can_focus_list = elm_widget_can_focus_child_list_get(child); if (can_focus_list) child_list = eina_list_merge(child_list, can_focus_list); } } return child_list; } EOLIAN static void _elm_widget_highlight_ignore_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Eina_Bool ignore) { sd->highlight_ignore = !!ignore; } EOLIAN static Eina_Bool _elm_widget_highlight_ignore_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->highlight_ignore; } EOLIAN static void _elm_widget_highlight_in_theme_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Eina_Bool highlight) { sd->highlight_in_theme = !!highlight; /* FIXME: if focused, it should switch from one mode to the other */ } void _elm_widget_highlight_in_theme_update(Eo *obj) { Evas_Object *top = elm_widget_top_get(obj); if (top && efl_isa(top, EFL_UI_WIN_CLASS)) { _elm_win_focus_highlight_in_theme_update( top, elm_widget_highlight_in_theme_get(obj)); } } EOLIAN static Eina_Bool _elm_widget_highlight_in_theme_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->highlight_in_theme; } EOLIAN static void _elm_widget_access_highlight_in_theme_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Eina_Bool highlight) { sd->access_highlight_in_theme = !!highlight; } EOLIAN static Eina_Bool _elm_widget_access_highlight_in_theme_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->access_highlight_in_theme; } EOLIAN static Eina_Bool _elm_widget_focus_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return (sd->focused && sd->top_win_focused); } EOLIAN static Eina_Bool _elm_widget_highlight_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->highlighted; } EOLIAN static Evas_Object* _elm_widget_focused_object_get(Eo *obj, Elm_Widget_Smart_Data *sd) { const Evas_Object *subobj; const Eina_List *l; if (!sd->focused || !sd->top_win_focused) return NULL; EINA_LIST_FOREACH(sd->subobjs, l, subobj) { Evas_Object *fobj; if (!_elm_widget_is(subobj)) continue; fobj = elm_widget_focused_object_get(subobj); if (fobj) return fobj; } return (Evas_Object *)obj; } EOLIAN static Evas_Object* _elm_widget_top_get(Eo *obj, Elm_Widget_Smart_Data *sd) { if (sd->parent_obj) { Evas_Object *ret = NULL; if (!efl_isa(sd->parent_obj, ELM_WIDGET_CLASS)) return NULL; ret = elm_obj_widget_top_get((Eo *) sd->parent_obj); return ret; } return (Evas_Object *)obj; } EAPI Eina_Bool elm_widget_is(const Evas_Object *obj) { return _elm_widget_is(obj); } EAPI Evas_Object * elm_widget_parent_widget_get(const Evas_Object *obj) { Evas_Object *parent; if (_elm_widget_is(obj)) { ELM_WIDGET_DATA_GET(obj, sd); if (!sd) return NULL; parent = sd->parent_obj; } else { parent = evas_object_data_get(obj, "elm-parent"); if (!parent) parent = evas_object_smart_parent_get(obj); } while (parent) { Evas_Object *elm_parent; if (_elm_widget_is(parent)) break; elm_parent = evas_object_data_get(parent, "elm-parent"); if (elm_parent) parent = elm_parent; else parent = evas_object_smart_parent_get(parent); } return parent; } EOLIAN static Evas_Object * _elm_widget_parent2_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->parent2; } EOLIAN static void _elm_widget_parent2_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Object *parent) { sd->parent2 = parent; } EAPI void elm_widget_event_callback_add(Eo *obj, Elm_Event_Cb func, const void *data) { API_ENTRY return; EINA_SAFETY_ON_NULL_RETURN(func); Elm_Event_Cb_Data *ecb = ELM_NEW(Elm_Event_Cb_Data); if (!ecb) { ERR("Failed to allocate memory"); return; } ecb->func = func; ecb->data = data; sd->event_cb = eina_list_append(sd->event_cb, ecb); } EAPI void * elm_widget_event_callback_del(Eo *obj, Elm_Event_Cb func, const void *data) { API_ENTRY return NULL; EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL); Eina_List *l; Elm_Event_Cb_Data *ecd; EINA_LIST_FOREACH(sd->event_cb, l, ecd) if ((ecd->func == func) && (ecd->data == data)) { free(ecd); sd->event_cb = eina_list_remove_list(sd->event_cb, l); return (void *)data; } return NULL; } EAPI Eina_Bool elm_widget_event_propagate(Eo *obj, Evas_Callback_Type type, void *event_info, Evas_Event_Flags *event_flags) { Evas_Object *parent = obj; Elm_Event_Cb_Data *ecd; Eina_List *l, *l_prev; while (parent && (!(event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD)))) { ELM_WIDGET_CHECK(parent) EINA_FALSE; Elm_Widget_Smart_Data *sd = efl_data_scope_get(parent, MY_CLASS); Eina_Bool int_ret = EINA_FALSE; if (elm_widget_disabled_get(obj)) { parent = sd->parent_obj; continue; } int_ret = elm_obj_widget_event(parent, obj, type, event_info); if (int_ret) return EINA_TRUE; EINA_LIST_FOREACH_SAFE(sd->event_cb, l, l_prev, ecd) { if (ecd->func((void *)ecd->data, parent, obj, type, event_info) || (event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD))) return EINA_TRUE; } parent = sd->parent_obj; } return EINA_FALSE; } /** * @internal * * Set custom focus chain. * * This function i set one new and overwrite any previous custom focus chain * with the list of objects. The previous list will be deleted and this list * will be managed. After setted, don't modity it. * * @note On focus cycle, only will be evaluated children of this container. * * @param obj The container widget * @param objs Chain of objects to pass focus * @ingroup Widget */ EOLIAN static void _elm_widget_focus_custom_chain_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_List *objs) { if (!_elm_widget_focus_chain_manager_is(obj)) return; elm_widget_focus_custom_chain_unset(obj); Eina_List *l; Evas_Object *o; EINA_LIST_FOREACH(objs, l, o) { evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, _elm_object_focus_chain_del_cb, obj); } sd->focus_chain = objs; } /** * @internal * * Get custom focus chain * * @param obj The container widget * @ingroup Widget */ EOLIAN static const Eina_List* _elm_widget_focus_custom_chain_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return (const Eina_List *)sd->focus_chain; } /** * @internal * * Unset custom focus chain * * @param obj The container widget * @ingroup Widget */ EOLIAN static void _elm_widget_focus_custom_chain_unset(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { Eina_List *l, *l_next; Evas_Object *o; EINA_LIST_FOREACH_SAFE(sd->focus_chain, l, l_next, o) { evas_object_event_callback_del_full(o, EVAS_CALLBACK_DEL, _elm_object_focus_chain_del_cb, obj); sd->focus_chain = eina_list_remove_list(sd->focus_chain, l); } } /** * @internal * * Append object to custom focus chain. * * @note If relative_child equal to NULL or not in custom chain, the object * will be added in end. * * @note On focus cycle, only will be evaluated children of this container. * * @param obj The container widget * @param child The child to be added in custom chain * @param relative_child The relative object to position the child * @ingroup Widget */ EOLIAN static void _elm_widget_focus_custom_chain_append(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *child, Evas_Object *relative_child) { EINA_SAFETY_ON_NULL_RETURN(child); if (!_elm_widget_focus_chain_manager_is(obj)) return; evas_object_event_callback_add(child, EVAS_CALLBACK_DEL, _elm_object_focus_chain_del_cb, obj); if (!relative_child) sd->focus_chain = eina_list_append(sd->focus_chain, child); else sd->focus_chain = eina_list_append_relative(sd->focus_chain, child, relative_child); } /** * @internal * * Prepend object to custom focus chain. * * @note If relative_child equal to NULL or not in custom chain, the object * will be added in begin. * * @note On focus cycle, only will be evaluated children of this container. * * @param obj The container widget * @param child The child to be added in custom chain * @param relative_child The relative object to position the child * @ingroup Widget */ EOLIAN static void _elm_widget_focus_custom_chain_prepend(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *child, Evas_Object *relative_child) { EINA_SAFETY_ON_NULL_RETURN(child); if (!_elm_widget_focus_chain_manager_is(obj)) return; evas_object_event_callback_add(child, EVAS_CALLBACK_DEL, _elm_object_focus_chain_del_cb, obj); if (!relative_child) sd->focus_chain = eina_list_prepend(sd->focus_chain, child); else sd->focus_chain = eina_list_prepend_relative(sd->focus_chain, child, relative_child); } /** * @internal * * Give focus to next object in object tree. * * Give focus to next object in focus chain of one object sub-tree. * If the last object of chain already have focus, the focus will go to the * first object of chain. * * @param obj The widget root of sub-tree * @param dir Direction to cycle the focus * * @ingroup Widget */ EOLIAN static void _elm_widget_focus_cycle(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Elm_Focus_Direction dir) { Evas_Object *target = NULL; Elm_Object_Item *target_item = NULL; if (!_elm_widget_is(obj)) return; elm_widget_focus_next_get(obj, dir, &target, &target_item); if (target) { /* access */ if (_elm_config->access_mode) { /* highlight cycle does not steal a focus, only after window gets the ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ACTIVATE message, target will steal focus, or focus its own job. */ if (!_elm_access_auto_highlight_get()) elm_widget_focus_steal(target, target_item); _elm_access_highlight_set(target); elm_widget_focus_region_show(target); } else elm_widget_focus_steal(target, target_item); } } /** * @internal * * Give focus to near object(in object tree) in one direction. * * Give focus to near object(in object tree) in direction of current * focused object. If none focusable object in given direction or * none focused object in object tree, the focus will not change. * * @param obj The reference widget * @param degree Degree changes clockwise. i.e. 0-degree: Up, * 90-degree: Right, 180-degree: Down, and 270-degree: Left * @return EINA_TRUE if focus is moved. * * @ingroup Widget */ EOLIAN static Eina_Bool _elm_widget_focus_direction_go(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, double degree) { Evas_Object *target = NULL; Elm_Object_Item *target_item = NULL; Evas_Object *current_focused = NULL; double weight = 0.0; if (!_elm_widget_is(obj)) return EINA_FALSE; if (!_is_focused(obj)) return EINA_FALSE; current_focused = elm_widget_focused_object_get(obj); if (elm_widget_focus_direction_get (obj, current_focused, degree, &target, &target_item, &weight)) { elm_widget_focus_steal(target, NULL); return EINA_TRUE; } return EINA_FALSE; } double _elm_widget_focus_direction_weight_get(const Evas_Object *obj1, const Evas_Object *obj2, double degree) { Evas_Coord obj_x1, obj_y1, w1, h1, obj_x2, obj_y2, w2, h2; double x1, yy1, x2, yy2, xx1, yyy1, xx2, yyy2; double ax, ay, cx, cy; double weight = -1.0, g = 0.0; if (obj1 == obj2) return 0.0; degree -= 90.0; while (degree >= 360.0) degree -= 360.0; while (degree < 0.0) degree += 360.0; evas_object_geometry_get(obj1, &obj_x1, &obj_y1, &w1, &h1); cx = obj_x1 + (w1 / 2.0); cy = obj_y1 + (h1 / 2.0); evas_object_geometry_get(obj2, &obj_x2, &obj_y2, &w2, &h2); /* For overlapping cases. */ if (ELM_RECTS_INTERSECT(obj_x1, obj_y1, w1, h1, obj_x2, obj_y2, w2, h2)) return 0.0; /* Change all points to relative one. */ x1 = obj_x1 - cx; xx1 = x1 + w1; yy1 = obj_y1 - cy; yyy1 = yy1 + h1; x2 = obj_x2 - cx; xx2 = x2 + w2; yy2 = obj_y2 - cy; yyy2 = yy2 + h2; /* Get crossing points (ax, ay) between obj1 and a line extending * to the direction of current degree. */ if (degree == 0.0) { ax = xx1; ay = 0.0; } else if (degree == 90.0) { ax = 0.0; ay = yyy1; } else if (degree == 180.0) { ax = x1; ay = 0.0; } else if (degree == 270.0) { ax = 0.0; ay = yy1; } else { g = tan(degree * (M_PI / 180.0)); if ((degree > 0.0) && (degree < 90.0)) { ay = g * xx1; if (ay <= yyy1) ax = xx1; else { ax = yyy1 / g; ay = yyy1; } } else if ((degree > 90.0) && (degree < 180.0)) { ay = g * x1; if (ay <= yyy1) ax = x1; else { ax = yyy1 / g; ay = yyy1; } } else if ((degree > 180.0) && (degree < 270.0)) { ay = g * x1; if (ay >= yy1) ax = x1; else { ax = yy1 / g; ay = yy1; } } else { ay = g * xx1; if (ay >= yy1) ax = xx1; else { ax = yy1 / g; ay = yy1; } } } /* Filter obj2, if it is not in the specific derection. */ int i = 0; double rx[4] = {0.0, 0.0, 0.0, 0.0}, ry[4] = {0.0, 0.0, 0.0, 0.0}; double t1, t2, u1, v1, u2, v2; if ((degree == 45.0) || (degree == 225.0) || (degree == 135.0) || (degree == 315.0)) { u1 = 1.0; v1 = 0.0; u2 = 0.0; v2 = 1.0; } else { double g2 = tan((degree + 45.0) * (M_PI / 180.0)); u1 = (-1.0 * g2); u2 = (1.0 / g2); v1 = v2 = 1.0; } t1 = (u1 * ax) + (v1 * ay); t2 = (u2 * ax) + (v2 * ay); #define _R(x) (int)((x + 0.05) * 10.0) if ((_R(t1 * ((u1 * x2) + (v1 * yy2))) > 0) && (_R(t2 * ((u2 * x2) + (v2 * yy2))) > 0)) { rx[i] = x2; ry[i++] = yy2; } if ((_R(t1 * ((u1 * x2) + (v1 * yyy2))) > 0) && (_R(t2 * ((u2 * x2) + (v2 * yyy2))) > 0)) { rx[i] = x2; ry[i++] = yyy2; } if ((_R(t1 * ((u1 * xx2) + (v1 * yy2))) > 0) && (_R(t2 * ((u2 * xx2) + (v2 * yy2))) > 0)) { rx[i] = xx2; ry[i++] = yy2; } if ((_R(t1 * ((u1 * xx2) + (v1 * yyy2))) > 0) && (_R(t2 * ((u2 * xx2) + (v2 * yyy2))) > 0)) { rx[i] = xx2; ry[i++] = yyy2; } if (i == 0) { if (degree == 0.0) { if ((_R(xx2) < 0) || (_R(yy2) > 0) || (_R(yyy2) < 0)) return 0.0; } else if (degree == 90.0) { if ((_R(yyy2) < 0) || (_R(x2) > 0) || (_R(xx2) < 0)) return 0.0; } else if (degree == 180.0) { if ((_R(x2) > 0) || (_R(yy2) > 0) || (_R(yyy2) < 0)) return 0.0; } else if (degree == 270.0) { if ((_R(yy2) > 0) || (_R(x2) > 0) || (_R(xx2) < 0)) return 0.0; } else { if ((_R(g * x2) >= _R(yy2)) && (_R((g * x2)) <= _R(yyy2))) { if (!((_R(ax * x2) > 0) && (_R(ay * (g * x2)) > 0))) return 0.0; } else if ((_R(g * xx2) >= _R(yy2)) && (_R((g * xx2)) <= _R(yyy2))) { if (!((_R(ax * xx2) > 0) && (_R(ay * (g * xx2)) > 0))) return 0.0; } else if ((_R((1.0 / g) * yy2) >= _R(xx2)) && (_R((1.0 / g) * yy2) <= _R(xx2))) { if (!((_R(ax * ((1.0 / g) * yy2)) > 0) && (_R(ay * yy2) > 0))) return 0.0; } else if ((_R((1.0 / g) * yyy2) >= _R(xx2)) && (_R((1.0 / g) * yyy2) <= _R(xx2))) { if (!((_R(ax * ((1.0 / g) * yyy2)) > 0) && (_R(ay * yyy2) > 0))) return 0.0; } else return 0.0; } } /* Calculate the weight for obj2. */ if (degree == 0.0) { if (_R(xx1) > _R(x2)) weight = -1.0; else if ((_R(yy2) >= _R(yy1)) && (_R(yyy2) <= _R(yyy1))) weight = (x2 - xx1) * (x2 - xx1); else if (_R(yy2) > 0) weight = ((x2 - xx1) * (x2 - xx1)) + (yy2 * yy2); else if (_R(yyy2) < 0) weight = ((x2 - xx1) * (x2 - xx1)) + (yyy2 * yyy2); else weight = (x2 - xx1) * (x2 - xx1); } else if (degree == 90.0) { if (_R(yyy1) > _R(yy2)) weight = -1.0; else if ((_R(x2) >= _R(x1)) && (_R(xx2) <= _R(xx1))) weight = (yy2 - yyy1) * (yy2 - yyy1); else if (_R(x2) > 0) weight = (x2 * x2) + ((yy2 - yyy1) * (yy2 - yyy1)); else if (_R(xx2) < 0) weight = (xx2 * xx2) + ((yy2 - yyy1) * (yy2 - yyy1)); else weight = (yy2 - yyy1) * (yy2 - yyy1); } else if (degree == 180.0) { if (_R(x1) < _R(xx2)) weight = -1.0; else if ((_R(yy2) >= _R(yy1)) && (_R(yyy2) <= _R(yyy1))) weight = (x1 - xx2) * (x1 - xx2); else if (_R(yy2) > 0) weight = ((x1 - xx2) * (x1 - xx2)) + (yy2 * yy2); else if (_R(yyy2) < 0) weight = ((x1 - xx2) * (x1 - xx2)) + (yyy2 * yyy2); else weight = (x1 - xx2) * (x1 - xx2); } else if (degree == 270.0) { if (_R(yy1) < _R(yyy2)) weight = -1.0; else if ((_R(x2) >= _R(x1)) && (_R(xx2) <= _R(xx1))) weight = (yy1 - yyy2) * (yy1 - yyy2); else if (_R(x2) > 0) weight = (x2 * x2) + ((yy1 - yyy2) * (yy1 - yyy2)); else if (_R(xx2) < 0) weight = (xx2 * xx2) + ((yy1 - yyy2) * (yy1 - yyy2)); else weight = (yy1 - yyy2) * (yy1 - yyy2); } else { int j = 0, k = 0; double sx[4] = {0.0, 0.0, 0.0, 0.0}, sy[4] = {0.0, 0.0, 0.0, 0.0}; double t_weight[4] = {-1.0, -1.0, -1.0, -1.0}; if ((_R(g * x2) >= _R(yy2)) && (_R(g * x2) <= _R(yyy2))) { sx[j] = x2; sy[j] = g * x2; t_weight[j++] = ((ax - x2) * (ax - x2)) + ((ay - (g * x2)) * (ay - (g * x2))); } if ((_R(g * xx2) >= _R(yy2)) && (_R(g * xx2) <= _R(yyy2))) { sx[j] = xx2; sy[j] = g * xx2; t_weight[j++] = ((ax - xx2) * (ax - xx2)) + ((ay - (g * xx2)) * (ay - (g * xx2))); } if ((_R((1.0 / g) * yy2) >= _R(x2)) && (_R((1.0 / g) * yy2) <= _R(xx2))) { sx[j] = (1.0 / g) * yy2; sy[j] = yy2; t_weight[j++] = ((ax - ((1.0 / g) * yy2)) * (ax - ((1.0 / g) * yy2))) + ((ay - yy2) * (ay - yy2)); } if ((_R((1.0 / g) * yyy2) >= _R(x2)) && (_R((1.0 / g) * yyy2) <= _R(xx2))) { sx[j] = (1.0 / g) * yyy2; sy[j] = yyy2; t_weight[j++] = ((ax - ((1.0 / g) * yyy2)) * (ax - ((1.0 / g) * yyy2))) + ((ay - yyy2) * (ay - yyy2)); } if ((j > 2) || ((j == 2) && ((_R(sx[0]) != _R(sx[1])) || (_R(sy[0]) != _R(sy[1]))))) { for (; k < j; k++) { if (_R(t_weight[k]) == 0) return -1.0; if ((1 / weight) < (1 / t_weight[k])) weight = t_weight[k]; } } else { for (; k < i; k++) { double ccx, ccy, t1_weight, x_diff, y_diff; ccx = ((1.0 / g) * rx[k] + ry[k]) / (g + (1.0 / g)); ccy = g * ccx; x_diff = rx[k] - ccx; if (x_diff < 0) x_diff *= -1.0; y_diff = ry[k] - ccy; if (y_diff < 0) y_diff *= -1.0; t1_weight = (((ax - ccx) * (ax - ccx)) + ((ay - ccy) * (ay - ccy))) + ((x_diff * x_diff * x_diff) + (y_diff * y_diff * y_diff)); if ((_R(t1_weight) != 0) && ((1 / weight) < (1 / t1_weight))) weight = t1_weight; } } } /* Return the current object's weight. */ if (weight == -1.0) return 0.0; if (_R(weight) == 0) return -1.0; #undef _R return 1.0 / weight; } /** * @internal * * Get near object in one direction of base object. * * Get near object(in the object sub-tree) in one direction of * base object. Return the near object by reference. * By initializing weight, you can filter objects locating far * from base object. If object is in the specific direction, * weight is (1/(distance^2)). If object is not exactly in one * direction, some penalty will be added. * * @param obj The widget root of sub-tree * @param base The base object of the direction * @param degree Degree changes clockwise. i.e. 0-degree: Up, * 90-degree: Right, 180-degree: Down, and 270-degree: Left * @param direction The near object in one direction * @param weight The weight is bigger when the object is located near * @return EINA_TRUE if near object is updated. * * @ingroup Widget */ EOLIAN static Eina_Bool _elm_widget_focus_direction_get(const Eo *obj, Elm_Widget_Smart_Data *sd, const Evas_Object *base, double degree, Evas_Object **direction, Elm_Object_Item **direction_item, double *weight) { double c_weight; /* -1 means the best was already decided. Don't need any more searching. */ if (!direction || !weight || !base || (obj == base)) return EINA_FALSE; /* Ignore if disabled */ if ((!evas_object_visible_get(obj)) || (elm_widget_disabled_get(obj)) || (elm_widget_tree_unfocusable_get(obj))) return EINA_FALSE; /* Try use hook */ if (_internal_elm_widget_focus_direction_manager_is(obj)) { Eina_Bool int_ret = EINA_FALSE; int_ret = elm_obj_widget_focus_direction((Eo *)obj, base, degree, direction, direction_item, weight); return int_ret; } if (!elm_widget_can_focus_get(obj) || _is_focused((Eo *)obj)) return EINA_FALSE; c_weight = _elm_widget_focus_direction_weight_get(base, obj, degree); if ((c_weight == -1.0) || ((c_weight != 0.0) && (*weight != -1.0) && ((int)(*weight * 1000000) <= (int)(c_weight * 1000000)))) { if (*direction && ((int)(*weight * 1000000) == (int)(c_weight * 1000000))) { ELM_WIDGET_DATA_GET(*direction, sd1); if (sd1) { if (sd->focus_order <= sd1->focus_order) return EINA_FALSE; } } *direction = (Evas_Object *)obj; *weight = c_weight; return EINA_TRUE; } return EINA_FALSE; } /** * @internal * * Get near object in one direction of base object in list. * * Get near object in one direction of base object in the specific * object list. Return the near object by reference. * By initializing weight, you can filter objects locating far * from base object. If object is in the specific direction, * weight is (1/(distance^2)). If object is not exactly in one * direction, some penalty will be added. * * @param obj The widget root of sub-tree * @param base The base object of the direction * @param items list with ordered objects * @param list_data_get function to get the object from one item of list * @param degree Degree changes clockwise. i.e. 0-degree: Up, * 90-degree: Right, 180-degree: Down, and 270-degree: Left * @param direction The near object in one direction * @param weight The weight is bigger when the object is located near * @return EINA_TRUE if near object is updated. * * @ingroup Widget */ EOLIAN static Eina_Bool _elm_widget_focus_list_direction_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const Evas_Object *base, const Eina_List *items, list_data_get_func_type list_data_get, double degree, Evas_Object **direction, Elm_Object_Item **direction_item, double *weight) { if (!direction || !weight || !base || !items) return EINA_FALSE; const Eina_List *l = items; Evas_Object *current_best = *direction; for (; l; l = eina_list_next(l)) { Evas_Object *cur = list_data_get(l); if (cur && _elm_widget_is(cur)) elm_widget_focus_direction_get(cur, base, degree, direction, direction_item, weight); } if (current_best != *direction) return EINA_TRUE; return EINA_FALSE; } /** * @internal * * Get next object in focus chain of object tree. * * Get next object in focus chain of one object sub-tree. * Return the next object by reference. If don't have any candidate to receive * focus before chain end, the first candidate will be returned. * * @param obj The widget root of sub-tree * @param dir Direction of focus chain * @param next The next object in focus chain * @return EINA_TRUE if don't need focus chain restart/loop back * to use 'next' obj. * * @ingroup Widget */ EOLIAN static Eina_Bool _elm_widget_focus_next_get(const Eo *obj, Elm_Widget_Smart_Data *sd, Elm_Focus_Direction dir, Evas_Object **next, Elm_Object_Item **next_item) { Elm_Access_Info *ac; if (!next) return EINA_FALSE; *next = NULL; /* Ignore if disabled */ if (_elm_config->access_mode && _elm_access_auto_highlight_get()) { if (!evas_object_visible_get(obj) || (elm_widget_tree_unfocusable_get(obj))) return EINA_FALSE; } else { if ((!evas_object_visible_get(obj)) || (elm_widget_disabled_get(obj)) || (elm_widget_tree_unfocusable_get(obj))) return EINA_FALSE; } /* Try use hook */ if (_elm_widget_focus_chain_manager_is(obj)) { Eina_Bool int_ret = EINA_FALSE; int_ret = elm_obj_widget_focus_next((Eo *)obj, dir, next, next_item); if (!int_ret && _is_focused((Eo *)obj)) { Evas_Object *o = NULL; if (dir == ELM_FOCUS_PREVIOUS) *next_item = sd->item_focus_previous; else if (dir == ELM_FOCUS_NEXT) *next_item = sd->item_focus_next; else if (dir == ELM_FOCUS_UP) *next_item = sd->item_focus_up; else if (dir == ELM_FOCUS_DOWN) *next_item = sd->item_focus_down; else if (dir == ELM_FOCUS_RIGHT) *next_item = sd->item_focus_right; else if (dir == ELM_FOCUS_LEFT) *next_item = sd->item_focus_left; if (*next_item) o = elm_object_item_widget_get(*next_item); if (!o) { if (dir == ELM_FOCUS_PREVIOUS) o = sd->focus_previous; else if (dir == ELM_FOCUS_NEXT) o = sd->focus_next; else if (dir == ELM_FOCUS_UP) o = sd->focus_up; else if (dir == ELM_FOCUS_DOWN) o = sd->focus_down; else if (dir == ELM_FOCUS_RIGHT) o = sd->focus_right; else if (dir == ELM_FOCUS_LEFT) o = sd->focus_left; } if (o) { *next = o; return EINA_TRUE; } } return int_ret; } /* access object does not check sd->can_focus, because an object could have highlight even though the object is not focusable. */ if (_elm_config->access_mode && _elm_access_auto_highlight_get()) { ac = _elm_access_info_get(obj); if (!ac) return EINA_FALSE; /* check whether the hover object is visible or not */ if (!evas_object_visible_get(ac->hoverobj)) return EINA_FALSE; } else if (!elm_widget_can_focus_get(obj)) return EINA_FALSE; if (_is_focused((Eo *)obj)) { if (dir == ELM_FOCUS_PREVIOUS) *next_item = sd->item_focus_previous; else if (dir == ELM_FOCUS_NEXT) *next_item = sd->item_focus_next; else if (dir == ELM_FOCUS_UP) *next_item = sd->item_focus_up; else if (dir == ELM_FOCUS_DOWN) *next_item = sd->item_focus_down; else if (dir == ELM_FOCUS_RIGHT) *next_item = sd->item_focus_right; else if (dir == ELM_FOCUS_LEFT) *next_item = sd->item_focus_left; if (*next_item) *next = elm_object_item_widget_get(*next_item); if (!(*next)) { if (dir == ELM_FOCUS_PREVIOUS) *next = sd->focus_previous; else if (dir == ELM_FOCUS_NEXT) *next = sd->focus_next; else if (dir == ELM_FOCUS_UP) *next = sd->focus_up; else if (dir == ELM_FOCUS_DOWN) *next = sd->focus_down; else if (dir == ELM_FOCUS_RIGHT) *next = sd->focus_right; else if (dir == ELM_FOCUS_LEFT) *next = sd->focus_left; } if (*next) return EINA_TRUE; } /* Return */ *next = (Evas_Object *)obj; return !ELM_WIDGET_FOCUS_GET(obj); } /** * @internal * * Get next object in focus chain of object tree in list. * * Get next object in focus chain of one object sub-tree ordered by one list. * Return the next object by reference. If don't have any candidate to receive * focus before list end, the first candidate will be returned. * * @param obj The widget root of sub-tree * @param items list with ordered objects * @param list_data_get function to get the object from one item of list * @param dir Direction of focus chain * @param next The next object in focus chain * @return EINA_TRUE if don't need focus chain restart/loop back * to use 'next' obj. * * @ingroup Widget */ EOLIAN static Eina_Bool _elm_widget_focus_list_next_get(const Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const Eina_List *items, list_data_get_func_type list_data_get, Elm_Focus_Direction dir, Evas_Object **next, Elm_Object_Item **next_item) { Eina_List *(*list_next)(const Eina_List *list) = NULL; Evas_Object *focused_object = NULL; if (!next) return EINA_FALSE; *next = NULL; if (!_elm_widget_is(obj)) return EINA_FALSE; if (!items) return EINA_FALSE; /* When Up, Down, Right, or Left, try direction_get first. */ focused_object = elm_widget_focused_object_get(obj); if (focused_object) { if ((dir == ELM_FOCUS_UP) || (dir == ELM_FOCUS_DOWN) || (dir == ELM_FOCUS_RIGHT) || (dir == ELM_FOCUS_LEFT)) { *next_item = elm_widget_focus_next_item_get(focused_object, dir); if (*next_item) *next = elm_object_item_widget_get(*next_item); else *next = elm_widget_focus_next_object_get(focused_object, dir); if (*next) return EINA_TRUE; else { Evas_Object *n = NULL; Elm_Object_Item *n_item = NULL; double degree = 0; double weight = 0.0; if (dir == ELM_FOCUS_UP) degree = 0.0; else if (dir == ELM_FOCUS_DOWN) degree = 180.0; else if (dir == ELM_FOCUS_RIGHT) degree = 90.0; else if (dir == ELM_FOCUS_LEFT) degree = 270.0; if (elm_widget_focus_list_direction_get(obj, focused_object, items, list_data_get, degree, &n, &n_item, &weight)) { *next_item = n_item; *next = n; return EINA_TRUE; } } } } /* Direction */ if (dir == ELM_FOCUS_PREVIOUS) { items = eina_list_last(items); list_next = eina_list_prev; } else if ((dir == ELM_FOCUS_NEXT) || (dir == ELM_FOCUS_UP) || (dir == ELM_FOCUS_DOWN) || (dir == ELM_FOCUS_RIGHT) || (dir == ELM_FOCUS_LEFT)) list_next = eina_list_next; else return EINA_FALSE; const Eina_List *l = items; /* Recovery last focused sub item */ if (ELM_WIDGET_FOCUS_GET(obj)) { for (; l; l = list_next(l)) { Evas_Object *cur = list_data_get(l); if (ELM_WIDGET_FOCUS_GET(cur)) break; } /* Focused object, but no focused sub item */ if (!l) l = items; } const Eina_List *start = l; Evas_Object *to_focus = NULL; Elm_Object_Item *to_focus_item = NULL; /* Iterate sub items */ /* Go to the end of list */ for (; l; l = list_next(l)) { Evas_Object *tmp = NULL; Elm_Object_Item *tmp_item = NULL; Evas_Object *cur = list_data_get(l); if (!cur) continue; if (!_elm_widget_is(cur)) continue; if (elm_widget_parent_get(cur) != obj) continue; /* Try Focus cycle in subitem */ if (elm_widget_focus_next_get(cur, dir, &tmp, &tmp_item)) { *next = tmp; *next_item = tmp_item; return EINA_TRUE; } else if ((dir == ELM_FOCUS_UP) || (dir == ELM_FOCUS_DOWN) || (dir == ELM_FOCUS_RIGHT) || (dir == ELM_FOCUS_LEFT)) { if (tmp && _is_focused(cur)) { *next = tmp; *next_item = tmp_item; return EINA_FALSE; } } else if ((tmp) && (!to_focus)) { to_focus = tmp; to_focus_item = tmp_item; } } l = items; /* Get First possible */ for (; l != start; l = list_next(l)) { Evas_Object *tmp = NULL; Elm_Object_Item *tmp_item = NULL; Evas_Object *cur = list_data_get(l); if (elm_widget_parent_get(cur) != obj) continue; /* Try Focus cycle in subitem */ elm_widget_focus_next_get(cur, dir, &tmp, &tmp_item); if (tmp) { *next = tmp; *next_item = tmp_item; return EINA_FALSE; } } *next = to_focus; *next_item = to_focus_item; return EINA_FALSE; } /** * @internal * * Get next object which was set with specific focus direction. * * Get next object which was set by elm_widget_focus_next_object_set * with specific focus directioin. * * @param obj The widget * @param dir Direction of focus * @return Widget which was registered with sepecific focus direction. * * @ingroup Widget */ EOLIAN static Evas_Object* _elm_widget_focus_next_object_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Focus_Direction dir) { Evas_Object *ret = NULL; if (dir == ELM_FOCUS_PREVIOUS) ret = sd->focus_previous; else if (dir == ELM_FOCUS_NEXT) ret = sd->focus_next; else if (dir == ELM_FOCUS_UP) ret = sd->focus_up; else if (dir == ELM_FOCUS_DOWN) ret = sd->focus_down; else if (dir == ELM_FOCUS_RIGHT) ret = sd->focus_right; else if (dir == ELM_FOCUS_LEFT) ret = sd->focus_left; return ret; } /** * @internal * * Set next object with specific focus direction. * * When a widget is set with specific focus direction, this widget will be * the first candidate when finding the next focus object. * Focus next object can be registered with six directions that are previous, * next, up, down, right, and left. * * @param obj The widget * @param next Next focus object * @param dir Direction of focus * * @ingroup Widget */ EOLIAN static void _elm_widget_focus_next_object_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Object *next, Elm_Focus_Direction dir) { if (dir == ELM_FOCUS_PREVIOUS) sd->focus_previous = next; else if (dir == ELM_FOCUS_NEXT) sd->focus_next = next; else if (dir == ELM_FOCUS_UP) sd->focus_up = next; else if (dir == ELM_FOCUS_DOWN) sd->focus_down = next; else if (dir == ELM_FOCUS_RIGHT) sd->focus_right = next; else if (dir == ELM_FOCUS_LEFT) sd->focus_left = next; } EOLIAN static Elm_Object_Item* _elm_widget_focus_next_item_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Focus_Direction dir) { Elm_Object_Item *ret = NULL; if (dir == ELM_FOCUS_PREVIOUS) ret = sd->item_focus_previous; else if (dir == ELM_FOCUS_NEXT) ret = sd->item_focus_next; else if (dir == ELM_FOCUS_UP) ret = sd->item_focus_up; else if (dir == ELM_FOCUS_DOWN) ret = sd->item_focus_down; else if (dir == ELM_FOCUS_RIGHT) ret = sd->item_focus_right; else if (dir == ELM_FOCUS_LEFT) ret = sd->item_focus_left; return ret; } EOLIAN static void _elm_widget_focus_next_item_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Object_Item *next_item, Elm_Focus_Direction dir) { if (dir == ELM_FOCUS_PREVIOUS) sd->item_focus_previous = next_item; else if (dir == ELM_FOCUS_NEXT) sd->item_focus_next = next_item; else if (dir == ELM_FOCUS_UP) sd->item_focus_up = next_item; else if (dir == ELM_FOCUS_DOWN) sd->item_focus_down = next_item; else if (dir == ELM_FOCUS_RIGHT) sd->item_focus_right = next_item; else if (dir == ELM_FOCUS_LEFT) sd->item_focus_left = next_item; } EOLIAN static void _elm_widget_parent_highlight_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool highlighted) { highlighted = !!highlighted; Evas_Object *o = elm_widget_parent_get(obj); if (o) elm_widget_parent_highlight_set(o, highlighted); sd->highlighted = highlighted; } EOLIAN static void _elm_widget_focus_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool focus) { if (!sd->focused) { focus_order++; sd->focus_order = focus_order; sd->focused = EINA_TRUE; elm_obj_widget_on_focus(obj, NULL); } if (focus) { if ((_is_focusable(sd->resize_obj)) && (!elm_widget_disabled_get(sd->resize_obj))) { elm_widget_focus_set(sd->resize_obj, focus); } else { const Eina_List *l; Evas_Object *child; EINA_LIST_FOREACH(sd->subobjs, l, child) { if (!_elm_widget_is(child)) continue; if ((_is_focusable(child)) && (!elm_widget_disabled_get(child))) { elm_widget_focus_set(child, focus); break; } } } } else { const Eina_List *l; Evas_Object *child; EINA_LIST_REVERSE_FOREACH(sd->subobjs, l, child) { if (!_elm_widget_is(child)) continue; if ((_is_focusable(child)) && (!elm_widget_disabled_get(child))) { elm_widget_focus_set(child, focus); break; } } } } EOLIAN static Evas_Object* _elm_widget_widget_parent_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->parent_obj; } static void _focused_object_clear(Elm_Widget_Smart_Data *sd) { if (sd->resize_obj && elm_widget_is(sd->resize_obj) && _is_focused(sd->resize_obj)) { elm_obj_widget_focused_object_clear(sd->resize_obj); } else { const Eina_List *l; Evas_Object *child; EINA_LIST_FOREACH(sd->subobjs, l, child) { if (_elm_widget_is(child) && _is_focused(child)) { elm_obj_widget_focused_object_clear(child); break; } } } } EOLIAN static void _elm_widget_focused_object_clear(Eo *obj, Elm_Widget_Smart_Data *sd) { if (!sd->focused) return; _focused_object_clear(sd); sd->focused = EINA_FALSE; if (sd->top_win_focused) elm_obj_widget_on_focus(obj, NULL); } EOLIAN static void _elm_widget_focus_steal(Eo *obj, Elm_Widget_Smart_Data *sd, Elm_Object_Item *item) { Evas_Object *parent, *parent2, *o; if (sd->focused) return; if (sd->disabled) return; if (!sd->can_focus) return; if (sd->tree_unfocusable) return; parent = obj; for (;; ) { o = elm_widget_parent_get(parent); if (!o) break; sd = efl_data_scope_get(o, MY_CLASS); if (sd->disabled || sd->tree_unfocusable) return; if (sd->focused) break; parent = o; } if ((!elm_widget_parent_get(parent)) && (!elm_widget_parent2_get(parent))) elm_obj_widget_focused_object_clear(parent); else { parent2 = elm_widget_parent_get(parent); if (!parent2) parent2 = elm_widget_parent2_get(parent); parent = parent2; sd = efl_data_scope_get(parent, MY_CLASS); if (sd) _focused_object_clear(sd); } _parent_focus(obj, item); elm_widget_focus_region_show(obj); return; } static void _parents_on_focus(Evas_Object *obj) { API_ENTRY return; if (!sd->focused || !sd->top_win_focused) return; Evas_Object *o = elm_widget_parent_get(obj); if (o) _parents_on_focus(o); elm_obj_widget_on_focus(obj, NULL); } EOLIAN static void _elm_widget_focus_restore(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED) { Evas_Object *newest = NULL; unsigned int newest_focus_order = 0; newest = elm_widget_newest_focus_order_get(obj, &newest_focus_order, EINA_TRUE); if (newest) _parents_on_focus(newest); } void _elm_widget_focus_auto_show(Evas_Object *obj) { Evas_Object *top = elm_widget_top_get(obj); if (top && efl_isa(top, EFL_UI_WIN_CLASS)) _elm_win_focus_auto_show(top); } void _elm_widget_top_win_focused_set(Evas_Object *obj, Eina_Bool top_win_focused) { const Eina_List *l; Evas_Object *child; API_ENTRY return; if (sd->top_win_focused == top_win_focused) return; EINA_LIST_FOREACH(sd->subobjs, l, child) { if (elm_widget_is(child)) _elm_widget_top_win_focused_set(child, top_win_focused); } sd->top_win_focused = top_win_focused; if (sd->focused && !sd->top_win_focused) elm_obj_widget_on_focus(obj, NULL); } Eina_Bool _elm_widget_top_win_focused_get(const Evas_Object *obj) { API_ENTRY return EINA_FALSE; return sd->top_win_focused; } static void _elm_widget_disabled_eval(const Evas_Object *obj, Eina_Bool disabled) { const Eina_List *l; Evas_Object *child; ELM_WIDGET_DATA_GET(obj, sd); if (disabled) { EINA_LIST_FOREACH(sd->subobjs, l, child) { if (elm_widget_is(child)) { elm_widget_focus_disabled_handle(child); elm_obj_widget_disable(child); _elm_widget_disabled_eval(child, EINA_TRUE); } } } else { EINA_LIST_FOREACH(sd->subobjs, l, child) if (elm_widget_is(child)) { ELM_WIDGET_DATA_GET(child, sdc); if (!sdc->disabled) { elm_widget_focus_disabled_handle(child); elm_obj_widget_disable(child); _elm_widget_disabled_eval(child, EINA_FALSE); } } } } static void elm_widget_disabled_internal(Eo *obj, Eina_Bool disabled) { Eina_Bool parent_state = EINA_FALSE; if (disabled) { elm_widget_focus_disabled_handle(obj); elm_obj_widget_disable(obj); _elm_widget_disabled_eval(obj, EINA_TRUE); } else { parent_state = elm_widget_disabled_get(elm_widget_parent_get(obj)); if (parent_state) return; elm_widget_focus_disabled_handle(obj); elm_obj_widget_disable(obj); _elm_widget_disabled_eval(obj, EINA_FALSE); } } EOLIAN static void _elm_widget_disabled_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool disabled) { if (sd->disabled == disabled) return; sd->disabled = !!disabled; elm_widget_disabled_internal(obj, disabled); if (efl_finalized_get(obj)) _full_eval_children(obj, sd); } EOLIAN static Eina_Bool _elm_widget_disabled_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { Eina_Bool disabled = EINA_FALSE; if (sd->disabled) disabled = EINA_TRUE; else disabled = elm_widget_disabled_get(elm_widget_parent_get(obj)); return disabled; } EOLIAN static void _elm_widget_show_region_set(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, Eina_Bool forceshow) { Evas_Object *parent_obj, *child_obj; Evas_Coord px, py, cx, cy, nx = 0, ny = 0; evas_smart_objects_calculate(evas_object_evas_get(obj)); if (!forceshow && (x == sd->rx) && (y == sd->ry) && (w == sd->rw) && (h == sd->rh)) return; sd->rx = x; sd->ry = y; sd->rw = w; sd->rh = h; if (sd->on_show_region) { sd->on_show_region (sd->on_show_region_data, obj); if (_elm_scrollable_is(obj)) { elm_interface_scrollable_content_pos_get(obj, &nx, &ny); x -= nx; y -= ny; } } do { parent_obj = sd->parent_obj; child_obj = sd->obj; if ((!parent_obj) || (!_elm_widget_is(parent_obj))) break; sd = efl_data_scope_get(parent_obj, MY_CLASS); if (!sd) break; evas_object_geometry_get(parent_obj, &px, &py, NULL, NULL); evas_object_geometry_get(child_obj, &cx, &cy, NULL, NULL); x += (cx - px); y += (cy - py); sd->rx = x; sd->ry = y; sd->rw = w; sd->rh = h; if (sd->on_show_region) { sd->on_show_region (sd->on_show_region_data, parent_obj); } } while (parent_obj); } EOLIAN static void _elm_widget_show_region_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h) { if (x) *x = sd->rx; if (y) *y = sd->ry; if (w) *w = sd->rw; if (h) *h = sd->rh; } /** * @internal * * Get the focus region of the given widget. * * @return show region or not * (@c EINA_TRUE = show region/@c EINA_FALSE = do not show region). Default is @c EINA_FALSE. * * The focus region is the area of a widget that should brought into the * visible area when the widget is focused. Mostly used to show the part of * an entry where the cursor is, for example. The area returned is relative * to the object @p obj. * * @param obj The widget object * @param x Where to store the x coordinate of the area * @param y Where to store the y coordinate of the area * @param w Where to store the width of the area * @param h Where to store the height of the area * * @ingroup Widget */ EOLIAN static Eina_Bool _elm_widget_focus_region_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h) { Eina_Bool int_ret = EINA_FALSE; int_ret = elm_obj_widget_on_focus_region((Eo *)obj, x, y, w, h); if (!int_ret) { evas_object_geometry_get(obj, NULL, NULL, w, h); if (x) *x = 0; if (y) *y = 0; } if ((*w <= 0) || (*h <= 0)) return EINA_FALSE; return EINA_TRUE; } EOLIAN static void _elm_widget_parents_bounce_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool *horiz, Eina_Bool *vert) { Evas_Object *parent_obj = obj; Eina_Bool h = EINA_FALSE, v = EINA_FALSE; *horiz = EINA_FALSE; *vert = EINA_FALSE; do { parent_obj = elm_widget_parent_get(parent_obj); if ((!parent_obj) || (!_elm_widget_is(parent_obj))) break; if (_elm_scrollable_is(parent_obj)) { elm_interface_scrollable_bounce_allow_get(parent_obj, &h, &v); if (h) *horiz = EINA_TRUE; if (v) *vert = EINA_TRUE; } } while (parent_obj); } EOLIAN static void _elm_widget_scroll_hold_push(Eo *obj, Elm_Widget_Smart_Data *sd) { sd->scroll_hold++; if (sd->scroll_hold == 1) { if (_elm_scrollable_is(obj)) elm_interface_scrollable_hold_set(obj, EINA_TRUE); else { Evas_Object *child; Eina_List *l; EINA_LIST_FOREACH(sd->subobjs, l, child) { if (elm_widget_is(child) && _elm_scrollable_is(child)) elm_interface_scrollable_hold_set(child, EINA_TRUE); } } } if (sd->parent_obj) elm_obj_widget_scroll_hold_push(sd->parent_obj); // FIXME: on delete/reparent hold pop } EOLIAN static void _elm_widget_scroll_hold_pop(Eo *obj, Elm_Widget_Smart_Data *sd) { sd->scroll_hold--; if (!sd->scroll_hold) { if (_elm_scrollable_is(obj)) elm_interface_scrollable_hold_set(obj, EINA_FALSE); else { Evas_Object *child; Eina_List *l; EINA_LIST_FOREACH(sd->subobjs, l, child) { if (elm_widget_is(child) && _elm_scrollable_is(child)) elm_interface_scrollable_hold_set(child, EINA_FALSE); } } } if (sd->parent_obj) elm_obj_widget_scroll_hold_pop(sd->parent_obj); if (sd->scroll_hold < 0) sd->scroll_hold = 0; } EOLIAN static int _elm_widget_scroll_hold_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->scroll_hold; } EOLIAN static void _elm_widget_scroll_freeze_push(Eo *obj, Elm_Widget_Smart_Data *sd) { sd->scroll_freeze++; if (sd->scroll_freeze == 1) { if (_elm_scrollable_is(obj)) elm_interface_scrollable_freeze_set(obj, EINA_TRUE); else { Evas_Object *child; Eina_List *l; EINA_LIST_FOREACH(sd->subobjs, l, child) { if (elm_widget_is(child) && _elm_scrollable_is(child)) elm_interface_scrollable_freeze_set(child, EINA_TRUE); } } } if (sd->parent_obj) elm_obj_widget_scroll_freeze_push(sd->parent_obj); // FIXME: on delete/reparent freeze pop } EOLIAN static void _elm_widget_scroll_freeze_pop(Eo *obj, Elm_Widget_Smart_Data *sd) { sd->scroll_freeze--; if (!sd->scroll_freeze) { if (_elm_scrollable_is(obj)) elm_interface_scrollable_freeze_set(obj, EINA_FALSE); else { Evas_Object *child; Eina_List *l; EINA_LIST_FOREACH(sd->subobjs, l, child) { if (elm_widget_is(child) && _elm_scrollable_is(child)) elm_interface_scrollable_freeze_set(child, EINA_FALSE); } } } if (sd->parent_obj) elm_obj_widget_scroll_freeze_pop(sd->parent_obj); if (sd->scroll_freeze < 0) sd->scroll_freeze = 0; } EOLIAN static int _elm_widget_scroll_freeze_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->scroll_freeze; } EOLIAN static void _elm_widget_efl_ui_base_scale_set(Eo *obj, Elm_Widget_Smart_Data *sd, double scale) { if (scale < 0.0) scale = 0.0; if (sd->scale != scale) { sd->scale = scale; elm_widget_theme(obj); } } EOLIAN static double _elm_widget_efl_ui_base_scale_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { // FIXME: save walking up the tree by storing/caching parent scale if (sd->scale == 0.0) { if (sd->parent_obj && elm_widget_is(sd->parent_obj)) { return efl_ui_scale_get(sd->parent_obj); } else { return 1.0; } } return sd->scale; } EOLIAN static void _elm_widget_theme_set(Eo *obj, Elm_Widget_Smart_Data *sd, Elm_Theme *th) { Eina_Bool apply = EINA_FALSE; if (sd->theme != th) { if (elm_widget_theme_get(obj) != th) apply = EINA_TRUE; if (sd->theme) elm_theme_free(sd->theme); sd->theme = th; if (th) th->ref++; if (apply) elm_widget_theme(obj); } } EOLIAN static void _elm_widget_part_text_set(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const char *part, const char *label) { if (evas_object_smart_type_check(obj, "elm_layout")) elm_layout_text_set(obj, part, label); } EOLIAN static const char* _elm_widget_part_text_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const char *part) { if (evas_object_smart_type_check(obj, "elm_layout")) return elm_layout_text_get(obj, part); return NULL; } static Elm_Translate_String_Data * _translate_string_data_get(Eina_Inlist *translate_strings, const char *part) { Elm_Translate_String_Data *ts; Eina_Stringshare *str; if (!translate_strings) return NULL; str = eina_stringshare_add(part); EINA_INLIST_FOREACH(translate_strings, ts) { if (ts->id == str) break; } eina_stringshare_del(str); return ts; } static Elm_Translate_String_Data * _part_text_translatable_set(Eina_Inlist **translate_strings, const char *part, Eina_Bool translatable, Eina_Bool preset) { Eina_Inlist *t; Elm_Translate_String_Data *ts; t = *translate_strings; ts = _translate_string_data_get(t, part); if (translatable) { if (!ts) { ts = ELM_NEW(Elm_Translate_String_Data); if (!ts) return NULL; ts->id = eina_stringshare_add(part); t = eina_inlist_append(t, (Eina_Inlist*) ts); } if (preset) ts->preset = EINA_TRUE; } //Delete this exist one if this part has been not preset. //see elm_widget_part_text_translatable_set() else if (ts && ((preset) || (!ts->preset))) { t = eina_inlist_remove(t, EINA_INLIST_GET(ts)); eina_stringshare_del(ts->id); eina_stringshare_del(ts->domain); eina_stringshare_del(ts->string); ELM_SAFE_FREE(ts, free); } *translate_strings = t; return ts; } EOLIAN static void _elm_widget_domain_translatable_part_text_set(Eo *obj, Elm_Widget_Smart_Data *sd, const char *part, const char *domain, const char *label) { Elm_Translate_String_Data *ts; if (!label) { _part_text_translatable_set(&sd->translate_strings, part, EINA_FALSE, EINA_FALSE); } else { ts = _part_text_translatable_set(&sd->translate_strings, part, EINA_TRUE, EINA_FALSE); if (!ts) return; if (!ts->string) ts->string = eina_stringshare_add(label); else eina_stringshare_replace(&ts->string, label); if (!ts->domain) ts->domain = eina_stringshare_add(domain); else eina_stringshare_replace(&ts->domain, domain); #ifdef HAVE_GETTEXT if (label[0]) label = dgettext(domain, label); #endif } sd->on_translate = EINA_TRUE; elm_obj_widget_part_text_set(obj, part, label); sd->on_translate = EINA_FALSE; } EOLIAN static const char* _elm_widget_translatable_part_text_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, const char *part) { Elm_Translate_String_Data *ts; ts = _translate_string_data_get(sd->translate_strings, part); if (ts) return ts->string; else return NULL; } EOLIAN static void _elm_widget_domain_part_text_translatable_set(Eo *obj, Elm_Widget_Smart_Data *sd, const char *part, const char *domain, Eina_Bool translatable) { Elm_Translate_String_Data *ts; const char *text = NULL; ts = _part_text_translatable_set(&sd->translate_strings, part, translatable, EINA_TRUE); if (!ts) return; if (!ts->domain) ts->domain = eina_stringshare_add(domain); else eina_stringshare_replace(&ts->domain, domain); text = elm_obj_widget_part_text_get(obj, part); if (!text || !text[0]) return; if (!ts->string) ts->string = eina_stringshare_add(text); //Try to translate text since we don't know the text is already translated. #ifdef HAVE_GETTEXT text = dgettext(domain, text); #endif sd->on_translate = EINA_TRUE; elm_obj_widget_part_text_set(obj, part, text); sd->on_translate = EINA_FALSE; } EAPI void elm_widget_translate(Evas_Object *obj) { ELM_WIDGET_CHECK(obj); elm_obj_widget_translate(obj); } static const char* _part_text_translate(Eina_Inlist *translate_strings, const char *part, const char *text) { Elm_Translate_String_Data *ts; ts = _translate_string_data_get(translate_strings, part); if (!ts) return text; if (!ts->string) ts->string = eina_stringshare_add(text); else eina_stringshare_replace(&ts->string, text); #ifdef HAVE_GETTEXT if (text && text[0]) text = dgettext(ts->domain, text); #endif return text; } EOLIAN static const char* _elm_widget_part_text_translate(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, const char *part, const char *text) { if (!sd->translate_strings || sd->on_translate) return text; return _part_text_translate(sd->translate_strings, part, text); } EOLIAN static Eina_Bool _elm_widget_translate(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED) { const Eina_List *l; Evas_Object *child; API_ENTRY return EINA_FALSE; EINA_LIST_FOREACH(sd->subobjs, l, child) { if (elm_widget_is(child)) elm_widget_translate(child); } if (sd->hover_obj) elm_widget_translate(sd->hover_obj); #ifdef HAVE_GETTEXT Elm_Translate_String_Data *ts; EINA_INLIST_FOREACH(sd->translate_strings, ts) { if (!ts->string) continue; const char *s = dgettext(ts->domain, ts->string); sd->on_translate = EINA_TRUE; elm_obj_widget_part_text_set(obj, ts->id, s); sd->on_translate = EINA_FALSE; } #endif efl_event_callback_legacy_call(obj, ELM_WIDGET_EVENT_LANGUAGE_CHANGED, NULL); return EINA_TRUE; } /** * @internal * * Resets the focus_move_policy mode from the system one * for widgets that are in automatic mode. * * @param obj The widget. * */ static void _elm_widget_focus_move_policy_reload(Evas_Object *obj) { API_ENTRY return; Elm_Focus_Move_Policy focus_move_policy = elm_config_focus_move_policy_get(); if (elm_widget_focus_move_policy_automatic_get(obj) && (sd->focus_move_policy != focus_move_policy)) { sd->focus_move_policy = focus_move_policy; } } EOLIAN static void _elm_widget_focus_reconfigure(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED) { const Eina_List *l; Evas_Object *child; API_ENTRY return; EINA_LIST_FOREACH(sd->subobjs, l, child) { if (elm_widget_is(child)) elm_widget_focus_reconfigure(child); } if (sd->hover_obj) elm_widget_focus_reconfigure(sd->hover_obj); _elm_widget_focus_move_policy_reload(obj); } EOLIAN static void _elm_widget_access_info_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, const char *txt) { eina_stringshare_del(sd->access_info); if (!txt) sd->access_info = NULL; else sd->access_info = eina_stringshare_add(txt); } EOLIAN static const char* _elm_widget_access_info_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->access_info; } EOLIAN static Elm_Theme* _elm_widget_theme_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { if (!sd->theme) { if (sd->parent_obj && elm_widget_is(sd->parent_obj)) return elm_widget_theme_get(sd->parent_obj); else return NULL; } return sd->theme; } EOLIAN static Efl_Ui_Theme_Apply _elm_widget_style_set(Eo *obj, Elm_Widget_Smart_Data *sd, const char *style) { + if (!sd->legacy && efl_finalized_get(obj)) + { + ERR("Efl.Ui.Widget.style can only be set before finalize!"); + return EFL_UI_THEME_APPLY_FAILED; + } + if (eina_stringshare_replace(&sd->style, style)) return elm_widget_theme(obj); return EFL_UI_THEME_APPLY_SUCCESS; } EOLIAN static const char* _elm_widget_style_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { const char *ret; ret = "default"; if (sd->style) ret = sd->style; return ret; } EOLIAN static void _elm_widget_tooltip_add(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Tooltip *tt) { sd->tooltips = eina_list_append(sd->tooltips, tt); } EOLIAN static void _elm_widget_tooltip_del(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Tooltip *tt) { sd->tooltips = eina_list_remove(sd->tooltips, tt); } EAPI void elm_widget_cursor_add(Eo *obj, Elm_Cursor *cur) { Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS); if (!sd) return; sd->cursors = eina_list_append(sd->cursors, cur); } EAPI void elm_widget_cursor_del(Eo *obj, Elm_Cursor *cur) { Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS); if (!sd) return; sd->cursors = eina_list_remove(sd->cursors, cur); } EOLIAN static void _elm_widget_drag_lock_x_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool lock) { if (sd->drag_x_locked == lock) return; sd->drag_x_locked = lock; if (sd->drag_x_locked) _propagate_x_drag_lock(obj, 1); else _propagate_x_drag_lock(obj, -1); } EOLIAN static void _elm_widget_drag_lock_y_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool lock) { if (sd->drag_y_locked == lock) return; sd->drag_y_locked = lock; if (sd->drag_y_locked) _propagate_y_drag_lock(obj, 1); else _propagate_y_drag_lock(obj, -1); } EOLIAN static Eina_Bool _elm_widget_drag_lock_x_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->drag_x_locked; } EOLIAN static Eina_Bool _elm_widget_drag_lock_y_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->drag_y_locked; } EOLIAN static int _elm_widget_drag_child_locked_x_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->child_drag_x_locked; } EOLIAN static int _elm_widget_drag_child_locked_y_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->child_drag_y_locked; } EOLIAN static void _elm_widget_item_loop_enabled_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd EINA_UNUSED, Eina_Bool enable EINA_UNUSED) { } EOLIAN static Eina_Bool _elm_widget_item_loop_enabled_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd EINA_UNUSED) { return EINA_FALSE; } EOLIAN static Efl_Ui_Theme_Apply _elm_widget_theme_object_set(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *edj, const char *wname, const char *welement, const char *wstyle) { Efl_Ui_Theme_Apply ret = _elm_theme_object_set(obj, edj, wname, welement, wstyle); if (!ret) { return EFL_UI_THEME_APPLY_FAILED; } if (sd->orient_mode != -1) { char buf[128]; snprintf(buf, sizeof(buf), "elm,state,orient,%d", sd->orient_mode); elm_widget_signal_emit(obj, buf, "elm"); } return ret; } static void _convert(Efl_Dbg_Info *info, Eina_Iterator *ptr_list) { void *p; int i = 0; EINA_ITERATOR_FOREACH(ptr_list, p) { char name[100]; snprintf(name, sizeof(name), "Candidate %d", i); EFL_DBG_INFO_APPEND(info, name, EINA_VALUE_TYPE_UINT64, p); i++; } eina_iterator_free(ptr_list); } EOLIAN static void _elm_widget_efl_object_dbg_info_get(Eo *eo_obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Efl_Dbg_Info *root) { efl_dbg_info_get(efl_super(eo_obj, MY_CLASS), root); Efl_Ui_Focus_Relations *rel = NULL; Efl_Dbg_Info *focus, *group = EFL_DBG_INFO_LIST_APPEND(root, MY_CLASS_NAME); EFL_DBG_INFO_APPEND(group, "Wid-Type", EINA_VALUE_TYPE_STRING, elm_widget_type_get(eo_obj)); EFL_DBG_INFO_APPEND(group, "Style", EINA_VALUE_TYPE_STRING, elm_widget_style_get(eo_obj)); EFL_DBG_INFO_APPEND(group, "Layer", EINA_VALUE_TYPE_INT, (int) evas_object_layer_get(eo_obj)); EFL_DBG_INFO_APPEND(group, "Scale", EINA_VALUE_TYPE_DOUBLE, evas_object_scale_get(eo_obj)); EFL_DBG_INFO_APPEND(group, "Has focus", EINA_VALUE_TYPE_CHAR, elm_object_focus_get(eo_obj)); EFL_DBG_INFO_APPEND(group, "Can focus", EINA_VALUE_TYPE_CHAR, elm_widget_can_focus_get(eo_obj)); EFL_DBG_INFO_APPEND(group, "Disabled", EINA_VALUE_TYPE_CHAR, elm_widget_disabled_get(eo_obj)); EFL_DBG_INFO_APPEND(group, "Mirrored", EINA_VALUE_TYPE_CHAR, efl_ui_mirrored_get(eo_obj)); EFL_DBG_INFO_APPEND(group, "Tree Unfocusable", EINA_VALUE_TYPE_CHAR, elm_widget_tree_unfocusable_get(eo_obj)); EFL_DBG_INFO_APPEND(group, "Automatic mirroring", EINA_VALUE_TYPE_CHAR, efl_ui_mirrored_automatic_get(eo_obj)); rel = efl_ui_focus_manager_fetch(_pd->focus.manager, eo_obj); if (rel) { focus = EFL_DBG_INFO_LIST_APPEND(group, "Focus"); EFL_DBG_INFO_APPEND(focus, "type", EINA_VALUE_TYPE_STRING, rel->type); EFL_DBG_INFO_APPEND(focus, "manager", EINA_VALUE_TYPE_UINT64, _pd->focus.manager); EFL_DBG_INFO_APPEND(focus, "parent", EINA_VALUE_TYPE_UINT64, rel->parent); EFL_DBG_INFO_APPEND(focus, "next", EINA_VALUE_TYPE_UINT64 , rel->next); EFL_DBG_INFO_APPEND(focus, "prev", EINA_VALUE_TYPE_UINT64 , rel->prev); EFL_DBG_INFO_APPEND(focus, "redirect", EINA_VALUE_TYPE_UINT64 , rel->redirect); #define ADD_PTR_LIST(name) \ Efl_Dbg_Info* name = EFL_DBG_INFO_LIST_APPEND(focus, ""#name""); \ _convert(name, eina_list_iterator_new(rel->name)); ADD_PTR_LIST(top) ADD_PTR_LIST(down) ADD_PTR_LIST(right) ADD_PTR_LIST(left) #undef ADD_PTR_LIST } //if thats a focus manager, give useful information like the border elements if (efl_isa(eo_obj, EFL_UI_FOCUS_MANAGER_CLASS)) { Efl_Dbg_Info *border; focus = EFL_DBG_INFO_LIST_APPEND(group, "Focus Manager"); border = EFL_DBG_INFO_LIST_APPEND(focus, "Border Elements"); _convert(border, efl_ui_focus_manager_border_elements_get(eo_obj) ); EFL_DBG_INFO_APPEND(focus, "redirect", EINA_VALUE_TYPE_UINT64, efl_ui_focus_manager_redirect_get(eo_obj)); } } EAPI Eina_Bool elm_widget_is_check(const Evas_Object *obj) { static int abort_on_warn = -1; if (elm_widget_is(obj)) return EINA_TRUE; ERR("Passing Object: %p.", obj); if (abort_on_warn == -1) { if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1; else abort_on_warn = 0; } if (abort_on_warn == 1) abort(); return EINA_FALSE; } EAPI const char * elm_widget_type_get(const Evas_Object *obj) { API_ENTRY return NULL; return efl_class_name_get(efl_class_get(obj)); } EAPI Eina_Bool elm_widget_type_check(const Evas_Object *obj, const char *type, const char *func) { const char *provided, *expected = "(unknown)"; static int abort_on_warn = -1; provided = elm_widget_type_get(obj); /* TODO: eventually migrate to check_ptr version */ if (evas_object_smart_type_check(obj, type)) return EINA_TRUE; if (type) expected = type; if ((!provided) || (!provided[0])) { provided = evas_object_type_get(obj); if ((!provided) || (!provided[0])) provided = "(unknown)"; } ERR("Passing Object: %p in function: %s, of type: '%s' when expecting" " type: '%s'", obj, func, provided, expected); if (abort_on_warn == -1) { if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1; else abort_on_warn = 0; } if (abort_on_warn == 1) abort(); return EINA_FALSE; } static Evas_Object * _widget_name_find(const Evas_Object *obj, const char *name, int recurse) { Eina_List *l; Evas_Object *child; const char *s; INTERNAL_ENTRY NULL; if (!_elm_widget_is(obj)) return NULL; EINA_LIST_FOREACH(sd->subobjs, l, child) { s = evas_object_name_get(child); if ((s) && (!strcmp(s, name))) return child; if ((recurse != 0) && ((child = _widget_name_find(child, name, recurse - 1)))) return child; } if (sd->hover_obj) { s = evas_object_name_get(sd->hover_obj); if ((s) && (!strcmp(s, name))) return sd->hover_obj; if ((recurse != 0) && ((child = _widget_name_find(sd->hover_obj, name, recurse - 1)))) return child; } return NULL; } EOLIAN static Evas_Object* _elm_widget_name_find(const Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const char *name, int recurse) { if (!name) return NULL; return _widget_name_find(obj, name, recurse); } /** * @internal * * Split string in words * * @param str Source string * @return List of const words * * @see elm_widget_stringlist_free() * @ingroup Widget */ EAPI Eina_List * elm_widget_stringlist_get(const char *str) { Eina_List *list = NULL; const char *s, *b; if (!str) return NULL; for (b = s = str; 1; s++) { if ((*s == ' ') || (!*s)) { char *t = malloc(s - b + 1); if (t) { strncpy(t, b, s - b); t[s - b] = 0; list = eina_list_append(list, eina_stringshare_add(t)); free(t); } b = s + 1; } if (!*s) break; } return list; } EAPI void elm_widget_stringlist_free(Eina_List *list) { const char *s; EINA_LIST_FREE(list, s) eina_stringshare_del(s); } EOLIAN static void _elm_widget_focus_hide_handle(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED) { if (!_elm_widget_is(obj)) return; _if_focused_revert(obj, EINA_TRUE); } EAPI void elm_widget_focus_mouse_up_handle(Evas_Object *obj) { Evas_Object *o = obj; do { if (_elm_widget_is(o)) break; o = evas_object_smart_parent_get(o); } while (o); elm_obj_widget_focus_mouse_up_handle(o); } EOLIAN static void _elm_widget_focus_mouse_up_handle(Eo *obj, Elm_Widget_Smart_Data *pd) { if (!obj) return; if (!_is_focusable(obj)) return; elm_widget_focus_steal(obj, NULL); if (pd->focus.manager && !pd->focus.logical) { Efl_Ui_Focus_Manager *m, *m2 = obj, *old = NULL; /* * The object we have clicked could be registered in a submanager. * This means we need to look as long as possible to higher redirect managers. * And set them to the redirect manager. */ m = elm_widget_top_get(obj); m2 = efl_ui_focus_user_manager_get(obj); if (m2 != m) { //first unset all redirect properties old = m; do { Efl_Ui_Focus_Manager *tmp; tmp = efl_ui_focus_manager_redirect_get(old); if (tmp) efl_ui_focus_manager_redirect_set(old, NULL); old = tmp; } while(old); //now set the redirect path to the new object do { Efl_Ui_Focus_Manager *new_manager;; new_manager = efl_ui_focus_user_manager_get(m2); //new manager is in a higher hirarchy than m2 //so we set m2 as redirect in new_manager efl_ui_focus_manager_redirect_set(new_manager, m2); m2 = new_manager; } while(m && m2 && m != m2); } efl_ui_focus_manager_focus(pd->focus.manager, obj); } } EOLIAN static void _elm_widget_focus_tree_unfocusable_handle(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED) { if (!elm_widget_parent_get(obj)) elm_widget_focused_object_clear(obj); else _if_focused_revert(obj, EINA_TRUE); } EOLIAN static void _elm_widget_focus_disabled_handle(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED) { elm_widget_focus_tree_unfocusable_handle(obj); } EOLIAN static unsigned int _elm_widget_focus_order_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->focus_order; } EOLIAN static Evas_Object* _elm_widget_newest_focus_order_get(const Eo *obj, Elm_Widget_Smart_Data *sd, unsigned int *newest_focus_order, Eina_Bool can_focus_only) { const Eina_List *l; Evas_Object *child, *cur, *best; if (!evas_object_visible_get(obj) || (elm_widget_disabled_get(obj)) || (elm_widget_tree_unfocusable_get(obj))) return NULL; best = NULL; if (*newest_focus_order < sd->focus_order) { if (!can_focus_only || elm_widget_can_focus_get(obj)) { *newest_focus_order = sd->focus_order; best = (Evas_Object *)obj; } } EINA_LIST_FOREACH(sd->subobjs, l, child) { if (!_elm_widget_is(child)) continue; cur = elm_widget_newest_focus_order_get (child, newest_focus_order, can_focus_only); if (!cur) continue; best = cur; } return best; } /* * @internal * * Get the focus highlight geometry of a widget. * * @param obj Widget object for the focus highlight * @param x Focus highlight x coordinate * @param y Focus highlight y coordinate * @param w Focus highlight object width * @param h Focus highlight object height * @param is_next @c EINA_TRUE if this request is for the new focused object, * @c EINA_FALSE if this request is for the previously focused object. This * information becomes important when the focus highlight is changed inside one * widget. * * @ingroup Widget */ /* * @internal * * Get the 'focus_part' geometry if there is any * * This queries if there is a 'focus_part' request from the edc style. If edc * style offers 'focus_part' edje data item, this function requests for the * geometry of a specific part which is described in 'focus_part' edje data. * * @param obj Widget object for the focus highlight * @param x Focus highlight x coordinate * @param y Focus highlight y coordinate * @param w Focus highlight object width * @param h Focus highlight object height * * x, y, w, h already contain the object's geometry. If there is a 'focus_part' * support, these values will be updated accordingly or the values will be * remained as they were. * * @ingroup Widget */ EAPI void elm_widget_focus_highlight_focus_part_geometry_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h) { Evas_Coord tx = 0, ty = 0, tw = 0, th = 0; const char *target_hl_part = NULL; const Evas_Object *edje_obj = NULL; if (obj && efl_isa(obj, EDJE_OBJECT_CLASS)) { edje_obj = obj; if (!(target_hl_part = edje_object_data_get(edje_obj, "focus_part"))) return; } else if (obj && efl_isa(obj, EFL_UI_LAYOUT_CLASS)) { edje_obj = elm_layout_edje_get(obj); if (!(target_hl_part = elm_layout_data_get(obj, "focus_part"))) return; } else return; edje_object_part_geometry_get(edje_obj, target_hl_part, &tx, &ty, &tw, &th); *x += tx; *y += ty; if (tw != *w) *w = tw; if (th != *h) *h = th; } EOLIAN static void _elm_widget_focus_highlight_geometry_get(const Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h) { Evas_Coord ox = 0, oy = 0, ow = 0, oh = 0; Evas_Object *scroller = (Evas_Object *)obj; evas_object_geometry_get(obj, x, y, w, h); elm_widget_focus_highlight_focus_part_geometry_get(sd->resize_obj, x, y, w, h); if (_elm_config->focus_autoscroll_mode != ELM_FOCUS_AUTOSCROLL_MODE_BRING_IN) return; while (scroller) { if (_elm_scrollable_is(scroller)) { elm_interface_scrollable_content_viewport_geometry_get(scroller, &ox, &oy, &ow, &oh); if (*y < oy) *y = oy; else if ((oy + oh) < (*y + *h)) *y = (oy + oh - *h); else if (*x < ox) *x = ox; else if ((ox + ow) < (*x + *w)) *x = (ox + ow - *w); break; } scroller = elm_widget_parent_get(scroller); } } EOLIAN static Elm_Object_Item* _elm_widget_focused_item_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED) { return NULL; } EOLIAN static void _elm_widget_focus_region_show_mode_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd, Elm_Focus_Region_Show_Mode mode) { _pd->focus_region_show_mode = mode; } EOLIAN static Elm_Focus_Region_Show_Mode _elm_widget_focus_region_show_mode_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd) { return _pd->focus_region_show_mode; } EAPI void elm_widget_activate(Evas_Object *obj, Elm_Activate act) { Evas_Object *parent; Eina_Bool ret; ELM_WIDGET_CHECK(obj); ret = EINA_FALSE; ret = elm_obj_widget_activate(obj, act); if (ret) return; parent = elm_widget_parent_get(obj); if (parent) elm_widget_activate(parent, act); return; } /** * @internal * * Sets the widget and child widget's Evas_Display_Mode. * * @param obj The widget. * @param dispmode Evas_Display_Mode to set widget's mode. * * Widgets are resized by several reasons. * Evas_Display_Mode can help for widgets to get one more reason of resize. * For example, elm conform widget resizes it's contents when keypad state changed. * After keypad showing, conform widget can change child's Evas_Display_Mode. * @ingroup Widget */ /* Legacy only */ EAPI void elm_widget_display_mode_set(Evas_Object *obj, Evas_Display_Mode dispmode) { Evas_Display_Mode prev_dispmode; Evas_Object *child; Eina_List *l; API_ENTRY return; prev_dispmode = evas_object_size_hint_display_mode_get(obj); if ((prev_dispmode == dispmode) || (prev_dispmode == EVAS_DISPLAY_MODE_DONT_CHANGE)) return; evas_object_size_hint_display_mode_set(obj, dispmode); EINA_LIST_FOREACH (sd->subobjs, l, child) { if (elm_widget_is(child)) elm_widget_display_mode_set(child, dispmode); } } EOLIAN static void _elm_widget_orientation_mode_disabled_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool disabled) { int orient_mode = -1; if (!disabled) { //Get current orient mode from it's parent otherwise, 0. sd->orient_mode = 0; ELM_WIDGET_DATA_GET(sd->parent_obj, sd_parent); if (!sd_parent) orient_mode = 0; else orient_mode = sd_parent->orient_mode; } elm_obj_widget_orientation_set(obj, orient_mode); } EOLIAN static Eina_Bool _elm_widget_orientation_mode_disabled_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { if (sd->orient_mode == -1) return EINA_TRUE; else return EINA_FALSE; } EOLIAN static void _elm_widget_orientation_set(Eo *obj, Elm_Widget_Smart_Data *sd, int orient_mode) { Evas_Object *child; Eina_List *l; sd->orient_mode = orient_mode; EINA_LIST_FOREACH (sd->subobjs, l, child) { if (elm_widget_is(child)) elm_obj_widget_orientation_set(child, orient_mode); } if (orient_mode != -1) { char buf[128]; snprintf(buf, sizeof(buf), "elm,state,orient,%d", orient_mode); elm_widget_signal_emit(obj, buf, "elm"); } } /** * @internal * * Returns the widget's focus move policy. * * @param obj The widget. * @return focus move policy of the object. * **/ EOLIAN static Elm_Focus_Move_Policy _elm_widget_focus_move_policy_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->focus_move_policy; } /** * @internal * * Sets the widget's focus move policy. * * @param obj The widget. * @param policy Elm_Focus_Move_Policy to set object's focus move policy. */ EOLIAN static void _elm_widget_focus_move_policy_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Focus_Move_Policy policy) { if (sd->focus_move_policy == policy) return; sd->focus_move_policy = policy; } /** * Returns the widget's focus_move_policy mode setting. * * @param obj The widget. * @return focus_move_policy mode setting of the object. * **/ EOLIAN static Eina_Bool _elm_widget_focus_move_policy_automatic_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd) { return sd->focus_move_policy_auto_mode; } /** * @internal * * Sets the widget's focus_move_policy mode setting. * When widget in automatic mode, it follows the system focus_move_policy mode set by * elm_config_focus_move_policy_set(). * @param obj The widget. * @param automatic EINA_TRUE for auto focus_move_policy mode. EINA_FALSE for manual. */ EOLIAN static void _elm_widget_focus_move_policy_automatic_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool automatic) { if (sd->focus_move_policy_auto_mode != automatic) { sd->focus_move_policy_auto_mode = automatic; if (automatic) { elm_widget_focus_move_policy_set(obj, elm_config_focus_move_policy_get()); } } } static void _track_obj_del(void *data, Evas *e, Evas_Object *obj, void *event_info); static void _track_obj_update(Evas_Object *track, Evas_Object *obj) { //Geometry Evas_Coord x, y, w, h; evas_object_geometry_get(obj, &x, &y, &w, &h); evas_object_move(track, x, y); evas_object_resize(track, w, h); //Visibility if (evas_object_visible_get(obj)) evas_object_show(track); else evas_object_hide(track); } static void _track_obj_view_update(void *data, const Efl_Event *event) { Elm_Widget_Item_Data *item = data; _track_obj_update(item->track_obj, event->object); } static void _track_obj_view_del(void *data, const Efl_Event *event); EFL_CALLBACKS_ARRAY_DEFINE(tracker_callbacks, { EFL_GFX_EVENT_RESIZE, _track_obj_view_update }, { EFL_GFX_EVENT_MOVE, _track_obj_view_update }, { EFL_GFX_EVENT_SHOW, _track_obj_view_update }, { EFL_GFX_EVENT_HIDE, _track_obj_view_update }, { EFL_EVENT_DEL, _track_obj_view_del }); static void _track_obj_view_del(void *data, const Efl_Event *event EINA_UNUSED) { Elm_Widget_Item_Data *item = data; while (evas_object_ref_get(item->track_obj) > 0) evas_object_unref(item->track_obj); evas_object_event_callback_del(item->track_obj, EVAS_CALLBACK_DEL, _track_obj_del); evas_object_del(item->track_obj); item->track_obj = NULL; } static void _track_obj_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { Elm_Widget_Item_Data *item = data; item->track_obj = NULL; if (!item->view) return; efl_event_callback_array_del(item->view, tracker_callbacks(), item); } static void _elm_widget_item_signal_cb(void *data, Evas_Object *obj EINA_UNUSED, const char *emission, const char *source) { Elm_Widget_Item_Signal_Data *wisd = data; wisd->func(wisd->data, wisd->item, emission, source); } static void * _elm_widget_item_signal_callback_list_get(Elm_Widget_Item_Data *item, Eina_List *position) { Elm_Widget_Item_Signal_Data *wisd = eina_list_data_get(position); void *data; item->signals = eina_list_remove_list(item->signals, position); data = wisd->data; if (_elm_widget_is(item->view)) elm_object_signal_callback_del(item->view, wisd->emission, wisd->source, _elm_widget_item_signal_cb); else if (efl_isa(item->view, EDJE_OBJECT_CLASS)) edje_object_signal_callback_del_full(item->view, wisd->emission, wisd->source, _elm_widget_item_signal_cb, wisd); eina_stringshare_del(wisd->emission); eina_stringshare_del(wisd->source); free(wisd); return data; } #define ERR_NOT_SUPPORTED(item, method) ERR("%s does not support %s API.", elm_widget_type_get(item->widget), method); static void _efl_del_cb(void *data EINA_UNUSED, const Efl_Event *event) { Elm_Widget_Item_Data *item = efl_data_scope_get(event->object, ELM_WIDGET_ITEM_CLASS); ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); if (item->del_func) item->del_func((void *) WIDGET_ITEM_DATA_GET(event->object), item->widget, item->eo_obj); } /** * @internal * * Allocate a new Elm_Widget_Item-derived structure. * * The goal of this structure is to provide common ground for actions * that a widget item have, such as the owner widget, callback to * notify deletion, data pointer and maybe more. * * @param widget the owner widget that holds this item, must be an elm_widget! * @param alloc_size any number greater than sizeof(Elm_Widget_Item) that will * be used to allocate memory. * * @return allocated memory that is already zeroed out, or NULL on errors. * * @see elm_widget_item_new() convenience macro. * @see elm_widget_item_del() to release memory. * @ingroup Widget */ EOLIAN static Eo * _elm_widget_item_efl_object_constructor(Eo *eo_item, Elm_Widget_Item_Data *item) { Evas_Object *widget; widget = efl_parent_get(eo_item); if (!_elm_widget_is(widget)) { ERR("Failed"); return NULL; } eo_item = efl_constructor(efl_super(eo_item, ELM_WIDGET_ITEM_CLASS)); EINA_MAGIC_SET(item, ELM_WIDGET_ITEM_MAGIC); item->widget = widget; item->eo_obj = eo_item; efl_event_callback_add(eo_item, EFL_EVENT_DEL, _efl_del_cb, NULL); return eo_item; } EOLIAN static void _elm_widget_item_efl_object_destructor(Eo *eo_item, Elm_Widget_Item_Data *item) { Elm_Translate_String_Data *ts; ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); evas_object_del(item->view); eina_stringshare_del(item->access_info); eina_stringshare_del(item->accessible_name); while (item->signals) _elm_widget_item_signal_callback_list_get(item, item->signals); while (item->translate_strings) { ts = EINA_INLIST_CONTAINER_GET(item->translate_strings, Elm_Translate_String_Data); eina_stringshare_del(ts->id); eina_stringshare_del(ts->domain); eina_stringshare_del(ts->string); item->translate_strings = eina_inlist_remove(item->translate_strings, item->translate_strings); free(ts); } eina_hash_free(item->labels); elm_interface_atspi_accessible_removed(eo_item); EINA_MAGIC_SET(item, EINA_MAGIC_NONE); efl_destructor(efl_super(eo_item, ELM_WIDGET_ITEM_CLASS)); } /** * @internal * * Releases widget item memory, calling back item_del_pre_hook() and * item_del_cb() if they exist. * * @param item a valid #Elm_Widget_Item to be deleted. * * If there is an Elm_Widget_Item::del_cb, then it will be called prior * to memory release. Note that elm_widget_item_pre_notify_del() calls * this function and then unset it, thus being useful for 2 step * cleanup whenever the del_cb may use any of the data that must be * deleted from item. * * The Elm_Widget_Item::view will be deleted (evas_object_del()) if it * is presented! * * Note that if item_del_pre_hook() returns @c EINA_TRUE, item free will be * deferred, or item will be freed here if it returns @c EINA_FALSE. * * @see elm_widget_item_del() convenience macro. * @ingroup Widget */ EOLIAN static void _elm_widget_item_del(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); item->on_deletion = EINA_TRUE; //Widget item delete callback Eina_Bool del_ok; del_ok = elm_wdg_item_del_pre(item->eo_obj); if (del_ok) efl_del(item->eo_obj); return; } EOLIAN static Eina_Bool _elm_widget_item_del_pre(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item EINA_UNUSED) { return EINA_TRUE; } /** * @internal * * Notify object will be deleted without actually deleting it. * * This function will callback Elm_Widget_Item::del_cb if it is set * and then unset it so it is not called twice (ie: from * elm_widget_item_del()). * * @param item a valid #Elm_Widget_Item to be notified * @see elm_widget_item_pre_notify_del() convenience macro. * @ingroup Widget */ EOLIAN static void _elm_widget_item_pre_notify_del(Eo *eo_item, Elm_Widget_Item_Data *item) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); if (!item->del_func) return; item->del_func((void *)WIDGET_ITEM_DATA_GET(eo_item), item->widget, item->eo_obj); item->del_func = NULL; } /** * @internal * * Set the function to notify when item is being deleted. * * This function will complain if there was a callback set already, * however it will set the new one. * * The callback will be called from elm_widget_item_pre_notify_del() * or elm_widget_item_del() will be called with: * - data: the Elm_Widget_Item::data value. * - obj: the Elm_Widget_Item::widget evas object. * - event_info: the item being deleted. * * @param item a valid #Elm_Widget_Item to be notified * @see elm_widget_item_del_cb_set() convenience macro. * @ingroup Widget */ EOLIAN static void _elm_widget_item_del_cb_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Evas_Smart_Cb func) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); if ((item->del_func) && (item->del_func != func)) WRN("You're replacing a previously set del_cb %p of item %p with %p", item->del_func, item->eo_obj, func); item->del_func = func; } /** * @internal * * Get owner widget of this item. * * @param item a valid #Elm_Widget_Item to get data from. * @return owner widget of this item. * @ingroup Widget */ EOLIAN static Evas_Object * _elm_widget_item_widget_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL); return item->widget; } EAPI Eina_Bool _elm_widget_onscreen_is(Evas_Object *widget) { Evas_Object *parent = widget; Eina_Rectangle r1, r2; Evas *evas = evas_object_evas_get(widget); if (!evas) return EINA_FALSE; evas_object_geometry_get(widget, &r1.x, &r1.y, &r1.w, &r1.h); if (eina_rectangle_is_empty(&r1)) return EINA_FALSE; // check if on canvas evas_output_viewport_get(evas, &r2.x, &r2.y, &r2.w, &r2.h); if (!eina_rectangles_intersect(&r1, &r2)) return EINA_FALSE; // check if inside scrollable parent viewport do { parent = elm_widget_parent_get(parent); if (parent && !evas_object_visible_get(parent)) return EINA_FALSE; if (parent && efl_isa(parent, ELM_INTERFACE_SCROLLABLE_MIXIN)) { evas_object_geometry_get(parent, &r2.x, &r2.y, &r2.w, &r2.h); if (!eina_rectangles_intersect(&r1, &r2)) return EINA_FALSE; } } while (parent && (parent != elm_widget_top_get(widget))); return EINA_TRUE; } EAPI Eina_Bool _elm_widget_item_onscreen_is(Elm_Object_Item *item) { Eina_Rectangle r1, r2; Elm_Widget_Item_Data *id = efl_data_scope_get(item, ELM_WIDGET_ITEM_CLASS); if (!id || !id->view) return EINA_FALSE; if (!evas_object_visible_get(id->view)) return EINA_FALSE; if (!_elm_widget_onscreen_is(id->widget)) return EINA_FALSE; evas_object_geometry_get(id->view, &r1.x, &r1.y, &r1.w, &r1.h); if (eina_rectangle_is_empty(&r1)) return EINA_FALSE; evas_object_geometry_get(id->widget, &r2.x, &r2.y, &r2.w, &r2.h); if (!eina_rectangles_intersect(&r1, &r2)) return EINA_FALSE; return EINA_TRUE; } EOLIAN static Elm_Atspi_State_Set _elm_widget_item_elm_interface_atspi_accessible_state_set_get(Eo *eo_item, Elm_Widget_Item_Data *item EINA_UNUSED) { Elm_Atspi_State_Set states = 0; STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSABLE); if (elm_object_item_focus_get(eo_item)) STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSED); if (!elm_object_item_disabled_get(eo_item)) { STATE_TYPE_SET(states, ELM_ATSPI_STATE_ENABLED); STATE_TYPE_SET(states, ELM_ATSPI_STATE_SENSITIVE); STATE_TYPE_SET(states, ELM_ATSPI_STATE_VISIBLE); } if (_elm_widget_item_onscreen_is(eo_item)) STATE_TYPE_SET(states, ELM_ATSPI_STATE_SHOWING); return states; } EAPI void elm_object_item_data_set(Elm_Object_Item *it, void *data) { WIDGET_ITEM_DATA_SET(it, data); } EAPI void * elm_object_item_data_get(const Elm_Object_Item *it) { return (void *) WIDGET_ITEM_DATA_GET(it); } EOLIAN static void _elm_widget_item_disabled_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Eina_Bool disabled) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); if (item->disabled == disabled) return; item->disabled = !!disabled; elm_wdg_item_disable(item->eo_obj); } EOLIAN static Eina_Bool _elm_widget_item_disabled_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE); return item->disabled; } EOLIAN static void _elm_widget_item_style_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *style EINA_UNUSED) { ERR_NOT_SUPPORTED(item, "elm_object_style_set()"); } EOLIAN static const char * _elm_widget_item_style_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ERR_NOT_SUPPORTED(item, "elm_object_style_get()"); return NULL; } EOLIAN static void _elm_widget_item_disable(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item EINA_UNUSED) { } EOLIAN static void _elm_widget_item_focus_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Eina_Bool focused EINA_UNUSED) { ERR_NOT_SUPPORTED(item, "elm_object_item_focus_set"); } EOLIAN static Eina_Bool _elm_widget_item_focus_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ERR_NOT_SUPPORTED(item, "elm_object_item_focus_get"); return EINA_FALSE; } EOLIAN static void _elm_widget_item_domain_translatable_part_text_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *part, const char *domain, const char *label) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); Elm_Translate_String_Data *ts; if (!label) { _part_text_translatable_set(&item->translate_strings, part, EINA_FALSE, EINA_FALSE); } else { ts = _part_text_translatable_set(&item->translate_strings, part, EINA_TRUE, EINA_FALSE); if (!ts) return; if (!ts->string) ts->string = eina_stringshare_add(label); else eina_stringshare_replace(&ts->string, label); if (!ts->domain) ts->domain = eina_stringshare_add(domain); else eina_stringshare_replace(&ts->domain, domain); #ifdef HAVE_GETTEXT if (label[0]) label = dgettext(domain, label); #endif } item->on_translate = EINA_TRUE; elm_wdg_item_part_text_set(item->eo_obj, part, label); item->on_translate = EINA_FALSE; } EOLIAN static const char * _elm_widget_item_translatable_part_text_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *part) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL); Elm_Translate_String_Data *ts; ts = _translate_string_data_get(item->translate_strings, part); if (ts) return ts->string; return NULL; } EOLIAN static void _elm_widget_item_domain_part_text_translatable_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *part, const char *domain, Eina_Bool translatable) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); Elm_Translate_String_Data *ts; const char *text; ts = _part_text_translatable_set(&item->translate_strings, part, translatable, EINA_TRUE); if (!ts) return; if (!ts->domain) ts->domain = eina_stringshare_add(domain); else eina_stringshare_replace(&ts->domain, domain); text = elm_wdg_item_part_text_get(item->eo_obj, part); if (!text || !text[0]) return; if (!ts->string) ts->string = eina_stringshare_add(text); //Try to translate text since we don't know the text is already translated. #ifdef HAVE_GETTEXT text = dgettext(domain, text); #endif item->on_translate = EINA_TRUE; elm_wdg_item_part_text_set(item->eo_obj, part, text); item->on_translate = EINA_FALSE; } EOLIAN static void _elm_widget_item_track_cancel(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); if (!item->track_obj) return; while (evas_object_ref_get(item->track_obj) > 0) evas_object_unref(item->track_obj); evas_object_del(item->track_obj); } EOLIAN static Evas_Object * _elm_widget_item_track(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL); if (item->track_obj) { evas_object_ref(item->track_obj); return item->track_obj; } if (!item->view) { WRN("view obj of the item(%p) is invalid. Please make sure the view obj is created!", item); return NULL; } Evas_Object *track = evas_object_rectangle_add(evas_object_evas_get(item->widget)); evas_object_color_set(track, 0, 0, 0, 0); evas_object_pass_events_set(track, EINA_TRUE); _track_obj_update(track, item->view); evas_object_event_callback_add(track, EVAS_CALLBACK_DEL, _track_obj_del, item); efl_event_callback_array_add(item->view, tracker_callbacks(), item); evas_object_ref(track); item->track_obj = track; return track; } EOLIAN static void _elm_widget_item_untrack(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); if (!item->track_obj) return; evas_object_unref(item->track_obj); if (evas_object_ref_get(item->track_obj) == 0) evas_object_del(item->track_obj); } EOLIAN static int _elm_widget_item_track_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, 0); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, 0); if (!item->track_obj) return 0; return evas_object_ref_get(item->track_obj); } typedef struct _Elm_Widget_Item_Tooltip Elm_Widget_Item_Tooltip; struct _Elm_Widget_Item_Tooltip { Elm_Widget_Item_Data *item; Elm_Tooltip_Item_Content_Cb func; Evas_Smart_Cb del_cb; const void *data; }; static Evas_Object * _elm_widget_item_tooltip_label_create(void *data, Evas_Object *obj EINA_UNUSED, Evas_Object *tooltip, void *item EINA_UNUSED) { Evas_Object *label = elm_label_add(tooltip); if (!label) return NULL; elm_object_style_set(label, "tooltip"); elm_object_text_set(label, data); return label; } static Evas_Object * _elm_widget_item_tooltip_trans_label_create(void *data, Evas_Object *obj EINA_UNUSED, Evas_Object *tooltip, void *item EINA_UNUSED) { Evas_Object *label = elm_label_add(tooltip); if (!label) return NULL; elm_object_style_set(label, "tooltip"); elm_object_translatable_text_set(label, data); return label; } static void _elm_widget_item_tooltip_label_del_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { eina_stringshare_del(data); } /** * @internal * * Set the text to be shown in the widget item. * * @param item Target item * @param text The text to set in the content * * Setup the text as tooltip to object. The item can have only one tooltip, * so any previous tooltip data is removed. * * @ingroup Widget */ EOLIAN static void _elm_widget_item_tooltip_text_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item EINA_UNUSED, const char *text) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); EINA_SAFETY_ON_NULL_RETURN(text); text = eina_stringshare_add(text); elm_wdg_item_tooltip_content_cb_set(item->eo_obj, _elm_widget_item_tooltip_label_create, text, _elm_widget_item_tooltip_label_del_cb); } EOLIAN static void _elm_widget_item_tooltip_translatable_text_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item EINA_UNUSED, const char *text) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); EINA_SAFETY_ON_NULL_RETURN(text); text = eina_stringshare_add(text); elm_wdg_item_tooltip_content_cb_set(item->eo_obj, _elm_widget_item_tooltip_trans_label_create, text, _elm_widget_item_tooltip_label_del_cb); } static Evas_Object * _elm_widget_item_tooltip_create(void *data, Evas_Object *obj, Evas_Object *tooltip) { Elm_Widget_Item_Tooltip *wit = data; return wit->func((void *)wit->data, obj, tooltip, wit->item->eo_obj); } static void _elm_widget_item_tooltip_del_cb(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) { Elm_Widget_Item_Tooltip *wit = data; if (wit->del_cb) wit->del_cb((void *)wit->data, obj, wit->item->eo_obj); free(wit); } /** * @internal * * Set the content to be shown in the tooltip item * * Setup the tooltip to item. The item can have only one tooltip, * so any previous tooltip data is removed. @p func(with @p data) will * be called every time that need show the tooltip and it should * return a valid Evas_Object. This object is then managed fully by * tooltip system and is deleted when the tooltip is gone. * * @param item the widget item being attached a tooltip. * @param func the function used to create the tooltip contents. * @param data what to provide to @a func as callback data/context. * @param del_cb called when data is not needed anymore, either when * another callback replaces @func, the tooltip is unset with * elm_widget_item_tooltip_unset() or the owner @a item * dies. This callback receives as the first parameter the * given @a data, and @c event_info is the item. * * @ingroup Widget */ EOLIAN static void _elm_widget_item_tooltip_content_cb_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Elm_Tooltip_Item_Content_Cb func, const void *data, Evas_Smart_Cb del_cb) { Elm_Widget_Item_Tooltip *wit; ELM_WIDGET_ITEM_CHECK_OR_GOTO(item, error_noitem); //ELM_WIDGET_ITEM_RETURN_IF_GOTO(item, error_noitem); if (!func) { elm_wdg_item_tooltip_unset(item->eo_obj); return; } wit = ELM_NEW(Elm_Widget_Item_Tooltip); if (!wit) goto error; wit->item = item; wit->func = func; wit->data = data; wit->del_cb = del_cb; elm_object_sub_tooltip_content_cb_set (item->view, item->widget, _elm_widget_item_tooltip_create, wit, _elm_widget_item_tooltip_del_cb); return; error_noitem: if (del_cb) del_cb((void *)data, NULL, item); return; error: if (del_cb) del_cb((void *)data, item->widget, item); } /** * @internal * * Unset tooltip from item * * @param item widget item to remove previously set tooltip. * * Remove tooltip from item. The callback provided as del_cb to * elm_widget_item_tooltip_content_cb_set() will be called to notify * it is not used anymore. * * @see elm_widget_item_tooltip_content_cb_set() * * @ingroup Widget */ EOLIAN static void _elm_widget_item_tooltip_unset(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); elm_object_tooltip_unset(item->view); } /** * @internal * * Sets a different style for this item tooltip. * * @note before you set a style you should define a tooltip with * elm_widget_item_tooltip_content_cb_set() or * elm_widget_item_tooltip_text_set() * * @param item widget item with tooltip already set. * @param style the theme style to use (default, transparent, ...) * * @ingroup Widget */ EOLIAN static void _elm_widget_item_tooltip_style_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *style) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); elm_object_tooltip_style_set(item->view, style); } EOLIAN static Eina_Bool _elm_widget_item_tooltip_window_mode_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Eina_Bool disable) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, EINA_FALSE); return elm_object_tooltip_window_mode_set(item->view, disable); } EOLIAN static Eina_Bool _elm_widget_item_tooltip_window_mode_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, EINA_FALSE); return elm_object_tooltip_window_mode_get(item->view); } /** * @internal * * Get the style for this item tooltip. * * @param item widget item with tooltip already set. * @return style the theme style in use, defaults to "default". If the * object does not have a tooltip set, then NULL is returned. * * @ingroup Widget */ EOLIAN static const char * _elm_widget_item_tooltip_style_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL); return elm_object_tooltip_style_get(item->view); } EOLIAN static void _elm_widget_item_cursor_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *cursor) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); elm_object_sub_cursor_set(item->view, item->widget, cursor); } EOLIAN static const char * _elm_widget_item_cursor_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL); return elm_object_cursor_get(item->view); } EOLIAN static void _elm_widget_item_cursor_unset(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); elm_object_cursor_unset(item->view); } /** * @internal * * Sets a different style for this item cursor. * * @note before you set a style you should define a cursor with * elm_widget_item_cursor_set() * * @param item widget item with cursor already set. * @param style the theme style to use (default, transparent, ...) * * @ingroup Widget */ EOLIAN static void _elm_widget_item_cursor_style_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *style) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); elm_object_cursor_style_set(item->view, style); } /** * @internal * * Get the style for this item cursor. * * @param item widget item with cursor already set. * @return style the theme style in use, defaults to "default". If the * object does not have a cursor set, then NULL is returned. * * @ingroup Widget */ EOLIAN static const char * _elm_widget_item_cursor_style_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL); return elm_object_cursor_style_get(item->view); } /** * @internal * * Set if the cursor set should be searched on the theme or should use * the provided by the engine, only. * * @note before you set if should look on theme you should define a cursor * with elm_object_cursor_set(). By default it will only look for cursors * provided by the engine. * * @param item widget item with cursor already set. * @param engine_only boolean to define it cursors should be looked only * between the provided by the engine or searched on widget's theme as well. * * @ingroup Widget */ EOLIAN static void _elm_widget_item_cursor_engine_only_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Eina_Bool engine_only) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); elm_object_cursor_theme_search_enabled_set(item->view, !engine_only); } /** * @internal * * Get the cursor engine only usage for this item cursor. * * @param item widget item with cursor already set. * @return engine_only boolean to define it cursors should be looked only * between the provided by the engine or searched on widget's theme as well. If * the object does not have a cursor set, then EINA_FALSE is returned. * * @ingroup Widget */ EOLIAN static Eina_Bool _elm_widget_item_cursor_engine_only_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE); return !elm_object_cursor_theme_search_enabled_get(item->view); } EOLIAN static void _elm_widget_item_part_content_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *part EINA_UNUSED, Evas_Object *content EINA_UNUSED) { ERR_NOT_SUPPORTED(item, "elm_object_part_content_set()"); } EOLIAN static Evas_Object * _elm_widget_item_part_content_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *part EINA_UNUSED) { ERR_NOT_SUPPORTED(item, "elm_object_part_content_get()"); return NULL; } EOLIAN static Evas_Object * _elm_widget_item_part_content_unset(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *part EINA_UNUSED) { ERR_NOT_SUPPORTED(item, "elm_object_part_content_unset()"); return NULL; } EOLIAN static void _elm_widget_item_part_text_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *part EINA_UNUSED, const char *label EINA_UNUSED) { ERR_NOT_SUPPORTED(item, "elm_object_part_text_set()"); } EOLIAN static const char * _elm_widget_item_part_text_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *part EINA_UNUSED) { ERR_NOT_SUPPORTED(item, "elm_object_part_text_get()"); return NULL; } static void _elm_widget_item_part_text_custom_free(void *data) { Elm_Label_Data *label; label = data; eina_stringshare_del(label->part); eina_stringshare_del(label->text); free(label); } EOLIAN static void _elm_widget_item_part_text_custom_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *part, const char *text) { Elm_Label_Data *label; ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); if (!item->labels) item->labels = eina_hash_stringshared_new(_elm_widget_item_part_text_custom_free); label = eina_hash_find(item->labels, part); if (!label) { label = malloc(sizeof(Elm_Label_Data)); if (!label) { ERR("Failed to allocate memory"); return; } label->part = eina_stringshare_add(part); label->text = eina_stringshare_add(text); eina_hash_add(item->labels, part, label); } else eina_stringshare_replace(&label->text, text); } EOLIAN static const char * _elm_widget_item_part_text_custom_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *part) { Elm_Label_Data *label; ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL); label = eina_hash_find(item->labels, part); return label ? label->text : NULL; } static Eina_Bool _elm_widget_item_part_text_custom_foreach(const Eina_Hash *labels EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *func_data) { Elm_Label_Data *label; Elm_Widget_Item_Data *item; label = data; item = func_data; elm_wdg_item_part_text_set(item->eo_obj, label->part, label->text); return EINA_TRUE; } EOLIAN static void _elm_widget_item_part_text_custom_update(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); if (item->labels) eina_hash_foreach(item->labels, _elm_widget_item_part_text_custom_foreach, item); } EOLIAN static void _elm_widget_item_signal_emit(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item EINA_UNUSED, const char *emission EINA_UNUSED, const char *source EINA_UNUSED) { } EOLIAN static void _elm_widget_item_signal_callback_add(Eo *eo_item, Elm_Widget_Item_Data *item, const char *emission, const char *source, Elm_Object_Item_Signal_Cb func, void *data) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); EINA_SAFETY_ON_NULL_RETURN(func); Elm_Widget_Item_Signal_Data *wisd; wisd = malloc(sizeof(Elm_Widget_Item_Signal_Data)); if (!wisd) return; wisd->item = eo_item; wisd->func = (Elm_Widget_Item_Signal_Cb)func; wisd->data = data; wisd->emission = eina_stringshare_add(emission); wisd->source = eina_stringshare_add(source); if (_elm_widget_is(item->view)) elm_object_signal_callback_add(item->view, emission, source, _elm_widget_item_signal_cb, wisd); else if (efl_isa(item->view, EDJE_OBJECT_CLASS)) edje_object_signal_callback_add(item->view, emission, source, _elm_widget_item_signal_cb, wisd); else { WRN("The %s widget item doesn't support signal callback add!", efl_class_name_get(efl_class_get(item->widget))); free(wisd); return; } item->signals = eina_list_append(item->signals, wisd); } EOLIAN static void * _elm_widget_item_signal_callback_del(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *emission, const char *source, Elm_Object_Item_Signal_Cb func) { Elm_Widget_Item_Signal_Data *wisd; Eina_List *l; ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL); EINA_LIST_FOREACH(item->signals, l, wisd) { if ((wisd->func == (Elm_Widget_Item_Signal_Cb)func) && !strcmp(wisd->emission, emission) && !strcmp(wisd->source, source)) return _elm_widget_item_signal_callback_list_get(item, l); } return NULL; } EOLIAN static void _elm_widget_item_access_info_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *txt) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); eina_stringshare_del(item->access_info); if (!txt) item->access_info = NULL; else item->access_info = eina_stringshare_add(txt); } EOLIAN static void _elm_widget_item_translate(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { ELM_WIDGET_ITEM_CHECK_OR_RETURN(item); ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item); #ifdef HAVE_GETTEXT Elm_Translate_String_Data *ts; EINA_INLIST_FOREACH(item->translate_strings, ts) { if (!ts->string) continue; const char *s = dgettext(ts->domain, ts->string); item->on_translate = EINA_TRUE; elm_wdg_item_part_text_set(item->eo_obj, ts->id, s); item->on_translate = EINA_FALSE; } #endif } EOLIAN static void _elm_widget_item_access_order_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Eina_List *objs) { _elm_access_widget_item_access_order_set(item, objs); } EOLIAN static const Eina_List * _elm_widget_item_access_order_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { return _elm_access_widget_item_access_order_get(item); } EOLIAN static void _elm_widget_item_access_order_unset(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { _elm_access_widget_item_access_order_unset(item); } EOLIAN static Evas_Object* _elm_widget_item_access_register(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { _elm_access_widget_item_register(item); return item->access_obj; } EOLIAN static void _elm_widget_item_access_unregister(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { _elm_access_widget_item_unregister(item); } EOLIAN static Evas_Object* _elm_widget_item_access_object_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item) { return item->access_obj; } EOLIAN static Evas_Object * _elm_widget_item_focus_next_object_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Elm_Focus_Direction dir) { Evas_Object *ret = NULL; if (dir == ELM_FOCUS_PREVIOUS) ret = item->focus_previous; else if (dir == ELM_FOCUS_NEXT) ret = item->focus_next; else if (dir == ELM_FOCUS_UP) ret = item->focus_up; else if (dir == ELM_FOCUS_DOWN) ret = item->focus_down; else if (dir == ELM_FOCUS_RIGHT) ret = item->focus_right; else if (dir == ELM_FOCUS_LEFT) ret = item->focus_left; return ret; } EOLIAN static void _elm_widget_item_focus_next_object_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Evas_Object *next, Elm_Focus_Direction dir) { if (dir == ELM_FOCUS_PREVIOUS) item->focus_previous = next; else if (dir == ELM_FOCUS_NEXT) item->focus_next = next; else if (dir == ELM_FOCUS_UP) item->focus_up = next; else if (dir == ELM_FOCUS_DOWN) item->focus_down = next; else if (dir == ELM_FOCUS_RIGHT) item->focus_right = next; else if (dir == ELM_FOCUS_LEFT) item->focus_left = next; } EOLIAN static Elm_Object_Item* _elm_widget_item_focus_next_item_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Elm_Focus_Direction dir) { Elm_Object_Item *ret = NULL; if (dir == ELM_FOCUS_PREVIOUS) ret = item->item_focus_previous; else if (dir == ELM_FOCUS_NEXT) ret = item->item_focus_next; else if (dir == ELM_FOCUS_UP) ret = item->item_focus_up; else if (dir == ELM_FOCUS_DOWN) ret = item->item_focus_down; else if (dir == ELM_FOCUS_RIGHT) ret = item->item_focus_right; else if (dir == ELM_FOCUS_LEFT) ret = item->item_focus_left; return ret; } EOLIAN static void _elm_widget_item_focus_next_item_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Elm_Object_Item *next_item, Elm_Focus_Direction dir) { if (dir == ELM_FOCUS_PREVIOUS) item->item_focus_previous = next_item; else if (dir == ELM_FOCUS_NEXT) item->item_focus_next = next_item; else if (dir == ELM_FOCUS_UP) item->item_focus_up = next_item; else if (dir == ELM_FOCUS_DOWN) item->item_focus_down = next_item; else if (dir == ELM_FOCUS_RIGHT) item->item_focus_right = next_item; else if (dir == ELM_FOCUS_LEFT) item->item_focus_left = next_item; } /* happy debug functions */ #ifdef ELM_DEBUG static void _sub_obj_tree_dump(const Evas_Object *obj, int lvl) { int i; for (i = 0; i < lvl * 3; i++) putchar(' '); if (_elm_widget_is(obj)) { Eina_List *l; INTERNAL_ENTRY; DBG("+ %s(%p)\n", elm_widget_type_get(obj), obj); EINA_LIST_FOREACH(sd->subobjs, l, obj) _sub_obj_tree_dump(obj, lvl + 1); } else DBG("+ %s(%p)\n", evas_object_type_get(obj), obj); } static void _sub_obj_tree_dot_dump(const Evas_Object *obj, FILE *output) { if (!_elm_widget_is(obj)) return; INTERNAL_ENTRY; Eina_Bool visible = evas_object_visible_get(obj); Eina_Bool disabled = elm_widget_disabled_get(obj); Eina_Bool focused = elm_widget_focus_get(obj); Eina_Bool can_focus = elm_widget_can_focus_get(obj); if (sd->parent_obj) { fprintf(output, "\"%p\" -- \"%p\" [ color=black", sd->parent_obj, obj); if (focused) fprintf(output, ", style=bold"); if (!visible) fprintf(output, ", color=gray28"); fprintf(output, " ];\n"); } fprintf(output, "\"%p\" [ label = \"{%p|%s|%s|visible: %d|" "disabled: %d|focused: %d/%d|focus order:%d}\"", obj, obj, elm_widget_type_get(obj), evas_object_name_get(obj), visible, disabled, focused, can_focus, sd->focus_order); if (focused) fprintf(output, ", style=bold"); if (!visible) fprintf(output, ", fontcolor=gray28"); if ((disabled) || (!visible)) fprintf(output, ", color=gray"); fprintf(output, " ];\n"); Eina_List *l; Evas_Object *o; EINA_LIST_FOREACH(sd->subobjs, l, o) _sub_obj_tree_dot_dump(o, output); } #endif EAPI void elm_widget_tree_dump(const Evas_Object *top) { #ifdef ELM_DEBUG if (!_elm_widget_is(top)) return; _sub_obj_tree_dump(top, 0); #else (void)top; return; #endif } EAPI void elm_widget_tree_dot_dump(const Evas_Object *top, FILE *output) { #ifdef ELM_DEBUG if (!_elm_widget_is(top)) return; fprintf(output, "graph " " { node [shape=record];\n"); _sub_obj_tree_dot_dump(top, output); fprintf(output, "}\n"); #else (void)top; (void)output; return; #endif } EOLIAN static Eo * _elm_widget_efl_object_constructor(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED) { Eo *parent = NULL; sd->on_create = EINA_TRUE; 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); parent = efl_parent_get(obj); elm_obj_widget_parent_set(obj, parent); sd->on_create = EINA_FALSE; elm_interface_atspi_accessible_role_set(obj, ELM_ATSPI_ROLE_UNKNOWN); return obj; } EOLIAN static Efl_Object* _elm_widget_efl_object_finalize(Eo *obj, Elm_Widget_Smart_Data *pd) { Eo *eo; eo = efl_finalize(efl_super(obj, MY_CLASS)); _full_eval(obj, pd); return eo; } EOLIAN static void _elm_widget_efl_object_destructor(Eo *obj, Elm_Widget_Smart_Data *sd) { if (sd->manager.provider) { efl_event_callback_del(sd->manager.provider, EFL_UI_FOCUS_USER_EVENT_MANAGER_CHANGED, _manager_changed_cb, obj); sd->manager.provider = NULL; } elm_interface_atspi_accessible_removed(obj); if (sd->logical.parent) { efl_weak_unref(&sd->logical.parent); sd->logical.parent = NULL; } sd->on_destroy = EINA_TRUE; efl_destructor(efl_super(obj, ELM_WIDGET_CLASS)); sd->on_destroy = EINA_FALSE; } +/* internal eo */ +static void +_elm_widget_legacy_ctor(Eo *obj, Elm_Widget_Smart_Data *sd) +{ + efl_canvas_object_legacy_ctor(efl_super(obj, MY_CLASS)); + sd->legacy = EINA_TRUE; +} + EOLIAN static Eina_Strbuf * _elm_widget_efl_object_debug_name_override(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED, Eina_Strbuf *sb) { const char *focus = ""; if (elm_obj_widget_focus_get(obj)) focus = ":focused"; sb = efl_debug_name_override(efl_super(obj, MY_CLASS), sb); eina_strbuf_append_printf(sb, "%s", focus); return sb; } EOLIAN static Eina_Bool _elm_widget_on_focus(Eo *obj, Elm_Widget_Smart_Data *sd, Elm_Object_Item *item EINA_UNUSED) { Eina_Bool focused; const Efl_Event_Description *desc; if (!elm_widget_can_focus_get(obj)) return EINA_FALSE; focused = elm_widget_focus_get(obj); desc = focused ? ELM_WIDGET_EVENT_FOCUSED : ELM_WIDGET_EVENT_UNFOCUSED; if (!sd->resize_obj) evas_object_focus_set(obj, focused); efl_event_callback_legacy_call(obj, desc, NULL); if (_elm_config->atspi_mode && !elm_widget_child_can_focus_get(obj)) elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_FOCUSED, focused); return EINA_TRUE; } EOLIAN static Eina_Bool _elm_widget_disable(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED) { return EINA_FALSE; } EOLIAN static Eina_Bool _elm_widget_widget_event(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Object *source EINA_UNUSED, Evas_Callback_Type type EINA_UNUSED, void *event_info EINA_UNUSED) { return EINA_FALSE; } EOLIAN static Eina_Bool _elm_widget_focus_next_manager_is(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED) { WRN("The %s widget does not implement the \"focus_next/focus_next_manager_is\" functions.", efl_class_name_get(efl_class_get(obj))); return EINA_FALSE; } static Eina_Bool _elm_widget_focus_direction_manager_is(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED) { WRN("The %s widget does not implement the \"focus_direction/focus_direction_manager_is\" functions.", efl_class_name_get(efl_class_get(obj))); return EINA_FALSE; } EOLIAN static Eina_Bool _elm_widget_activate(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Elm_Activate act EINA_UNUSED) { WRN("The %s widget does not implement the \"activate\" functions.", efl_class_name_get(efl_class_get(obj))); return EINA_TRUE; } EOLIAN static void _elm_widget_class_constructor(Efl_Class *klass) { evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass); } EOLIAN static Eina_Bool _elm_widget_elm_interface_atspi_component_focus_grab(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED) { if (elm_object_focus_allow_get(obj)) { Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); if (!ee) return EINA_FALSE; ecore_evas_activate(ee); elm_object_focus_set(obj, EINA_TRUE); return EINA_TRUE; } return EINA_FALSE; } EOLIAN static const char* _elm_widget_elm_interface_atspi_accessible_name_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd) { const char *ret, *name; char *accessible_name; name = elm_interface_atspi_accessible_name_get(efl_super(obj, ELM_WIDGET_CLASS)); if (name) return name; ret = elm_object_text_get(obj); if (!ret) return NULL; accessible_name = _elm_util_mkup_to_text(ret); eina_stringshare_del(_pd->accessible_name); _pd->accessible_name = eina_stringshare_add(accessible_name); free(accessible_name); return _pd->accessible_name; } EOLIAN static Eina_List* _elm_widget_elm_interface_atspi_accessible_children_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd) { Eina_List *l, *accs = NULL; Evas_Object *widget; Elm_Atspi_Type type; EINA_LIST_FOREACH(pd->subobjs, l, widget) { if (!elm_object_widget_check(widget)) continue; if (!efl_isa(widget, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN)) continue; type = elm_interface_atspi_accessible_type_get(widget); if (type == ELM_ATSPI_TYPE_DISABLED) continue; if (type == ELM_ATSPI_TYPE_SKIPPED) { Eina_List *children; children = elm_interface_atspi_accessible_children_get(widget); accs = eina_list_merge(accs, children); continue; } accs = eina_list_append(accs, widget); } return accs; } EOLIAN static Eo* _elm_widget_elm_interface_atspi_accessible_parent_get(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED) { Elm_Atspi_Type type; Elm_Interface_Atspi_Accessible *parent = obj; do { ELM_WIDGET_DATA_GET_OR_RETURN(parent, wd, NULL); parent = wd->parent_obj; type = elm_interface_atspi_accessible_type_get(parent); } while (parent && (type == ELM_ATSPI_TYPE_SKIPPED)); return efl_isa(parent, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN) ? parent : NULL; } EOLIAN static Elm_Atspi_State_Set _elm_widget_elm_interface_atspi_accessible_state_set_get(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED) { Elm_Atspi_State_Set states = 0; states = elm_interface_atspi_accessible_state_set_get(efl_super(obj, ELM_WIDGET_CLASS)); if (evas_object_visible_get(obj)) { STATE_TYPE_SET(states, ELM_ATSPI_STATE_VISIBLE); if (_elm_widget_onscreen_is(obj)) STATE_TYPE_SET(states, ELM_ATSPI_STATE_SHOWING); } if (!elm_widget_child_can_focus_get(obj)) { if (elm_object_focus_allow_get(obj)) STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSABLE); if (elm_object_focus_get(obj)) STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSED); } if (!elm_object_disabled_get(obj)) { STATE_TYPE_SET(states, ELM_ATSPI_STATE_ENABLED); STATE_TYPE_SET(states, ELM_ATSPI_STATE_SENSITIVE); } return states; } EOLIAN static Eina_List* _elm_widget_elm_interface_atspi_accessible_attributes_get(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED) { Eina_List *ret = NULL; Elm_Atspi_Attribute *attr = calloc(1, sizeof(Elm_Atspi_Attribute)); if (!attr) return NULL; attr->key = eina_stringshare_add("type"); attr->value = eina_stringshare_add(evas_object_type_get(obj)); ret = eina_list_append(ret, attr); return ret; } EOLIAN static void _elm_widget_item_elm_interface_atspi_component_extents_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd EINA_UNUSED, Eina_Bool screen_coords, int *x, int *y, int *w, int *h) { int ee_x, ee_y; if (!sd->view) { if (x) *x = -1; if (y) *y = -1; if (w) *w = -1; if (h) *h = -1; return; } evas_object_geometry_get(sd->view, x, y, w, h); if (screen_coords) { Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(sd->view)); if (!ee) return; ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL); if (x) *x += ee_x; if (y) *y += ee_y; } } EOLIAN static Eina_Bool _elm_widget_item_elm_interface_atspi_component_extents_set(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd EINA_UNUSED, Eina_Bool screen_coords EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED) { return EINA_FALSE; } EOLIAN static int _elm_widget_item_elm_interface_atspi_component_layer_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd EINA_UNUSED) { if (!sd->view) return -1; return evas_object_layer_get(sd->view); } EOLIAN static Eina_Bool _elm_widget_item_elm_interface_atspi_component_focus_grab(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *_pd EINA_UNUSED) { elm_object_item_focus_set(obj, EINA_TRUE); return elm_object_item_focus_get(obj); } EOLIAN static double _elm_widget_item_elm_interface_atspi_component_alpha_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd EINA_UNUSED) { int alpha; if (!sd->view) return -1.0; evas_object_color_get(sd->view, NULL, NULL, NULL, &alpha); return (double)alpha / 255.0; } EOLIAN static Efl_Object * _elm_widget_efl_object_provider_find(Eo *obj, Elm_Widget_Smart_Data *pd, const Efl_Object *klass) { Efl_Object *lookup = NULL; if ((klass == EFL_CONFIG_INTERFACE) || (klass == EFL_CONFIG_GLOBAL_CLASS)) return _efl_config_obj; if (pd->provider_lookup) return NULL; pd->provider_lookup = EINA_TRUE; lookup = efl_provider_find(pd->parent_obj, klass); if (!lookup) lookup = efl_provider_find(efl_super(obj, MY_CLASS), klass); pd->provider_lookup = EINA_FALSE; return lookup; } EOLIAN static Efl_Ui_Focus_Manager* _elm_widget_efl_ui_focus_user_parent_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd EINA_UNUSED) { return pd->focus.parent; } EOLIAN static Efl_Ui_Focus_Manager* _elm_widget_efl_ui_focus_user_manager_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd EINA_UNUSED) { return pd->focus.manager; } EOLIAN static Eina_Rectangle _elm_widget_efl_ui_focus_object_focus_geometry_get(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED) { Eina_Rectangle rect; efl_gfx_geometry_get(obj, &rect.x , &rect.y, &rect.w, &rect.h); return rect; } EOLIAN static void _elm_widget_efl_ui_focus_object_focus_set(Eo *obj, Elm_Widget_Smart_Data *pd, Eina_Bool focus) { pd->focused = focus; elm_obj_widget_on_focus(obj, NULL); efl_ui_focus_object_focus_set(efl_super(obj, MY_CLASS), focus); } EOLIAN static Efl_Ui_Focus_Manager* _elm_widget_focus_manager_factory(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd EINA_UNUSED, Efl_Ui_Focus_Object *root EINA_UNUSED) { ERR("No manager presented"); return NULL; } /* Legacy APIs */ /* elm_object_content_xxx APIs are supposed to work on all objects for which * elm_object_widget_check() returns true. The below checks avoid printing out * undesired ERR messages. */ EAPI void elm_widget_content_part_set(Evas_Object *obj, const char *part, Evas_Object *content) { ELM_WIDGET_CHECK(obj); if (!efl_isa(obj, EFL_PART_INTERFACE)) return; if (!part) { part = elm_widget_default_content_part_get(obj); if (!part) return; } efl_content_set(efl_part(obj, part), content); } EAPI Evas_Object * elm_widget_content_part_get(const Evas_Object *obj, const char *part) { ELM_WIDGET_CHECK(obj) NULL; if (!efl_isa(obj, EFL_PART_INTERFACE)) return NULL; if (!part) { part = elm_widget_default_content_part_get(obj); if (!part) return NULL; } return efl_content_get(efl_part(obj, part)); } EAPI Evas_Object * elm_widget_content_part_unset(Evas_Object *obj, const char *part) { ELM_WIDGET_CHECK(obj) NULL; if (!efl_isa(obj, EFL_PART_INTERFACE)) return NULL; if (!part) { part = elm_widget_default_content_part_get(obj); if (!part) return NULL; } return efl_content_unset(efl_part(obj, part)); } EAPI void elm_widget_signal_emit(Eo *obj, const char *emission, const char *source) { ELM_WIDGET_CHECK(obj); if (evas_object_smart_type_check(obj, "elm_layout")) elm_layout_signal_emit(obj, emission, source); else if (evas_object_smart_type_check(obj, "elm_icon")) { WRN("Deprecated function. This functionality on icon objects" " will be dropped on a next release."); _elm_icon_signal_emit(obj, emission, source); } } EAPI void elm_widget_signal_callback_add(Eo *obj, const char *emission, const char *source, Edje_Signal_Cb func, void *data) { ELM_WIDGET_CHECK(obj); EINA_SAFETY_ON_NULL_RETURN(func); if (evas_object_smart_type_check(obj, "elm_layout")) elm_layout_signal_callback_add(obj, emission, source, func, data); else if (evas_object_smart_type_check(obj, "elm_icon")) { WRN("Deprecated function. This functionality on icon objects" " will be dropped on a next release."); _elm_icon_signal_callback_add(obj, emission, source, func, data); } } EAPI void * elm_widget_signal_callback_del(Eo *obj, const char *emission, const char *source, Edje_Signal_Cb func) { void *data = NULL; ELM_WIDGET_CHECK(obj) NULL; EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL); if (evas_object_smart_type_check(obj, "elm_layout")) data = elm_layout_signal_callback_del(obj, emission, source, func); else if (evas_object_smart_type_check(obj, "elm_icon")) { WRN("Deprecated function. This functionality on icon objects" " will be dropped on a next release."); data = _elm_icon_signal_callback_del(obj, emission, source, func); } return data; } /* Internal EO APIs and hidden overrides */ EFL_FUNC_BODY_CONST(elm_widget_default_content_part_get, const char *, NULL) EFL_FUNC_BODY_CONST(elm_widget_default_text_part_get, const char *, NULL) ELM_PART_CONTENT_DEFAULT_SET(elm_widget, NULL) ELM_PART_TEXT_DEFAULT_GET(elm_widget, NULL) #define ELM_WIDGET_EXTRA_OPS \ EFL_CANVAS_GROUP_ADD_DEL_OPS(elm_widget), \ ELM_PART_CONTENT_DEFAULT_OPS(elm_widget), \ ELM_PART_TEXT_DEFAULT_OPS(elm_widget), \ + EFL_OBJECT_OP_FUNC(efl_canvas_object_legacy_ctor, _elm_widget_legacy_ctor), \ EFL_OBJECT_OP_FUNC(efl_dbg_info_get, _elm_widget_efl_object_dbg_info_get) #include "elm_widget_item.eo.c" #include "elm_widget.eo.c" diff --git a/src/lib/elementary/elm_widget.eo b/src/lib/elementary/elm_widget.eo index 5c369ba18b..59ab22617c 100644 --- a/src/lib/elementary/elm_widget.eo +++ b/src/lib/elementary/elm_widget.eo @@ -1,814 +1,814 @@ import edje_types; import elm_general; import efl_input_types; /* FIXME: This shouldn't be here. */ type list_data_get_func_type: __undefined_type; [[Elementary list data get function type]] type region_hook_func_type: __undefined_type; [[Elementary region hook function type]] type @extern Evas.Callback_Type: __undefined_type; [[Evas event type]] enum Elm.Activate { [[ Used in 'Virtual' function @Elm.Widget.activate. ]] default = 0, [[Activate default]] up, [[Activate up]] down, [[Activate down]] right, [[Activate right]] left, [[Activate left]] back, [[Activate back]] } struct Elm.Tooltip; [[Elementary tooltip]] struct @extern Elm.Theme; [[Elementary theme]] abstract Elm.Widget (Efl.Canvas.Group, Elm.Interface.Atspi_Accessible, Elm.Interface.Atspi_Component, Efl.Ui.Focus.User, Efl.Ui.Focus.Object, Efl.Ui.Base, Efl.Ui.Cursor) { [[Elementary widget abstract class]] legacy_prefix: elm_widget; eo_prefix: elm_obj_widget; event_prefix: elm_widget; data: Elm_Widget_Smart_Data; methods { @property resize_object @protected { [[This is the internal canvas object managed by a widget. This property is protected as it is meant for widget implementations only, to set and access the internal canvas object. Do use this function unless you're implementing a widget. ]] set { [[Sets the new resize object for this widget.]] } values { sobj: Efl.Canvas.Object @nullable; [[A canvas object (often a $Efl.Canvas.Layout object).]] } } @property disabled { [[Whether the widget is enabled (accepts and reacts to user inputs). Each widget may handle the disabled state differently, but overall disabled widgets shall not respond to any input events. This is $false by default, meaning the widget is enabled. ]] values { disabled: bool(false); [[$true if the widget is disabled.]] } } @property style { [[The widget style to use. Styles define different look and feel for widgets, and may provide different parts for layout-based widgets. Styles vary from widget to widget and may be defined by other themes by means of extensions and overlays. The style can only be set before @Efl.Object.finalize, which means at construction time of the object (inside $efl_add in C). ]] - set { + set @protected { [[Can only be called during construction, before finalize.]] return: Efl.Ui.Theme.Apply(0); [[Whether the style was successfully applied or not, see the values of @Efl.Ui.Theme.Apply for more information.]] } get { [[Returns the current style of a widget.]] } values { style: string; [[Name of the style to use. Refer to each widget's documentation for the available style names, or to the themes in use.]] } } @property focus { [[Focus property]] values { focus: bool; [[$true if the widget has focus, $false otherwise]] } } @property drag_lock_y { [[Lock the Y axis from being dragged]] values { lock: bool; [[$true if the Y axis is locked, $false otherwise]] } } @property focus_highlight_style { [[Control the widget focus highlight style.]] set { return: bool; [[$true on success, $false otherwise.]] } get { } values { style: string; [[The name of the focus highlight style.]] } } @property tree_unfocusable { [[Make the elementary object and its children to be unfocusable (or focusable). If the tree is set as unfocusable, newest focused object which is not in this tree will get focus. This API can be helpful for an object to be deleted. When an object will be deleted soon, it and its children may not want to get focus (by focus reverting or by other focus controls). Then, just use this API before deleting.]] values { tree_unfocusable: bool; [[$true for unfocusable, $false for focusable.]] } } @property theme { [[Widget theme]] values { th: ptr(Elm.Theme) @nullable; [[Elementary theme]] } } @property highlight_ignore { [[Highlight ignore]] values { ignore: bool; [[$true if highlights are ignored, $false otherwise]] } } @property orientation_mode_disabled { [[Orientation mode disabled or enabled]] values { disabled: bool; [[$true if orientation mode is disabled, $false otherwise]] } } @property focus_custom_chain { [[A custom chain of objects to pass focus. Note: On focus cycle, only will be evaluated children of this container.]] set { [[This function overwrites any previous custom focus chain within the list of objects. The previous list will be deleted and this list will be managed by elementary. After it is set, don't modify it.]] values { objs: list; [[Chain of objects to pass focus]] } } get { values { objs: const(list); [[Chain of objects]] } } } @property can_focus { [[The ability for an Elementary object to be focused. Unfocusable objects do nothing when programmatically focused, being the nearest focusable parent object the one really getting focus. Also, when they receive mouse input, they will get the event, but not take away the focus from where it was previously. Note: Objects which are meant to be interacted with by input events are created able to be focused, by default. All the others are not.]] values { can_focus: bool; [[$true if the object can be focused, $false if not.]] } } @property highlight_in_theme { [[Highlight in theme property]] values { highlight: bool; [[$true if widget gets hightlight, $false otherwise]] } } @property widget_parent @protected { [[The internal widget parent]] set { legacy: elm_widget_parent_set; /* Needed because we don't do duplication removal for legacy names. */ } get { legacy: elm_widget_parent_get; /* Needed because we don't do duplication removal for legacy names. */ } values { parent: Efl.Canvas.Object @nullable; [[Widget parent object]] } } @property access_info { [[Accessibility information]] values { txt: string @nullable; [[Accessibility text description]] } } @property drag_lock_x { [[Drag lock on X axis]] values { lock: bool; [[$true if drag is locked on X axis, $false otherwise]] } } @property access_highlight_in_theme { [[Accessibility highlight in theme]] values { highlight: bool; [[$true if highlighted, $false otherwise]] } } @property focus_region_show_mode { [[Control the focus_region_show mode.]] values { mode: Elm.Focus.Region.Show_Mode; [[Focus region show mode]] } } @property parent_highlight { [[Parent highlight property]] set { } values { highlighted: bool; [[$true if highlighted, $false otherwise]] } } @property theme_object { [[Theme object property]] set { return: Efl.Ui.Theme.Apply; [[Theme apply]] } values { edj: Efl.Canvas.Object; [[Edje object]] wname: string; [[Widget name]] welement: string; [[Widget element]] wstyle: string; [[Widget style]] } } @property hover_object { [[Hover object property]] set { } values { sobj: Efl.Canvas.Object @nullable; [[Hover sub object]] } } /* internal only - most objects use data = null as they work on themselves except scroller itself */ @property on_show_region_hook { [[Region hook on show property]] set { } values { func: region_hook_func_type @nullable; [[Region hook function]] data: void_ptr @optional; [[Data pointer]] } } /* this is a part api */ @property domain_part_text_translatable { [[Translate domain text part property]] set { } values { part: string; [[Part name]] domain: string; [[Domain]] translatable: bool; [[$true if translatable, $false otherwise]] } } @property orientation { [[Widget orientation]] set { } values { rotation: int; [[Orientation]] } } @property domain_translatable_part_text { [[Domain translatable text part property]] set { } values { part: string; [[Part name]] domain: string; [[Domain name]] label: string; [[Label]] } } @property scroll_hold { [[Scroll hold property]] get { return: int; [[FIXME]] } } @property drag_child_locked_y { [[Drag child locked Y axis property]] get { return: int; [[FIXME]] } } @property item_loop_enabled { [[Control item loop feature.]] values { enable: bool; [[$true if item loop is enabled, $false otherwise]] } } @property child_can_focus { [[Child can focus property]] get { return: bool; [[$true if child can focus, $false otherwise]] } } @property scroll_freeze { [[Scroll freeze property]] get { return: int; [[FIXME]] } } @property focus_region { [[Focus region property]] get { return: bool; [[$true on success, $false otherwise]] } values { x: int; [[X coordinate]] y: int; [[Y coordinate]] w: int; [[Width]] h: int; [[Height]] } } @property top { [[Top widget property]] get { return: Efl.Canvas.Object; [[Top widget]] } } @property focus_order { [[Focus order property]] get { return: uint; [[FIXME]] } } @property drag_child_locked_x { [[Drag child locked X axis]] get { return: int; [[FIXME]] } } @property can_focus_child_list { [[Can focus children list]] get { return: free(own(list), eina_list_free) @warn_unused; [[List of children which can focus]] } } @property focused_item { get { [[Get the focused widget item.]] return: Elm.Widget.Item; [[Focused item]] } } @property parents_bounce { [[Parents bounce property]] get { } values { horiz: bool; [[$true if parents bounce horizontally, $false otherwise]] vert: bool; [[$true if parents bounce vertically, $false otherwise]] } } @property parent_widget { [[Parent widget property]] get @pure_virtual { return: Efl.Canvas.Object; [[Parent widget]] legacy: null; } } @property highlight { [[Highlight property]] get { return: bool; [[$true if widget is highlight, $false otherwise]] } } @property focused_object { [[Current focused object in object tree.]] get { return: Efl.Canvas.Object; [[Current focused or $null, if there is no focused object.]] } } @property parent2 { [[Second parent property]] values { parent: Efl.Canvas.Object @nullable; [[Second parent]] } } @property part_text { [[Part text property]] keys { part: string; [[Part name]] } values { label: string; [[Label]] } } newest_focus_order_get @const { [[Get newest focus in order]] return: Efl.Canvas.Object; [[Handle to focused widget]] params { @out newest_focus_order: uint; [[Newest focus order]] @in can_focus_only: bool; [[$true only us widgets which can focus, $false otherweise]] } } scroll_hold_push { [[Push scroll hold]] } focus_next_object_set { [[Set the next object with specific focus direction. @since 1.8]] params { @in next: Efl.Canvas.Object @nullable; [[Focus next object]] @in dir: Elm.Focus_Direction; [[Focus direction]] } } focus_next_object_get @const { [[Get the next object with specific focus direction. @since 1.8]] return: Efl.Canvas.Object; [[Focus next object]] params { @in dir: Elm.Focus_Direction; [[Focus direction]] } } focus_next_item_set { [[Set the next object item with specific focus direction. @since 1.16]] params { @in next_item: Elm.Widget.Item @nullable; [[Focus next object item]] @in dir: Elm.Focus_Direction; [[Focus direction]] } } focus_next_item_get @const { [[Get the next object item with specific focus direction. @since 1.16]] return: Elm.Widget.Item; [[Focus next object item]] params { @in dir: Elm.Focus_Direction; [[Focus direction]] } } focus_tree_unfocusable_handle { [[Handle focus tree unfocusable]] } focus_custom_chain_prepend { [[Prepend object to custom focus chain. Note: If @"relative_child" equal to $null or not in custom chain, the object will be added in begin. Note: On focus cycle, only will be evaluated children of this container.]] params { @in child: Efl.Canvas.Object; [[The child to be added in custom chain.]] @in relative_child: Efl.Canvas.Object @optional; [[The relative object to position the child.]] } } part_text_translate { [[Translate part text]] return: string; [[Translated text]] params { @in part: string; [[Part name]] @in text: string; [[Text]] } } focus_highlight_geometry_get @const { [[Get the focus highlight geometry of widget.]] params { @out x: int; [[X coordinate]] @out y: int; [[Y coordinate]] @out w: int; [[Width]] @out h: int; [[Height]] } } activate { [['Virtual' function to activate widget.]] params { @in act: Elm.Activate; [[Activate]] } return: bool; [[$true on success, $false otherwise]] legacy: null; /* the legacy API has not the same number of parameter to we don't generate it. */ } sub_object_add { [['Virtual' function handling sub objects being added.]] return: bool; [[$true on success, $false otherwise]] params { @in sobj: Efl.Canvas.Object; [[Sub object]] } } focus_direction_manager_is { [['Virtual' function which checks if handling of passing focus to sub-objects in given direction is supported by widget.]] return: bool; [[$true on success, $false otherwise]] legacy: null; } widget_event { [['Virtual' function handling input events on the widget.]] legacy: elm_widget_event; params { @in source: Efl.Canvas.Object; [[Source object]] @in type: Evas.Callback_Type; [[Callback type]] @in event_info: void_ptr; [[Event info]] } return: bool; [[$true on success, $false otherwise]] } access { [['Virtual' function on the widget being set access.]] params { @in acs: bool; [[$true if access is set, $false otherwise]] } legacy: null; } on_focus { [['Virtual' function handling focus in/out events on the widget]] params { @in item: Elm.Widget.Item @nullable; [[Widget]] } return: bool; [[$true if this widget can handle focus, $false otherwise]] } on_focus_region { [['Virtual' function returning an inner area of a widget that should be brought into the visible area of a broader viewport, may this context arise.]] params { @out x: int; [[X coordinate]] @out y: int; [[Y coordinate]] @out w: int; [[Width]] @out h: int; [[Height]] } return: bool; [[$true on success, $false otherwise]] } focus_cycle { [[Give focus to next object with specific focus direction in object tree.]] params { @in dir: Elm.Focus_Direction; [[Direction to move the focus.]] } } focus_direction @pure_virtual { [['Virtual' function handling passing focus to sub-objects given a direction, in degrees.]] params { @in base: const(Efl.Canvas.Object); [[Base object]] @in degree: double; [[Degree]] @out direction: Efl.Canvas.Object; [[Direction]] @out direction_item: Elm.Widget.Item; [[Direction item]] @out weight: double; [[Weight]] } return: bool; [[$true on success, $false otherwise]] } focus_next_manager_is { [['Virtual' function which checks if handling of passing focus to sub-objects is supported by widget.]] return: bool; [[$true on success, $false otherwise]] } name_find @const { [[Find widget by name]] return: Efl.Canvas.Object; [[Widget]] params { @in name: string; [[Widget name]] @in recurse: int; [[Depth in the tree to search for the widget]] } } focus_list_direction_get @const { [[Get focus list direction]] return: bool; [[$true on success, $false otherwise]] params { @in base: const(Efl.Canvas.Object); [[Base object]] @in items: const(list); [[Item list]] @in list_data_get: list_data_get_func_type; [[Data get function]] @in degree: double; [[Degree]] @out direction: Efl.Canvas.Object; [[Direction]] @out direction_item: Elm.Widget.Item; [[Direction item]] @out weight: double; [[Weight]] } } focused_object_clear { [[Clear focused object]] } focus_direction_go { [[Go in focus direction]] return: bool; [[$true on success, $false otherwise]] params { @in degree: double; [[Degree]] } } show_region_set { [[Set show region]] params { @in x: int; [[X coordinate]] @in y: int; [[Y coordinate]] @in w: int; [[Width]] @in h: int; [[Height]] @in forceshow: bool; [[$true if show should be forced, $false otherwise]] } } show_region_get @const { [[Get show region]] params { @out x: int @optional; [[X coordinate]] @out y: int @optional; [[Y coordinate]] @out w: int @optional; [[Width]] @out h: int @optional; [[Height]] } } scroll_freeze_pop { [[Pop scroller freeze]] } tooltip_del { [[Delet widget tooltip]] params { @in tt: ptr(Elm.Tooltip); [[Tooltip to be deleted]] } } focus_next_get @const { [[Get next focus item]] return: bool; [[$true on success, $false otherwise]] params { @in dir: Elm.Focus_Direction; [[Focus direction]] @out next: Efl.Canvas.Object; [[Next object]] @out next_item: Elm.Widget.Item; [[Next item]] } } translatable_part_text_get @const { [[Get translatable part text]] return: string; [[Part text]] params { @in part: string; [[Part name]] } } focus_restore { [[Restore the focus state of the sub-tree. This API will restore the focus state of the sub-tree to the latest state. If a sub-tree is unfocused and wants to get back to the latest focus state, this API will be helpful.]] } scroll_hold_pop { [[Pop scroller hold]] } translate { [['Virtual' function handling language changes on Elementary.]] return: bool; [[$true on success, $false otherwise]] legacy: null; } scroll_freeze_push { [[Push scroller freeze]] } focus_custom_chain_unset { [[Unset a custom focus chain on a given Elementary widget. Any focus chain previously set is removed entirely after this call.]] } focus_steal { [[Steal focus]] params { @in item: Elm.Widget.Item @nullable; [[Widget to steal focus from]] } } focus_hide_handle { [[Handle hide focus]] } focus_next @pure_virtual { [['Virtual' function handling passing focus to sub-objects.]] params { @in dir: Elm.Focus_Direction; [[Focus direction]] @out next: Efl.Canvas.Object; [[Next object]] @out next_item: Elm.Widget.Item; [[Next item]] } return: bool; [[$true on success, $false otherwise]] } focus_list_next_get @const { [[Get next item in focus list]] return: bool; [[$true on success, $false otherwise]] params { @in items: const(list); [[Item list]] @in list_data_get: list_data_get_func_type; [[Function type]] @in dir: Elm.Focus_Direction; [[Focus direction]] @out next: Efl.Canvas.Object; [[Next object]] @out next_item: Elm.Widget.Item; [[Next item]] } } focus_mouse_up_handle { [[Handle focus mouse up]] legacy: null; } theme_apply { [['Virtual' function on the widget being re-themed.]] return: Efl.Ui.Theme.Apply; [[Theme apply]] } focus_direction_get @const { [[Get focus direction]] return: bool; [[$true on success, $false otherwise]] params { @in base: const(Efl.Canvas.Object); [[Base]] @in degree: double; [[Degree]] @out direction: Efl.Canvas.Object; [[Direction]] @out direction_item: Elm.Widget.Item; [[Direction item]] @out weight: double; [[Weight]] } } disable { [['Virtual' function on the widget being disabled.]] return: bool; [[$true on success, $false otherwise]] } sub_object_del { [['Virtual' function handling sub objects being removed.]] return: bool; [[$true on success, $false otherwise]] params { @in sobj: Efl.Canvas.Object; [[Object to be deleted]] } } tooltip_add { [[Add tooltip to widget]] params { @in tt: ptr(Elm.Tooltip); [[Tooltip]] } } focus_region_show @const { [[Show focus region]] } focus_disabled_handle { [[Handle disable widget focus]] } focus_custom_chain_append { [[Append object to custom focus chain. Note: If @"relative_child" equal to $null or not in custom chain, the object will be added in end. Note: On focus cycle, only will be evaluated children of this container.]] params { @in child: Efl.Canvas.Object; [[The child to be added in custom chain.]] @in relative_child: Efl.Canvas.Object @optional; [[The relative object to position the child.]] } } @property focus_move_policy { [[The widget's focus move policy.]] values { policy: Efl.Ui.Focus.Move_Policy; [[Focus move policy]] } } @property focus_move_policy_automatic { [[Control the widget's focus_move_policy mode setting. @since 1.18]] values { automatic: bool; [[$true to follow system focus move policy change, $false otherwise]] } } focus_reconfigure { [[@since 1.18]] } focus_register { [[Register focus with focus manager]] params { manager : Efl.Ui.Focus.Manager; [[The manager to register against]] logical : Efl.Ui.Focus.Object; [[The logical parent to use]] @inout logical_flag : bool; [[reference to the flag indicating if the should be logical or not change this flag to the value you have it registered]] } return : bool; [[return $true or $false if the registration was successfull or not]] } focus_manager_factory { [[If the widget needs a manager, this function is called It can be used and overriden to inject your own manager or set custom options on the manager ]] params { root : Efl.Ui.Focus.Object; [[the logical root to use in the manager.]] } return : Efl.Ui.Focus.Manager; } } implements { class.constructor; Efl.Object.constructor; Efl.Object.finalize; Efl.Object.destructor; Efl.Object.provider_find; Efl.Object.debug_name_override; Efl.Gfx.color { set; } Efl.Gfx.visible { set; } Efl.Gfx.position { set; } Efl.Gfx.size { set; } Efl.Canvas.Object.clip { set; } Efl.Canvas.Object.no_render { set; } Efl.Canvas.Object.is_frame_object { set; } Efl.Canvas.Group.group_calculate; Efl.Canvas.Group.group_member_del; Efl.Canvas.Group.group_member_add; Elm.Interface.Atspi_Accessible.name { get; } Elm.Interface.Atspi_Accessible.state_set { get; } Elm.Interface.Atspi_Accessible.children { get; } Elm.Interface.Atspi_Accessible.parent { get; } Elm.Interface.Atspi_Accessible.attributes { get; } Elm.Interface.Atspi_Component.focus_grab; Efl.Ui.Focus.User.manager { get; } Efl.Ui.Focus.User.parent { get; } Efl.Ui.Focus.Object.focus_geometry { get; } Efl.Ui.Focus.Object.focus { set; } Efl.Ui.Base.scale { get; set; } Efl.Ui.Base.mirrored { get; set; } Efl.Ui.Base.mirrored_automatic { get; set; } Efl.Ui.Cursor.cursor { get; set; } Efl.Ui.Cursor.cursor_style { get; set; } Efl.Ui.Cursor.cursor_theme_search_enabled { get; set; } } events { moved; [[Called when widget moved]] focused; [[Called when widget was focused]] unfocused; [[Called when widget was unfocused]] language,changed; [[Called when widget language changed]] access,changed; [[Called when accessibility changed]] } } diff --git a/src/lib/elementary/elm_widget.h b/src/lib/elementary/elm_widget.h index 8c7382fd5b..86d5b6f4a5 100644 --- a/src/lib/elementary/elm_widget.h +++ b/src/lib/elementary/elm_widget.h @@ -1,872 +1,881 @@ #ifndef ELM_WIDGET_H #define ELM_WIDGET_H /* DO NOT USE THIS HEADER UNLESS YOU ARE PREPARED FOR BREAKING OF YOUR * CODE. THIS IS ELEMENTARY'S INTERNAL WIDGET API (for now) AND IS NOT * FINAL. CALL elm_widget_api_check(ELM_INTERNAL_API_VERSION) TO CHECK * IT AT RUNTIME. * * How to make your own widget? like this (where wname is your widget * name (space) and wparentname is you widget's parent widget name * (the base widget class if its a 'root' one). * * #include * #include "elm_priv.h" * * static const char ELM_WNAME_SMART_NAME[] = "elm_wname"; * * #define ELM_WNAME_DATA_GET(o, sd) \ * Elm_WName_Smart_Data * sd = evas_object_smart_data_get(o) * * #define ELM_WNAME_CHECK(obj) \ * if (!obj || !elm_widget_type_check((obj), ELM_WNAME_SMART_NAME, \ * __func__)) \ * return * * typedef struct _Elm_WName_Smart_Class * { * Elm_WParentName_Smart_Class base; * } Elm_WName_Smart_Class; * * typedef struct _Elm_WName_Smart_Data Elm_WName_Smart_Data; * struct _Elm_WName_Smart_Data * { * Elm_WParentName_Smart_Data base; * Evas_Object *sub; // or any private data needed for an instance * // add any other instance data here too * }; * * static const char SIG_CLICKED[] = "clicked"; * static const Evas_Smart_Cb_Description _smart_callbacks[] = { * {SIG_CLICKED, ""}, * {NULL, NULL} * }; * * EVAS_SMART_SUBCLASS_NEW * (ELM_WNAME_SMART_NAME, _elm_wname, Elm_WName_Smart_Class, * Elm_WParentName_Smart_Class, elm_wparentname_smart_class_get, * _smart_callbacks); * * static Eina_Bool * _elm_wname_smart_on_focus(Evas_Object *obj) * { * ELM_WNAME_DATA_GET(obj, sd); * * // handle focus going in and out - optional, but if you want to, * // define this virtual function to handle it (e.g. to emit a * // signal to an edje object) * * if (elm_widget_focus_get(obj)) * { * edje_object_signal_emit(sd->sub, "elm,action,focus", "elm"); * evas_object_focus_set(sd->sub, EINA_TRUE); * } * else * { * edje_object_signal_emit(sd->sub, "elm,action,unfocus", "elm"); * evas_object_focus_set(sd->sub, EINA_FALSE); * } * * return EINA_TRUE; * } * * static Eina_Bool * _elm_wname_smart_theme(Evas_Object *obj) * { * ELM_WNAME_DATA_GET(obj, sd); * * if (!ELM_WIDGET_CLASS(_elm_wname_parent_sc)->theme(obj)) * return EINA_FALSE; * * // handle changes in theme/scale etc here. always call the * // parent class's version, as even the base class implements it. * * elm_widget_theme_object_set(obj, sd->sub, "wname", "base", * elm_widget_style_get(obj)); * * return EINA_TRUE; * } * * static Eina_Bool * _elm_widget_smart_disable(Evas_Object *obj) * { * ELM_WNAME_DATA_GET(obj, sd); * * // optional, but handle if the widget gets disabled or not * if (elm_widget_disabled_get(obj)) * edje_object_signal_emit(sd->sub, "elm,state,disabled", "elm"); * else * edje_object_signal_emit(sd->sub, "elm,state,enabled", "elm"); * * return EINA_TRUE; * } * * static void * _elm_wname_smart_add(Evas_Object *obj) * { * EVAS_SMART_DATA_ALLOC(obj, Elm_WName_Smart_Data); * * ELM_WIDGET_CLASS(_elm_wname_parent_sc)->base.add(obj); * * priv->sub = edje_object_add(evas_object_evas_get(obj)); * // just an example having an Edje object here. if it's really the case * // you have a sub edje object as a resize object, consider inheriting * // from @ref elm-layout-class. * elm_widget_can_focus_set(obj, EINA_TRUE); * * // for this widget we will add 1 sub object that is an edje object * priv->sub = edje_object_add(e); * // set the theme. this follows a scheme for group name like this: * // "elm/WIDGETNAME/ELEMENT/STYLE" * // so here it will be: * // "elm/wname/base/default" * // changing style changes style name from default (all widgets start * // with the default style) and element is for your widget internal * // structure as you see fit * elm_widget_theme_object_set * (obj, priv->sub, "wname", "base", "default"); * // listen to a signal from the edje object to produce widget smart * // callback (like click) * edje_object_signal_callback_add * (priv->sub, "elm,action,click", "", _clicked_signal_cb, obj); * // set this sub object as the "resize object". widgets get 1 resize * // object that is resized along with the object wrapper. * elm_widget_resize_object_set(obj, priv->sub); * } * * static void * _elm_wname_smart_del(Evas_Object *obj) * { * ELM_WNAME_DATA_GET(obj, sd); * * // deleting 'virtual' function implementation - on deletion of * // object delete object struct, etc. * * ELM_WIDGET_CLASS(_elm_wname_parent_sc)->base.del(obj); * } * * static void * _elm_wname_smart_set_user(Elm_WName_Smart_Class *sc) * { * ELM_WIDGET_CLASS(sc)->base.add = _elm_wname_smart_add; * ELM_WIDGET_CLASS(sc)->base.del = _elm_wname_smart_del; * * ELM_WIDGET_CLASS(sc)->theme = _elm_wname_smart_theme; * ELM_WIDGET_CLASS(sc)->disable = _elm_wname_smart_disable; * ELM_WIDGET_CLASS(sc)->on_focus = _elm_wname_smart_on_focus; * } * * // actual API to create your widget. add more to manipulate it as * // needed mark your calls with EAPI to make them "external api" * // calls. * * EAPI Evas_Object * * elm_wname_add(Evas_Object *parent) * { * Evas_Object *obj; * * EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL); * * obj = elm_widget_add(_elm_check_smart_class_new(), parent); * if (!obj) return NULL; * * if (!elm_widget_sub_object_add(parent, obj)) * ERR("could not add %p as sub object of %p", obj, parent); * * return obj; * } * * // example - do "whatever" to the widget (here just emit a signal) * EAPI void * elm_wname_whatever(Evas_Object *obj) * { * // check if type is correct - check will return if it fails * ELM_WNAME_CHECK(obj); * // get widget data - type is correct and sane by this point, so this * // should never fail * ELM_WNAME_DATA_GET(obj, sd); * // do whatever you like * edje_object_signal_emit(sd->sub, "elm,state,action,whatever", "elm"); * } * * // you can add more - you need to see elementary's code to know how * // to handle all cases. remember this api is not stable and may * change. it's internal */ #ifndef ELM_INTERNAL_API_ARGESFSDFEFC #warning "You are using an internal elementary API. This API is not stable" #warning "and is subject to change. You use this at your own risk." #warning "Remember to call elm_widget_api_check(ELM_INTERNAL_API_VERSION);" #warning "in your widgets before you call any other elm_widget calls to do" #warning "a correct runtime version check. Also remember - you don't NEED" #warning "to make an Elementary widget is almost ALL cases. You can easily" #warning "make a smart object with Evas's API and do everything you need" #warning "there. You only need a widget if you want to seamlessly be part" #warning "of the focus tree and want to transparently become a container" #warning "for any number of child Elementary widgets" #error "ERROR. Compile aborted." #endif #define ELM_INTERNAL_API_VERSION 7000 /** * @defgroup Widget Widgets Extension Infrastructure * * This section is intended for people willing to create @b custom * Elementary widgets or to contribute new (useful, unique) widgets * upstream. If neither is your case, this text won't be of any use * for you. * * Elementary widgets are built in a @b hierarchical fashion. The idea * is to factorize as much code as possible between widgets with * behavioral similarities, as long as to facilitate the creation of * @b custom, new widgets, may the user need them. * * It all starts with a base class, which aggregates behaviour * @b every Elementary widget is supposed to have: * #Elm_Widget_Smart_Class. Every Elementary widget will be of that * type, be it directly or by means of @b inheriting from it. * * #Elm_Widget_Smart_Class happens to be an @c Evas_Smart_Class. If * you check out Evas' documentation on it, you'll see it's how one is * supposed to create custom Evas objects, what Elementary widgets * are. * * Once one instantiates an Elementary widget, since it inherits from * #Elm_Widget_Smart_Class, the system will raise a class instance of * that type for you. But that happens only @b once: the first time * you ask for an Elementary widget (of a given type). All subsequent * ones will only point to the very same class instance. Since it's * the class which points to the functions implementing the behavior * of objects of that type, all of the live instances of Elementary * widgets (of that type) will share the same blob of code loaded in * memory to execute their routines. * * Now go and take a look at #Elm_Widget_Smart_Class's fields. Because * it inherits from Evas' base smart class, we got a field of that * type as the first member, so that Evas can handle Elementary * objects internally as if they were 'normal' Evas objects. Evas has * the Evas-only behavior function pointers in there, so it's all it * needs. * * Then, comes a version field, so that whenever we got to update or * change the fields on our base smart class, there'll be a runtime * check of the version expected by Elementary and the one provided by * any code linking with it. A mismatch will show the developer of * that code he/she needs to recompile and link its code to a newer * version of Elementary. * * The next fields are the class functions themselves. We call them * 'virtual' because, as in object-oriented languages, one is supposed * here to override them on inheriting classes. On most of * inheritances you'll probably want to call the parent's version of * the class function too: you must analyse each case to tell. * * Take a look at #Elm_Widget_Smart_Data. That's private data bound to * each Elementary object @b instance. It aggregates data needed for * all widgets, since it's meant for the #Elm_Widget_Smart_Class-typed * ones. * * When inheriting from that base type, instance data for this new * class has to have, as the first member, a field of type * #Elm_Widget_Smart_Data. This has to be respected recursively -- if * a third class is to be created inheriting from the one that is a * direct 'child' of #Elm_Widget_Smart_Class, then the private data on * this third class has to have, as its first field, a variable of the * type of the private data of the second class (its parent), direct * child of #Elm_Widget_Smart_Class. * * It is from the base private data, #Elm_Widget_Smart_Data, that we * reach an object's class functions, by the given object * instance. This is the reason of the first field of that struct: a * pointer set to point to its class when the object is instantiated. * * The following figure illustrates the widget inheritance schema. * * @image html elm-widget-hierarchy.png * @image rtf elm-widget-hierarchy.png * @image latex elm-widget-hierarchy.eps * * @section elm-hierarchy-tree Elementary Widgets Hierarchy Tree * * The following figure illustrates the Elementary widget inheritance * tree. * * @image html elm-widget-tree.png * @image rtf elm-widget-tree.png * @image latex elm-widget-tree.eps */ typedef void (*Elm_Widget_Text_Set_Cb)(void *data, const char *part, const char *text); typedef void (*Elm_Widget_Content_Set_Cb)(void *data, const char *part, Evas_Object *content); typedef const char *(*Elm_Widget_Text_Get_Cb)(const void *data, const char *part); typedef Evas_Object *(*Elm_Widget_Content_Get_Cb)(const void *data, const char *part); typedef Evas_Object *(*Elm_Widget_Content_Unset_Cb)(const void *data, const char *part); typedef void (*Elm_Widget_Signal_Emit_Cb)(void *data, const char *emission, const char *source); typedef void (*Elm_Widget_Disable_Cb)(void *data); typedef Eina_Bool (*Elm_Widget_Del_Pre_Cb)(void *data); typedef void (*Elm_Widget_Item_Signal_Cb)(void *data, Elm_Object_Item *item, const char *emission, const char *source); typedef void (*Elm_Widget_Style_Set_Cb)(void *data, const char *style); typedef const char *(*Elm_Widget_Style_Get_Cb)(const void *data); typedef void (*Elm_Widget_Focus_Set_Cb)(void *data, Eina_Bool focused); typedef Eina_Bool (*Elm_Widget_Focus_Get_Cb)(const void *data); typedef void (*Elm_Access_On_Highlight_Cb)(void *data); typedef void (*region_hook_func_type)(void *data, Evas_Object *obj); typedef void * (*list_data_get_func_type)(const Eina_List * l); #include "elm_widget.eo.h" /** * @addtogroup Widget * @{ */ /* Please, ALWAYS update the ELM_WIDGET_SMART_CLASS_INIT macro * whenever you change the following struct! */ /** * Base widget smart class. It has the 'virtual' functions for all * general, common actions on Elementary widgets. */ typedef struct _Elm_Widget_Smart_Class { Evas_Smart_Class base; /**< Base smart class struct, needed for all smart objects */ int version; /**< Version of this smart class definition */ void (*parent_set)(Evas_Object *obj, Evas_Object *parent); /**< 'Virtual' function handling parent widget attachment to new object */ Eina_Bool (*on_focus)(Evas_Object *obj); /**< 'Virtual' function handling focus in/out events on the widget */ Eina_Bool (*disable)(Evas_Object *obj); /**< 'Virtual' function on the widget being disabled */ Eina_Bool (*theme)(Evas_Object *obj); /**< 'Virtual' function on the widget being re-themed */ Eina_Bool (*translate)(Evas_Object *obj); /**< 'Virtual' function handling language changes on Elementary */ Eina_Bool (*event)(Evas_Object *obj, Evas_Object *source, Evas_Callback_Type type, void *event_info); /**< 'Virtual' function handling input events on the widget */ Eina_Bool (*on_focus_region)(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h); /**< 'Virtual' function returning an inner area of a widget that should be brought into the visible area of a broader viewport, may this context arise. On the base Elementary widget class, it defaults to the object's total area, so only override it if you have to. */ Eina_Bool (*focus_next)(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next, Elm_Object_Item **next_item); /**< 'Virtual' function handling passing focus to sub-objects */ Eina_Bool (*focus_direction)(const Evas_Object *obj, const Evas_Object *base, double degree, Evas_Object **target, Elm_Object_Item **target_item, double *weight); /**< 'Virtual' function handling passing focus to sub-objects given a direction, in degrees */ Eina_Bool (*sub_object_add)(Evas_Object *obj, Evas_Object *sobj); /**< 'Virtual' function handling sub objects being added */ Eina_Bool (*sub_object_del)(Evas_Object *obj, Evas_Object *sobj); /**< 'Virtual' function handling sub objects being removed */ void (*access)(Evas_Object *obj, Eina_Bool is_access); /**< 'Virtual' function on the widget being set access */ Eina_Bool (*activate)(Evas_Object *obj, Elm_Activate act); /**< 'Virtual' function to activate widget */ } Elm_Widget_Smart_Class; /** * Base widget smart data. This is data bound to an Elementary object * @b instance, so its particular to that specific object and not * shared between all objects in its class. It is here, though, that * we got a pointer to the object's class, the first field -- @c * 'api'. */ typedef struct _Elm_Widget_Smart_Data { Evas_Object *obj; /**< object pointer for this widget smart data */ Evas_Object *parent_obj; /**< parent object of a widget in the elementary tree */ Evas_Object *parent2; /**< parent object for an inlined window */ Evas_Coord x, y, w, h; Eina_List *subobjs; /**< list of widgets' sub objects in the elementary tree */ Evas_Object *resize_obj; /**< an unique object for each widget that shows the look of a widget. Resize object's geometry is same as the widget. This resize object is different from that of window's resize object. */ Evas_Object *hover_obj; Eina_List *tooltips, *cursors; Evas_Object *focus_previous, *focus_next; Evas_Object *focus_up, *focus_down, *focus_right, *focus_left; Elm_Object_Item *item_focus_previous, *item_focus_next; Elm_Object_Item *item_focus_up, *item_focus_down, *item_focus_right, *item_focus_left; /* "show region" coordinates. all widgets got those because this * info may be set and queried recursively through the widget * parenting tree */ Evas_Coord rx, ry, rw, rh; /* scrolling hold/freeze hints. all widgets got those because this * info may be set and queried recursively through the widget * parenting tree */ int scroll_hold; int scroll_freeze; double scale; Elm_Theme *theme; const char *style; const char *focus_highlight_style; /**< custom focus style for a widget */ const char *access_info; const char *accessible_name; unsigned int focus_order; Eina_Bool focus_order_on_calc; int child_drag_x_locked; int child_drag_y_locked; Eina_Inlist *translate_strings; Eina_List *focus_chain; Eina_List *event_cb; /* this is a hook to be set on-the-fly on widgets. this is code * handling the request of showing a specific region from an inner * widget (mainly issued by entries, on cursor moving) */ void *on_show_region_data; void (*on_show_region)(void *data, Evas_Object *obj); int orient_mode; /* -1 is disabled */ Elm_Focus_Move_Policy focus_move_policy; Elm_Focus_Region_Show_Mode focus_region_show_mode; struct { Efl_Ui_Focus_Manager *manager; //manager which is currently regsitered in Efl_Ui_Focus_Object *parent; //the parent where it is currently registered Eina_Bool logical; } focus; struct { int child_count; Efl_Ui_Focus_Object *parent; } logical; struct { Efl_Ui_Focus_Manager *manager; Efl_Ui_Focus_User *provider; } manager; Eina_Bool drag_x_locked : 1; Eina_Bool drag_y_locked : 1; Eina_Bool can_focus : 1; Eina_Bool child_can_focus : 1; Eina_Bool focused : 1; Eina_Bool top_win_focused : 1; Eina_Bool tree_unfocusable : 1; Eina_Bool focus_move_policy_auto_mode : 1; /* This is TRUE by default */ Eina_Bool highlight_ignore : 1; Eina_Bool highlight_in_theme : 1; Eina_Bool access_highlight_in_theme : 1; Eina_Bool disabled : 1; Eina_Bool is_mirrored : 1; Eina_Bool mirrored_auto_mode : 1; /* This is TRUE by default */ Eina_Bool still_in : 1; Eina_Bool highlighted : 1; Eina_Bool highlight_root : 1; Eina_Bool on_translate : 1; /**< This is true when any types of elm translate function is being called. */ Eina_Bool on_create : 1; /**< This is true when the widget is on creation(general widget constructor). */ Eina_Bool on_destroy: 1; /**< This is true when the widget is on destruction(general widget destructor). */ Eina_Bool provider_lookup : 1; /**< This is true when efl_provider_find is currently walking the tree */ + Eina_Bool legacy : 1; /**< Widget was created with a legacy API, not efl_add() */ } Elm_Widget_Smart_Data; /** * @} */ /**< base structure for all widget items that are not Elm_Widget themselves */ typedef struct _Elm_Widget_Item_Data Elm_Widget_Item_Data; typedef struct _Elm_Widget_Item_Signal_Data Elm_Widget_Item_Signal_Data; /**< accessibility information to be able to set and get from the access API */ typedef struct _Elm_Access_Info Elm_Access_Info; /**< accessibility info item */ typedef struct _Elm_Access_Item Elm_Access_Item; typedef struct _Elm_Action Elm_Action; /** Internal type for mouse cursors */ typedef struct _Elm_Cursor Elm_Cursor; #define ELM_ACCESS_DONE -1 /* sentence done - send done event here */ #define ELM_ACCESS_CANCEL -2 /* stop reading immediately */ struct _Elm_Access_Item { int type; const void *data; Elm_Access_Info_Cb func; }; struct _Elm_Access_Info { Evas_Object *hoverobj; Eina_List *items; Ecore_Timer *delay_timer; void *on_highlight_data; Elm_Access_On_Highlight_Cb on_highlight; void *activate_data; Elm_Access_Activate_Cb activate; /* the owner widget item that owns this access info */ Elm_Widget_Item_Data *widget_item; /* the owner part object that owns this access info */ Evas_Object *part_object; Evas_Object *next; Evas_Object *prev; }; struct _Elm_Action { const char *name; Eina_Bool (*func)(Evas_Object *obj, const char *params); }; void _elm_access_shutdown(void); void _elm_access_mouse_event_enabled_set(Eina_Bool enabled); /* if auto_higlight is EINA_TRUE, it does not steal a focus, it just moves a highlight */ void _elm_access_auto_highlight_set(Eina_Bool enabled); Eina_Bool _elm_access_auto_highlight_get(void); void _elm_access_widget_item_access_order_set(Elm_Widget_Item_Data *item, Eina_List *objs); const Eina_List *_elm_access_widget_item_access_order_get(const Elm_Widget_Item_Data *item); void _elm_access_widget_item_access_order_unset(Elm_Widget_Item_Data *item); // widget focus highlight void _elm_widget_focus_highlight_start(const Evas_Object *obj); void _elm_widget_highlight_in_theme_update(Eo *obj); // win focus highlight void _elm_win_focus_highlight_start(Evas_Object *obj); void _elm_win_focus_highlight_in_theme_update(Evas_Object *obj, Eina_Bool in_theme); Evas_Object *_elm_win_focus_highlight_object_get(Evas_Object *obj); void _elm_win_focus_auto_show(Evas_Object *obj); void _elm_win_focus_auto_hide(Evas_Object *obj); EAPI void _elm_access_clear(Elm_Access_Info *ac); EAPI void _elm_access_text_set(Elm_Access_Info *ac, int type, const char *text); EAPI void _elm_access_callback_set(Elm_Access_Info *ac, int type, Elm_Access_Info_Cb func, const void *data); EAPI char *_elm_access_text_get(const Elm_Access_Info *ac, int type, const Evas_Object *obj); /* this is ok it actually returns a strduped string - it's meant to! */ EAPI void _elm_access_read(Elm_Access_Info *ac, int type, const Evas_Object *obj); EAPI void _elm_access_say(const char *txt); EAPI Elm_Access_Info *_elm_access_info_get(const Evas_Object *obj); EAPI void _elm_access_object_highlight(Evas_Object *obj); EAPI void _elm_access_object_unhighlight(Evas_Object *obj); EAPI void _elm_access_object_highlight_disable(Evas *e); EAPI void _elm_access_object_register(Evas_Object *obj, Evas_Object *hoverobj); EAPI void _elm_access_object_unregister(Evas_Object *obj, Evas_Object *hoverobj); EAPI Eina_Bool _elm_access_2nd_click_timeout(Evas_Object *obj); EAPI void _elm_access_highlight_set(Evas_Object* obj); EAPI Evas_Object * _elm_access_edje_object_part_object_register(Evas_Object *obj, const Evas_Object *partobj, const char* part); EAPI void _elm_access_edje_object_part_object_unregister(Evas_Object* obj, const Evas_Object *eobj, const char* part); EAPI void _elm_access_widget_item_register(Elm_Widget_Item_Data *item); EAPI void _elm_access_widget_item_unregister(Elm_Widget_Item_Data *item); EAPI void _elm_access_on_highlight_hook_set(Elm_Access_Info *ac, Elm_Access_On_Highlight_Cb func, void *data); EAPI void _elm_access_activate_callback_set(Elm_Access_Info *ac, Elm_Access_Activate_Cb func, void *data); EAPI void _elm_access_highlight_object_activate(Evas_Object *obj, Elm_Activate act); EAPI void _elm_access_highlight_cycle(Evas_Object *obj, Elm_Focus_Direction dir); EINA_DEPRECATED EAPI Elm_Access_Info *_elm_access_object_get(const Evas_Object *obj); #define ELM_PREFS_DATA_MAGIC 0xe1f5da7a /**< put this as the first member in your widget item struct */ #define ELM_WIDGET_ITEM Elm_Widget_Item_Data base struct _Elm_Widget_Item_Signal_Data { Elm_Object_Item *item; Elm_Widget_Item_Signal_Cb func; const char *emission; const char *source; void *data; }; #define WIDGET_ITEM_DATA_GET(eo_obj) \ efl_key_data_get((Eo *) eo_obj, "__elm_widget_item_data") #define WIDGET_ITEM_DATA_SET(eo_obj, data) \ efl_key_data_set((Eo *) eo_obj, "__elm_widget_item_data", data) struct _Elm_Widget_Item_Data { /* ef1 ~~ efl, el3 ~~ elm */ #define ELM_WIDGET_ITEM_MAGIC 0xef1e1301 EINA_MAGIC; /* simple accessor macros */ #define VIEW(X) X->base->view #define WIDGET(X) X->base->widget #define EO_OBJ(X) ((X)?X->base->eo_obj:NULL) /**< the owner widget that owns this item */ Evas_Object *widget; /**< The Eo item, useful to invoke eo_do when only the item data is available */ Eo *eo_obj; /**< the base view object */ Evas_Object *view; /**< user delete callback function */ Evas_Smart_Cb del_func; /**< widget delete callback function. don't expose this callback call */ Elm_Widget_Del_Pre_Cb del_pre_func; Evas_Object *focus_previous, *focus_next; Evas_Object *focus_up, *focus_down, *focus_right, *focus_left; Elm_Object_Item *item_focus_previous, *item_focus_next; Elm_Object_Item *item_focus_up, *item_focus_down, *item_focus_right, *item_focus_left; Evas_Object *access_obj; const char *access_info; const char *accessible_name; Eina_List *access_order; Eina_Inlist *translate_strings; Eina_List *signals; Eina_Hash *labels; Evas_Object *track_obj; Eina_Bool disabled : 1; Eina_Bool on_deletion : 1; Eina_Bool on_translate : 1; Eina_Bool still_in : 1; }; #define ELM_NEW(t) calloc(1, sizeof(t)) EAPI Evas_Object *elm_widget_add(Evas_Smart *, Evas_Object *); EAPI void elm_widget_parent_set(Evas_Object *, Evas_Object *); EAPI Eina_Bool elm_widget_api_check(int ver); EAPI Eina_Bool elm_widget_access(Evas_Object *obj, Eina_Bool is_access); EAPI Efl_Ui_Theme_Apply elm_widget_theme(Evas_Object *obj); EAPI void elm_widget_theme_specific(Evas_Object *obj, Elm_Theme *th, Eina_Bool force); EAPI void elm_widget_translate(Evas_Object *obj); EAPI void elm_widget_on_show_region_hook_set(Evas_Object *obj, void (*func)(void *data, Evas_Object *obj), void *data); EAPI Eina_Bool elm_widget_sub_object_parent_add(Evas_Object *sobj); EAPI Eina_Bool elm_widget_sub_object_add(Evas_Object *obj, Evas_Object *sobj); EAPI Eina_Bool elm_widget_sub_object_del(Evas_Object *obj, Evas_Object *sobj); EAPI void elm_widget_resize_object_set(Evas_Object *obj, Evas_Object *sobj); EAPI void elm_widget_hover_object_set(Evas_Object *obj, Evas_Object *sobj); EAPI void elm_widget_signal_emit(Evas_Object *obj, const char *emission, const char *source); EAPI void elm_widget_signal_callback_add(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func, void *data); EAPI void *elm_widget_signal_callback_del(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func); EAPI void elm_widget_can_focus_set(Evas_Object *obj, Eina_Bool can_focus); EAPI Eina_Bool elm_widget_can_focus_get(const Evas_Object *obj); EAPI Eina_Bool elm_widget_child_can_focus_get(const Evas_Object *obj); EAPI Eina_List *elm_widget_can_focus_child_list_get(const Evas_Object *obj); EAPI void elm_widget_tree_unfocusable_set(Evas_Object *obj, Eina_Bool tree_unfocusable); EAPI Eina_Bool elm_widget_tree_unfocusable_get(const Evas_Object *obj); EAPI void elm_widget_highlight_ignore_set(Evas_Object *obj, Eina_Bool ignore); EAPI Eina_Bool elm_widget_highlight_ignore_get(const Evas_Object *obj); EAPI void elm_widget_highlight_in_theme_set(Evas_Object *obj, Eina_Bool highlight); EAPI Eina_Bool elm_widget_highlight_in_theme_get(const Evas_Object *obj); EAPI void elm_widget_access_highlight_in_theme_set(Evas_Object *obj, Eina_Bool highlight); EAPI Eina_Bool elm_widget_access_highlight_in_theme_get(const Evas_Object *obj); EAPI Eina_Bool elm_widget_focus_get(const Evas_Object *obj); EAPI Eina_Bool elm_widget_highlight_get(const Evas_Object *obj); EAPI Evas_Object *elm_widget_focused_object_get(const Evas_Object *obj); EAPI Evas_Object *elm_widget_top_get(const Evas_Object *obj); EAPI Eina_Bool elm_widget_is(const Evas_Object *obj); EAPI Evas_Object *elm_widget_parent_widget_get(const Evas_Object *obj); EAPI void elm_widget_event_callback_add(Evas_Object *obj, Elm_Event_Cb func, const void *data); EAPI void *elm_widget_event_callback_del(Evas_Object *obj, Elm_Event_Cb func, const void *data); EAPI Eina_Bool elm_widget_event_propagate(Evas_Object *obj, Evas_Callback_Type type, void *event_info, Evas_Event_Flags *event_flags); EAPI void elm_widget_focus_custom_chain_set(Evas_Object *obj, Eina_List *objs); EAPI void elm_widget_focus_custom_chain_unset(Evas_Object *obj); EAPI const Eina_List *elm_widget_focus_custom_chain_get(const Evas_Object *obj); EAPI void elm_widget_focus_custom_chain_append(Evas_Object *obj, Evas_Object *child, Evas_Object *relative_child); EAPI void elm_widget_focus_custom_chain_prepend(Evas_Object *obj, Evas_Object *child, Evas_Object *relative_child); EAPI void elm_widget_focus_cycle(Evas_Object *obj, Elm_Focus_Direction dir); EAPI Eina_Bool elm_widget_focus_direction_go(Evas_Object *obj, double degree); EAPI Eina_Bool elm_widget_focus_direction_get(const Evas_Object *obj, const Evas_Object *base, double degree, Evas_Object **direction, Elm_Object_Item **direction_item, double *weight); EAPI Eina_Bool elm_widget_focus_next_get(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next, Elm_Object_Item **next_item); EAPI Eina_Bool elm_widget_focus_list_direction_get(const Evas_Object *obj, const Evas_Object *base, const Eina_List *items, void *(*list_data_get)(const Eina_List *list), double degree, Evas_Object **direction, Elm_Object_Item **direction_item, double *weight); EAPI Eina_Bool elm_widget_focus_list_next_get(const Evas_Object *obj, const Eina_List *items, void *(*list_data_get)(const Eina_List *list), Elm_Focus_Direction dir, Evas_Object **next, Elm_Object_Item **next_item); EAPI Evas_Object *elm_widget_focus_next_object_get(const Evas_Object *obj, Elm_Focus_Direction dir); EAPI void elm_widget_focus_next_object_set(Evas_Object *obj, Evas_Object *next, Elm_Focus_Direction dir); EAPI Elm_Object_Item *elm_widget_focus_next_item_get(const Evas_Object *obj, Elm_Focus_Direction dir); EAPI void elm_widget_focus_next_item_set(Evas_Object *obj, Elm_Object_Item *next_item, Elm_Focus_Direction dir); EAPI Eina_Bool elm_widget_focus_highlight_style_set(Evas_Object *obj, const char *style); EAPI const char *elm_widget_focus_highlight_style_get(const Evas_Object *obj); EAPI void elm_widget_parent_highlight_set(Evas_Object *obj, Eina_Bool highlighted); EAPI void elm_widget_focus_set(Evas_Object *obj, Eina_Bool focus); EAPI void elm_widget_focused_object_clear(Evas_Object *obj); EAPI Evas_Object *elm_widget_parent_get(const Evas_Object *obj); EAPI Evas_Object *elm_widget_parent2_get(const Evas_Object *obj); EAPI void elm_widget_parent2_set(Evas_Object *obj, Evas_Object *parent); EAPI void elm_widget_focus_steal(Evas_Object *obj, Elm_Object_Item *next_item); EAPI Evas_Object *elm_widget_newest_focus_order_get(const Evas_Object *obj, unsigned int *newest_focus_order, Eina_Bool can_focus_only); EAPI void elm_widget_display_mode_set(Evas_Object *obj, Evas_Display_Mode dispmode); EAPI Eina_Bool elm_widget_focus_highlight_enabled_get(const Evas_Object *obj); EAPI void elm_widget_focus_highlight_focus_part_geometry_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h); Evas_Object *_elm_widget_focus_highlight_object_get(const Evas_Object *obj); double _elm_widget_focus_direction_weight_get(const Evas_Object *obj1, const Evas_Object *obj2, double degree); EAPI const Elm_Widget_Smart_Class *elm_widget_smart_class_get(void); /** * @internal * * Restore the focus state of the sub-tree. * * This API will restore the focus state of the sub-tree to the latest * state. If a sub-tree is unfocused and wants to get back to the latest * focus state, this API will be helpful. * * @param obj The widget root of sub-tree * * @ingroup Widget */ EAPI void elm_widget_focus_restore(Evas_Object *obj); EAPI void elm_widget_disabled_set(Evas_Object *obj, Eina_Bool disabled); EAPI Eina_Bool elm_widget_disabled_get(const Evas_Object *obj); EAPI void elm_widget_show_region_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, Eina_Bool forceshow); EAPI void elm_widget_show_region_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h); EAPI Eina_Bool elm_widget_focus_region_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h); EAPI void elm_widget_focus_region_show(const Evas_Object *obj); EAPI void elm_widget_parents_bounce_get(const Evas_Object *obj, Eina_Bool *horiz, Eina_Bool *vert); EAPI void elm_widget_scroll_hold_push(Evas_Object *obj); EAPI void elm_widget_scroll_hold_pop(Evas_Object *obj); EAPI int elm_widget_scroll_hold_get(const Evas_Object *obj); EAPI void elm_widget_scroll_freeze_push(Evas_Object *obj); EAPI void elm_widget_scroll_freeze_pop(Evas_Object *obj); EAPI int elm_widget_scroll_freeze_get(const Evas_Object *obj); EAPI void elm_widget_theme_set(Evas_Object *obj, Elm_Theme *th); EAPI Elm_Theme *elm_widget_theme_get(const Evas_Object *obj); EAPI Efl_Ui_Theme_Apply elm_widget_style_set(Evas_Object *obj, const char *style); EAPI const char *elm_widget_style_get(const Evas_Object *obj); EAPI void elm_widget_type_set(Evas_Object *obj, const char *type); EAPI const char *elm_widget_type_get(const Evas_Object *obj); EAPI void elm_widget_tooltip_add(Evas_Object *obj, Elm_Tooltip *tt); EAPI void elm_widget_tooltip_del(Evas_Object *obj, Elm_Tooltip *tt); EAPI void elm_widget_cursor_add(Evas_Object *obj, Elm_Cursor *cur); EAPI void elm_widget_cursor_del(Evas_Object *obj, Elm_Cursor *cur); EAPI void elm_widget_drag_lock_x_set(Evas_Object *obj, Eina_Bool lock); EAPI void elm_widget_drag_lock_y_set(Evas_Object *obj, Eina_Bool lock); EAPI Eina_Bool elm_widget_drag_lock_x_get(const Evas_Object *obj); EAPI Eina_Bool elm_widget_drag_lock_y_get(const Evas_Object *obj); EAPI int elm_widget_drag_child_locked_x_get(const Evas_Object *obj); EAPI int elm_widget_drag_child_locked_y_get(const Evas_Object *obj); EAPI void elm_widget_item_loop_enabled_set(Evas_Object *obj, Eina_Bool enable); EAPI Eina_Bool elm_widget_item_loop_enabled_get(const Evas_Object *obj); EAPI Efl_Ui_Theme_Apply elm_widget_theme_object_set(Evas_Object *obj, Evas_Object *edj, const char *wname, const char *welement, const char *wstyle); EAPI Eina_Bool elm_widget_type_check(const Evas_Object *obj, const char *type, const char *func); EAPI Evas_Object *elm_widget_name_find(const Evas_Object *obj, const char *name, int recurse); EAPI Eina_List *elm_widget_stringlist_get(const char *str); EAPI void elm_widget_stringlist_free(Eina_List *list); EAPI void elm_widget_focus_hide_handle(Evas_Object *obj); EAPI void elm_widget_focus_mouse_up_handle(Evas_Object *obj); EAPI void elm_widget_focus_tree_unfocusable_handle(Evas_Object *obj); EAPI void elm_widget_focus_disabled_handle(Evas_Object *obj); EAPI unsigned int elm_widget_focus_order_get(const Evas_Object *obj); EAPI void elm_widget_activate(Evas_Object *obj, Elm_Activate act); EAPI void elm_widget_part_text_set(Evas_Object *obj, const char *part, const char *label); EAPI const char *elm_widget_part_text_get(const Evas_Object *obj, const char *part); EAPI void elm_widget_domain_translatable_part_text_set(Evas_Object *obj, const char *part, const char *domain, const char *text); EAPI const char *elm_widget_translatable_part_text_get(const Evas_Object *obj, const char *part); EAPI void elm_widget_domain_part_text_translatable_set(Evas_Object *obj, const char *part, const char *domain, Eina_Bool translatable); EAPI const char * elm_widget_part_text_translate(Evas_Object *obj, const char *part, const char *text); EAPI void elm_widget_content_part_set(Evas_Object *obj, const char *part, Evas_Object *content); EAPI Evas_Object *elm_widget_content_part_get(const Evas_Object *obj, const char *part); EAPI Evas_Object *elm_widget_content_part_unset(Evas_Object *obj, const char *part); EAPI void elm_widget_access_info_set(Evas_Object *obj, const char *txt); EAPI const char *elm_widget_access_info_get(const Evas_Object *obj); EAPI void elm_widget_orientation_set(Evas_Object *obj, int rotation); EAPI Elm_Object_Item *elm_widget_focused_item_get(const Evas_Object *obj); EAPI void elm_widget_orientation_mode_disabled_set(Evas_Object *obj, Eina_Bool disabled); EAPI Eina_Bool elm_widget_orientation_mode_disabled_get(const Evas_Object *obj); EAPI void elm_widget_focus_highlight_geometry_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h); void _elm_widget_item_highlight_in_theme(Evas_Object *obj, Elm_Object_Item *it); EAPI void elm_widget_focus_move_policy_set(Evas_Object *obj, Elm_Focus_Move_Policy policy); EAPI Elm_Focus_Move_Policy elm_widget_focus_move_policy_get(const Evas_Object *obj); EAPI Eina_Bool elm_widget_focus_move_policy_automatic_get(const Evas_Object *obj); EAPI void elm_widget_focus_move_policy_automatic_set(Evas_Object *obj, Eina_Bool automatic); EAPI void elm_widget_focus_region_show_mode_set(Evas_Object *obj, Elm_Focus_Region_Show_Mode mode); EAPI Elm_Focus_Region_Show_Mode elm_widget_focus_region_show_mode_get(const Evas_Object *obj); EAPI void elm_widget_focus_reconfigure(Evas_Object *obj); /* debug function. don't use it unless you are tracking parenting issues */ EAPI void elm_widget_tree_dump(const Evas_Object *top); EAPI void elm_widget_tree_dot_dump(const Evas_Object *top, FILE *output); EAPI Eina_Bool _elm_widget_onscreen_is(Evas_Object *widget); EAPI Eina_Bool _elm_widget_item_onscreen_is(Elm_Object_Item *item); #define ELM_WIDGET_DATA_GET_OR_RETURN(o, ptr, ...) \ Elm_Widget_Smart_Data *ptr; \ ptr = efl_data_scope_get(o, ELM_WIDGET_CLASS); \ if (EINA_UNLIKELY(!ptr)) \ { \ CRI("no widget data for object %p (%s)", \ o, evas_object_type_get(o)); \ return __VA_ARGS__; \ } #define ELM_WIDGET_CHECK(obj) \ if (EINA_UNLIKELY(!efl_isa((obj), ELM_WIDGET_CLASS))) \ return #define ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, ...) \ do { \ if (item && (item)->on_deletion) { \ WRN("Elm_Widget_Item " # item " is deleting"); \ return __VA_ARGS__; \ } \ } while (0) #define ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, ...) \ do { \ if (!item) { \ CRI("Elm_Widget_Item " # item " is NULL"); \ return __VA_ARGS__; \ } \ if ((item)->eo_obj && \ efl_isa((item)->eo_obj, ELM_WIDGET_ITEM_CLASS)) break; \ if (!EINA_MAGIC_CHECK(item, ELM_WIDGET_ITEM_MAGIC)) { \ EINA_MAGIC_FAIL(item, ELM_WIDGET_ITEM_MAGIC); \ return __VA_ARGS__; \ } \ } while (0) #define ELM_WIDGET_ITEM_CHECK_OR_GOTO(item, label) \ do { \ if (!item) { \ CRI("Elm_Widget_Item " # item " is NULL"); \ goto label; \ } \ if ((item)->eo_obj && \ efl_isa((item)->eo_obj, ELM_WIDGET_ITEM_CLASS)) break; \ if (!EINA_MAGIC_CHECK(item, ELM_WIDGET_ITEM_MAGIC)) { \ EINA_MAGIC_FAIL(item, ELM_WIDGET_ITEM_MAGIC); \ goto label; \ } \ } while (0) static inline Eina_Bool _elm_widget_sub_object_redirect_to_top(Evas_Object *obj, Evas_Object *sobj) { Eina_Bool ret = elm_widget_sub_object_del(obj, sobj); if (ret) ret = elm_widget_sub_object_add(elm_widget_top_get(obj), sobj); return ret; } +static inline Eina_Bool +elm_widget_is_legacy(const Eo *obj) +{ + Elm_Widget_Smart_Data *sd = (Elm_Widget_Smart_Data *) + efl_data_scope_safe_get(obj, ELM_WIDGET_CLASS); + return sd ? sd->legacy : EINA_FALSE; +} + /* to be used by INTERNAL classes on Elementary, so that the widgets * parsing script skips it */ #define ELM_INTERNAL_SMART_SUBCLASS_NEW EVAS_SMART_SUBCLASS_NEW EAPI Eina_Bool elm_selection_selection_has_owner(Evas_Object *obj); EAPI Eina_Bool _elm_layout_part_aliasing_eval(const Evas_Object *obj, const char **part, Eina_Bool is_text); /* Internal EO APIs */ const char *elm_widget_default_content_part_get(const Eo *obj); const char *elm_widget_default_text_part_get(const Eo *obj); #define ELM_WIDGET_ITEM_PROTECTED #include "elm_widget_item.eo.h" #endif