Add evas_object_table, make evas_object_box more consistent.

Table code is still *incomplete*, it just do homogeneous layouts as
I'm still trying to figure out how to make it great.

I'm not expecting to make layout configurable, as we did for box, but
if you think it's required we can do that later.

Now that the public API of both BOX and TABLE are in, we can add these
as parts of Edje.



SVN revision: 37359
This commit is contained in:
Gustavo Sverzut Barbieri 2008-10-31 17:42:47 +00:00
parent 602c8edb12
commit f2791cdc56
5 changed files with 1001 additions and 112 deletions

View File

@ -87,6 +87,13 @@ typedef enum _Evas_Colorspace
EVAS_COLORSPACE_RGB565_A5P /**< 16bit rgb565 + Alpha plane at end - 5 bits of the 8 being used per alpha byte */
} Evas_Colorspace; /**< Colorspaces for pixel data supported by Evas */
typedef enum _Evas_Object_Table_Homogeneous_Mode
{
EVAS_OBJECT_TABLE_HOMOGENEOUS_NONE = 0,
EVAS_OBJECT_TABLE_HOMOGENEOUS_TABLE = 1,
EVAS_OBJECT_TABLE_HOMOGENEOUS_ITEM = 2
} Evas_Object_Table_Homogeneous_Mode;
typedef struct _Evas_Transform Evas_Transform; /**< An Evas projective or affine transform */
typedef struct _Evas_Rectangle Evas_Rectangle; /**< A generic rectangle handle */
typedef struct _Evas_Coord_Rectangle Evas_Coord_Rectangle; /**< A generic rectangle handle */
@ -791,7 +798,7 @@ extern "C" {
EAPI void evas_object_smart_callback_call (Evas_Object *obj, const char *event, void *event_info);
EAPI void evas_object_smart_changed (Evas_Object *obj);
EAPI void evas_object_smart_need_recalculate_set(Evas_Object *obj, Evas_Bool value);
EAPI Evas_Bool evas_object_smart_need_recalculate_get(Evas_Object *obj);
EAPI Evas_Bool evas_object_smart_need_recalculate_get(const Evas_Object *obj);
EAPI void evas_object_smart_calculate (Evas_Object *obj);
@ -993,10 +1000,12 @@ extern "C" {
{
Evas_Object_Smart_Clipped_Data base;
const Evas_Object_Box_Api *api;
double align_h;
double align_v;
int padding_h;
int padding_v;
struct {
double h, v;
} align;
struct {
Evas_Coord h, v;
} pad;
Eina_List *children;
Evas_Object_Box_Layout layout;
};
@ -1022,14 +1031,10 @@ extern "C" {
EAPI void evas_object_box_layout_flow_vertical(Evas_Object *o, Evas_Object_Box_Data *priv);
EAPI void evas_object_box_layout_stack(Evas_Object *o, Evas_Object_Box_Data *priv);
EAPI double evas_object_box_align_h_get(Evas_Object *o);
EAPI double evas_object_box_align_v_get(Evas_Object *o);
EAPI void evas_object_box_align_h_set(Evas_Object *o, double align_h);
EAPI void evas_object_box_align_v_set(Evas_Object *o, double align_v);
EAPI int evas_object_box_padding_h_get(Evas_Object *o);
EAPI int evas_object_box_padding_v_get(Evas_Object *o);
EAPI void evas_object_box_padding_h_set(Evas_Object *o, int padding_h);
EAPI void evas_object_box_padding_v_set(Evas_Object *o, int padding_v);
EAPI void evas_object_box_align_set(Evas_Object *o, double horizontal, double vertical);
EAPI void evas_object_box_align_get(const Evas_Object *o, double *horizontal, double *vertical);
EAPI void evas_object_box_padding_set(Evas_Object *o, Evas_Coord horizontal, Evas_Coord vertical);
EAPI void evas_object_box_padding_get(const Evas_Object *o, Evas_Coord *horizontal, Evas_Coord *vertical);
EAPI Evas_Object_Box_Option *evas_object_box_append(Evas_Object *o, Evas_Object *child);
EAPI Evas_Object_Box_Option *evas_object_box_prepend(Evas_Object *o, Evas_Object *child);
@ -1046,6 +1051,21 @@ extern "C" {
EAPI Evas_Bool evas_object_box_option_property_vget(Evas_Object *o, Evas_Object_Box_Option *opt, int property, va_list args);
EAPI void evas_object_table_smart_set(Evas_Smart_Class *sc);
EAPI Evas_Object *evas_object_table_add(Evas *evas);
EAPI Evas_Object *evas_object_table_add_to(Evas_Object *parent);
EAPI void evas_object_table_homogeneous_set(Evas_Object *o, Evas_Object_Table_Homogeneous_Mode homogeneous);
EAPI Evas_Object_Table_Homogeneous_Mode evas_object_table_homogeneous_get(const Evas_Object *o);
EAPI void evas_object_table_padding_set(Evas_Object *o, Evas_Coord horizontal, Evas_Coord vertical);
EAPI void evas_object_table_padding_get(const Evas_Object *o, Evas_Coord *horizontal, Evas_Coord *vertical);
EAPI void evas_object_table_align_set(Evas_Object *o, double horizontal, double vertical);
EAPI void evas_object_table_align_get(const Evas_Object *o, double *horizontal, double *vertical);
EAPI Evas_Bool evas_object_table_pack(Evas_Object *o, Evas_Object *child, unsigned short col, unsigned short row, unsigned short colspan, unsigned short rowspan);
EAPI Evas_Bool evas_object_table_unpack(Evas_Object *o, Evas_Object *child);
EAPI void evas_object_table_clear(Evas_Object *o, Evas_Bool delete);
EAPI void evas_object_table_col_row_size_get(const Evas_Object *o, int *cols, int *rows);
#ifdef __cplusplus
}

View File

@ -34,6 +34,7 @@ evas_object_rectangle.c \
evas_object_smart.c \
evas_object_smart_clipped.c \
evas_object_box.c \
evas_object_table.c \
evas_object_text.c \
evas_object_textblock.c \
evas_font_dir.c \

View File

@ -329,10 +329,10 @@ _evas_object_box_smart_add(Evas_Object *o)
_parent_sc.add(o);
priv->children = NULL;
priv->align_h = 0.5;
priv->align_v = 0.5;
priv->padding_h = 0;
priv->padding_v = 0;
priv->align.h = 0.5;
priv->align.v = 0.5;
priv->pad.h = 0;
priv->pad.v = 0;
priv->layout = evas_object_box_layout_horizontal;
}
@ -672,7 +672,7 @@ evas_object_box_layout_horizontal(Evas_Object *o, Evas_Object_Box_Data *priv)
Evas_Object_Box_Option *objects[n_children];
evas_object_geometry_get(o, &x, &y, &w, &h);
global_pad = priv->padding_h;
global_pad = priv->pad.h;
req_w = global_pad * (n_children - 1);
EINA_LIST_FOREACH(priv->children, l, opt)
@ -706,15 +706,15 @@ evas_object_box_layout_horizontal(Evas_Object *o, Evas_Object_Box_Data *priv)
remaining = _evas_object_box_layout_horizontal_weight_apply
(priv, objects, weight_use, remaining, weight_total);
if (priv->align_h >= 0.0)
x += remaining * priv->align_h;
if (priv->align.h >= 0.0)
x += remaining * priv->align.h;
else if (n_children == 1)
x += remaining / 2;
else
{ /* justified */
_fixed_point_divide_and_decompose_integer
(remaining, n_children - 1, &global_pad, &pad_inc);
global_pad += priv->padding_h;
global_pad += priv->pad.h;
}
EINA_LIST_FOREACH(priv->children, l, opt)
@ -830,7 +830,7 @@ evas_object_box_layout_vertical(Evas_Object *o, Evas_Object_Box_Data *priv)
Evas_Object_Box_Option *objects[n_children];
evas_object_geometry_get(o, &x, &y, &w, &h);
global_pad = priv->padding_v;
global_pad = priv->pad.v;
req_h = global_pad * (n_children - 1);
EINA_LIST_FOREACH(priv->children, l, opt)
@ -864,15 +864,15 @@ evas_object_box_layout_vertical(Evas_Object *o, Evas_Object_Box_Data *priv)
remaining = _evas_object_box_layout_vertical_weight_apply
(priv, objects, weight_use, remaining, weight_total);
if (priv->align_v >= 0.0)
y += remaining * priv->align_v;
if (priv->align.v >= 0.0)
y += remaining * priv->align.v;
else if (n_children == 1)
y += remaining / 2;
else
{ /* justified */
_fixed_point_divide_and_decompose_integer
(remaining, n_children - 1, &global_pad, &pad_inc);
global_pad += priv->padding_v;
global_pad += priv->pad.v;
}
EINA_LIST_FOREACH(priv->children, l, opt)
@ -956,7 +956,7 @@ evas_object_box_layout_homogeneous_horizontal(Evas_Object *o, Evas_Object_Box_Da
evas_object_geometry_get(o, &x, &y, &w, &h);
share = w - priv->padding_h * (n_children - 1);
share = w - priv->pad.h * (n_children - 1);
_fixed_point_divide_and_decompose_integer
(share, n_children, &cell_sz, &inc);
@ -987,7 +987,7 @@ evas_object_box_layout_homogeneous_horizontal(Evas_Object *o, Evas_Object_Box_Da
evas_object_resize(opt->obj, new_w, new_h);
evas_object_move(opt->obj, x + off_x, y + off_y);
x += cell_sz + priv->padding_h;
x += cell_sz + priv->pad.h;
sub_pixel += inc;
if (sub_pixel >= 1 << 16)
{
@ -1021,7 +1021,7 @@ evas_object_box_layout_homogeneous_vertical(Evas_Object *o, Evas_Object_Box_Data
evas_object_geometry_get(o, &x, &y, &w, &h);
share = h - priv->padding_v * (n_children - 1);
share = h - priv->pad.v * (n_children - 1);
_fixed_point_divide_and_decompose_integer
(share, n_children, &cell_sz, &inc);
@ -1051,7 +1051,7 @@ evas_object_box_layout_homogeneous_vertical(Evas_Object *o, Evas_Object_Box_Data
evas_object_resize(opt->obj, new_w, new_h);
evas_object_move(opt->obj, x + off_x, y + off_y);
y += cell_sz + priv->padding_v;
y += cell_sz + priv->pad.v;
sub_pixel += inc;
if (sub_pixel >= 1 << 16)
{
@ -1129,18 +1129,18 @@ evas_object_box_layout_homogeneous_max_size_horizontal(Evas_Object *o, Evas_Obje
cell_sz = child_w + padding_l + padding_r;
}
global_pad = priv->padding_h;
global_pad = priv->pad.h;
remaining = w - n_children * cell_sz - global_pad * (n_children - 1);
if (priv->align_h >= 0.0)
x += remaining * priv->align_h;
if (priv->align.h >= 0.0)
x += remaining * priv->align.h;
else if (n_children == 1)
x += remaining / 2;
else
{ /* justified */
_fixed_point_divide_and_decompose_integer
(remaining, n_children - 1, &global_pad, &pad_inc);
global_pad += priv->padding_h;
global_pad += priv->pad.h;
}
EINA_LIST_FOREACH(priv->children, l, opt)
@ -1216,18 +1216,18 @@ evas_object_box_layout_homogeneous_max_size_vertical(Evas_Object *o, Evas_Object
cell_sz = child_h + padding_t + padding_b;
}
global_pad = priv->padding_v;
global_pad = priv->pad.v;
remaining = h - n_children * cell_sz - global_pad * (n_children - 1);
if (priv->align_v >= 0.0)
y += remaining * priv->align_v;
if (priv->align.v >= 0.0)
y += remaining * priv->align.v;
else if (n_children == 1)
y += remaining / 2;
else
{ /* justified */
_fixed_point_divide_and_decompose_integer
(remaining, n_children - 1, &global_pad, &pad_inc);
global_pad += priv->padding_v;
global_pad += priv->pad.v;
}
EINA_LIST_FOREACH(priv->children, l, opt)
@ -1286,7 +1286,7 @@ _evas_object_box_layout_flow_horizontal_row_info_collect(Evas_Object_Box_Data *p
evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h);
child_w += padding_l + padding_r + priv->padding_h;
child_w += padding_l + padding_r + priv->pad.h;
child_h += padding_t + padding_b;
remain_w -= child_w;
@ -1398,8 +1398,8 @@ evas_object_box_layout_flow_horizontal(Evas_Object *o, Evas_Object_Box_Data *pri
v_justify = 0;
remain_y = h - (off_y + max_h);
if (priv->align_v >= 0.0)
inc_y = priv->align_v * remain_y;
if (priv->align.v >= 0.0)
inc_y = priv->align.v * remain_y;
else if (row_count == 0)
y += remain_y / 2;
else /* y-justified */
@ -1413,7 +1413,7 @@ evas_object_box_layout_flow_horizontal(Evas_Object *o, Evas_Object_Box_Data *pri
row_size = row_break[r] - i;
remain_x = (w - row_width[r]);
if (priv->align_h < 0.0)
if (priv->align.h < 0.0)
{
if (row_size == 0)
x += remain_x / 2;
@ -1440,8 +1440,8 @@ evas_object_box_layout_flow_horizontal(Evas_Object *o, Evas_Object_Box_Data *pri
y_remain = row_max_h[r] - child_h;
off_x = padding_l;
if (priv->align_h >= 0.0)
off_x += remain_x * priv->align_h;
if (priv->align.h >= 0.0)
off_x += remain_x * priv->align.h;
off_y = y_remain * align_y;
evas_object_move(opt->obj, x + off_x, y + off_y);
@ -1480,7 +1480,7 @@ _evas_object_box_layout_flow_vertical_col_info_collect(Evas_Object_Box_Data *pri
evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h);
child_w += padding_l + padding_r;
child_h += padding_t + padding_b + priv->padding_v;
child_h += padding_t + padding_b + priv->pad.v;
remain_h -= child_h;
if (remain_h >= 0)
@ -1565,8 +1565,8 @@ evas_object_box_layout_flow_vertical(Evas_Object *o, Evas_Object_Box_Data *priv)
h_justify = 0;
remain_x = w - (off_x + max_w);
if (priv->align_h >= 0)
inc_x = priv->align_h * remain_x;
if (priv->align.h >= 0)
inc_x = priv->align.h * remain_x;
else if (col_count == 0)
x += remain_x / 2;
else /* x-justified */
@ -1580,7 +1580,7 @@ evas_object_box_layout_flow_vertical(Evas_Object *o, Evas_Object_Box_Data *priv)
col_size = col_break[c] - i;
remain_y = (h - col_height[c]);
if (priv->align_v < 0.0)
if (priv->align.v < 0.0)
{
if (col_size == 0)
y += remain_y / 2;
@ -1608,8 +1608,8 @@ evas_object_box_layout_flow_vertical(Evas_Object *o, Evas_Object_Box_Data *priv)
off_x = x_remain * align_x;
off_y = padding_t;
if (priv->align_v >= 0.0)
off_y += remain_y * priv->align_v;
if (priv->align.v >= 0.0)
off_y += remain_y * priv->align.v;
evas_object_move(opt->obj, x + off_x, y + off_y);
@ -1691,87 +1691,69 @@ evas_object_box_layout_stack(Evas_Object *o, Evas_Object_Box_Data *priv)
}
/**
* Get horizontal alignment of the box @a o.
*/
double
evas_object_box_align_h_get(Evas_Object *o)
{
EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0.0);
return priv->align_h;
}
/**
* Get horizontal padding of the box @a o.
*/
int
evas_object_box_padding_h_get(Evas_Object *o)
{
EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0);
return priv->padding_h;
}
/**
* Get vertical alignment of the box @a o.
*/
double
evas_object_box_align_v_get(Evas_Object *o)
{
EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0.0);
return priv->align_v;
}
/**
* Get vertical padding of the box @a o.
*/
int
evas_object_box_padding_v_get(Evas_Object *o)
{
EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0);
return priv->padding_v;
}
/**
* Set horizontal alignment of the box @a o.
* Set the alignment of the whole bounding box of contents.
*/
void
evas_object_box_align_h_set(Evas_Object *o, double align_h)
evas_object_box_align_set(Evas_Object *o, double horizontal, double vertical)
{
EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(o, priv);
priv->align_h = align_h;
if (priv->align.h == horizontal && priv->align.v == vertical)
return;
priv->align.h = horizontal;
priv->align.v = vertical;
evas_object_smart_changed(o);
}
/**
* Set horizontal padding of the box @a o.
* Get alignment of the whole bounding box of contents.
*/
void
evas_object_box_padding_h_set(Evas_Object *o, int padding_h)
evas_object_box_align_get(const Evas_Object *o, double *horizontal, double *vertical)
{
EVAS_OBJECT_BOX_DATA_GET(o, priv);
if (priv)
{
if (horizontal) *horizontal = priv->align.h;
if (vertical) *vertical = priv->align.v;
}
else
{
if (horizontal) *horizontal = 0.5;
if (vertical) *vertical = 0.5;
}
}
/**
* Set the space (padding) between cells.
*/
void
evas_object_box_padding_set(Evas_Object *o, Evas_Coord horizontal, Evas_Coord vertical)
{
EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(o, priv);
priv->padding_h = padding_h;
if (priv->pad.h == horizontal && priv->pad.v == vertical)
return;
priv->pad.h = horizontal;
priv->pad.v = vertical;
evas_object_smart_changed(o);
}
/**
* Set vertical alignment of the box @a o.
* Get the (space) padding between cells.
*/
void
evas_object_box_align_v_set(Evas_Object *o, double align_v)
evas_object_box_padding_get(const Evas_Object *o, Evas_Coord *horizontal, Evas_Coord *vertical)
{
EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(o, priv);
priv->align_v = align_v;
evas_object_smart_changed(o);
}
/**
* Set vertical padding of the box @a o.
*/
void
evas_object_box_padding_v_set(Evas_Object *o, int padding_v)
{
EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(o, priv);
priv->padding_v = padding_v;
evas_object_smart_changed(o);
EVAS_OBJECT_BOX_DATA_GET(o, priv);
if (priv)
{
if (horizontal) *horizontal = priv->pad.h;
if (vertical) *vertical = priv->pad.v;
}
else
{
if (horizontal) *horizontal = 0;
if (vertical) *vertical = 0;
}
}
/**

View File

@ -506,7 +506,7 @@ evas_object_smart_need_recalculate_set(Evas_Object *obj, Evas_Bool value)
* @ingroup Evas_Smart_Object_Group
*/
EAPI Evas_Bool
evas_object_smart_need_recalculate_get(Evas_Object *obj)
evas_object_smart_need_recalculate_get(const Evas_Object *obj)
{
Evas_Object_Smart *o;
MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);

View File

@ -0,0 +1,886 @@
#include "evas_common.h"
typedef struct _Evas_Object_Table_Data Evas_Object_Table_Data;
typedef struct _Evas_Object_Table_Option Evas_Object_Table_Option;
struct _Evas_Object_Table_Option
{
Evas_Object *obj;
unsigned short col, row, colspan, rowspan, end_col, end_row;
struct {
Evas_Coord w, h;
} min, max;
struct {
double h, v;
} align;
struct {
Evas_Coord l, r, t, b;
} pad;
Evas_Bool expand_h : 1; /* XXX required? */
Evas_Bool expand_v : 1; /* XXX required? */
};
struct _Evas_Object_Table_Data
{
Evas_Object_Smart_Clipped_Data base;
Eina_List *children;
struct {
Evas_Coord h, v;
} pad;
struct {
double h, v;
} align;
struct {
int cols, rows;
} size;
Evas_Object_Table_Homogeneous_Mode homogeneous;
Evas_Bool hints_changed : 1;
Evas_Bool expand_h : 1;
Evas_Bool expand_v : 1;
};
/**
* @addtogroup Evas_Object_Table
* @{
* @ingroup Evas_Smart_Object_Group
*/
#define EVAS_OBJECT_TABLE_DATA_GET(o, ptr) \
Evas_Object_Table_Data *ptr = evas_object_smart_data_get(o)
#define EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, ptr) \
EVAS_OBJECT_TABLE_DATA_GET(o, ptr); \
if (!ptr) \
{ \
fprintf(stderr, "CRITICAL: no widget data for object %p (%s)\n", \
o, evas_object_type_get(o)); \
fflush(stderr); \
abort(); \
return; \
}
#define EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, ptr, val) \
EVAS_OBJECT_TABLE_DATA_GET(o, ptr); \
if (!ptr) \
{ \
fprintf(stderr, "CRITICAL: no widget data for object %p (%s)\n", \
o, evas_object_type_get(o)); \
fflush(stderr); \
abort(); \
return val; \
}
static const char EVAS_OBJECT_TABLE_OPTION_KEY[] = "Evas_Object_Table_Option";
static Evas_Object_Table_Option *
_evas_object_table_option_get(Evas_Object *o)
{
return evas_object_data_get(o, EVAS_OBJECT_TABLE_OPTION_KEY);
}
static void
_evas_object_table_option_set(Evas_Object *o, const Evas_Object_Table_Option *opt)
{
evas_object_data_set(o, EVAS_OBJECT_TABLE_OPTION_KEY, opt);
}
static Evas_Object_Table_Option *
_evas_object_table_option_del(Evas_Object *o)
{
return evas_object_data_del(o, EVAS_OBJECT_TABLE_OPTION_KEY);
}
static void
_on_child_del(void *data, Evas *evas, Evas_Object *child, void *einfo)
{
Evas_Object *table = data;
evas_object_table_unpack(table, child);
}
static void
_on_child_hints_changed(void *data, Evas *evas, Evas_Object *child, void *einfo)
{
Evas_Object *table = data;
EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(table, priv);
priv->hints_changed = 1;
evas_object_smart_changed(table);
}
static void
_evas_object_table_child_connect(Evas_Object *o, Evas_Object *child)
{
evas_object_event_callback_add
(child, EVAS_CALLBACK_DEL, _on_child_del, o);
evas_object_event_callback_add
(child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_child_hints_changed, o);
}
static void
_evas_object_table_child_disconnect(Evas_Object *o, Evas_Object *child)
{
evas_object_event_callback_del_full
(child, EVAS_CALLBACK_DEL, _on_child_del, o);
evas_object_event_callback_del_full
(child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_child_hints_changed, o);
}
static void
_evas_object_table_calculate_cell(const Evas_Object_Table_Option *opt, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
{
Evas_Coord cw, ch;
*w -= opt->pad.l + opt->pad.r;
if (*w < opt->min.w)
cw = opt->min.w;
else if ((opt->max.w > -1) && (*w > opt->max.w))
cw = opt->max.w;
else
cw = *w;
*h -= opt->pad.t + opt->pad.b;
if (*h < opt->min.h)
ch = opt->min.h;
else if ((opt->max.h > -1) && (*h > opt->max.h))
ch = opt->max.h;
else
ch = *h;
*x += opt->pad.l;
if (cw != *w)
{
*x += (*w - cw) * opt->align.h;
*w = cw;
}
*y += opt->pad.t;
if (ch != *h)
{
*y += (*h - ch) * opt->align.v;
*h = ch;
}
}
/* static Evas_Bool */
/* _evas_object_table_check_hints_homogeneous_table(Evas_Object *child, double *align, Evas_Coord min, const char *axis_name) */
/* { */
/* if (*align < 0.0) */
/* { */
/* /\* assume expand and align to the center. */
/* * this is compatible with evas_object_box behavior and is the */
/* * same as weight > 0.0. */
/* *\/ */
/* *align = 0.5; */
/* return 0; */
/* } */
/* else if (min < 1) */
/* { */
/* fprintf(stderr, */
/* "WARNING: child %p [%s, %s] has no minimum width " */
/* "and no %s expand (weight is not > 0.0). " */
/* "Assuming weight > 0.0\n", */
/* child, evas_object_type_get(child), evas_object_name_get(child), */
/* axis_name); */
/* return 0; */
/* } */
/* return 1; */
/* } */
static void
_evas_object_table_calculate_hints_homogeneous(Evas_Object *o, Evas_Object_Table_Data *priv)
{
Eina_List *l;
Evas_Object_Table_Option *opt;
Evas_Coord minw, minh, o_minw, o_minh;
Evas_Bool expand_h, expand_v;
o_minw = 0;
o_minh = 0;
minw = 0;
minh = 0;
expand_h = 0;
expand_v = 0;
EINA_LIST_FOREACH(priv->children, l, opt)
{
Evas_Object *child = opt->obj;
Evas_Coord child_minw, child_minh, cell_minw, cell_minh;
double weightw, weighth;
evas_object_size_hint_min_get(child, &opt->min.w, &opt->min.h);
evas_object_size_hint_max_get(child, &opt->max.w, &opt->max.h);
evas_object_size_hint_padding_get
(child, &opt->pad.l, &opt->pad.r, &opt->pad.t, &opt->pad.b);
evas_object_size_hint_align_get(child, &opt->align.h, &opt->align.v);
evas_object_size_hint_weight_get(child, &weightw, &weighth);
child_minw = opt->min.w + opt->pad.l + opt->pad.r;
child_minh = opt->min.h + opt->pad.t + opt->pad.b;
cell_minw = (child_minw + opt->colspan - 1) / opt->colspan;
cell_minh = (child_minh + opt->rowspan - 1) / opt->rowspan;
if ((weightw > 0.0) &&
((opt->max.w < 0) ||
((opt->max.w > -1) && (opt->min.w < opt->max.w))))
{
opt->expand_h = 1;
expand_h = 1;
}
/* else if ((priv->homogeneous == EVAS_OBJECT_TABLE_HOMOGENEOUS_TABLE) && */
/* (!_evas_object_table_check_hints_homogeneous_table */
/* (child, &opt->align.h, opt->min.w, "horizontal"))) */
/* { */
/* opt->expand_h = 1; */
/* expand_h = 1; */
/* } */
if ((weighth > 0.0) &&
((opt->max.h < 0) ||
((opt->max.h > -1) && (opt->min.h < opt->max.h))))
{
opt->expand_v = 1;
expand_v = 1;
}
/* else if ((priv->homogeneous == EVAS_OBJECT_TABLE_HOMOGENEOUS_TABLE) && */
/* (!_evas_object_table_check_hints_homogeneous_table */
/* (child, &opt->align.v, opt->min.h, "vertical"))) */
/* { */
/* opt->expand_v = 1; */
/* expand_v = 1; */
/* } */
if (opt->align.h < 0.0)
opt->align.h = 0.5;
if (opt->align.v < 0.0)
opt->align.v = 0.5;
/* greatest mininum values, with paddings */
if (minw < cell_minw)
minw = cell_minw;
if (minh < cell_minh)
minh = cell_minh;
/* greatest mininum values, without paddings */
if (o_minw < opt->min.w)
o_minw = opt->min.w;
if (o_minh < opt->min.h)
o_minh = opt->min.h;
}
if (priv->homogeneous == EVAS_OBJECT_TABLE_HOMOGENEOUS_ITEM)
{
if (o_minw < 1)
{
fputs("ERROR: homogeneous table based on item size but no "
"horizontal mininum size specified! Using expand.\n",
stderr);
expand_h = 1;
}
if (o_minh < 1)
{
fputs("ERROR: homogeneous table based on item size but no "
"vertical mininum size specified! Using expand.\n",
stderr);
expand_v = 1;
}
}
minw = priv->size.cols * (minw + priv->pad.h) - priv->pad.h;
minh = priv->size.rows * (minh + priv->pad.v) - priv->pad.v;
priv->hints_changed = 0;
priv->expand_h = expand_h;
priv->expand_v = expand_v;
if ((minw > 0 ) || (minh > 0))
evas_object_size_hint_min_set(o, minw, minh);
// XXX hint max?
}
static void
_evas_object_table_calculate_layout_homogeneous_sizes_item(const Evas_Object *o, const Evas_Object_Table_Data *priv, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
{
Evas_Coord minw, minh;
Evas_Bool expand_h, expand_v;
evas_object_size_hint_min_get(o, &minw, &minh);
expand_h = priv->expand_h;
expand_v = priv->expand_v;
if (*w < minw)
expand_h = 0;
if (!expand_h)
{
*x += (*w - minw) * priv->align.h;
*w = minw;
}
if (*h < minh)
expand_v = 0;
if (!expand_v)
{
*y += (*h - minh) * priv->align.v;
*h = minh;
}
}
static void
_evas_object_table_calculate_layout_homogeneous_sizes(const Evas_Object *o, const Evas_Object_Table_Data *priv, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h, Evas_Coord *cellw, Evas_Coord *cellh)
{
evas_object_geometry_get(o, x, y, w, h);
if (priv->homogeneous == EVAS_OBJECT_TABLE_HOMOGENEOUS_ITEM)
_evas_object_table_calculate_layout_homogeneous_sizes_item
(o, priv, x, y, w, h);
*cellw = (*w + priv->size.cols - 1) / priv->size.cols;
*cellh = (*h + priv->size.rows - 1) / priv->size.rows;
}
static void
_evas_object_table_calculate_layout_homogeneous(Evas_Object *o, Evas_Object_Table_Data *priv)
{
Evas_Coord x, y, w, h, cellw, cellh;
Eina_List *l;
Evas_Object_Table_Option *opt;
_evas_object_table_calculate_layout_homogeneous_sizes
(o, priv, &x, &y, &w, &h, &cellw, &cellh);
EINA_LIST_FOREACH(priv->children, l, opt)
{
Evas_Object *child = opt->obj;
Evas_Coord cx, cy, cw, ch;
cx = x + opt->col * (cellw + priv->pad.h);
cy = y + opt->row * (cellh + priv->pad.v);
cw = opt->colspan * cellw - priv->pad.h;
ch = opt->rowspan * cellh - priv->pad.v;
_evas_object_table_calculate_cell(opt, &cx, &cy, &cw, &ch);
evas_object_move(child, cx, cy);
evas_object_resize(child, cw, ch);
}
}
static void
_evas_object_table_smart_calculate_homogeneous(Evas_Object *o, Evas_Object_Table_Data *priv)
{
if (priv->hints_changed)
_evas_object_table_calculate_hints_homogeneous(o, priv);
_evas_object_table_calculate_layout_homogeneous(o, priv);
}
static void
_evas_object_table_calculate_hints_regular(Evas_Object *o, Evas_Object_Table_Data *priv)
{
puts("XXX TODO: calculate hints for non-homogeneous tables");
}
static void
_evas_object_table_calculate_layout_regular(Evas_Object *o, Evas_Object_Table_Data *priv)
{
puts("XXX TODO: calculate layout for non-homogeneous tables");
}
static void
_evas_object_table_smart_calculate_regular(Evas_Object *o, Evas_Object_Table_Data *priv)
{
if (priv->hints_changed)
_evas_object_table_calculate_hints_regular(o, priv);
_evas_object_table_calculate_layout_regular(o, priv);
}
static Evas_Smart_Class _parent_sc = {NULL};
static void
_evas_object_table_smart_add(Evas_Object *o)
{
Evas_Object_Table_Data *priv;
priv = evas_object_smart_data_get(o);
if (!priv)
{
priv = calloc(1, sizeof(*priv));
if (!priv)
{
fputs("ERROR: could not allocate object private data.\n", stderr);
return;
}
evas_object_smart_data_set(o, priv);
}
priv->pad.h = 0;
priv->pad.v = 0;
priv->align.h = 0.5;
priv->align.v = 0.5;
priv->size.cols = 0;
priv->size.rows = 0;
priv->homogeneous = EVAS_OBJECT_TABLE_HOMOGENEOUS_NONE;
priv->hints_changed = 1;
priv->expand_h = 0;
priv->expand_v = 0;
_parent_sc.add(o);
}
static void
_evas_object_table_smart_del(Evas_Object *o)
{
EVAS_OBJECT_TABLE_DATA_GET(o, priv);
Eina_List *l;
l = priv->children;
while (l)
{
Evas_Object_Table_Option *opt = l->data;
_evas_object_table_child_disconnect(o, opt->obj);
_evas_object_table_option_del(opt->obj);
free(opt);
l = eina_list_remove_list(l, l);
}
_parent_sc.del(o);
}
static void
_evas_object_table_smart_resize(Evas_Object *o, int w, int h)
{
evas_object_smart_changed(o);
}
static void
_evas_object_table_smart_calculate(Evas_Object *o)
{
EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv);
if ((priv->size.cols < 1) || (priv->size.rows < 1))
{
fprintf(stderr, "DBG: nothing to do: cols=%d, rows=%d\n",
priv->size.cols, priv->size.rows);
return;
}
if (priv->homogeneous)
_evas_object_table_smart_calculate_homogeneous(o, priv);
else
_evas_object_table_smart_calculate_regular(o, priv);
}
static Evas_Smart *
_evas_object_table_smart_class_new(void)
{
static Evas_Smart_Class sc = {
"Evas_Object_Table", EVAS_SMART_CLASS_VERSION,
};
if (!_parent_sc.name)
evas_object_table_smart_set(&sc);
return evas_smart_class_new(&sc);
}
/**
* Create a new table.
*
* It's set to non-homogeneous by default, add children with
* evas_object_table_pack().
*/
Evas_Object *
evas_object_table_add(Evas *evas)
{
Evas_Object *o;
Evas_Smart *smart;
if (!smart)
smart = _evas_object_table_smart_class_new();
o = evas_object_smart_add(evas, smart);
return o;
}
/**
* Create a table that is child of a given element @a parent.
*
* @see evas_object_table_add()
*/
Evas_Object *
evas_object_table_add_to(Evas_Object *parent)
{
Evas *evas;
Evas_Object *o;
evas = evas_object_evas_get(parent);
o = evas_object_table_add(evas);
evas_object_smart_member_add(o, parent);
return o;
}
/**
* Set the default table @a api struct (Evas_Smart_Class)
* with the default values. May be used to extend that API.
*/
void
evas_object_table_smart_set(Evas_Smart_Class *sc)
{
if (!sc)
return;
if (!_parent_sc.name)
evas_object_smart_clipped_smart_set(&_parent_sc);
sc->add = _evas_object_table_smart_add;
sc->del = _evas_object_table_smart_del;
sc->move = _parent_sc.move;
sc->resize = _evas_object_table_smart_resize;
sc->show = _parent_sc.show;
sc->hide = _parent_sc.hide;
sc->color_set = _parent_sc.color_set;
sc->clip_set = _parent_sc.clip_set;
sc->clip_unset = _parent_sc.clip_unset;
sc->calculate = _evas_object_table_smart_calculate;
sc->member_add = _parent_sc.member_add;
sc->member_del = _parent_sc.member_del;
}
/**
* Set how this table should layout children.
*
* @par EVAS_OBJECT_TABLE_HOMOGENEOUS_NONE
* If table does not use homogeneous mode then columns and rows will
* be calculated based on hints of individual cells. This operation
* mode is more flexible, but more complex and heavy to calculate as
* well.
*
* @par EVAS_OBJECT_TABLE_HOMOGENEOUS_TABLE
* When homogeneous is relative to table the own table size is divided
* equally among children, filling the whole table area. That is, if
* table has @c WIDTH and @c COLUMNS, each cell will get <tt>WIDTH /
* COLUMNS</tt> pixels. If children have minimum size that is larger
* than this amount (including padding), then it will overflow and be
* aligned respecting the alignment hint, possible overlapping sibling
* cells. @b Weight hint is used as a boolean, if greater than zero it
* will make the child expand in that axis, taking as much space as
* possible (bounded to maximum size hint). Negative alignment will be
* considered as 0.5.
*
* @par EVAS_OBJECT_TABLE_HOMOGENEOUS_ITEM
* When homogeneous is relative to item it means the greatest minimum
* cell size will be used. That is, if no element is set to expand,
* the table will have its contents to a minimum size, the bounding
* box of all these children will be aligned relatively to the table
* object using evas_object_table_align_get(). If the table area is
* too small to hold this minimum bounding box, then the objects will
* keep their size and the bounding box will overflow the box area,
* still respecting the alignment. @b Weight hint is used as a
* boolean, if greater than zero it will make that cell expand in that
* axis, toggling the <b>expand mode</b>, which makes the table behave
* much like @b EVAS_OBJECT_TABLE_HOMOGENEOUS_TABLE, except that the
* bounding box will overflow and items will not overlap siblings. If
* no minimum size is provided at all then the table will fallback to
* expand mode as well.
*/
void
evas_object_table_homogeneous_set(Evas_Object *o, Evas_Object_Table_Homogeneous_Mode homogeneous)
{
EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv);
if (priv->homogeneous == homogeneous)
return;
priv->homogeneous = homogeneous;
priv->hints_changed = 1;
evas_object_smart_changed(o);
}
/**
* Get the current layout homogeneous mode.
*
* @see evas_object_table_homogeneous_set()
*/
Evas_Object_Table_Homogeneous_Mode
evas_object_table_homogeneous_get(const Evas_Object *o)
{
EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, 0);
return priv->homogeneous;
}
/**
* Set the alignment of the whole bounding box of contents.
*/
void
evas_object_table_align_set(Evas_Object *o, double horizontal, double vertical)
{
EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv);
if (priv->align.h == horizontal && priv->align.v == vertical)
return;
priv->align.h = horizontal;
priv->align.v = vertical;
evas_object_smart_changed(o);
}
/**
* Get alignment of the whole bounding box of contents.
*/
void
evas_object_table_align_get(const Evas_Object *o, double *horizontal, double *vertical)
{
EVAS_OBJECT_TABLE_DATA_GET(o, priv);
if (priv)
{
if (horizontal) *horizontal = priv->align.h;
if (vertical) *vertical = priv->align.v;
}
else
{
if (horizontal) *horizontal = 0.5;
if (vertical) *vertical = 0.5;
}
}
/**
* Set padding between cells.
*/
void
evas_object_table_padding_set(Evas_Object *o, Evas_Coord horizontal, Evas_Coord vertical)
{
EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv);
if (priv->pad.h == horizontal && priv->pad.v == vertical)
return;
priv->pad.h = horizontal;
priv->pad.v = vertical;
evas_object_smart_changed(o);
}
/**
* Get padding between cells.
*/
void
evas_object_table_padding_get(const Evas_Object *o, Evas_Coord *horizontal, Evas_Coord *vertical)
{
EVAS_OBJECT_TABLE_DATA_GET(o, priv);
if (priv)
{
if (horizontal) *horizontal = priv->pad.h;
if (vertical) *vertical = priv->pad.v;
}
else
{
if (horizontal) *horizontal = 0;
if (vertical) *vertical = 0;
}
}
/**
* Add a new child to table.
*
* @param col relative-horizontal position to place child.
* @param row relative-vertical position to place child.
* @param colspan how many relative-horizontal position to use for this child.
* @param rowspan how many relative-vertical position to use for this child.
*
* @return 1 on success, 0 on failure.
*/
Evas_Bool
evas_object_table_pack(Evas_Object *o, Evas_Object *child, unsigned short col, unsigned short row, unsigned short colspan, unsigned short rowspan)
{
EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, 0);
Evas_Object_Table_Option *opt;
if (rowspan < 1)
{
fputs("ERROR: rowspan < 1\n", stderr);
return 0;
}
if (colspan < 1)
{
fputs("ERROR: colspan < 1\n", stderr);
return 0;
}
opt = _evas_object_table_option_get(child);
if (opt)
{
fputs("ERROR: cannot add object that is already part of a table!\n",
stderr);
return 0;
}
opt = malloc(sizeof(*opt));
if (!opt)
{
fputs("ERROR: could not allocate table option data.\n", stderr);
return 0;
}
opt->obj = child;
opt->col = col;
opt->row = row;
opt->colspan = colspan;
opt->rowspan = rowspan;
opt->end_col = col + colspan;
opt->end_row = row + rowspan;
opt->min.w = 0;
opt->min.h = 0;
opt->max.w = 0;
opt->max.h = 0;
opt->align.h = 0.5;
opt->align.v = 0.5;
opt->pad.l = 0;
opt->pad.r = 0;
opt->pad.t = 0;
opt->pad.b = 0;
opt->expand_h = 0;
opt->expand_v = 0;
priv->children = eina_list_append(priv->children, opt);
if (priv->size.cols < opt->end_col)
priv->size.cols = opt->end_col;
if (priv->size.rows < opt->end_row)
priv->size.rows = opt->end_row;
_evas_object_table_option_set(child, opt);
evas_object_smart_member_add(child, o);
_evas_object_table_child_connect(o, child);
priv->hints_changed = 1;
evas_object_smart_changed(o);
return 1;
}
static void
_evas_object_table_remove_opt(Evas_Object_Table_Data *priv, Evas_Object_Table_Option *opt)
{
Eina_List *l;
int max_row, max_col, was_greatest;
max_row = 0;
max_col = 0;
was_greatest = 0;
l = priv->children;
while (l)
{
Evas_Object_Table_Option *cur_opt = l->data;
if (cur_opt != opt)
{
if (max_col < cur_opt->end_col)
max_col = cur_opt->end_col;
if (max_row < cur_opt->end_row)
max_row = cur_opt->end_row;
l = l->next;
}
else
{
Eina_List *tmp = l->next;
priv->children = eina_list_remove_list(priv->children, l);
if ((priv->size.cols > opt->end_col) &&
(priv->size.rows > opt->end_row))
break;
else
{
was_greatest = 1;
l = tmp;
}
}
}
if (was_greatest)
{
priv->size.cols = max_col;
priv->size.rows = max_row;
}
}
/**
* Remove child from table.
*
* @note removing a child will immediately call a walk over children in order
* to recalculate numbers of columns and rows. If you plan to remove
* all children, use evas_object_table_clear() instead.
*
* @return 1 on success, 0 on failure.
*/
Evas_Bool
evas_object_table_unpack(Evas_Object *o, Evas_Object *child)
{
EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, 0);
Evas_Object_Table_Option *opt;
if (o != evas_object_smart_parent_get(child))
{
fputs("ERROR: cannot unpack child from incorrect table!\n", stderr);
return;
}
opt = _evas_object_table_option_del(child);
if (!opt)
{
fputs("ERROR: cannot unpack child with no packing option!\n", stderr);
return;
}
_evas_object_table_child_disconnect(o, child);
_evas_object_table_remove_opt(priv, opt);
evas_object_smart_member_del(child);
free(opt);
priv->hints_changed = 1;
evas_object_smart_changed(o);
return 1;
}
/**
* Faster way to remove all child objects.
*
* @param delete if true, it will delete just removed children.
*/
void
evas_object_table_clear(Evas_Object *o, Evas_Bool delete)
{
EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv);
Eina_List *l;
l = priv->children;
while (l)
{
Evas_Object_Table_Option *opt = l->data;
_evas_object_table_child_disconnect(o, opt->obj);
_evas_object_table_option_del(opt->obj);
evas_object_smart_member_del(opt->obj);
if (delete)
evas_object_del(opt->obj);
free(opt);
l = eina_list_remove_list(l, l);
}
priv->children = NULL;
priv->size.cols = 0;
priv->size.rows = 0;
evas_object_smart_changed(o);
}
/**
* Get the number of columns and rows this table takes.
*
* @note columns and rows are virtual entities, one can specify a table
* with a single object that takes 4 columns and 5 rows. The only
* difference for a single cell table is that paddings will be
* accounted proportionally.
*/
void
evas_object_table_col_row_size_get(const Evas_Object *o, int *cols, int *rows)
{
EVAS_OBJECT_TABLE_DATA_GET(o, priv);
if (priv)
{
if (cols) *cols = priv->size.cols;
if (rows) *rows = priv->size.rows;
}
else
{
if (cols) *cols = -1;
if (rows) *rows = -1;
}
}