[box] added extended mode to horizontal box
[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 extended mode
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  * extended arranging contents left to right.
141  *
142  * @param obj The box object
143  * @param extended The extended flag (1 = extended, 0 = normal)
144  *
145  * @ingroup Box
146  */
147 EAPI void
148 elm_box_extended_set(Evas_Object *obj, Eina_Bool extended)
149 {
150    ELM_CHECK_WIDTYPE(obj, widtype);
151    Widget_Data *wd = elm_widget_data_get(obj);
152    if (!wd) return;
153    wd->extended = !!extended;
154    if (extended)
155            wd->horizontal = 1;  /* Do NOT support vertical extended mode */
156    evas_object_smart_calculate(wd->box);
157
158 }
159
160
161 /**
162  * Set the horizontal orientation
163  *
164  * By default box object arrange their contents vertically from top to bottom.
165  * By calling this and providing @p orizontal as true, the box will become
166  * horizontal arranging contents left to right.
167  *
168  * @param obj The box object
169  * @param horizontal The horizontal flag (1 = horizontal, 0 = vertical)
170  *
171  * @ingroup Box
172  */
173 EAPI void
174 elm_box_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
175 {
176    ELM_CHECK_WIDTYPE(obj, widtype);
177    Widget_Data *wd = elm_widget_data_get(obj);
178    if (!wd) return;
179    wd->horizontal = !!horizontal;
180    evas_object_smart_calculate(wd->box);
181    /*if (wd->horizontal)
182      {
183         if (wd->homogeneous)
184           evas_object_box_layout_set(wd->box,
185                 evas_object_box_layout_homogeneous_horizontal, NULL, NULL);
186         else
187           evas_object_box_layout_set(wd->box, evas_object_box_layout_horizontal,
188                                      NULL, NULL);
189      }
190    else
191      {
192         if (wd->homogeneous)
193           evas_object_box_layout_set(wd->box,
194                 evas_object_box_layout_homogeneous_vertical, NULL, NULL);
195         else
196           evas_object_box_layout_set(wd->box, evas_object_box_layout_horizontal,
197                                      NULL, NULL);
198      }*/
199 }
200
201 /**
202  * Set homogenous layout
203  *
204  * If enabled, homogenous layout makes all items the same size. This size is
205  * of course governed by the size of the largest item in the box.
206  *
207  * @param obj The box object
208  * @param homogenous The homogenous flag (1 = on, 2 = off)
209  *
210  * @ingroup Box
211  */
212 EAPI void
213 elm_box_homogenous_set(Evas_Object *obj, Eina_Bool homogenous)
214 {
215    ELM_CHECK_WIDTYPE(obj, widtype);
216    Widget_Data *wd = elm_widget_data_get(obj);
217    if (!wd) return;
218    wd->homogeneous = !!homogenous;
219    evas_object_smart_calculate(wd->box);
220    /*if (wd->horizontal)
221      {
222         if (wd->homogeneous)
223           evas_object_box_layout_set(wd->box,
224                 evas_object_box_layout_homogeneous_horizontal, NULL, NULL);
225         else
226           evas_object_box_layout_set(wd->box, evas_object_box_layout_horizontal,
227                                      NULL, NULL);
228      }
229    else
230      {
231         if (wd->homogeneous)
232           evas_object_box_layout_set(wd->box,
233                 evas_object_box_layout_homogeneous_vertical, NULL, NULL);
234         else
235           evas_object_box_layout_set(wd->box, evas_object_box_layout_horizontal,
236                                      NULL, NULL);
237      }*/
238 }
239
240 /**
241  * This adds a box at the start of the box (top or left based on orientation)
242  *
243  * This will add the @p subobj to the box object indicated at the beginning
244  * of the box (the left or top end).
245  *
246  * @param obj The box object
247  * @param subobj The object to add to the box
248  *
249  * @ingroup Box
250  */
251 EAPI void
252 elm_box_pack_start(Evas_Object *obj, Evas_Object *subobj)
253 {
254    ELM_CHECK_WIDTYPE(obj, widtype);
255    Widget_Data *wd = elm_widget_data_get(obj);
256    if (!wd) return;
257    elm_widget_sub_object_add(obj, subobj);
258    evas_object_box_prepend(wd->box, subobj);
259 }
260
261 /**
262  * This adds a box at the end of the box (bottom or right based on orientation)
263  *
264  * This will add the @p subobj to the box object indicated at the end
265  * of the box (the right or bottom end).
266  *
267  * @param obj The box object
268  * @param subobj The object to add to the box
269  *
270  * @ingroup Box
271  */
272 EAPI void
273 elm_box_pack_end(Evas_Object *obj, Evas_Object *subobj)
274 {
275    ELM_CHECK_WIDTYPE(obj, widtype);
276    Widget_Data *wd = elm_widget_data_get(obj);
277    if (!wd) return;
278    elm_widget_sub_object_add(obj, subobj);
279    evas_object_box_append(wd->box, subobj);
280 }
281
282 /**
283  * This adds adds an object to the box before the indicated object
284  *
285  * This will add the @p subobj to the box indicated before the object
286  * indicated with @p before. If @p before is not already in the box, results
287  * are undefined. Before means either to the left of the indicated object or
288  * above it depending on orientation.
289  *
290  * @param obj The box object
291  * @param subobj The object to add to the box
292  * @param before The object before which to add it
293  *
294  * @ingroup Box
295  */
296 EAPI void
297 elm_box_pack_before(Evas_Object *obj, Evas_Object *subobj, Evas_Object *before)
298 {
299    ELM_CHECK_WIDTYPE(obj, widtype);
300    Widget_Data *wd = elm_widget_data_get(obj);
301    if (!wd) return;
302    elm_widget_sub_object_add(obj, subobj);
303    evas_object_box_insert_before(wd->box, subobj, before);
304 }
305
306 /**
307  * This adds adds an object to the box after the indicated object
308  *
309  * This will add the @p subobj to the box indicated after the object
310  * indicated with @p after. If @p after is not already in the box, results
311  * are undefined. After means either to the right of the indicated object or
312  * below it depending on orientation.
313  *
314  * @param obj The box object
315  * @param subobj The object to add to the box
316  * @param after The object after which to add it
317  *
318  * @ingroup Box
319  */
320 EAPI void
321 elm_box_pack_after(Evas_Object *obj, Evas_Object *subobj, Evas_Object *after)
322 {
323    ELM_CHECK_WIDTYPE(obj, widtype);
324    Widget_Data *wd = elm_widget_data_get(obj);
325    if (!wd) return;
326    elm_widget_sub_object_add(obj, subobj);
327    evas_object_box_insert_after(wd->box, subobj, after);
328 }
329
330 /**
331  * This clears the box items
332  *
333  * This delete all members of the box object, but not the box itself.
334  *
335  * @param obj The box object
336  *
337  * @ingroup Box
338  */
339 EAPI void
340 elm_box_clear(Evas_Object *obj)
341 {
342    ELM_CHECK_WIDTYPE(obj, widtype);
343    Widget_Data *wd = elm_widget_data_get(obj);
344    if (!wd) return;
345    evas_object_box_remove_all(wd->box, 1);
346 }
347
348 /**
349  * This unpack a box item
350  *
351  * This unpack the selected member from the box object, but does not delete
352  * the box itself or the packed items.
353  *
354  * @param obj The box object
355  *
356  * @ingroup Box
357  */
358 EAPI void
359 elm_box_unpack(Evas_Object *obj, Evas_Object *subobj)
360 {
361    ELM_CHECK_WIDTYPE(obj, widtype);
362    Widget_Data *wd = elm_widget_data_get(obj);
363    if (!wd) return;
364    evas_object_box_remove(wd->box, subobj);
365 }
366
367 /**
368  * This unpack the box items
369  *
370  * This unpack all members from the box object, but does not delete
371  * the box itself or the packed items.
372  *
373  * @param obj The box object
374  *
375  * @ingroup Box
376  */
377 EAPI void
378 elm_box_unpack_all(Evas_Object *obj)
379 {
380    ELM_CHECK_WIDTYPE(obj, widtype);
381    Widget_Data *wd = elm_widget_data_get(obj);
382    if (!wd) return;
383    evas_object_box_remove_all(wd->box, 0);
384 }