summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCedric BAIL <cedric.bail@free.fr>2019-07-10 18:03:46 -0700
committerMarcel Hollerbach <mail@marcel-hollerbach.de>2019-07-17 21:57:51 +0200
commit2d481d859354205465db2ba3df07d2bcfcbd7979 (patch)
treec0446a76c44ba126e6f20c216d7cf5e838977b75
parenta68e18a903ffb0fa14d1b5ebeb3efc3a8db95812 (diff)
downloadefl-2d481d859354205465db2ba3df07d2bcfcbd7979.tar.gz
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
-rw-r--r--src/lib/efl/Efl.h1
-rw-r--r--src/lib/efl/interfaces/efl_model_provider.c36
-rw-r--r--src/lib/efl/interfaces/efl_model_provider.eo12
-rw-r--r--src/lib/efl/interfaces/meson.build2
-rw-r--r--src/lib/elementary/efl_ui_widget.c77
-rw-r--r--src/lib/elementary/elm_widget.h1
6 files changed, 121 insertions, 8 deletions
diff --git a/src/lib/efl/Efl.h b/src/lib/efl/Efl.h
index d2746eeedc..97c21ec3fb 100644
--- a/src/lib/efl/Efl.h
+++ b/src/lib/efl/Efl.h
@@ -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 */
diff --git a/src/lib/efl/interfaces/efl_model_provider.c b/src/lib/efl/interfaces/efl_model_provider.c
new file mode 100644
index 0000000000..d60bb4469c
--- /dev/null
+++ b/src/lib/efl/interfaces/efl_model_provider.c
@@ -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"
diff --git a/src/lib/efl/interfaces/efl_model_provider.eo b/src/lib/efl/interfaces/efl_model_provider.eo
new file mode 100644
index 0000000000..6fa68f520b
--- /dev/null
+++ b/src/lib/efl/interfaces/efl_model_provider.eo
@@ -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; }
+ }
+}
diff --git a/src/lib/efl/interfaces/meson.build b/src/lib/efl/interfaces/meson.build
index d09a24c255..abfe721dac 100644
--- a/src/lib/efl/interfaces/meson.build
+++ b/src/lib/efl/interfaces/meson.build
@@ -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([
diff --git a/src/lib/elementary/efl_ui_widget.c b/src/lib/elementary/efl_ui_widget.c
index f7749d9a66..95522038f8 100644
--- a/src/lib/elementary/efl_ui_widget.c
+++ b/src/lib/elementary/efl_ui_widget.c
@@ -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);
diff --git a/src/lib/elementary/elm_widget.h b/src/lib/elementary/elm_widget.h
index f9fe403388..dfdfdb83f7 100644
--- a/src/lib/elementary/elm_widget.h
+++ b/src/lib/elementary/elm_widget.h
@@ -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;