From 96a61a6d1150063e3efd610aeef3bb326c95cf2c Mon Sep 17 00:00:00 2001 From: Cedric BAIL Date: Mon, 11 Feb 2019 18:28:22 -0800 Subject: [PATCH] elementary: implemente property_bind support on all widget using property reflection. This means that all property that are registered in the reflection table of any Eo class will be available for binding with a model. This will increase the amount of useful binding quickly. Reviewed-by: Vitor Sousa da Silva Differential Revision: https://phab.enlightenment.org/D7941 Change-Id: Ia938748ab83c9a9fc0afcff5bd65b57fb9780312 --- src/lib/elementary/efl_ui_widget.c | 184 ++++++++++++++++++++++++++++++++++++ src/lib/elementary/efl_ui_widget.eo | 4 + src/lib/elementary/elm_widget.h | 5 + 3 files changed, 193 insertions(+) diff --git a/src/lib/elementary/efl_ui_widget.c b/src/lib/elementary/efl_ui_widget.c index eac485b..7612e06 100644 --- a/src/lib/elementary/efl_ui_widget.c +++ b/src/lib/elementary/efl_ui_widget.c @@ -6509,6 +6509,190 @@ _efl_ui_widget_part_bg_efl_gfx_image_scale_type_get(const Eo *obj, void *pd EINA return efl_gfx_image_scale_type_get(bg_obj); } +typedef struct _Efl_Ui_Property_Bound Efl_Ui_Property_Bound; +struct _Efl_Ui_Property_Bound +{ + Eina_Stringshare *key; // Local object property + Eina_Stringshare *property; // Model property + Eina_Future *f; +}; + +static void +_efl_ui_property_bind_free(void *data) +{ + Efl_Ui_Property_Bound *prop = data; + + eina_stringshare_del(prop->key); + eina_stringshare_del(prop->property); + free(prop); +} + +static void +_efl_ui_property_bind_clean(Eo *obj EINA_UNUSED, + void *data, + const Eina_Future *f EINA_UNUSED) +{ + Efl_Ui_Property_Bound *prop = data; + + prop->f = NULL; +} + +static void +_efl_ui_property_bind_get(Efl_Ui_Widget_Data *pd, Efl_Ui_Property_Bound *prop) +{ + Eina_Value *value = efl_model_property_get(pd->properties.model, prop->property); + Eina_Future *f; + Eina_Error err; + + err = efl_property_reflection_set(pd->obj, prop->key, eina_value_reference_copy(value)); + eina_value_free(value); + + if (!err) return ; + + // Report back the error to the model + if (prop->f) eina_future_cancel(prop->f); + f = efl_model_property_set(pd->properties.model, prop->property, + eina_value_error_new(err)); + prop->f = efl_future_then(pd->obj, f, .free = _efl_ui_property_bind_clean, .data = prop); +} + +static void +_efl_ui_property_bind_set(Efl_Ui_Widget_Data *pd, Efl_Ui_Property_Bound *prop) +{ + Eina_Value value = efl_property_reflection_get(pd->obj, prop->key); + Eina_Future *f; + + if (prop->f) eina_future_cancel(prop->f); + f = efl_model_property_set(pd->properties.model, prop->property, eina_value_dup(&value)); + prop->f = efl_future_then(pd->obj, f, .free = _efl_ui_property_bind_clean, .data = prop); + eina_value_flush(&value); +} + +static void +_efl_ui_model_property_bind_changed(void *data, const Efl_Event *event) +{ + Efl_Model_Property_Event *evt = event->info; + Efl_Ui_Widget_Data *pd = data; + Eina_Array_Iterator it; + const char *prop; + unsigned int i; + + EINA_ARRAY_ITER_NEXT(evt->changed_properties, i, prop, it) + { + Eina_Stringshare *sp = eina_stringshare_add(prop); + Efl_Ui_Property_Bound *lookup; + + lookup = eina_hash_find(pd->properties.model_lookup, sp); + if (lookup) _efl_ui_property_bind_get(pd, lookup); + eina_stringshare_del(sp); + } +} + +static void +_efl_ui_view_property_bind_changed(void *data, const Efl_Event *event) +{ + Efl_Ui_Property_Event *evt = event->info; + Efl_Ui_Widget_Data *pd = data; + Eina_Array_Iterator it; + Eina_Stringshare *prop; + unsigned int i; + + EINA_ARRAY_ITER_NEXT(evt->changed_properties, i, prop, it) + { + Efl_Ui_Property_Bound *lookup; + + lookup = eina_hash_find(pd->properties.view_lookup, prop); + if (lookup) _efl_ui_property_bind_set(pd, lookup); + } +} + +static Eina_Error +_efl_ui_widget_efl_ui_property_bind_property_bind(Eo *obj, Efl_Ui_Widget_Data *pd, + const char *key, const char *property) +{ + Efl_Ui_Property_Bound *prop; + + // Check if the property is available from the reflection table of the object. + if (!efl_property_reflection_exist(obj, key)) return EFL_PROPERTY_ERROR_INVALID_KEY; + + if (!pd->properties.model_lookup) + { + pd->properties.model_lookup = eina_hash_stringshared_new(_efl_ui_property_bind_free); + pd->properties.view_lookup = eina_hash_stringshared_new(NULL); + if (pd->properties.model) + { + efl_event_callback_add(pd->properties.model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, + _efl_ui_model_property_bind_changed, pd); + efl_event_callback_add(obj, EFL_UI_PROPERTY_BIND_EVENT_PROPERTIES_CHANGED, + _efl_ui_view_property_bind_changed, pd); + } + } + + prop = calloc(1, sizeof (Efl_Ui_Property_Bound)); + if (!prop) return ENOMEM; + prop->key = eina_stringshare_add(key); + prop->property = eina_stringshare_add(property); + + eina_hash_direct_add(pd->properties.model_lookup, prop->property, prop); + eina_hash_direct_add(pd->properties.view_lookup, prop->key, prop); + + _efl_ui_property_bind_get(pd, prop); + + + return 0; +} + +static void +_efl_ui_widget_efl_ui_view_model_set(Eo *obj, + Efl_Ui_Widget_Data *pd, + Efl_Model *model) +{ + if (pd->properties.model) + { + // Remove any existing handler that might exist for any reason + efl_event_callback_del(pd->properties.model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, + _efl_ui_model_property_bind_changed, pd); + efl_event_callback_del(obj, EFL_UI_PROPERTY_BIND_EVENT_PROPERTIES_CHANGED, + _efl_ui_view_property_bind_changed, pd); + } + + efl_replace(&pd->properties.model, model); + + if (pd->properties.model && pd->properties.model_lookup) + { + // Set the properties handler just in case + efl_event_callback_add(pd->properties.model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, + _efl_ui_model_property_bind_changed, pd); + efl_event_callback_add(obj, EFL_UI_PROPERTY_BIND_EVENT_PROPERTIES_CHANGED, + _efl_ui_view_property_bind_changed, pd); + } +} + +static Efl_Model * +_efl_ui_widget_efl_ui_view_model_get(const Eo *obj EINA_UNUSED, Efl_Ui_Widget_Data *pd) +{ + return pd->properties.model; +} + +static void +_efl_ui_widget_efl_object_invalidate(Eo *obj, Efl_Ui_Widget_Data *pd) +{ + efl_invalidate(efl_super(obj, EFL_UI_WIDGET_CLASS)); + + if (pd->properties.model) + { + efl_event_callback_del(pd->properties.model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, + _efl_ui_model_property_bind_changed, pd); + efl_event_callback_del(obj, EFL_UI_PROPERTY_BIND_EVENT_PROPERTIES_CHANGED, + _efl_ui_view_property_bind_changed, pd); + efl_replace(&pd->properties.model, NULL); + } + if (pd->properties.view_lookup) eina_hash_free(pd->properties.view_lookup); + pd->properties.view_lookup = NULL; + if (pd->properties.model_lookup) eina_hash_free(pd->properties.model_lookup); + pd->properties.model_lookup = NULL; +} + #include "efl_ui_widget_part_bg.eo.c" /* Efl.Part Bg end */ diff --git a/src/lib/elementary/efl_ui_widget.eo b/src/lib/elementary/efl_ui_widget.eo index a107754..5b6b52c 100644 --- a/src/lib/elementary/efl_ui_widget.eo +++ b/src/lib/elementary/efl_ui_widget.eo @@ -23,6 +23,7 @@ abstract @beta Efl.Ui.Widget extends Efl.Canvas.Group implements Efl.Access.Obje Efl.Access.Component, Efl.Part, Efl.Ui.Focus.Object, Efl.Ui.L10n, Efl.Ui.Selection, Efl.Ui.Dnd, + Efl.Ui.Property_Bind, Efl.Ui.View, //TIZEN_ONLY(20160527): widget: add AtspiAction interface to all widgets Efl.Access.Widget.Action // @@ -652,6 +653,7 @@ abstract @beta Efl.Ui.Widget extends Efl.Canvas.Group implements Efl.Access.Obje class.constructor; Efl.Object.constructor; Efl.Object.finalize; + Efl.Object.invalidate; Efl.Object.destructor; Efl.Object.provider_find; Efl.Object.debug_name_override; @@ -716,6 +718,8 @@ abstract @beta Efl.Ui.Widget extends Efl.Canvas.Group implements Efl.Access.Obje /******* * END * *******/ + Efl.Ui.View.model { get; set; } + Efl.Ui.Property_Bind.property_bind; } constructors { .style @optional; diff --git a/src/lib/elementary/elm_widget.h b/src/lib/elementary/elm_widget.h index 9a6472a..415c2d5 100644 --- a/src/lib/elementary/elm_widget.h +++ b/src/lib/elementary/elm_widget.h @@ -409,6 +409,11 @@ typedef struct _Elm_Widget_Smart_Data Evas_Object *prev, *next, *up, *down, *right, *left; Elm_Object_Item *item_prev, *item_next, *item_up, *item_down, *item_right, *item_left; } legacy_focus; + struct { + Efl_Model *model; + Eina_Hash *model_lookup; + Eina_Hash *view_lookup; + } properties; Eina_Bool scroll_x_locked : 1; Eina_Bool scroll_y_locked : 1; -- 2.7.4