2529774ba3b9ad85105bbdb940161c9e61dca99c
[framework/uifw/elementary.git] / src / lib / elm_box.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup Box Box
6  * @ingroup Elementary
7  *
8  * A box object arranges objects in a single row within a box. Sub objects can
9  * be added at the start, end or before or after any existing object in the
10  * box already. It can have its orientation changed too. How a child object is
11  * sized and otherwise arranged within the box depends on evas hints.
12  * evas_object_size_hint_align_set() will set either the alignment within its
13  * region if the region allocated is bigger than the object size. If you want
14  * the sub object sized up to fill the allocated region, use -1.0 for the
15  * apporpriate horizontal or vertical axes. evas_object_size_hint_weight_set()
16  * will set the packing weight. The weights of all items being packed are added
17  * up and if items are to be sized up to fit, those with the higher weights get
18  * proportionally more space.
19  *
20  * NOTE: Objects should not be added to box objects using _add() calls.
21  */
22 typedef struct _Widget_Data Widget_Data;
23
24 struct _Widget_Data
25 {
26    Evas_Object *box;
27    Eina_Bool horizontal:1;
28    Eina_Bool homogeneous:1;
29    Eina_Bool extended:1;
30 };
31
32 static const char *widtype = NULL;
33 static void _del_hook(Evas_Object *obj);
34 static void _sizing_eval(Evas_Object *obj);
35 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
36 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
37
38 static void
39 _del_pre_hook(Evas_Object *obj)
40 {
41     Widget_Data *wd = elm_widget_data_get(obj);
42    if (!wd) return;
43     evas_object_event_callback_del_full
44         (wd->box, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, obj);
45     evas_object_box_remove_all(wd->box, 0);
46 }
47
48 static void
49 _del_hook(Evas_Object *obj)
50 {
51    Widget_Data *wd = elm_widget_data_get(obj);
52    if (!wd) return;
53    free(wd);
54 }
55
56 static void
57 _sizing_eval(Evas_Object *obj)
58 {
59    Widget_Data *wd = elm_widget_data_get(obj);
60    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
61    Evas_Coord w, h;
62    if (!wd) return;
63    evas_object_size_hint_min_get(wd->box, &minw, &minh);
64    evas_object_size_hint_max_get(wd->box, &maxw, &maxh);
65    evas_object_size_hint_min_set(obj, minw, minh);
66    evas_object_size_hint_max_set(obj, maxw, maxh);
67    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
68    if (w < minw) w = minw;
69    if (h < minh) h = minh;
70    if ((maxw >= 0) && (w > maxw)) w = maxw;
71    if ((maxh >= 0) && (h > maxh)) h = maxh;
72    evas_object_resize(obj, w, h);
73 }
74
75 static void
76 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
77 {
78    _sizing_eval(data);
79 }
80
81 static void
82 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
83 {
84    _sizing_eval(obj);
85 }
86
87 static void
88 _layout(Evas_Object *o, Evas_Object_Box_Data *priv, void *data)
89 {
90    Widget_Data *wd = data;
91    if (!wd) return;
92    _els_box_layout_ex(o, priv, wd->horizontal, wd->homogeneous, wd->extended);
93 }
94
95
96 /**
97  * Add a new box to the parent
98  *
99  * @param parent The parent object
100  * @return The new object or NULL if it cannot be created
101  *
102  * @ingroup Box
103  */
104 EAPI Evas_Object *
105 elm_box_add(Evas_Object *parent)
106 {
107    Evas_Object *obj;
108    Evas *e;
109    Widget_Data *wd;
110
111    wd = ELM_NEW(Widget_Data);
112    e = evas_object_evas_get(parent);
113    obj = elm_widget_add(e);
114    ELM_SET_WIDTYPE(widtype, "box");
115    elm_widget_type_set(obj, "box");
116    elm_widget_sub_object_add(parent, obj);
117    elm_widget_data_set(obj, wd);
118    elm_widget_del_hook_set(obj, _del_hook);
119    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
120
121    wd->box = evas_object_box_add(e);
122    /*evas_object_box_layout_set(wd->box, evas_object_box_layout_vertical,
123                               NULL, NULL);*/
124    evas_object_box_layout_set(wd->box, _layout, wd, NULL);
125
126    evas_object_event_callback_add(wd->box, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
127                                   _changed_size_hints, obj);
128    elm_widget_resize_object_set(obj, wd->box);
129
130    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
131
132    return obj;
133 }
134
135 /**
136  * Set the horizontal orientation
137  *
138  * By default box object arrange their contents vertically from top to bottom.
139  * By calling this and providing @p orizontal as true, the box will become
140  * horizontal arranging contents left to right.
141  *
142  * @param obj The box object
143  * @param horizontal The horizontal flag (1 = horizontal, 0 = vertical)
144  *
145  * @ingroup Box
146  */
147 EAPI void
148 elm_box_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
149 {
150    ELM_CHECK_WIDTYPE(obj, widtype);
151    Widget_Data *wd = elm_widget_data_get(obj);
152    if (!wd) return;
153    wd->horizontal = !!horizontal;
154    evas_object_smart_calculate(wd->box);
155    /*if (wd->horizontal)
156      {
157         if (wd->homogeneous)
158           evas_object_box_layout_set(wd->box,
159                 evas_object_box_layout_homogeneous_horizontal, NULL, NULL);
160         else
161           evas_object_box_layout_set(wd->box, evas_object_box_layout_horizontal,
162                                      NULL, NULL);
163      }
164    else
165      {
166         if (wd->homogeneous)
167           evas_object_box_layout_set(wd->box,
168                 evas_object_box_layout_homogeneous_vertical, NULL, NULL);
169         else
170           evas_object_box_layout_set(wd->box, evas_object_box_layout_horizontal,
171                                      NULL, NULL);
172      }*/
173 }
174
175 /**
176  * Set homogenous layout
177  *
178  * If enabled, homogenous layout makes all items the same size. This size is
179  * of course governed by the size of the largest item in the box.
180  *
181  * @param obj The box object
182  * @param homogenous The homogenous flag (1 = on, 2 = off)
183  *
184  * @ingroup Box
185  */
186 EAPI void
187 elm_box_homogenous_set(Evas_Object *obj, Eina_Bool homogenous)
188 {
189    ELM_CHECK_WIDTYPE(obj, widtype);
190    Widget_Data *wd = elm_widget_data_get(obj);
191    if (!wd) return;
192    wd->homogeneous = !!homogenous;
193    evas_object_smart_calculate(wd->box);
194    /*if (wd->horizontal)
195      {
196         if (wd->homogeneous)
197           evas_object_box_layout_set(wd->box,
198                 evas_object_box_layout_homogeneous_horizontal, NULL, NULL);
199         else
200           evas_object_box_layout_set(wd->box, evas_object_box_layout_horizontal,
201                                      NULL, NULL);
202      }
203    else
204      {
205         if (wd->homogeneous)
206           evas_object_box_layout_set(wd->box,
207                 evas_object_box_layout_homogeneous_vertical, NULL, NULL);
208         else
209           evas_object_box_layout_set(wd->box, evas_object_box_layout_horizontal,
210                                      NULL, NULL);
211      }*/
212 }
213
214 /**
215  * This adds a box at the start of the box (top or left based on orientation)
216  *
217  * This will add the @p subobj to the box object indicated at the beginning
218  * of the box (the left or top end).
219  *
220  * @param obj The box object
221  * @param subobj The object to add to the box
222  *
223  * @ingroup Box
224  */
225 EAPI void
226 elm_box_pack_start(Evas_Object *obj, Evas_Object *subobj)
227 {
228    ELM_CHECK_WIDTYPE(obj, widtype);
229    Widget_Data *wd = elm_widget_data_get(obj);
230    if (!wd) return;
231    elm_widget_sub_object_add(obj, subobj);
232    evas_object_box_prepend(wd->box, subobj);
233 }
234
235 /**
236  * This adds a box at the end of the box (bottom or right based on orientation)
237  *
238  * This will add the @p subobj to the box object indicated at the end
239  * of the box (the right or bottom end).
240  *
241  * @param obj The box object
242  * @param subobj The object to add to the box
243  *
244  * @ingroup Box
245  */
246 EAPI void
247 elm_box_pack_end(Evas_Object *obj, Evas_Object *subobj)
248 {
249    ELM_CHECK_WIDTYPE(obj, widtype);
250    Widget_Data *wd = elm_widget_data_get(obj);
251    if (!wd) return;
252    elm_widget_sub_object_add(obj, subobj);
253    evas_object_box_append(wd->box, subobj);
254 }
255
256 /**
257  * This adds adds an object to the box before the indicated object
258  *
259  * This will add the @p subobj to the box indicated before the object
260  * indicated with @p before. If @p before is not already in the box, results
261  * are undefined. Before means either to the left of the indicated object or
262  * above it depending on orientation.
263  *
264  * @param obj The box object
265  * @param subobj The object to add to the box
266  * @param before The object before which to add it
267  *
268  * @ingroup Box
269  */
270 EAPI void
271 elm_box_pack_before(Evas_Object *obj, Evas_Object *subobj, Evas_Object *before)
272 {
273    ELM_CHECK_WIDTYPE(obj, widtype);
274    Widget_Data *wd = elm_widget_data_get(obj);
275    if (!wd) return;
276    elm_widget_sub_object_add(obj, subobj);
277    evas_object_box_insert_before(wd->box, subobj, before);
278 }
279
280 /**
281  * This adds adds an object to the box after the indicated object
282  *
283  * This will add the @p subobj to the box indicated after the object
284  * indicated with @p after. If @p after is not already in the box, results
285  * are undefined. After means either to the right of the indicated object or
286  * below it depending on orientation.
287  *
288  * @param obj The box object
289  * @param subobj The object to add to the box
290  * @param after The object after which to add it
291  *
292  * @ingroup Box
293  */
294 EAPI void
295 elm_box_pack_after(Evas_Object *obj, Evas_Object *subobj, Evas_Object *after)
296 {
297    ELM_CHECK_WIDTYPE(obj, widtype);
298    Widget_Data *wd = elm_widget_data_get(obj);
299    if (!wd) return;
300    elm_widget_sub_object_add(obj, subobj);
301    evas_object_box_insert_after(wd->box, subobj, after);
302 }
303
304 /**
305  * This clears the box items
306  *
307  * This delete all members of the box object, but not the box itself.
308  *
309  * @param obj The box object
310  *
311  * @ingroup Box
312  */
313 EAPI void
314 elm_box_clear(Evas_Object *obj)
315 {
316    ELM_CHECK_WIDTYPE(obj, widtype);
317    Widget_Data *wd = elm_widget_data_get(obj);
318    if (!wd) return;
319    evas_object_box_remove_all(wd->box, 1);
320 }
321
322 /**
323  * This unpack a box item
324  *
325  * This unpack the selected member from the box object, but does not delete
326  * the box itself or the packed items.
327  *
328  * @param obj The box object
329  *
330  * @ingroup Box
331  */
332 EAPI void
333 elm_box_unpack(Evas_Object *obj, Evas_Object *subobj)
334 {
335    ELM_CHECK_WIDTYPE(obj, widtype);
336    Widget_Data *wd = elm_widget_data_get(obj);
337    if (!wd) return;
338    evas_object_box_remove(wd->box, subobj);
339 }
340
341 /**
342  * This unpack the box items
343  *
344  * This unpack all members from the box object, but does not delete
345  * the box itself or the packed items.
346  *
347  * @param obj The box object
348  *
349  * @ingroup Box
350  */
351 EAPI void
352 elm_box_unpack_all(Evas_Object *obj)
353 {
354    ELM_CHECK_WIDTYPE(obj, widtype);
355    Widget_Data *wd = elm_widget_data_get(obj);
356    if (!wd) return;
357    evas_object_box_remove_all(wd->box, 0);
358 }
359
360
361 EAPI void
362 elm_box_extended_set(Evas_Object *obj, Eina_Bool extended)
363 {
364    ELM_CHECK_WIDTYPE(obj, widtype);
365    Widget_Data *wd = elm_widget_data_get(obj);
366    if (!wd) return;
367    wd->extended = !!extended;
368    if (extended)
369            wd->horizontal = 1;  /* Do NOT support vertical extended mode */
370    evas_object_smart_calculate(wd->box);
371 }
372
373
374