Efl.Ui.Grid: Implement custom layout functions

Untested yet. Will need to add the common 3 classes:
- standard
- homogenous
- homogenous max_size

And then implement a true custom layout function, that
respects weights in a certain manner (need to define it
clearly).
This commit is contained in:
Jean-Philippe Andre 2016-04-18 20:17:24 +09:00
parent e4889ca367
commit a0f92d9bef
6 changed files with 195 additions and 47 deletions

View File

@ -200,13 +200,13 @@ static const Eo_Class_Description custom_engine_class_desc = {
EO_CLASS_DESCRIPTION_OPS(custom_engine_op_desc), NULL, 0, NULL, NULL
};
EO_DEFINE_CLASS(custom_engine_class_get, &custom_engine_class_desc, EFL_PACK_ENGINE_INTERFACE, NULL)
EO_DEFINE_CLASS(_test_ui_box_custom_engine_class_get, &custom_engine_class_desc, EFL_PACK_ENGINE_INTERFACE, NULL)
static Eina_Bool
custom_check_cb(void *data, const Eo_Event *event)
{
Eina_Bool chk = elm_check_selected_get(event->obj);
efl_pack_layout_engine_set(data, chk ? custom_engine_class_get() : NULL, NULL);
efl_pack_layout_engine_set(data, chk ? _test_ui_box_custom_engine_class_get() : NULL, NULL);
return EO_CALLBACK_CONTINUE;
}

View File

