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 <vitorsousa@expertisesolutions.com.br>
Differential Revision: https://phab.enlightenment.org/D7941
This commit is contained in:
Cedric BAIL 2019-02-11 18:28:22 -08:00
parent cbd8c45afe
commit d1d30f442b
3 changed files with 194 additions and 1 deletions

View File

@ -5940,6 +5940,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 */

View File

@ -16,7 +16,8 @@ struct Efl.Ui.Widget_Focus_State {
abstract @beta Efl.Ui.Widget extends Efl.Canvas.Group implements Efl.Access.Object,
Efl.Access.Component, Efl.Part, Efl.Ui.Focus.Object,
Efl.Ui.L10n,
Efl.Ui.Selection, Efl.Ui.Dnd
Efl.Ui.Selection, Efl.Ui.Dnd,
Efl.Ui.Property_Bind, Efl.Ui.View
{
[[Efl UI widget abstract class]]
//eo_prefix: efl_ui_widget;
@ -388,6 +389,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;
@ -415,6 +417,8 @@ abstract @beta Efl.Ui.Widget extends Efl.Canvas.Group implements Efl.Access.Obje
Efl.Ui.Focus.Object.on_focus_update;
Efl.Ui.L10n.translation_update; [[This implements the calls to $gettext() and $text_set().]]
Efl.Part.part_get; [[Returns @Efl.Ui.Widget_Part.]]
Efl.Ui.View.model { get; set; }
Efl.Ui.Property_Bind.property_bind;
}
constructors {
.style @optional;

View File

@ -383,6 +383,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;