diff --git a/legacy/evas/src/lib/Evas.h b/legacy/evas/src/lib/Evas.h index 1c5593a943..2af0d7e3b3 100644 --- a/legacy/evas/src/lib/Evas.h +++ b/legacy/evas/src/lib/Evas.h @@ -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 } diff --git a/legacy/evas/src/lib/canvas/Makefile.am b/legacy/evas/src/lib/canvas/Makefile.am index ad9abcded7..a1834b7303 100644 --- a/legacy/evas/src/lib/canvas/Makefile.am +++ b/legacy/evas/src/lib/canvas/Makefile.am @@ -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 \ diff --git a/legacy/evas/src/lib/canvas/evas_object_box.c b/legacy/evas/src/lib/canvas/evas_object_box.c index 12f1289c84..d116b277ef 100644 --- a/legacy/evas/src/lib/canvas/evas_object_box.c +++ b/legacy/evas/src/lib/canvas/evas_object_box.c @@ -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; + } } /** diff --git a/legacy/evas/src/lib/canvas/evas_object_smart.c b/legacy/evas/src/lib/canvas/evas_object_smart.c index 291f854167..86f44192a3 100644 --- a/legacy/evas/src/lib/canvas/evas_object_smart.c +++ b/legacy/evas/src/lib/canvas/evas_object_smart.c @@ -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); diff --git a/legacy/evas/src/lib/canvas/evas_object_table.c b/legacy/evas/src/lib/canvas/evas_object_table.c new file mode 100644 index 0000000000..0e3aa1495c --- /dev/null +++ b/legacy/evas/src/lib/canvas/evas_object_table.c @@ -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 WIDTH / + * COLUMNS 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 expand mode, 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; + } +}