@ -10,47 +10,68 @@ typedef enum {
NONE_BUT_FILL,
EQUAL,
ONE,
TWO
TWO,
CUSTOM
} Weight_Mode;
#define P(i) ((void*)(intptr_t)i)
#define I(p) ((int)(intptr_t)p)
static void _custom_engine_layout_do(Eo *obj, void *pd, Efl_Pack *pack, const void *data);
/* Common Eo Class boilerplate. */
static const Eo_Op_Description custom_engine_op_desc[] = {
EO_OP_CLASS_FUNC_OVERRIDE(efl_pack_engine_layout_do, _custom_engine_layout_do),
};
static const Eo_Class_Description custom_engine_class_desc = {
EO_VERSION, "Custom Layout Engine", EO_CLASS_TYPE_INTERFACE,
EO_CLASS_DESCRIPTION_OPS(custom_engine_op_desc), NULL, 0, NULL, NULL
};
EO_DEFINE_CLASS(_test_ui_grid_custom_engine_class_get, &custom_engine_class_desc, EFL_PACK_ENGINE_INTERFACE, NULL)
#define CUSTOM_ENGINE_CLASS _test_ui_grid_custom_engine_class_get()
static Eina_Bool
weights_cb(void *data, const Eo_Event *event)
{
Weight_Mode mode = elm_radio_state_value_get(event->obj);
Eo *grid = data;
if (mode != CUSTOM)
efl_pack_layout_engine_set(grid, NULL, NULL);
switch (mode)
{
case NONE:
evas_object_size_hint_align_set(data, 0.5, 0.5);
evas_object_size_hint_align_set(grid, 0.5, 0.5);
for (int i = 0; i < 7; i++)
evas_object_size_hint_weight_set(objects[i], 0, 0);
break;
case NONE_BUT_FILL:
evas_object_size_hint_align_set(data, -1, -1);
evas_object_size_hint_align_set(grid, -1, -1);
for (int i = 0; i < 7; i++)
evas_object_size_hint_weight_set(objects[i], 0, 0);
break;
case EQUAL:
evas_object_size_hint_align_set(data, 0.5, 0.5);
evas_object_size_hint_align_set(grid, 0.5, 0.5);
for (int i = 0; i < 7; i++)
evas_object_size_hint_weight_set(objects[i], 1, 1);
break;
case ONE:
evas_object_size_hint_align_set(data, 0.5, 0.5);
evas_object_size_hint_align_set(grid, 0.5, 0.5);
for (int i = 0; i < 6; i++)
evas_object_size_hint_weight_set(objects[i], 0, 0);
evas_object_size_hint_weight_set(objects[6], 1, 1);
break;
case TWO:
evas_object_size_hint_align_set(data, 0.5, 0.5);
evas_object_size_hint_align_set(grid, 0.5, 0.5);
for (int i = 0; i < 5; i++)
evas_object_size_hint_weight_set(objects[i], 0, 0);
evas_object_size_hint_weight_set(objects[5], 1, 1);
evas_object_size_hint_weight_set(objects[6], 1, 1);
break;
case CUSTOM:
efl_pack_layout_engine_set(grid, CUSTOM_ENGINE_CLASS, NULL);
break;
}
return EO_CALLBACK_CONTINUE;
@ -123,6 +144,49 @@ child_evt_cb(void *data, const Eo_Event *event)
return EO_CALLBACK_CONTINUE;
}
static void
_custom_engine_layout_do(Eo *obj EINA_UNUSED, void *pd EINA_UNUSED,
Efl_Pack *pack, const void *data EINA_UNUSED)
{
/* Example custom layout for grid:
* divide space into regions of same size, place objects in center of their
* cells using their min size
* Note: This is a TERRIBLE layout function (disregards align, weight, ...)
*/
int rows, cols, gw, gh, gx, gy, c, r, cs, rs, gmw = 0, gmh = 0;
Eina_Iterator *it;
Eo *item;
efl_gfx_size_get(pack, &gw, &gh);
efl_gfx_position_get(pack, &gx, &gy);
efl_pack_grid_size_get(pack, &cols, &rows);
if (!cols || !rows) goto end;
it = efl_pack_contents_iterate(pack);
EINA_ITERATOR_FOREACH(it, item)
{
if (efl_pack_child_position_get(pack, item, &c, &r, &cs, &rs))
{
int x, y, mw, mh;
evas_object_size_hint_min_get(item, &mw, &mh);
x = gx + c * gw / cols + (cs * gw / cols - mw) / 2;
y = gy + r * gh / rows + (rs * gh / rows - mh) / 2;
efl_gfx_size_set(item, mw, mh);
efl_gfx_position_set(item, x, y);
gmw = MAX(gmw, mw);
gmh = MAX(gmh, mh);
}
}
eina_iterator_free(it);
end:
evas_object_size_hint_min_set(pack, gmw * cols, gmh * rows);
}
void
test_ui_grid(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
@ -211,6 +275,15 @@ test_ui_grid(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_i
efl_pack(bx, o);
efl_gfx_visible_set(o, 1);
o = elm_radio_add(win);
elm_object_text_set(o, "Custom layout");
eo_event_callback_add(o, ELM_RADIO_EVENT_CHANGED, weights_cb, grid);
evas_object_size_hint_align_set(o, 0, 0.5);
elm_radio_state_value_set(o, CUSTOM);
elm_radio_group_add(o, chk);
efl_pack(bx, o);
efl_gfx_visible_set(o, 1);
elm_radio_value_set(chk, EQUAL);

View File

@ -36,7 +36,7 @@ interface Efl.Pack_Grid (Efl.Pack_Linear)
@property pack_child_position {
[[position and span of the $subobj in this container, may be modified to move the $subobj]]
set { [[same as grid_pack]] }
get {}
get { return: bool; [[returns false if item is not a child]] }
keys {
subobj: Efl.Pack_Item*;
}

View File

@ -148,16 +148,6 @@ _evas_box_custom_layout(Evas_Object *evas_box EINA_UNUSED,
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)
{
@ -170,7 +160,11 @@ _efl_ui_box_efl_pack_engine_layout_do(Eo *klass EINA_UNUSED,
void *_pd EINA_UNUSED,
Eo *obj, const void *data EINA_UNUSED)
{
_layout_do(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 Eina_Bool

View File

@ -8,6 +8,7 @@
#include "elm_priv.h"
#include "efl_ui_grid.eo.h"
#include "../evas/canvas/evas_table.eo.h"
#define MY_CLASS EFL_UI_GRID_CLASS
#define MY_CLASS_NAME "Efl.Ui.Grid"
@ -15,6 +16,7 @@
typedef struct _Efl_Ui_Grid_Data Efl_Ui_Grid_Data;
typedef struct _Grid_Item_Iterator Grid_Item_Iterator;
typedef struct _Grid_Item Grid_Item;
typedef struct _Custom_Table_Data Custom_Table_Data;
static Eina_Bool _subobj_del_cb(void *data, const Eo_Event *event);
static void _item_remove(Efl_Ui_Grid *obj, Efl_Ui_Grid_Data *pd, Efl_Pack_Item *subobj);
@ -34,6 +36,9 @@ struct _Grid_Item
struct _Efl_Ui_Grid_Data
{
const Eo_Class *layout_engine;
const void *layout_data;
Grid_Item *items;
int count;
@ -49,12 +54,18 @@ struct _Efl_Ui_Grid_Data
struct _Grid_Item_Iterator
{
Eina_List *list;
Eina_Iterator iterator;
Eina_Iterator *real_iterator;
Eina_List *list;
Efl_Ui_Grid *object;
};
struct _Custom_Table_Data
{
Efl_Ui_Grid *parent;
Efl_Ui_Grid_Data *gd;
};
static const Eo_Callback_Array_Item subobj_callbacks [] = {
{ EO_BASE_EVENT_DEL, _subobj_del_cb },
{ NULL, NULL }
@ -173,7 +184,6 @@ _efl_ui_grid_elm_widget_theme_apply(Eo *obj, Efl_Ui_Grid_Data *pd EINA_UNUSED)
static void
_layout_updated_emit(Efl_Ui_Grid *obj)
{
/* FIXME: can't be called properly since there is no smart calc event */
eo_event_callback_call(obj, EFL_PACK_EVENT_LAYOUT_UPDATED, NULL);
}
@ -197,7 +207,6 @@ _sizing_eval(Evas_Object *obj, Efl_Ui_Grid_Data *pd EINA_UNUSED)
if ((maxw >= 0) && (w > maxw)) w = maxw;
if ((maxh >= 0) && (h > maxh)) h = maxh;
evas_object_resize(obj, w, h);
_layout_updated_emit(obj);
}
static void
@ -210,14 +219,93 @@ _table_size_hints_changed(void *data, Evas *e EINA_UNUSED,
_sizing_eval(data, pd);
}
EOLIAN static void
_efl_ui_grid_evas_object_smart_add(Eo *obj, Efl_Ui_Grid_Data *pd EINA_UNUSED)
/* Custom table class: overrides smart_calculate. */
static void _custom_table_calc(Eo *obj, Custom_Table_Data *pd);
static const Eo_Op_Description custom_table_op_desc[] = {
EO_OP_CLASS_FUNC_OVERRIDE(evas_obj_smart_calculate, _custom_table_calc),
};
static const Eo_Class_Description custom_table_class_desc = {
EO_VERSION, "Efl.Ui.Grid.Internal", EO_CLASS_TYPE_REGULAR,
EO_CLASS_DESCRIPTION_OPS(custom_table_op_desc), NULL,
sizeof(Custom_Table_Data), NULL, NULL
};
EO_DEFINE_CLASS(_efl_ui_grid_custom_table_class_get, &custom_table_class_desc,
EVAS_TABLE_CLASS, NULL)
#define CUSTOM_TABLE_CLASS _efl_ui_grid_custom_table_class_get()
static void
_custom_table_calc(Eo *obj, Custom_Table_Data *pd)
{
int cols, rows;
evas_object_table_col_row_size_get(obj, &cols, &rows);
if ((cols < 1) || (rows < 1)) return;
efl_pack_layout_update(pd->parent);
_layout_updated_emit(pd->parent);
}
/* End of custom table class */
EOLIAN Eina_Bool
_efl_ui_grid_efl_pack_layout_engine_set(Eo *obj, Efl_Ui_Grid_Data *pd, const Eo_Class *engine, const void *data)
{
pd->layout_engine = engine ? engine : eo_class_get(obj);
pd->layout_data = data;
efl_pack_layout_request(obj);
return EINA_TRUE;
}
EOLIAN void
_efl_ui_grid_efl_pack_layout_engine_get(Eo *obj EINA_UNUSED, Efl_Ui_Grid_Data *pd, const Eo_Class **engine, const void **data)
{
if (engine) *engine = pd->layout_engine;
if (data) *data = pd->layout_data;
}
EOLIAN static void
_efl_ui_grid_efl_pack_layout_update(Eo *obj, Efl_Ui_Grid_Data *pd)
{
_sizing_eval(obj, pd);
efl_pack_engine_layout_do(pd->layout_engine, obj, pd->layout_data);
}
EOLIAN static void
_efl_ui_grid_efl_pack_engine_layout_do(Eo *klass EINA_UNUSED,
void *_pd EINA_UNUSED,
Eo *obj, const void *data EINA_UNUSED)
{
ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
evas_obj_smart_calculate(eo_super(wd->resize_obj, CUSTOM_TABLE_CLASS));
}
EOLIAN void
_efl_ui_grid_evas_object_smart_calculate(Eo *obj, Efl_Ui_Grid_Data *pd EINA_UNUSED)
{
ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
efl_pack_layout_update(obj);
}
EOLIAN static void
_efl_ui_grid_evas_object_smart_add(Eo *obj, Efl_Ui_Grid_Data *pd)
{
Custom_Table_Data *custom;
Evas_Object *table;
pd->layout_engine = MY_CLASS;
elm_widget_sub_object_parent_add(obj);
table = evas_object_table_add(evas_object_evas_get(obj));
table = eo_add(CUSTOM_TABLE_CLASS, obj);
custom = eo_data_scope_get(table, CUSTOM_TABLE_CLASS);
custom->gd = pd;
custom->parent = obj;
evas_object_table_homogeneous_set(table, EVAS_OBJECT_TABLE_HOMOGENEOUS_TABLE);
elm_widget_resize_object_set(obj, table, EINA_TRUE);
@ -276,6 +364,8 @@ _efl_ui_grid_eo_base_constructor(Eo *obj, Efl_Ui_Grid_Data *pd)
return obj;
}
EOLIAN static void
_efl_ui_grid_efl_pack_padding_set(Eo *obj, Efl_Ui_Grid_Data *pd EINA_UNUSED, double h, double v, Eina_Bool scalable)
{
@ -408,11 +498,12 @@ _efl_ui_grid_efl_pack_grid_pack_child_position_set(Eo *obj, Efl_Ui_Grid_Data *pd
_pack_at(obj, pd, subobj, col, row, colspan, rowspan, EINA_FALSE);
}
EOLIAN static void
EOLIAN static Eina_Bool
_efl_ui_grid_efl_pack_grid_pack_child_position_get(Eo *obj, Efl_Ui_Grid_Data *pd EINA_UNUSED, Evas_Object *subobj, int *col, int *row, int *colspan, int *rowspan)
{
int c = -1, r = -1, cs = 0, rs = 0;
Grid_Item *gi;
Eina_Bool ret = EINA_FALSE;
if (obj != elm_widget_parent_widget_get(subobj))
{
@ -429,11 +520,14 @@ _efl_ui_grid_efl_pack_grid_pack_child_position_get(Eo *obj, Efl_Ui_Grid_Data *pd
rs = gi->row_span;
}
ret = EINA_TRUE;
end:
if (col) *col = c;
if (row) *row = r;
if (colspan) *colspan = cs;
if (rowspan) *rowspan = rs;
return ret;
}
EOLIAN static Efl_Pack_Item *
@ -533,21 +627,6 @@ _efl_ui_grid_efl_pack_unpack_all(Eo *obj, Efl_Ui_Grid_Data *pd EINA_UNUSED)
evas_object_table_clear(wd->resize_obj, EINA_FALSE);
}
EOLIAN void
_efl_ui_grid_evas_object_smart_calculate(Eo *obj, Efl_Ui_Grid_Data *pd EINA_UNUSED)
{
ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
evas_object_smart_calculate(wd->resize_obj);
}
EOLIAN void
_efl_ui_grid_efl_pack_layout_update(Eo *obj, Efl_Ui_Grid_Data *pd)
{
_sizing_eval(obj, pd);
_layout_updated_emit(obj);
}
EOLIAN void
_efl_ui_grid_efl_pack_layout_request(Eo *obj, Efl_Ui_Grid_Data *pd EINA_UNUSED)
{

View File

@ -1,7 +1,5 @@
class Efl.Ui.Grid (Elm.Widget, Efl.Pack_Grid)
class Efl.Ui.Grid (Elm.Widget, Efl.Pack_Grid, Efl.Pack_Engine)
{
methods {
}
implements {
Eo.Base.constructor;
@ -41,5 +39,9 @@ class Efl.Ui.Grid (Elm.Widget, Efl.Pack_Grid)
Efl.Pack_Linear.pack_end;
Efl.Pack_Linear.direction.set;
Efl.Pack_Linear.direction.get;
Efl.Pack.layout_engine.get;
Efl.Pack.layout_engine.set;
Efl.Pack_Engine.layout_do;
}
}