Efl.Ui.Box: Implement way to override layout function

So, since we don't have function pointers, all the solutions
to reimplementing the layout function are quite convoluted:

1. use events
2. reimplement layout func
3. use an extra object
4. use a generic class (non instanciated)

Promises don't apply here (layout will run multiple times).

Problems:

1. Multiple event callbacks will be called, resulting in
   potential performance impact, extra events, etc...
   Also, there is no way to define standard implementations
   that would be provided by the framework.

2. Reimplementation of a function requires extra EO work
   (create an EO class, etc...), doesn't allow on-the-fly
   change of the layout method.

3. Probably the best solution is to have an object implementing
   the layout. But this means creating an extra object along
   with the container.

4. To avoid the extra object, use a class, and reimplement
   a @class function. This unfortunately requires extra
   EO work.

Solution 4. has been selected, but it's not very nice...
This commit is contained in:
Jean-Philippe Andre 2016-04-12 16:20:54 +09:00
parent 94228d2683
commit 24eccb6d62
9 changed files with 97 additions and 13 deletions

View File

@ -26,6 +26,7 @@ efl_eolian_files = \
lib/efl/interfaces/efl_orientation.eo \
lib/efl/interfaces/efl_flipable.eo \
lib/efl/interfaces/efl_pack.eo \
lib/efl/interfaces/efl_pack_engine.eo \
lib/efl/interfaces/efl_pack_linear.eo \
lib/efl/interfaces/efl_pack_grid.eo \
lib/efl/interfaces/efl_pack_named.eo \

View File

