[elm_softkey] Some Null check in softkey panel item add
[framework/uifw/elementary.git] / src / lib / elm_gridbox.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup Gridbox Gridbox
6  * @ingroup Elementary
7  *
8  * This is a gridbox widget to show multiple objects in a grid
9  */
10
11 typedef struct _Widget_Data Widget_Data;
12
13 struct _Widget_Data
14 {
15    Evas_Object *tbl, *scr;
16    Evas_Coord itemsize_h, itemsize_v;
17    Evas_Coord minw, minh;
18    Evas_Coord horizontal, vertical;
19    int x, y;
20    Eina_Bool homogeneous:1;
21 };
22
23 static void _del_hook(Evas_Object * obj);
24
25 static void _sizing_eval(Evas_Object * obj, int mode);
26
27 static void _changed_size_hints(void *data, Evas * e, Evas_Object * obj,
28                                 void *event_info);
29 static void _changed_size_min(void *data, Evas * e, Evas_Object * obj,
30                               void *event_info);
31 static void _sub_del(void *data, Evas_Object * obj, void *event_info);
32
33 static void _show_event(void *data, Evas_Object * obj, void *event_info);
34
35 static void
36 _del_pre_hook(Evas_Object * obj)
37 {
38    Widget_Data *wd = elm_widget_data_get(obj);
39
40    evas_object_event_callback_del_full(wd->tbl,
41                                        EVAS_CALLBACK_CHANGED_SIZE_HINTS,
42                                        _changed_size_hints, obj);
43    evas_object_event_callback_del_full(wd->tbl, EVAS_CALLBACK_RESIZE,
44                                        _changed_size_min, obj);
45    evas_object_del(wd->tbl);
46    wd->tbl = NULL;
47    evas_object_del(wd->scr);
48    wd->scr = NULL;
49 }
50
51 static void
52 _del_hook(Evas_Object * obj)
53 {
54    Widget_Data *wd = elm_widget_data_get(obj);
55
56    free(wd);
57 }
58
59 static Eina_Bool
60 _arrange_table(Evas_Object * obj)
61 {
62    Widget_Data *wd = elm_widget_data_get(obj);
63
64    Eina_List *l, *l_temp = NULL;
65
66    Evas_Object *item;
67
68    int i = 0;
69
70    if (wd)
71      {
72         if (wd->tbl)
73           {
74              int index =
75                 eina_list_count(evas_object_table_children_get(wd->tbl));
76              if (!index)
77                 return EINA_FALSE;
78
79              elm_gridbox_item_size_set(obj, wd->itemsize_h, wd->itemsize_v);
80              l = evas_object_table_children_get(wd->tbl);
81
82              EINA_LIST_FOREACH(l, l_temp, item)
83              {
84                 evas_object_table_unpack(wd->tbl, item);
85                 elm_widget_sub_object_del(wd->tbl, item);
86                 evas_object_table_pack(wd->tbl, item, i % wd->x, i / wd->x, 1,
87                                        1);
88                 i++;
89              }
90           }
91      }
92
93    return EINA_TRUE;
94 }
95
96 static void
97 _sizing_eval(Evas_Object * obj, int mode)
98 {
99    Widget_Data *wd = elm_widget_data_get(obj);
100
101    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
102
103    Evas_Coord w, h;
104
105    evas_object_size_hint_min_get(wd->scr, &minw, &minh);
106    evas_object_size_hint_max_get(wd->scr, &maxw, &maxh);
107    evas_object_size_hint_min_set(obj, minw, minh);
108    evas_object_size_hint_max_set(obj, maxw, maxh);
109    evas_object_geometry_get(wd->scr, NULL, NULL, &w, &h);
110
111    if (w < minw)
112       w = minw;
113    if (h < minh)
114       h = minh;
115    if ((maxw >= 0) && (w > maxw))
116       w = maxw;
117    if ((maxh >= 0) && (h > maxh))
118       h = maxh;
119    evas_object_resize(obj, w, h);
120
121    wd->minw = w;
122    wd->minh = h;
123    if (w < wd->itemsize_h || h < wd->itemsize_v)
124       return;
125    if (wd->homogeneous)
126      {
127         wd->x = w / wd->itemsize_h;
128         wd->y = h / wd->itemsize_v;
129         wd->horizontal = (wd->minw - wd->x * wd->itemsize_h) / wd->x;
130         wd->vertical = (wd->minh - wd->y * wd->itemsize_v) / wd->y;
131         elm_gridbox_padding_set(obj, wd->horizontal, wd->vertical);
132      }
133
134    if (!mode)
135       _arrange_table(obj);
136 }
137
138 static void
139 _changed_size_hints(void *data, Evas * e, Evas_Object * obj, void *event_info)
140 {
141    _sizing_eval(data, 0);
142 }
143
144 static void
145 _changed_size_min(void *data, Evas * e, Evas_Object * obj, void *event_info)
146 {
147    _sizing_eval(data, 0);
148 }
149
150 static void
151 _sub_del(void *data, Evas_Object * obj, void *event_info)
152 {
153    _sizing_eval(obj, 1);
154 }
155
156 static void
157 _show_event(void *data, Evas_Object * obj, void *event_info)
158 {
159    _sizing_eval(data, 0);
160 }
161
162 static void
163 _freeze_on(void *data, Evas_Object * obj, void *event_info)
164 {
165    Widget_Data *wd = elm_widget_data_get(obj);
166
167    if (!wd)
168       return;
169    evas_object_smart_callback_call(wd->scr, "scroll-freeze-on", NULL);
170 }
171
172 static void
173 _freeze_off(void *data, Evas_Object * obj, void *event_info)
174 {
175    Widget_Data *wd = elm_widget_data_get(obj);
176
177    if (!wd)
178       return;
179    evas_object_smart_callback_call(wd->scr, "scroll-freeze-off", NULL);
180 }
181
182 /**
183  * Add a new gridbox to the parent
184  *
185  * @param parent The parent object
186  * @return The new object or NULL if it cannot be created
187  *
188  * @ingroup Gridbox
189  */
190 EAPI Evas_Object *
191 elm_gridbox_add(Evas_Object * parent)
192 {
193    Evas_Object *obj;
194
195    Evas *e;
196
197    Widget_Data *wd;
198
199    wd = ELM_NEW(Widget_Data);
200    e = evas_object_evas_get(parent);
201    obj = elm_widget_add(e);
202    elm_widget_type_set(obj, "gridbox");
203    elm_widget_sub_object_add(parent, obj);
204    elm_widget_data_set(obj, wd);
205    elm_widget_del_hook_set(obj, _del_hook);
206    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
207
208    wd->scr = elm_scroller_add(parent);
209    elm_widget_resize_object_set(obj, wd->scr);
210    elm_scroller_bounce_set(wd->scr, 0, 1);
211
212    wd->tbl = evas_object_table_add(e);
213    evas_object_size_hint_weight_set(wd->tbl, 0.0, 0.0);
214    elm_scroller_content_set(wd->scr, wd->tbl);
215    evas_object_show(wd->tbl);
216
217    evas_object_event_callback_add(wd->scr, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
218                                   _changed_size_hints, obj);
219    evas_object_event_callback_add(wd->scr, EVAS_CALLBACK_RESIZE,
220                                   _changed_size_min, obj);
221    evas_object_event_callback_add(wd->scr, EVAS_CALLBACK_SHOW, _show_event,
222                                   obj);
223
224    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
225    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
226    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
227
228    _sizing_eval(obj, 0);
229
230    return obj;
231 }
232
233 /**
234  * Set padding between cells.
235  *
236  * @param obj The layout object.
237  * @param horizontal set the horizontal padding.
238  * @param vertical set the vertical padding.
239  *
240  * @ingroup Gridbox
241  */
242 EAPI void
243 elm_gridbox_padding_set(Evas_Object * obj, Evas_Coord horizontal,
244                         Evas_Coord vertical)
245 {
246    Widget_Data *wd = elm_widget_data_get(obj);
247
248    if (!wd)
249       return;
250
251    wd->horizontal = horizontal;
252    wd->vertical = vertical;
253    if (wd->tbl)
254       evas_object_table_padding_set(wd->tbl, horizontal, vertical);
255 }
256
257 /**
258  * Set gridbox item size
259  *
260  * @param obj The gridbox object
261  * @param h_pagesize The horizontal item size
262  * @param v_pagesize The vertical item size
263  *
264  * @ingroup Gridbox
265  */
266 EAPI void
267 elm_gridbox_item_size_set(Evas_Object * obj, Evas_Coord h_itemsize,
268                           Evas_Coord v_itemsize)
269 {
270    Widget_Data *wd = elm_widget_data_get(obj);
271
272    Evas_Coord minw = -1, minh = -1;
273
274    Evas_Coord w, h;
275
276    if (!wd)
277       return;
278
279    wd->itemsize_h = h_itemsize;
280    wd->itemsize_v = v_itemsize;
281    evas_object_size_hint_min_get(wd->scr, &minw, &minh);
282    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
283    if (w < minw)
284       w = minw;
285    if (h < minh)
286       h = minh;
287    wd->x = w / h_itemsize;
288    wd->y = h / v_itemsize;
289
290    if (!wd->x)
291       wd->x = 1;
292    if (!wd->y)
293       wd->y = 1;
294    _sizing_eval(obj, 1);
295 }
296
297 /**
298  * Add a subobject on the gridbox
299  *
300  * @param obj The table object
301  * @param subobj The subobject to be added to the gridbox
302  *
303  * @ingroup Gridbox
304  */
305 EAPI void
306 elm_gridbox_pack(Evas_Object * obj, Evas_Object * subobj)
307 {
308    Widget_Data *wd = elm_widget_data_get(obj);
309
310    int index = eina_list_count(evas_object_table_children_get(wd->tbl));
311
312    evas_object_size_hint_min_set(subobj, wd->itemsize_h, wd->itemsize_v);
313    evas_object_size_hint_max_set(subobj, wd->itemsize_h, wd->itemsize_v);
314    elm_widget_sub_object_add(obj, subobj);
315    evas_object_table_pack(wd->tbl, subobj, index % wd->x, index / wd->x, 1, 1);
316 }
317
318 /**
319  * Unpack a subobject on the gridbox
320  *
321  * @param obj The gribox object
322  * @param subobj The subobject to be removed to the gridbox
323  *
324  * @ingroup Gridbox
325  */
326 EAPI Eina_Bool
327 elm_gridbox_unpack(Evas_Object * obj, Evas_Object * subobj)
328 {
329    Widget_Data *wd = elm_widget_data_get(obj);
330
331    Eina_Bool ret = 0;
332
333    elm_widget_sub_object_del(wd->tbl, subobj);
334    ret = evas_object_table_unpack(wd->tbl, subobj);
335
336    _arrange_table(obj);
337
338    return ret;
339 }
340
341 /**
342  * Get the list of children for the gridbox.
343  *
344  * @param obj The gribox object
345  *
346  * @ingroup Gridbox
347  */
348 EAPI Eina_List *
349 elm_gridbox_children_get(Evas_Object * obj)
350 {
351    Widget_Data *wd = elm_widget_data_get(obj);
352
353    Eina_List *new_list = NULL;
354
355    new_list = evas_object_table_children_get(wd->tbl);
356
357    return new_list;
358 }
359
360 /**
361  * Set homogenous paddding layout
362  *
363  * @param obj The gribox object
364  * @param homogenous The homogenous flag (1 = on, 0 = off)
365  *
366  * @ingroup Gridbox
367  */
368 EAPI void
369 elm_gridbox_homogenous_padding_set(Evas_Object * obj, Eina_Bool homogenous)
370 {
371    Widget_Data *wd = elm_widget_data_get(obj);
372
373    wd->homogeneous = homogenous;
374 }