From fb48db4d9dfb0337b6d5d4386271c834b206b463 Mon Sep 17 00:00:00 2001 From: Cedric BAIL Date: Fri, 26 Jan 2018 16:56:53 -0800 Subject: [PATCH] elementary: migrate Efl.Ui.Layout to use the new Efl.Model API. --- src/lib/elementary/efl_ui_layout_object.c | 346 ++++++++++++++---------------- src/lib/elementary/elm_widget_layout.h | 14 +- 2 files changed, 173 insertions(+), 187 deletions(-) diff --git a/src/lib/elementary/efl_ui_layout_object.c b/src/lib/elementary/efl_ui_layout_object.c index 9f4a241..8833e47 100644 --- a/src/lib/elementary/efl_ui_layout_object.c +++ b/src/lib/elementary/efl_ui_layout_object.c @@ -814,7 +814,6 @@ _efl_ui_layout_efl_canvas_group_group_del(Eo *obj, Efl_Ui_Layout_Object_Data *sd { Efl_Ui_Layout_Sub_Object_Data *sub_d; Efl_Ui_Layout_Sub_Object_Cursor *pc; - Efl_Ui_Layout_Sub_Connect *sc; Edje_Signal_Data *esd; Evas_Object *child; Eina_List *l; @@ -853,24 +852,20 @@ _efl_ui_layout_efl_canvas_group_group_del(Eo *obj, Efl_Ui_Layout_Object_Data *sd free(esd); } - if(sd->model) + if(sd->connect.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; + efl_event_callback_del(sd->connect.model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, + _efl_model_properties_changed_cb, sd); + efl_unref(sd->connect.model); + sd->connect.model = NULL; } - EINA_LIST_FREE(sd->prop_connect, sc) - { - if (sc->future) efl_future_cancel(sc->future); - sc->future = NULL; - eina_stringshare_del(sc->name); - eina_stringshare_del(sc->property); - free(sc); - } - sd->prop_connect = NULL; - eina_hash_free(sd->factories); - sd->factories = NULL; + eina_hash_free(sd->connect.properties); + sd->connect.properties = NULL; + eina_hash_free(sd->connect.signals); + sd->connect.signals = NULL; + eina_hash_free(sd->connect.factories); + sd->connect.factories = NULL; /* let's make our Edje object the *last* to be processed, since it * may (smart) parent other sub objects here */ @@ -1311,9 +1306,8 @@ _efl_ui_layout_text_generic_set(Eo *obj, Efl_Ui_Layout_Object_Data *sd, const ch { ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE); - Eina_List *l; Efl_Ui_Layout_Sub_Object_Data *sub_d = NULL; - Efl_Ui_Layout_Sub_Connect *sc; + Eina_List *l; EINA_LIST_FOREACH(sd->subs, l, sub_d) { @@ -1378,19 +1372,18 @@ _efl_ui_layout_text_generic_set(Eo *obj, Efl_Ui_Layout_Object_Data *sd, const ch sub_d->obj = _elm_access_edje_object_part_object_register (obj, elm_layout_edje_get(obj), part); - if (sd->model) + if (sd->connect.model && !sd->connect.updating) { - EINA_LIST_FOREACH(sd->prop_connect, l, sc) + char *property = eina_hash_find(sd->connect.properties, sub_d->part); + + if (property) { - if (sc->name == sub_d->part && !sd->view_updated) - { - Eina_Value v; - eina_value_setup(&v, EINA_VALUE_TYPE_STRING); - eina_value_set(&v, text); - efl_model_property_set(sd->model, sc->property, &v); - eina_value_flush(&v); - break; - } + Eina_Value v = EINA_VALUE_EMPTY; + + eina_value_setup(&v, EINA_VALUE_TYPE_STRING); + eina_value_set(&v, text); + + efl_model_property_set(sd->connect.model, property, &v); } } @@ -2022,237 +2015,224 @@ _efl_ui_layout_efl_object_dbg_info_get(Eo *eo_obj, Efl_Ui_Layout_Object_Data *_p } static void -_prop_future_error_cb(void* data, Efl_Event const*event EINA_UNUSED) +_efl_ui_layout_view_model_property_update(Efl_Ui_Layout_Object_Data *pd, const char *part, const char *fetch) { - Efl_Ui_Layout_Sub_Connect *sc = data; - sc->future = NULL; + Eina_Value *v = NULL; + char *value; + + v = efl_model_property_get(pd->connect.model, fetch); + value = eina_value_to_string(v); + + pd->connect.updating = EINA_TRUE; // Prevent recursive call to property_set while updating text + efl_text_set(efl_part(pd->obj, part), value); + pd->connect.updating = EINA_FALSE; + + eina_value_free(v); + free(value); } static void -_view_update(Efl_Ui_Layout_Sub_Connect *sc, const char *property) +_efl_ui_layout_view_model_signal_update(Efl_Ui_Layout_Object_Data *pd, const char *signal, const char *fetch) { + Eina_Value *v = NULL; Eina_Strbuf *buf; + char *value; - if (sc->is_signal == EINA_FALSE) + v = efl_model_property_get(pd->connect.model, fetch); + + // FIXME: previous implementation would just do that for signal/part == "selected" + if (eina_value_type_get(v) == EINA_VALUE_TYPE_UCHAR) { - EFL_UI_LAYOUT_DATA_GET(sc->obj, pd); - pd->view_updated = EINA_TRUE; - elm_layout_text_set(sc->obj, sc->name, property); - pd->view_updated = EINA_FALSE; - return; + Eina_Bool bl; + + eina_value_bool_get(v, &bl); + if (bl) value = strdup("selected"); + else value = strdup("unselected"); + } + else + { + value = eina_value_to_string(v); } buf = eina_strbuf_new(); - eina_strbuf_append(buf, sc->name); - eina_strbuf_replace_all(buf, "%v", property); + // FIXME: is it really the form of signal we want to send ? + eina_strbuf_append_printf(buf, "%s%s", signal, value); + elm_layout_signal_emit(pd->obj, eina_strbuf_string_get(buf), + elm_widget_is_legacy(pd->obj) ? "elm" : "efl"); - if (elm_widget_is_legacy(sc->obj)) - elm_layout_signal_emit(sc->obj, eina_strbuf_string_get(buf), "elm"); - else - elm_layout_signal_emit(sc->obj, eina_strbuf_string_get(buf), "efl"); eina_strbuf_free(buf); + eina_value_free(v); + free(value); } static void -_prop_future_then_cb(void* data, Efl_Event const*event) +_efl_ui_layout_view_model_content_update(Efl_Ui_Layout_Object_Data *pd, Efl_Ui_Factory *factory, const char *name) { - Efl_Ui_Layout_Sub_Connect *sc = data; - const Eina_Value_Type *vtype; - Eina_Value *value = (Eina_Value *)((Efl_Future_Event_Success*)event->info)->value; - Eina_Stringshare *selected; - char *text; + Efl_Gfx_Entity *content; - sc->future = NULL; - vtype= eina_value_type_get(value); - - if (vtype == EINA_VALUE_TYPE_STRING || vtype == EINA_VALUE_TYPE_STRINGSHARE) - { - eina_value_get(value, &text); - _view_update(sc, text); - return; - } - - selected = eina_stringshare_add("selected"); - if (vtype == EINA_VALUE_TYPE_UCHAR && sc->property == selected) - { - Eina_Bool sb = EINA_FALSE; - eina_value_get(value, &sb); - if (sb) - _view_update(sc, "selected"); - else - _view_update(sc, "unselected"); - } - else - { - text = eina_value_to_string(value); - _view_update(sc, text); - free(text); - } - - eina_stringshare_del(selected); + content = efl_ui_factory_create(factory, pd->connect.model, pd->obj); + elm_layout_content_set(pd->obj, name, content); } static void _efl_ui_layout_view_model_update(Efl_Ui_Layout_Object_Data *pd) { - Efl_Ui_Layout_Sub_Connect *sc; - Eina_List *l; + Eina_Hash_Tuple *tuple; + Eina_Iterator *it; - if (!pd->prop_connect || !pd->model) return; + if (!pd->connect.model) return ; - EINA_LIST_FOREACH(pd->prop_connect, l, sc) - { - if (sc->future) efl_future_cancel(sc->future); - sc->future = efl_model_property_get(pd->model, sc->property); - efl_future_then(sc->future, &_prop_future_then_cb, &_prop_future_error_cb, NULL, sc); - } + it = eina_hash_iterator_tuple_new(pd->connect.properties); + EINA_ITERATOR_FOREACH(it, tuple) + _efl_ui_layout_view_model_property_update(pd, tuple->data, tuple->key); + eina_iterator_free(it); + + it = eina_hash_iterator_tuple_new(pd->connect.signals); + EINA_ITERATOR_FOREACH(it, tuple) + _efl_ui_layout_view_model_signal_update(pd, tuple->data, tuple->key); + eina_iterator_free(it); + + it = eina_hash_iterator_tuple_new(pd->connect.factories); + EINA_ITERATOR_FOREACH(it, tuple) + _efl_ui_layout_view_model_content_update(pd, tuple->data, tuple->key); + eina_iterator_free(it); } static void _efl_model_properties_changed_cb(void *data, const Efl_Event *event) { - Efl_Ui_Layout_Object_Data *pd = data; Efl_Model_Property_Event *evt = event->info; - Eina_Stringshare *ss_prop; - Efl_Ui_Layout_Sub_Connect *sc; + Efl_Ui_Layout_Object_Data *pd = data; const char *prop; Eina_Array_Iterator it; unsigned int i; - Eina_List *l; - if (!evt->changed_properties || !pd->prop_connect) return; + if (!evt->changed_properties) return ; EINA_ARRAY_ITER_NEXT(evt->changed_properties, i, prop, it) { - ss_prop = eina_stringshare_add(prop); - EINA_LIST_FOREACH(pd->prop_connect, l, sc) - { - if (sc->property == ss_prop) - { - if (sc->future) efl_future_cancel(sc->future); - sc->future = efl_model_property_get(pd->model, sc->property); - efl_future_then(sc->future, &_prop_future_then_cb, &_prop_future_error_cb, NULL, sc); - } - } - eina_stringshare_del(ss_prop); + Eina_Stringshare *sprop = eina_stringshare_add(prop); + const char *part; + const char *signal; + Efl_Ui_Factory *factory; + + part = eina_hash_find(pd->connect.properties, sprop); + if (part) _efl_ui_layout_view_model_property_update(pd, part, sprop); + + signal = eina_hash_find(pd->connect.signals, sprop); + if (signal) _efl_ui_layout_view_model_signal_update(pd, signal, sprop); + + factory = eina_hash_find(pd->connect.factories, sprop); + if (factory) _efl_ui_layout_view_model_content_update(pd, factory, sprop); + + eina_stringshare_del(sprop); } } -EOLIAN static void -_efl_ui_layout_object_efl_ui_view_model_set(Eo *obj EINA_UNUSED, Efl_Ui_Layout_Object_Data *pd, Efl_Model *model) +static void +_efl_ui_layout_connect_hash(Efl_Ui_Layout_Object_Data *pd) { - Efl_Ui_Layout_Sub_Connect *sc; - Eina_List *l; + if (pd->connect.properties) return ; - if (pd->model) - { - efl_event_callback_del(pd->model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _efl_model_properties_changed_cb, pd); - EINA_LIST_FOREACH(pd->prop_connect, l, sc) - if (sc->future) efl_future_cancel(sc->future); + // FIXME: fix destruction function definition + pd->connect.properties = eina_hash_stringshared_new(NULL); // Hash of property targeting a part + pd->connect.signals = eina_hash_stringshared_new(NULL); // Hash of property triggering a signal + pd->connect.factories = eina_hash_stringshared_new(EINA_FREE_CB(efl_unref)); // Hash of property triggering a content creation +} - efl_unref(pd->model); - pd->model = NULL; - } +EOLIAN static void +_efl_ui_layout_object_efl_ui_view_model_set(Eo *obj, Efl_Ui_Layout_Object_Data *pd, Efl_Model *model) +{ + Eina_Stringshare *name; + Eina_Hash_Tuple *tuple; + Eina_Iterator *it; + + efl_replace(&pd->connect.model, model); 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); + efl_event_callback_add(pd->connect.model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, + _efl_model_properties_changed_cb, pd); } - else - { - EINA_LIST_FOREACH(pd->prop_connect, l, sc) - { - if (!sc->is_signal) - elm_layout_text_set(obj, sc->name, NULL); - } - return; - } + _efl_ui_layout_connect_hash(pd); - if (pd->prop_connect) - _efl_ui_layout_view_model_update(pd); + // Reset to empty state + it = eina_hash_iterator_key_new(pd->connect.properties); + EINA_ITERATOR_FOREACH(it, name) + { + efl_text_set(efl_part(obj, name), NULL); + } + eina_iterator_free(it); - if (pd->factories) + it = eina_hash_iterator_tuple_new(pd->connect.factories); + EINA_ITERATOR_FOREACH(it, tuple) { - Eina_Hash_Tuple *tuple; - Eina_Stringshare *name; - Efl_Ui_Factory *factory; - Efl_Gfx_Entity *content; + Efl_Ui_Factory *factory; + Efl_Gfx_Entity *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); + name = tuple->key; + factory = tuple->data; + content = elm_layout_content_get(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); + elm_layout_content_set(obj, name, NULL); + efl_ui_factory_release(factory, content); } + eina_iterator_free(it); + + // Refresh content if necessary + _efl_ui_layout_view_model_update(pd); } EOLIAN static Efl_Model * _efl_ui_layout_object_efl_ui_view_model_get(const Eo *obj EINA_UNUSED, Efl_Ui_Layout_Object_Data *pd) { - return pd->model; + return pd->connect.model; } EOLIAN static void _efl_ui_layout_object_efl_ui_model_connect_connect(Eo *obj EINA_UNUSED, Efl_Ui_Layout_Object_Data *pd, const char *name, const char *property) { EINA_SAFETY_ON_NULL_RETURN(name); - EINA_SAFETY_ON_NULL_RETURN(property); - Efl_Ui_Layout_Sub_Connect *sc, *fsc; - Eina_List *l; + Eina_Stringshare *sprop; + Eina_Hash *hash = NULL; + char *data = NULL; if (!_elm_layout_part_aliasing_eval(obj, &name, EINA_TRUE)) return; - sc = calloc(1, sizeof(*sc)); - sc->obj = obj; - sc->property = eina_stringshare_add(property); + _efl_ui_layout_connect_hash(pd); + + sprop = eina_stringshare_add(property); - if (strncmp(SIGNAL_PREFIX, name, sizeof(SIGNAL_PREFIX) -1) == 0) + // FIXME: prevent double connect of name to multiple property ? + if (strncmp(SIGNAL_PREFIX, name, sizeof(SIGNAL_PREFIX) - 1) == 0) { - sc->name = eina_stringshare_add(name+sizeof(SIGNAL_PREFIX) -1); - sc->is_signal = EINA_TRUE; + hash = pd->connect.signals; + data = strdup(name + sizeof(SIGNAL_PREFIX) - 1); } else { - sc->name = eina_stringshare_add(name); - sc->is_signal = EINA_FALSE; + hash = pd->connect.properties; + data = strdup(name); } - EINA_LIST_FOREACH(pd->prop_connect, l, fsc) + if (!sprop) { - if (fsc->name == sc->name && fsc->property == sc->property) - { - eina_stringshare_del(sc->name); - eina_stringshare_del(sc->property); - free(sc); - return; - } + // FIXME: remove the entry from the hash ? } - - pd->prop_connect = eina_list_append(pd->prop_connect, sc); - - if (pd->model) + else { - sc->future = efl_model_property_get(pd->model, sc->property); - efl_future_then(sc->future, &_prop_future_then_cb, &_prop_future_error_cb, NULL, sc); + eina_hash_add(hash, sprop, data); } + + // Update display right away if possible + if (!pd->connect.model) return ; + + if (hash == pd->connect.signals) + _efl_ui_layout_view_model_signal_update(pd, data, sprop); + else + _efl_ui_layout_view_model_property_update(pd, data, sprop); } EOLIAN static void @@ -2269,13 +2249,13 @@ _efl_ui_layout_object_efl_ui_factory_model_connect(Eo *obj EINA_UNUSED, Efl_Ui_L ss_name = eina_stringshare_add(name); - if (!pd->factories) - pd->factories = eina_hash_stringshared_new(EINA_FREE_CB(efl_unref)); + if (!pd->connect.factories) + pd->connect.factories = eina_hash_stringshared_new(EINA_FREE_CB(efl_unref)); - new_ev = efl_ui_factory_create(factory, pd->model, obj); + new_ev = efl_ui_factory_create(factory, pd->connect.model, obj); EINA_SAFETY_ON_NULL_RETURN(new_ev); - old_factory = eina_hash_set(pd->factories, ss_name, efl_ref(factory)); + old_factory = eina_hash_set(pd->connect.factories, ss_name, efl_ref(factory)); if (old_factory) { old_ev = elm_layout_content_get(obj, name); diff --git a/src/lib/elementary/elm_widget_layout.h b/src/lib/elementary/elm_widget_layout.h index a0833b6..5b87179 100644 --- a/src/lib/elementary/elm_widget_layout.h +++ b/src/lib/elementary/elm_widget_layout.h @@ -53,9 +53,16 @@ typedef struct _Elm_Layout_Smart_Data Eina_List *subs; /**< List of Elm_Layout_Sub_Object_Data structs, to hold the actual sub objects such as text, content and the children of box and table. */ Eina_List *edje_signals; /**< The list of edje signal callbacks. */ Eina_List *parts_cursors; /**< The list of cursor names of layout parts. This is a list of Elm_Layout_Sub_Object_Cursor struct. */ - Eina_List *prop_connect; /**< The list of properties connected to layout parts. */ - Eina_Hash *factories; /**< The hash with parts connected to factories. */ - Efl_Model *model; /**< The model */ + + struct { + Eina_Hash *properties; /**< The list of properties connected to layout parts. */ + Eina_Hash *signals; /**< The list of signals connected. */ + Eina_Hash *factories; /**< The hash with parts connected to factories. */ + Efl_Model *model; /**< The model */ + + Eina_Bool updating : 1; + } connect; + int frozen; /**< Layout freeze counter */ Eina_Bool needs_size_calc : 1; /**< This flas is set true when the layout sizing eval is already requested. This defers sizing evaluation until smart calculation to avoid unnecessary calculation. */ @@ -64,7 +71,6 @@ typedef struct _Elm_Layout_Smart_Data Eina_Bool can_access : 1; /**< This is true when all text(including textblock) parts can be accessible by accessibility. */ Eina_Bool destructed_is : 1; /**< This flag indicates if Efl.Ui.Layout destructor was called. This is needed to avoid unnecessary calculation of subobject deletion during layout object's deletion. */ Eina_Bool file_set : 1; /**< This flag indicates if Efl.Ui.Layout source is set from a file*/ - Eina_Bool view_updated : 1; /**< This flag indicates to Efl.Ui.Layout don't update model in text_set */ } Efl_Ui_Layout_Object_Data; /** -- 2.7.4