================================================================
[framework/uifw/elementary.git] / src / lib / elm_table.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup Table Table
6  * @ingroup Elementary
7  *
8  * Arranges widgets in a table where items can also span multiple
9  * columns or rows - even overlap (and then be raised or lowered
10  * accordingly to adjust stacking if they do overlap).
11  */
12
13 typedef struct _Widget_Data Widget_Data;
14
15 struct _Widget_Data
16 {
17    Evas_Object *tbl;
18 };
19
20 static const char *widtype = NULL;
21 static void _del_hook(Evas_Object *obj);
22 static void _sizing_eval(Evas_Object *obj);
23 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
24 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
25
26 static void
27 _del_pre_hook(Evas_Object *obj)
28 {
29    Widget_Data *wd = elm_widget_data_get(obj);
30    if (!wd) return;
31    evas_object_event_callback_del_full
32      (wd->tbl, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, obj);
33    evas_object_del(wd->tbl);
34 }
35
36 static void
37 _del_hook(Evas_Object *obj)
38 {
39    Widget_Data *wd = elm_widget_data_get(obj);
40    if (!wd) return;
41    free(wd);
42 }
43
44 static Eina_Bool
45 _elm_table_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
46 {
47    Widget_Data *wd = elm_widget_data_get(obj);
48    const Eina_List *items;
49    void *(*list_data_get) (const Eina_List *list);
50    Eina_List *(*list_free) (Eina_List *list);
51
52    if ((!wd) || (!wd->tbl))
53      return EINA_FALSE;
54
55    /* Focus chain */
56    /* TODO: Change this to use other chain */
57    if ((items = elm_widget_focus_custom_chain_get(obj)))
58      {
59         list_data_get = eina_list_data_get;
60         list_free = NULL;
61      }
62    else
63      {
64         items = evas_object_table_children_get(wd->tbl);
65         list_data_get = eina_list_data_get;
66         list_free = eina_list_free;
67
68         if (!items) return EINA_FALSE;
69      }
70
71    Eina_Bool ret = elm_widget_focus_list_next_get(obj, items, list_data_get,
72                                                    dir, next);
73
74    if (list_free)
75      list_free((Eina_List *)items);
76
77    return ret;
78 }
79
80 static void
81 _sizing_eval(Evas_Object *obj)
82 {
83    Widget_Data *wd = elm_widget_data_get(obj);
84    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
85    Evas_Coord w, h;
86    if (!wd) return;
87    evas_object_size_hint_min_get(wd->tbl, &minw, &minh);
88    evas_object_size_hint_max_get(wd->tbl, &maxw, &maxh);
89    evas_object_size_hint_min_set(obj, minw, minh);
90    evas_object_size_hint_max_set(obj, maxw, maxh);
91    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
92    if (w < minw) w = minw;
93    if (h < minh) h = minh;
94    if ((maxw >= 0) && (w > maxw)) w = maxw;
95    if ((maxh >= 0) && (h > maxh)) h = maxh;
96    evas_object_resize(obj, w, h);
97 }
98
99 static void
100 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
101 {
102    _sizing_eval(data);
103 }
104
105 static void
106 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
107 {
108    _sizing_eval(obj);
109 }
110
111 /**
112  * Add a new table to the parent
113  *
114  * @param parent The parent object
115  * @return The new object or NULL if it cannot be created
116  *
117  * @ingroup Table
118  */
119 EAPI Evas_Object *
120 elm_table_add(Evas_Object *parent)
121 {
122    Evas_Object *obj;
123    Evas *e;
124    Widget_Data *wd;
125
126    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
127
128    wd = ELM_NEW(Widget_Data);
129    e = evas_object_evas_get(parent);
130    if (!e) return NULL;
131    obj = elm_widget_add(e);
132    ELM_SET_WIDTYPE(widtype, "table");
133    elm_widget_type_set(obj, "table");
134    elm_widget_sub_object_add(parent, obj);
135    elm_widget_data_set(obj, wd);
136    elm_widget_del_hook_set(obj, _del_hook);
137    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
138    elm_widget_focus_next_hook_set(obj, _elm_table_focus_next_hook);
139    elm_widget_can_focus_set(obj, EINA_FALSE);
140    elm_widget_highlight_ignore_set(obj, EINA_FALSE);
141
142    wd->tbl = evas_object_table_add(e);
143    evas_object_event_callback_add(wd->tbl, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
144                                   _changed_size_hints, obj);
145    elm_widget_resize_object_set(obj, wd->tbl);
146
147    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
148
149    return obj;
150 }
151
152 /**
153  * Set the homogenous layout in the table
154  *
155  * @param obj The layout object
156  * @param homogenous A boolean to set (or no) layout homogenous
157  * in the table
158  * (1 = homogenous,  0 = no homogenous)
159  *
160  * @ingroup Table
161  */
162 EAPI void
163 elm_table_homogenous_set(Evas_Object *obj, Eina_Bool homogenous)
164 {
165    ELM_CHECK_WIDTYPE(obj, widtype);
166    Widget_Data *wd = elm_widget_data_get(obj);
167    if (!wd) return;
168    evas_object_table_homogeneous_set(wd->tbl, homogenous);
169 }
170
171 /**
172  * Get the current table homogenous mode.
173  *
174  * @param obj The table object
175  * @return a boolean to set (or no) layout homogenous in the table
176  * (1 = homogenous,  0 = no homogenous)
177  *
178  * @ingroup Table
179  */
180 EAPI Eina_Bool
181 elm_table_homogenous_get(const Evas_Object *obj)
182 {
183    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
184    Widget_Data *wd = elm_widget_data_get(obj);
185    if (!wd) return EINA_FALSE;
186    return evas_object_table_homogeneous_get(wd->tbl);
187 }
188
189 /**
190  * Set padding between cells.
191  *
192  * @param obj The layout object.
193  * @param horizontal set the horizontal padding.
194  * @param vertical set the vertical padding.
195  *
196  * @ingroup Table
197  */
198 EAPI void
199 elm_table_padding_set(Evas_Object *obj, Evas_Coord horizontal, Evas_Coord vertical)
200 {
201    ELM_CHECK_WIDTYPE(obj, widtype);
202    Widget_Data *wd = elm_widget_data_get(obj);
203    if (!wd) return;
204    evas_object_table_padding_set(wd->tbl, horizontal, vertical);
205 }
206
207 /**
208  * Get padding between cells.
209  *
210  * @param obj The layout object.
211  * @param horizontal set the horizontal padding.
212  * @param vertical set the vertical padding.
213  *
214  * @ingroup Table
215  */
216 EAPI void
217 elm_table_padding_get(const Evas_Object *obj, Evas_Coord *horizontal, Evas_Coord *vertical)
218 {
219    ELM_CHECK_WIDTYPE(obj, widtype);
220    Widget_Data *wd = elm_widget_data_get(obj);
221    if (!wd) return;
222    evas_object_table_padding_get(wd->tbl, horizontal, vertical);
223 }
224
225 /**
226  * Add a subobject on the table with the coordinates passed
227  *
228  * @param obj The table object
229  * @param subobj The subobject to be added to the table
230  * @param x Coordinate to X axis
231  * @param y Coordinate to Y axis
232  * @param w Horizontal length
233  * @param h Vertical length
234  *
235  * @ingroup Table
236  */
237 EAPI void
238 elm_table_pack(Evas_Object *obj, Evas_Object *subobj, int x, int y, int w, int h)
239 {
240    ELM_CHECK_WIDTYPE(obj, widtype);
241    Widget_Data *wd = elm_widget_data_get(obj);
242    if (!wd) return;
243    elm_widget_sub_object_add(obj, subobj);
244    evas_object_table_pack(wd->tbl, subobj, x, y, w, h);
245 }
246
247 /**
248  * Remove child from table.
249  *
250  * @param obj The table object
251  * @param subobj The subobject
252  *
253  * @ingroup Table
254  */
255 EAPI void
256 elm_table_unpack(Evas_Object *obj, Evas_Object *subobj)
257 {
258    ELM_CHECK_WIDTYPE(obj, widtype);
259    Widget_Data *wd = elm_widget_data_get(obj);
260    if (!wd) return;
261    elm_widget_sub_object_del(obj, subobj);
262    evas_object_table_unpack(wd->tbl, subobj);
263 }
264
265 /**
266  * Faster way to remove all child objects from a table object.
267  *
268  * @param obj The table object
269  * @param clear If true, it will delete just removed children
270  *
271  * @ingroup Table
272  */
273 EAPI void
274 elm_table_clear(Evas_Object *obj, Eina_Bool clear)
275 {
276    ELM_CHECK_WIDTYPE(obj, widtype);
277    Widget_Data *wd = elm_widget_data_get(obj);
278    if (!wd) return;
279    evas_object_table_clear(wd->tbl, clear);
280 }