@ -119,6 +119,7 @@ static inline void efl_gfx_color16_type_set(Efl_Gfx_Color *color,
/* Packing & containers */
#include "interfaces/efl_pack_item.eo.h"
#include "interfaces/efl_pack.eo.h"
#include "interfaces/efl_pack_engine.eo.h"
#include "interfaces/efl_pack_linear.eo.h"
#include "interfaces/efl_pack_grid.eo.h"
#include "interfaces/efl_pack_named.eo.h"

View File

@ -34,6 +34,7 @@ EAPI const Eo_Event_Description _EFL_GFX_PATH_CHANGED =
EO_EVENT_DESCRIPTION("Graphics path changed");
#include "interfaces/efl_pack.eo.c"
#include "interfaces/efl_pack_engine.eo.c"
#include "interfaces/efl_pack_linear.eo.c"
#include "interfaces/efl_pack_grid.eo.c"
#include "interfaces/efl_pack_named.eo.c"

View File

@ -56,6 +56,18 @@ interface Efl.Pack (Efl.Pack_Item)
scalable: bool;
}
}
@property layout_engine {
[[Implementation of this container's layout algorithm.
The default value is the same as the widget class (eg. Efl.Ui.Box).
]]
set { return: bool; }
get {}
values {
engine: const(Eo.Class)*; [[A class implementing a class function layout_do]]
data: void*; [[Any data to pass along to layout_do]]
}
}
layout_update @protected {
[[Implementation of this container's layout algorithm.
@ -73,6 +85,6 @@ interface Efl.Pack (Efl.Pack_Item)
events {
child,added;
child,removed;
layout,updated;
layout,updated; [[sent after the layout was updated]]
}
}

View File

@ -0,0 +1,12 @@
interface Efl.Pack_Engine
{
legacy_prefix: null;
methods {
layout_do @class {
params {
pack: Efl.Pack*;
data: void*;
}
}
}
}

View File

@ -1,5 +1,8 @@
#include "efl_ui_box_private.h"
// FIXME: stop using Evas.Box
#include <../evas/canvas/evas_box.eo.h>
/* COPIED FROM ELM_BOX
* - removed transition stuff (TODO: add back - needs clean API first)
*/
@ -136,6 +139,59 @@ _on_size_hints_changed(void *data, Evas *e EINA_UNUSED,
_sizing_eval(data, pd);
}
static void
_evas_box_custom_layout(Evas_Object *evas_box EINA_UNUSED,
Evas_Object_Box_Data *bd EINA_UNUSED, void *data)
{
Efl_Ui_Box *obj = data;
efl_pack_layout_update(obj);
}
static void
_layout_do(Efl_Ui_Box *obj)
{
ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
Evas_Object_Box_Data *bd;
bd = eo_data_scope_get(wd->resize_obj, EVAS_BOX_CLASS);
_efl_ui_box_custom_layout(obj, bd);
}
EOLIAN static void
_efl_ui_box_efl_pack_layout_update(Eo *obj, Efl_Ui_Box_Data *pd)
{
efl_pack_engine_layout_do(pd->layout_engine, obj, pd->layout_data);
eo_event_callback_call(obj, EFL_PACK_EVENT_LAYOUT_UPDATED, NULL);
}
EOLIAN static void
_efl_ui_box_efl_pack_engine_layout_do(Eo *klass EINA_UNUSED,
void *_pd EINA_UNUSED,
Eo *obj, void *data EINA_UNUSED)
{
_layout_do(obj);
}
EOLIAN static Eina_Bool
_efl_ui_box_efl_pack_layout_engine_set(Eo *obj EINA_UNUSED, Efl_Ui_Box_Data *pd,
const Eo_Class *klass, const void *data)
{
EINA_SAFETY_ON_FALSE_RETURN_VAL(eo_isa(klass, EFL_PACK_INTERFACE), EINA_FALSE);
pd->layout_engine = klass;
pd->layout_data = data;
return EINA_TRUE;
}
EOLIAN static void
_efl_ui_box_efl_pack_layout_engine_get(Eo *obj EINA_UNUSED, Efl_Ui_Box_Data *pd,
const Eo_Class **klass, const void **data)
{
if (klass) *klass = pd->layout_engine;
if (data) *data = pd->layout_data;
}
EOLIAN static void
_efl_ui_box_evas_object_smart_calculate(Eo *obj, Efl_Ui_Box_Data *pd)
{
@ -155,7 +211,7 @@ _efl_ui_box_evas_object_smart_add(Eo *obj, Efl_Ui_Box_Data *_pd EINA_UNUSED)
ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
elm_widget_resize_object_set(obj, evas_object_box_add(e), EINA_TRUE);
evas_object_box_layout_set(wd->resize_obj, _efl_ui_box_custom_layout, obj, NULL);
evas_object_box_layout_set(wd->resize_obj, _evas_box_custom_layout, obj, NULL);
evas_object_event_callback_add(wd->resize_obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_size_hints_changed, obj);
evas_object_event_callback_add(obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_size_hints_changed, obj);
@ -219,6 +275,7 @@ _efl_ui_box_eo_base_constructor(Eo *obj, Efl_Ui_Box_Data *pd)
elm_interface_atspi_accessible_role_set(obj, ELM_ATSPI_ROLE_FILLER);
pd->orient = EFL_ORIENT_RIGHT;
pd->layout_engine = MY_CLASS;
return obj;
}
@ -391,12 +448,6 @@ _efl_ui_box_efl_pack_linear_child_at_set(Eo *obj, Efl_Ui_Box_Data *pd EINA_UNUSE
}
}
EOLIAN static void
_efl_ui_box_efl_pack_layout_update(Eo *obj, Efl_Ui_Box_Data *pd)
{
_sizing_eval(obj, pd);
}
EOLIAN static void
_efl_ui_box_efl_pack_layout_request(Eo *obj, Efl_Ui_Box_Data *pd EINA_UNUSED)
{

View File

@ -1,4 +1,4 @@
class Efl.Ui.Box (Elm.Widget, Efl.Pack_Linear)
class Efl.Ui.Box (Elm.Widget, Efl.Pack_Engine, Efl.Pack_Linear)
{
legacy_prefix: null;
implements {
@ -25,6 +25,8 @@ class Efl.Ui.Box (Elm.Widget, Efl.Pack_Linear)
Efl.Pack.padding.set;
Efl.Pack.layout_update;
Efl.Pack.layout_request;
Efl.Pack.layout_engine.get;
Efl.Pack.layout_engine.set;
Efl.Pack_Linear.pack_begin;
Efl.Pack_Linear.pack_end;
Efl.Pack_Linear.pack_before;
@ -35,5 +37,7 @@ class Efl.Ui.Box (Elm.Widget, Efl.Pack_Linear)
//Efl.Pack_Linear.child_index.set;
Efl.Pack_Linear.direction.set;
Efl.Pack_Linear.direction.get;
Efl.Pack_Engine.layout_do;
}
}

View File

@ -19,10 +19,8 @@ struct _Item_Calc
};
void
_efl_ui_box_custom_layout(Evas_Object *evas_box EINA_UNUSED,
Evas_Object_Box_Data *bd, void *data)
_efl_ui_box_custom_layout(Efl_Ui_Box *ui_box, Evas_Object_Box_Data *bd)
{
Efl_Ui_Box *ui_box = data;
Efl_Ui_Box_Data *pd = eo_data_scope_get(ui_box, EFL_UI_BOX_CLASS);
Evas_Object_Box_Option *opt;
Evas_Object *o;

View File

@ -13,13 +13,17 @@
#define MY_CLASS EFL_UI_BOX_CLASS
#define MY_CLASS_NAME "Efl.Ui.Box"
void _efl_ui_box_custom_layout(Evas_Object *evas_box, Evas_Object_Box_Data *priv, void *data);
// FIXME: stop using evas box
void _efl_ui_box_custom_layout(Efl_Ui_Box *box, Evas_Object_Box_Data *priv);
typedef struct _Efl_Ui_Box_Data Efl_Ui_Box_Data;
typedef struct _Box_Item_Iterator Box_Item_Iterator;
struct _Efl_Ui_Box_Data
{
const Eo_Class *layout_engine;
void *layout_data;
Efl_Orient orient;
Eina_Bool homogeneous : 1;
Eina_Bool delete_me : 1;