Fixed problem layout is broken, when screen resolution set to WVGA
[apps/home/quickpanel.git] / daemon / notifications / noti_gridbox.c
1 /*
2  * Copyright 2012  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *  http://floralicense.org/license/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <Ecore_X.h>
18
19 #include "quickpanel-ui.h"
20 #include "common.h"
21 #include "list_util.h"
22 #include "quickpanel_def.h"
23 #include "noti_gridbox.h"
24 #include "noti_box.h"
25
26 #define E_DATA_LAYOUT_PORTRAIT "layout_portrait"
27 #define E_DATA_LAYOUT_LANDSCAPE "layout_landscape"
28 #define E_DATA_CB_DELETE_ITEM "cb_delete_item"
29 #define E_DATA_CB_REMOVED "cb_removed"
30 #define E_DATA_APP_DATA "app_data"
31
32 typedef struct _gridbox_info_layout {
33         int n_per_rows;
34         int padding_top;
35         int padding_left;
36         int padding_right;
37         int padding_bottom;
38         int padding_between;
39         int child_w;
40         int child_h;
41         int limit_w;
42         double scale;
43 } gridbox_info_layout;
44
45 typedef struct _gridbox_info_animation {
46         Evas_Object *gridbox;
47         Evas_Object *item;
48
49         void (*update_cb)(Evas_Object *list, void *data, int is_prepend);
50         Evas_Object *container;
51         void *noti;
52         int pos;
53 } gridbox_info_animation;
54
55 static void _gridbox_layout_get_pos(int order, int *x, int *y, void *data) {
56         gridbox_info_layout *info_layout = data;
57
58         retif(data == NULL, , "invalid parameter");
59         retif(x == NULL, , "invalid parameter");
60         retif(y == NULL, , "invalid parameter");
61
62         int n_per_row = info_layout->n_per_rows;
63
64         int row = (order - 1) / n_per_row;
65         int column = (order - 1) - (row * n_per_row);
66
67         //DBG("order:%d r:%d c:%d", order, row, column);
68
69         int row_x = info_layout->padding_left
70                         + ((info_layout->child_w + info_layout->padding_between) * column);
71
72         int row_y = info_layout->padding_top
73                         + ((info_layout->child_h + info_layout->padding_between) * row);
74
75         *x = row_x;
76         *y = row_y;
77 }
78
79 static void _gridbox_layout(Evas_Object *o, Evas_Object_Box_Data *priv,
80                 void *data) {
81         int n_children;
82         int x, y, w, h;
83         int off_x = 0, off_y = 0;
84         Eina_List *l;
85         Eina_List *l_next;
86         Evas_Object_Box_Option *opt;
87         int child_w;
88         int space_w = 0;
89         int num_padding_between = 0;
90
91         retif(o == NULL, , "invalid parameter");
92         retif(priv == NULL, , "invalid parameter");
93         retif(data == NULL, , "invalid parameter");
94
95         gridbox_info_layout *info_layout = (gridbox_info_layout *) data;
96
97         n_children = eina_list_count(priv->children);
98         DBG("layout function:%d", n_children);
99         if (!n_children) {
100                 evas_object_size_hint_min_set(o, -1, 0);
101                 return;
102         }
103
104         //box geometry
105         evas_object_geometry_get(o, &x, &y, &w, &h);
106
107         //set info about children
108         opt = eina_list_data_get(priv->children);
109
110         num_padding_between = info_layout->n_per_rows / 2;
111         num_padding_between += (info_layout->n_per_rows > 1 && (info_layout->n_per_rows % 2) > 0) ? 1 : 0;
112
113         space_w = (info_layout->padding_left * 2) + (info_layout->padding_between * num_padding_between);
114         child_w = (info_layout->limit_w - space_w) / info_layout->n_per_rows;
115
116         info_layout->child_w = child_w;
117
118         DBG("grid layout children:%d %d", info_layout->child_w, info_layout->child_h);
119
120         int order_children = 1;
121         EINA_LIST_FOREACH_SAFE(priv->children, l, l_next, opt)
122         {
123                 _gridbox_layout_get_pos(order_children, &off_x, &off_y, info_layout);
124                 evas_object_move(opt->obj, x + off_x, y + off_y);
125                 evas_object_size_hint_min_set(opt->obj, info_layout->child_w,
126                                 info_layout->child_h);
127                 evas_object_resize(opt->obj, info_layout->child_w,
128                                 info_layout->child_h);
129                 order_children++;
130         }
131
132         evas_object_size_hint_min_set(o, -1,
133                         off_y + info_layout->child_h + info_layout->padding_bottom);
134 }
135
136 HAPI Evas_Object *gridbox_create(Evas_Object *parent, void *data) {
137
138         retif(parent == NULL, NULL, "invalid parameter");
139         retif(data == NULL, NULL, "invalid parameter");
140         struct appdata *ad = data;
141         Evas_Object *gridbox = NULL;
142
143         gridbox_info_layout *info_layout_portrait = NULL;
144         gridbox_info_layout *info_layout_landscape = NULL;
145
146         info_layout_portrait = (gridbox_info_layout *) malloc(
147                         sizeof(gridbox_info_layout));
148         retif(info_layout_portrait == NULL, NULL, "memory allocation failed");
149         info_layout_portrait->padding_between = 12 * ad->scale;
150         info_layout_portrait->padding_top = 0;
151         info_layout_portrait->padding_left = 14 * ad->scale;
152         info_layout_portrait->padding_bottom = 12 * ad->scale;
153         info_layout_portrait->n_per_rows = 2;
154         info_layout_portrait->child_w = 0; //340;
155         info_layout_portrait->child_h = BOX_HEIGHT_P * ad->scale; //400;
156         info_layout_portrait->limit_w = ad->win_width; //400;
157         info_layout_portrait->scale = ad->scale;
158
159         info_layout_landscape = (gridbox_info_layout *) malloc(
160                         sizeof(gridbox_info_layout));
161         retif(info_layout_landscape == NULL, NULL, "memory allocation failed");
162         info_layout_landscape->padding_between = 12 * ad->scale;
163         info_layout_landscape->padding_top = 0;
164         info_layout_landscape->padding_left = 14 * ad->scale;
165         info_layout_landscape->padding_bottom = 12 * ad->scale;
166         info_layout_landscape->n_per_rows = 3;
167         info_layout_landscape->child_w = 0; //409;
168         info_layout_landscape->child_h = BOX_HEIGHT_L * ad->scale; //400;
169         info_layout_landscape->limit_w = ad->win_height; //400;
170         info_layout_landscape->scale = ad->scale;
171
172         gridbox = elm_box_add(parent);
173         evas_object_size_hint_weight_set(gridbox, EVAS_HINT_EXPAND,
174                         EVAS_HINT_EXPAND);
175         evas_object_size_hint_align_set(gridbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
176
177         if (ad->angle == 270 || ad->angle == 90)
178                 elm_box_layout_set(gridbox, _gridbox_layout, info_layout_landscape,
179                                 NULL);
180         else
181                 elm_box_layout_set(gridbox, _gridbox_layout, info_layout_portrait,
182                                 NULL);
183
184         evas_object_show(gridbox);
185
186         evas_object_data_set(gridbox, E_DATA_LAYOUT_PORTRAIT, info_layout_portrait);
187         evas_object_data_set(gridbox, E_DATA_LAYOUT_LANDSCAPE,
188                         info_layout_landscape);
189         evas_object_data_set(gridbox, E_DATA_CB_DELETE_ITEM, NULL);
190         evas_object_data_set(gridbox, E_DATA_APP_DATA, ad);
191
192         qp_item_data *qid
193                 = quickpanel_list_util_item_new(QP_ITEM_TYPE_NOTI, NULL);
194         quickpanel_list_util_item_set_tag(gridbox, qid);
195
196         return gridbox;
197 }
198
199 HAPI void gridbox_remove(Evas_Object *gridbox) {
200
201         retif(gridbox == NULL, , "invalid parameter");
202
203         gridbox_info_layout *info_layout_portrait = evas_object_data_get(gridbox,
204                         E_DATA_LAYOUT_PORTRAIT);
205         gridbox_info_layout *info_layout_landscape = evas_object_data_get(gridbox,
206                         E_DATA_LAYOUT_LANDSCAPE);
207
208         gridbox_remove_all_item(gridbox, 0);
209         evas_object_data_del(gridbox, E_DATA_LAYOUT_PORTRAIT);
210         evas_object_data_del(gridbox, E_DATA_LAYOUT_LANDSCAPE);
211         evas_object_data_del(gridbox, E_DATA_CB_DELETE_ITEM);
212         evas_object_data_del(gridbox, E_DATA_APP_DATA);
213         quickpanel_list_util_item_del_tag(gridbox);
214         evas_object_del(gridbox);
215
216         if (info_layout_portrait != NULL)
217                 free(info_layout_portrait);
218         if (info_layout_landscape != NULL)
219                 free(info_layout_landscape);
220 }
221
222 HAPI void gridbox_set_item_deleted_cb(Evas_Object *gridbox,
223                 void(*deleted_cb)(void *data, Evas_Object *obj)) {
224         retif(gridbox == NULL, , "invalid parameter");
225         retif(deleted_cb == NULL, , "invalid parameter");
226
227         evas_object_data_set(gridbox, E_DATA_CB_DELETE_ITEM, deleted_cb);
228 }
229
230 static void _gridbox_call_item_deleted_cb(Evas_Object *gridbox, void *data,
231                 Evas_Object *obj) {
232         retif(gridbox == NULL, , "invalid parameter");
233
234         void (*deleted_cb)(void *data, Evas_Object *obj) = NULL;
235
236         deleted_cb = evas_object_data_get(gridbox, E_DATA_CB_DELETE_ITEM);
237
238         if (deleted_cb != NULL) {
239                 deleted_cb(data, obj);
240         }
241 }
242
243 HAPI void gridbox_add_item(Evas_Object *gridbox, Evas_Object *item, int is_prepend) {
244         const char *signal = NULL;
245
246         retif(gridbox == NULL, , "invalid parameter");
247         retif(item == NULL, , "invalid parameter");
248
249         struct appdata *ad = evas_object_data_get(gridbox, E_DATA_APP_DATA);
250
251         if (ad != NULL) {
252                 if (ad->angle == 270 || ad->angle == 90) {
253                         signal = "box.landscape";
254                 } else {
255                         signal = "box.portrait";
256                 }
257         }
258
259         DBG("set to %s, %x", signal, item);
260
261         elm_object_signal_emit(item, signal, "box.prog");
262         edje_object_message_signal_process(_EDJ(item));
263         elm_layout_sizing_eval(item);
264
265         if (is_prepend == GRIDBOX_PREPEND)
266                 elm_box_pack_start(gridbox, item);
267         else
268                 elm_box_pack_end(gridbox, item);
269 }
270
271 static void _gridbox_remove_item_anim_cb(void *data, Elm_Transit *transit) {
272         DBG("");
273         retif(data == NULL, , "invalid parameter");
274         retif(transit == NULL, , "invalid parameter");
275
276         gridbox_info_animation *info_animation = data;
277
278         retif(info_animation->gridbox == NULL, , "invalid parameter");
279         retif(info_animation->item == NULL, , "invalid parameter");
280
281         DBG("remove:%p", info_animation->item);
282
283         void *node = noti_box_node_get(info_animation->item);
284         elm_box_unpack(info_animation->gridbox, info_animation->item);
285         noti_box_remove(info_animation->item);
286         _gridbox_call_item_deleted_cb(info_animation->gridbox,
287                         node, NULL);
288
289         if (info_animation->update_cb != NULL) {
290                 retif(info_animation->container == NULL, , "invalid parameter");
291                 retif(info_animation->noti == NULL, , "invalid parameter");
292
293                 info_animation->update_cb(info_animation->container,
294                                 info_animation->noti, info_animation->pos);
295         }
296
297         free(info_animation);
298         info_animation = NULL;
299 }
300
301 HAPI void gridbox_remove_item(Evas_Object *gridbox, Evas_Object *item, int with_animation) {
302         DBG("remove:%p", item);
303         retif(gridbox == NULL, , "invalid parameter");
304         retif(item == NULL, , "invalid parameter");
305
306         if (noti_box_get_status(item) == STATE_DELETING) {
307                 return ;
308         }
309         noti_box_set_status(item, STATE_DELETING);
310
311         if (with_animation == 1) {
312                 gridbox_info_animation *info_animation = (gridbox_info_animation *) malloc(
313                                 sizeof(gridbox_info_animation));
314                 if (info_animation == NULL)
315                         return;
316                 info_animation->gridbox = gridbox;
317                 info_animation->item = item;
318                 info_animation->update_cb = NULL;
319                 info_animation->container = NULL;
320                 info_animation->noti = NULL;
321                 info_animation->pos = 0;
322
323                 Elm_Transit *transit = elm_transit_add();
324                 //Fade in and out with layout object.
325                 elm_transit_object_add(transit, item);
326                 elm_transit_effect_fade_add(transit);
327                 elm_transit_duration_set(transit, 0.7);
328                 elm_transit_del_cb_set(transit, _gridbox_remove_item_anim_cb,
329                                 info_animation);
330                 elm_transit_go(transit);
331         } else {
332                 void *node = noti_box_node_get(item);
333                 elm_box_unpack(gridbox, item);
334                 noti_box_remove(item);
335                 _gridbox_call_item_deleted_cb(gridbox,
336                                 node, NULL);
337         }
338 }
339
340 HAPI void gridbox_remove_all_item(Evas_Object *gridbox, int with_animation) {
341         DBG("");
342         retif(gridbox == NULL, , "invalid parameter");
343
344         Eina_List *l;
345         Eina_List *l_next;
346         Evas_Object *obj;
347         Eina_List *item_list = elm_box_children_get(gridbox);
348
349         EINA_LIST_FOREACH_SAFE(item_list, l, l_next, obj)
350         {
351                 if (obj != NULL) {
352                         // call deleted callback
353                         gridbox_remove_item(gridbox, obj, with_animation);
354                 }
355         }
356 }
357
358 HAPI void gridbox_update_item(Evas_Object *gridbox, Evas_Object *item) {
359
360         retif(gridbox == NULL, , "invalid parameter");
361         retif(item == NULL, , "invalid parameter");
362 }
363
364 HAPI void gridbox_remove_and_add_item(Evas_Object *gridbox, Evas_Object *item
365                 ,void (*update_cb)(Evas_Object *list, void *data, int is_prepend)
366                 ,void *container, void *data, int pos) {
367
368         retif(gridbox == NULL, , "invalid parameter");
369         retif(item == NULL, , "invalid parameter");
370         retif(update_cb == NULL, , "invalid parameter");
371         retif(container == NULL, , "invalid parameter");
372         retif(data == NULL, , "invalid parameter");
373
374         if (noti_box_get_status(item) == STATE_DELETING) {
375                 return ;
376         }
377         noti_box_set_status(item, STATE_DELETING);
378
379         gridbox_info_animation *info_animation = (gridbox_info_animation *) malloc(
380                         sizeof(gridbox_info_animation));
381         if (info_animation == NULL)
382                 return;
383         info_animation->gridbox = gridbox;
384         info_animation->item = item;
385         info_animation->update_cb = update_cb;
386         info_animation->container = container;
387         info_animation->noti = data;
388         info_animation->pos = pos;
389
390         Elm_Transit *transit = elm_transit_add();
391         //Fade in and out with layout object.
392         elm_transit_object_add(transit, item);
393         elm_transit_effect_fade_add(transit);
394         elm_transit_duration_set(transit, 0.4);
395         elm_transit_del_cb_set(transit, _gridbox_remove_item_anim_cb,
396                         info_animation);
397         elm_transit_go(transit);
398 }
399
400 HAPI void gridbox_finalize_rotation_cb(void *data) {
401         retif(data == NULL, , "invalid parameter");
402         Evas_Object *gridbox = data;
403
404         elm_box_recalculate(gridbox);
405 }
406
407 HAPI void gridbox_rotation(Evas_Object *gridbox, int angle) {
408         const char *signal = NULL;
409
410         retif(gridbox == NULL, , "invalid parameter");
411
412         gridbox_info_layout *info_layout_portrait = evas_object_data_get(gridbox,
413                         E_DATA_LAYOUT_PORTRAIT);
414         gridbox_info_layout *info_layout_landscape = evas_object_data_get(gridbox,
415                         E_DATA_LAYOUT_LANDSCAPE);
416
417         retif(info_layout_portrait == NULL || info_layout_landscape == NULL, ,
418                         "gridbox is crashed");
419
420         Eina_List *l;
421         Eina_List *l_next;
422         Evas_Object *obj;
423         Eina_List *item_list = elm_box_children_get(gridbox);
424
425         if (angle == 270 || angle == 90) {
426                 signal = "box.landscape";
427         } else {
428                 signal = "box.portrait";
429         }
430
431         DBG("all count:%d", eina_list_count (item_list));
432
433         EINA_LIST_FOREACH_SAFE(item_list, l, l_next, obj)
434         {
435                 if (obj != NULL) {
436                         elm_object_signal_emit(obj, signal, "box.prog");
437                         edje_object_message_signal_process(_EDJ(obj));
438                         elm_layout_sizing_eval(obj);
439                         DBG("set to %s, %x", signal, obj);
440                 }
441         }
442
443         if (angle == 270 || angle == 90) {
444                 elm_box_layout_set(gridbox, _gridbox_layout, info_layout_landscape,
445                                 NULL);
446
447 #if 0
448                 layout_data = elm_box_transition_new(0.0, _gridbox_layout,
449                                 info_layout_portrait, NULL, _gridbox_layout,
450                                 info_layout_landscape, NULL, gridbox_finalize_rotation_cb,
451                                 gridbox);
452 #endif
453         } else {
454                 elm_box_layout_set(gridbox, _gridbox_layout, info_layout_portrait,
455                                 NULL);
456 #if 0
457                 layout_data = elm_box_transition_new(0.0, _gridbox_layout,
458                                 info_layout_landscape, NULL, _gridbox_layout,
459                                 info_layout_portrait, NULL, gridbox_finalize_rotation_cb,
460                                 gridbox);
461 #endif
462         }
463
464 #if 0
465         elm_box_layout_set(gridbox, elm_box_layout_transition, layout_data,
466                         elm_box_transition_free);
467 #endif
468         DBG("Angle  Rotation  is %d", angle);
469 }