summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCedric BAIL <cedric.bail@free.fr>2019-01-10 16:40:25 -0800
committerCedric BAIL <cedric.bail@free.fr>2019-01-30 12:06:18 -0800
commitf30c7c6a1ea5f9d6ff369edaebd3cb9cb8b5caac (patch)
tree3033f4f28f1043d05c4589ff7e0f2f005b01416e
parent4aa6285a75ea69a7b608890f4ff44a6aecbf349f (diff)
downloadefl-f30c7c6a1ea5f9d6ff369edaebd3cb9cb8b5caac.tar.gz
elementary: add internal Efl_Ui_Model_Average.
This model enable View that require to compute the size of their item to rely on its logic to store all items size independently. It has the same interface as the Homogeneous and should be exchangeable for a View. It provide an average total size at all time. It use Efl.Ui.Model_Exact to do most of the work and is a good example on how to alter a Model logic. Reviewed-by: SangHyeon Jade Lee <sh10233.lee@samsung.com> Differential Revision: https://phab.enlightenment.org/D7661
-rw-r--r--src/Makefile_Elementary.am2
-rw-r--r--src/lib/elementary/efl_ui_model_average.c181
-rw-r--r--src/lib/elementary/efl_ui_model_average.eo19
-rw-r--r--src/lib/elementary/elm_priv.h1
-rw-r--r--src/lib/elementary/meson.build2
5 files changed, 205 insertions, 0 deletions
diff --git a/src/Makefile_Elementary.am b/src/Makefile_Elementary.am
index f9485bb9b7..ed2a629d14 100644
--- a/src/Makefile_Elementary.am
+++ b/src/Makefile_Elementary.am
@@ -179,6 +179,7 @@ elm_private_eolian_files = \
lib/elementary/efl_ui_model_size.eo \
lib/elementary/efl_ui_model_homogeneous.eo \
lib/elementary/efl_ui_model_exact.eo \
+ lib/elementary/efl_ui_model_average.eo \
$(NULL)
# Legacy classes - not part of public EO API
@@ -892,6 +893,7 @@ lib_elementary_libelementary_la_SOURCES = \
lib/elementary/efl_ui_model_size.c \
lib/elementary/efl_ui_model_homogeneous.c \
lib/elementary/efl_ui_model_exact.c \
+ lib/elementary/efl_ui_model_average.c \
$(NULL)
diff --git a/src/lib/elementary/efl_ui_model_average.c b/src/lib/elementary/efl_ui_model_average.c
new file mode 100644
index 0000000000..be4dca59a1
--- /dev/null
+++ b/src/lib/elementary/efl_ui_model_average.c
@@ -0,0 +1,181 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Elementary.h>
+#include "elm_priv.h"
+
+// This class rely on the parent class to do all the individual holding of value,
+// it only compute the average size of an item and answer for that property alone.
+
+// FIXME: handle child being removed
+typedef struct _Efl_Ui_Model_Average_Data Efl_Ui_Model_Average_Data;
+struct _Efl_Ui_Model_Average_Data
+{
+ Efl_Ui_Model_Average_Data *parent;
+
+ struct {
+ unsigned long long width;
+ unsigned long long height;
+ unsigned long long wseen;
+ unsigned long long hseen;
+ } total;
+
+ Eina_Bool wseen : 1;
+ Eina_Bool hseen : 1;
+};
+
+typedef struct _Efl_Ui_Model_Average_Update Efl_Ui_Model_Average_Update;
+struct _Efl_Ui_Model_Average_Update
+{
+ unsigned long long *total;
+ unsigned long long *seen;
+ unsigned int previous;
+};
+
+static Eina_Value
+_efl_ui_model_average_update(Eo *obj EINA_UNUSED, void *data, const Eina_Value v)
+{
+ Efl_Ui_Model_Average_Update *request = data;
+ unsigned int now;
+
+ if (!eina_value_uint_convert(&v, &now))
+ goto on_error;
+
+ *(request->total) += now - request->previous;
+ if (request->seen) *(request->seen) += 1;
+
+ on_error:
+ return v;
+}
+
+static void
+_efl_ui_model_average_clean(Eo *obj EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED)
+{
+ free(data);
+}
+
+static Eina_Future *
+_efl_ui_model_average_prepare(Eo *obj,
+ unsigned long long *total, unsigned long long *seen,
+ const char *property, Eina_Value *value)
+{
+ Efl_Ui_Model_Average_Update *update;
+ Eina_Value *previous;
+ Eina_Future *f;
+
+ update = calloc(1, sizeof (Efl_Ui_Model_Average_Update));
+ if (!update) return efl_loop_future_rejected(obj, ENOMEM);
+
+ previous = efl_model_property_get(obj, property);
+ if (eina_value_type_get(previous) == EINA_VALUE_TYPE_ERROR)
+ {
+ Eina_Error err;
+
+ // Check the case when that property hasn't been set before
+ if (!eina_value_error_convert(previous, &err))
+ goto on_error;
+ if (err != EAGAIN) goto on_error;
+ }
+ else if (!eina_value_uint_convert(previous, &update->previous))
+ goto on_error;
+ eina_value_free(previous);
+
+ update->total = total;
+ update->seen = seen;
+
+ // We have to make the change after we fetch the old value, otherwise, well, no old value left
+ f = efl_model_property_set(efl_super(obj, EFL_UI_MODEL_AVERAGE_CLASS), property, value);
+
+ return efl_future_then(obj, f,
+ .success = _efl_ui_model_average_update,
+ .free = _efl_ui_model_average_clean,
+ .data = update);
+ on_error:
+ eina_value_free(previous);
+ free(update);
+ return efl_loop_future_rejected(obj, EFL_MODEL_ERROR_INCORRECT_VALUE);
+}
+
+static Eina_Future *
+_efl_ui_model_average_efl_model_property_set(Eo *obj, Efl_Ui_Model_Average_Data *pd, const char *property, Eina_Value *value)
+{
+ Eina_Future *f = NULL;
+
+ if (!pd->parent) goto end;
+
+ // In vertical list mode we do not need to compute the average width size
+ /* if (!strcmp(property, _efl_model_property_selfw)) */
+ /* { */
+ /* f = _efl_ui_model_average_prepare(obj, &pd->parent->total.width, */
+ /* pd->wseen ? NULL : &pd->parent->total.wseen, */
+ /* property, value, EINA_TRUE); */
+ /* pd->wseen = EINA_TRUE; */
+ /* } */
+ if (!strcmp(property, _efl_model_property_selfh))
+ {
+ f = _efl_ui_model_average_prepare(obj, &pd->parent->total.height,
+ pd->hseen ? NULL : &pd->parent->total.hseen,
+ property, value);
+ pd->hseen = EINA_TRUE;
+ }
+
+ end:
+ if (!f)
+ f = efl_model_property_set(efl_super(obj, EFL_UI_MODEL_AVERAGE_CLASS), property, value);
+
+ return f;
+}
+
+static inline Eina_Value *
+_efl_ui_model_average_compute(const Eo *obj, Eina_Value *r, unsigned long long total, unsigned long long seen)
+{
+ unsigned int count;
+
+ eina_value_free(r);
+
+ // Protection against divide by zero
+ if (!seen) return eina_value_uint_new(0);
+
+ count = efl_model_children_count_get(obj);
+ // We are doing the multiply first in an attempt to not reduce the precision to early on.
+ return eina_value_uint_new((total * count) / seen);
+}
+
+static Eina_Value *
+_efl_ui_model_average_efl_model_property_get(const Eo *obj, Efl_Ui_Model_Average_Data *pd, const char *property)
+{
+ const Eina_Value_Type *t;
+ Eina_Value *r;
+
+ r = efl_model_property_get(efl_super(obj, EFL_UI_MODEL_AVERAGE_CLASS), property);
+ if (!r) return r;
+
+ // We are checking that the parent class was able to provide an answer to the request for property "Total.Width"
+ // or "Total.Height" which means that we are an object that should compute its size. This avoid computing the
+ // pointer to the parent object.
+ t = eina_value_type_get(r);
+ if (t == EINA_VALUE_TYPE_UINT)
+ {
+ if (!strcmp(property, _efl_model_property_totalh))
+ r = _efl_ui_model_average_compute(obj, r, pd->total.height, pd->total.hseen);
+ // We do not need to average the width in vertical list mode as this is done by the parent class
+ /* if (!strcmp(property, _efl_model_property_totalw)) */
+ /* r = _efl_ui_model_average_compute(obj, r, pd->total.width, pd->total.wseen); */
+ }
+
+ return r;
+}
+
+static Efl_Object *
+_efl_ui_model_average_efl_object_constructor(Eo *obj, Efl_Ui_Model_Average_Data *pd)
+{
+ Eo *parent = efl_parent_get(obj);
+
+ if (parent && efl_isa(parent, EFL_UI_MODEL_AVERAGE_CLASS))
+ pd->parent = efl_data_scope_get(efl_parent_get(obj), EFL_UI_MODEL_AVERAGE_CLASS);
+
+ return efl_constructor(efl_super(obj, EFL_UI_MODEL_AVERAGE_CLASS));
+}
+
+#include "efl_ui_model_average.eo.c"
diff --git a/src/lib/elementary/efl_ui_model_average.eo b/src/lib/elementary/efl_ui_model_average.eo
new file mode 100644
index 0000000000..1af87f986e
--- /dev/null
+++ b/src/lib/elementary/efl_ui_model_average.eo
@@ -0,0 +1,19 @@
+class Efl.Ui.Model_Average extends Efl.Ui.Model_Exact
+{
+ [[Class to be used to store object item size for List/Grid View.
+
+ This model provide the same feature as @Efl.Ui.Model_Exact except for the
+ @Efl.Model.property "$total.width" and "$total.height" which reflect an
+ estimated value of the total size by using the currently know size from its
+ children as an average size for all its children. As more children fill
+ "$self.width" and "$self.height", this model will figure out a more precise
+ answer. Once all children size is known, the result will be exact and the same
+ as @Efl.Ui.Model_Exact.
+
+ This model only supporting vertical list at this point.]]
+
+ implements {
+ Efl.Object.constructor;
+ Efl.Model.property { set; get; }
+ }
+} \ No newline at end of file
diff --git a/src/lib/elementary/elm_priv.h b/src/lib/elementary/elm_priv.h
index a5f187df17..e0b284b6b6 100644
--- a/src/lib/elementary/elm_priv.h
+++ b/src/lib/elementary/elm_priv.h
@@ -72,6 +72,7 @@
# include "efl_ui_model_size.eo.h"
# include "efl_ui_model_homogeneous.eo.h"
# include "efl_ui_model_exact.eo.h"
+# include "efl_ui_model_average.eo.h"
extern const char *_efl_model_property_itemw;
extern const char *_efl_model_property_itemh;
diff --git a/src/lib/elementary/meson.build b/src/lib/elementary/meson.build
index c4453b7c9e..f9c508de0b 100644
--- a/src/lib/elementary/meson.build
+++ b/src/lib/elementary/meson.build
@@ -340,6 +340,7 @@ priv_eo_files = [
'efl_ui_model_size.eo',
'efl_ui_model_homogeneous.eo',
'efl_ui_model_exact.eo',
+ 'efl_ui_model_average.eo',
]
priv_eo_file_target = []
@@ -911,6 +912,7 @@ elementary_src = [
'efl_ui_model_size.c',
'efl_ui_model_homogeneous.c',
'efl_ui_model_exact.c',
+ 'efl_ui_model_average.c',
]
elementary_deps = [emile, eo, efl, edje, ethumb, ethumb_client, emotion, ecore_imf, ecore_con, eldbus, efreet, efreet_mime, efreet_trash, eio, atspi, dl, intl]