forked from enlightenment/efl
efl: add a Efl.Model_Provider that every widget will look up for in their parent tree.
This is done to simplify code as you only need to set the model on the provider and all the widget that are using it as a provider will automatically be updated. The child will find a provider during at the time the first property binding is set on the widget by checking if the parent have an Efl.Model_Provider set. It is not necessary to set a model to have a valid lookup on a Efl.Model_Provider. To disable a widget lookup, you can just force set a model on it (even NULL) and it will disable the lookup. Reviewed-by: Marcel Hollerbach <mail@marcel-hollerbach.de> Differential Revision: https://phab.enlightenment.org/D9290
This commit is contained in:
parent
a68e18a903
commit
2d481d8593
|
@ -147,6 +147,7 @@ typedef Efl_Gfx_Path_Command_Type Efl_Gfx_Path_Command;
|
|||
#include "interfaces/efl_ui_property_bind.eo.h"
|
||||
#include "interfaces/efl_ui_factory.eo.h"
|
||||
#include "interfaces/efl_ui_factory_bind.eo.h"
|
||||
#include "interfaces/efl_model_provider.eo.h"
|
||||
#include "interfaces/efl_cached_item.eo.h"
|
||||
|
||||
/* Observable interface */
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "Efl.h"
|
||||
|
||||
typedef struct _Efl_Model_Provider_Data Efl_Model_Provider_Data;
|
||||
struct _Efl_Model_Provider_Data
|
||||
{
|
||||
Efl_Model *model;
|
||||
};
|
||||
|
||||
static void
|
||||
_efl_model_provider_efl_ui_view_model_set(Eo *obj, Efl_Model_Provider_Data *pd,
|
||||
Efl_Model *model)
|
||||
{
|
||||
Efl_Model_Changed_Event ev;
|
||||
|
||||
ev.previous = efl_ref(pd->model);
|
||||
ev.current = efl_ref(model);
|
||||
efl_replace(&pd->model, model);
|
||||
|
||||
efl_event_callback_call(obj, EFL_UI_VIEW_EVENT_MODEL_CHANGED, &ev);
|
||||
|
||||
efl_unref(ev.previous);
|
||||
efl_unref(ev.current);
|
||||
}
|
||||
|
||||
static Efl_Model *
|
||||
_efl_model_provider_efl_ui_view_model_get(const Eo *obj EINA_UNUSED,
|
||||
Efl_Model_Provider_Data *pd)
|
||||
{
|
||||
return pd->model;
|
||||
}
|
||||
|
||||
#include "efl_model_provider.eo.c"
|
|
@ -0,0 +1,12 @@
|
|||
class @beta Efl.Model_Provider extends Efl.Object implements Efl.Ui.View
|
||||
{
|
||||
[[EFL object that provide a model to all.
|
||||
|
||||
You can use this when you would otherwise have to call @Efl.Ui.View.model.set
|
||||
on multiple widgets by registering this object using @Efl.Object.provider_register
|
||||
on a parent that they all depends on.
|
||||
]]
|
||||
implements {
|
||||
Efl.Ui.View.model { get; set; }
|
||||
}
|
||||
}
|
|
@ -63,6 +63,7 @@ pub_eo_files = [
|
|||
'efl_gfx_blur.eo',
|
||||
'efl_gfx_hint.eo',
|
||||
'efl_model.eo',
|
||||
'efl_model_provider.eo',
|
||||
'efl_interpolator.eo',
|
||||
'efl_gfx_image_orientable.eo',
|
||||
'efl_container.eo',
|
||||
|
@ -167,6 +168,7 @@ efl_src += files([
|
|||
'efl_file.c',
|
||||
'efl_ui_layout_orientable_readonly.c',
|
||||
'efl_text_markup_util.c',
|
||||
'efl_model_provider.c',
|
||||
])
|
||||
|
||||
#efl_header_src += files([
|
||||
|
|
|
@ -5786,20 +5786,71 @@ _efl_ui_widget_model_update(Efl_Ui_Widget_Data *pd)
|
|||
_efl_ui_property_bind_get(pd, property);
|
||||
}
|
||||
|
||||
static void _efl_ui_widget_model_provider_model_change(void *data, const Efl_Event *event EINA_UNUSED);
|
||||
static void _efl_ui_widget_model_provider_invalidate(void *data, const Efl_Event *event EINA_UNUSED);
|
||||
|
||||
EFL_CALLBACKS_ARRAY_DEFINE(efl_ui_widget_model_provider_callbacks,
|
||||
{ EFL_EVENT_INVALIDATE, _efl_ui_widget_model_provider_invalidate },
|
||||
{ EFL_UI_VIEW_EVENT_MODEL_CHANGED, _efl_ui_widget_model_provider_model_change });
|
||||
|
||||
static void
|
||||
_efl_ui_widget_model_provider_model_change(void *data, const Efl_Event *event)
|
||||
{
|
||||
Efl_Ui_Widget_Data *pd = data;
|
||||
|
||||
efl_replace(&pd->properties.model,
|
||||
efl_ui_view_model_get(pd->properties.provider));
|
||||
_efl_ui_widget_model_update(pd);
|
||||
|
||||
efl_event_callback_call(pd->obj, EFL_UI_VIEW_EVENT_MODEL_CHANGED, event->info);
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_ui_widget_model_provider_invalidate(void *data, const Efl_Event *event EINA_UNUSED)
|
||||
{
|
||||
Efl_Ui_Widget_Data *pd = data;
|
||||
|
||||
efl_event_callback_array_del(pd->properties.provider,
|
||||
efl_ui_widget_model_provider_callbacks(),
|
||||
pd);
|
||||
efl_replace(&pd->properties.provider, NULL);
|
||||
efl_replace(&pd->properties.model, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_ui_widget_model_register(Eo *obj, Efl_Ui_Widget_Data *pd)
|
||||
{
|
||||
if (pd->properties.registered) return ;
|
||||
if (pd->properties.model_lookup)
|
||||
|
||||
if (!pd->properties.model)
|
||||
{
|
||||
Efl_Model_Changed_Event ev;
|
||||
|
||||
efl_replace(&pd->properties.provider,
|
||||
efl_provider_find(obj, EFL_MODEL_PROVIDER_CLASS));
|
||||
if (!pd->properties.provider) return ;
|
||||
efl_event_callback_array_add(pd->properties.provider,
|
||||
efl_ui_widget_model_provider_callbacks(),
|
||||
pd);
|
||||
|
||||
efl_replace(&pd->properties.model,
|
||||
efl_ui_view_model_get(pd->properties.provider));
|
||||
|
||||
if (!pd->properties.model) return ;
|
||||
|
||||
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);
|
||||
pd->properties.registered = EINA_TRUE;
|
||||
ev.current = pd->properties.model;
|
||||
ev.previous = NULL;
|
||||
efl_event_callback_call(obj, EFL_UI_VIEW_EVENT_MODEL_CHANGED, &ev);
|
||||
}
|
||||
|
||||
if (!pd->properties.model) return ;
|
||||
if (!pd->properties.model_lookup) return ;
|
||||
|
||||
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);
|
||||
pd->properties.registered = EINA_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -5815,6 +5866,9 @@ _efl_ui_widget_model_unregister(Eo *obj, Efl_Ui_Widget_Data *pd)
|
|||
|
||||
pd->properties.registered = EINA_FALSE;
|
||||
}
|
||||
// Invalidate must be called before setting a new model and even if no model is registered
|
||||
if (pd->properties.provider)
|
||||
_efl_ui_widget_model_provider_invalidate(pd, NULL);
|
||||
}
|
||||
static Eina_Error
|
||||
_efl_ui_widget_efl_ui_property_bind_property_bind(Eo *obj, Efl_Ui_Widget_Data *pd,
|
||||
|
@ -5822,6 +5876,11 @@ _efl_ui_widget_efl_ui_property_bind_property_bind(Eo *obj, Efl_Ui_Widget_Data *p
|
|||
{
|
||||
Efl_Ui_Property_Bound *prop;
|
||||
|
||||
// Always check for a model and fetch a provider in case a binded property
|
||||
// is provided by a class down the hierarchy, but they still need to be notified
|
||||
// when a model change
|
||||
_efl_ui_widget_model_register(obj, pd);
|
||||
|
||||
// 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;
|
||||
|
||||
|
@ -5830,7 +5889,6 @@ _efl_ui_widget_efl_ui_property_bind_property_bind(Eo *obj, Efl_Ui_Widget_Data *p
|
|||
pd->properties.model_lookup = eina_hash_stringshared_new(_efl_ui_property_bind_free);
|
||||
pd->properties.view_lookup = eina_hash_stringshared_new(NULL);
|
||||
}
|
||||
_efl_ui_widget_model_register(obj, pd);
|
||||
|
||||
prop = calloc(1, sizeof (Efl_Ui_Property_Bound));
|
||||
if (!prop) return ENOMEM;
|
||||
|
@ -5864,7 +5922,10 @@ _efl_ui_widget_efl_ui_view_model_set(Eo *obj,
|
|||
// Set the properties handler just in case
|
||||
_efl_ui_widget_model_register(obj, pd);
|
||||
|
||||
efl_event_callback_call(obj, EFL_UI_VIEW_EVENT_MODEL_CHANGED, &ev);
|
||||
// In case the model set was NULL, but we did found a model provider
|
||||
// we shouldn't emit a second event. Otherwise we should.
|
||||
if (ev.current == pd->properties.model)
|
||||
efl_event_callback_call(obj, EFL_UI_VIEW_EVENT_MODEL_CHANGED, &ev);
|
||||
|
||||
if (pd->properties.model) _efl_ui_widget_model_update(pd);
|
||||
|
||||
|
|
|
@ -386,6 +386,7 @@ typedef struct _Elm_Widget_Smart_Data
|
|||
} legacy_focus;
|
||||
struct {
|
||||
Efl_Model *model;
|
||||
Efl_Model_Provider *provider;
|
||||
Eina_Hash *model_lookup;
|
||||
Eina_Hash *view_lookup;
|
||||
Eina_Bool registered : 1;
|
||||
|
|
Loading…
Reference in New Issue