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
This commit is contained in:
Cedric BAIL 2019-01-10 16:40:25 -08:00
parent 4aa6285a75
commit f30c7c6a1e
5 changed files with 205 additions and 0 deletions

View File

@ -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)

View File

@ -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"

View File

@ -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; }
}
}

View File

@ -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;

View File

@ -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]