Merge "From: Kim Shinwoo <kimcinoo.efl@gmail.com> Subject: [E-devel] [patch][elementa...
[framework/uifw/elementary.git] / src / lib / elc_popup.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 #define ELM_POPUP_ACTION_BUTTON_MAX 3
5 typedef struct _Widget_Data Widget_Data;
6 typedef struct _Elm_Popup_Content_Item Elm_Popup_Content_Item;
7 typedef struct _Action_Area_Data Action_Area_Data;
8
9 struct _Widget_Data
10 {
11    Evas_Object *base;
12    Evas_Object *notify;
13    Evas_Object *title_icon;
14    Evas_Object *content_area;
15    Evas_Object *content_text_obj;
16    Evas_Object *action_area;
17    Evas_Object *box;
18    Evas_Object *scr;
19    Evas_Object *content;
20    Eina_List *items;
21    const char *title_text;
22    Action_Area_Data *buttons[ELM_POPUP_ACTION_BUTTON_MAX];
23    Elm_Wrap_Type content_text_wrap_type;
24    unsigned int button_count;
25    Evas_Coord max_sc_w;
26    Evas_Coord max_sc_h;
27    Eina_Bool scr_size_recalc:1;
28 };
29
30 struct _Elm_Popup_Content_Item
31 {
32    Elm_Widget_Item base;
33    const char *label;
34    Evas_Object *icon;
35    Evas_Smart_Cb func;
36    Eina_Bool disabled:1;
37 };
38
39 struct _Action_Area_Data
40 {
41    Evas_Object *obj;
42    Evas_Object *btn;
43    Eina_Bool delete_me;
44 };
45
46 static const char *widtype = NULL;
47 static void _del_hook(Evas_Object *obj);
48 static void _theme_hook(Evas_Object *obj);
49 static void _text_set_hook(Evas_Object *obj, const char *part,
50                                           const char *label);
51 static const char *_text_get_hook(const Evas_Object *obj,
52                                                  const char *part);
53 static void _content_set_hook(Evas_Object *obj, const char *part,
54                                              Evas_Object *content);
55 static Evas_Object *_content_get_hook(Evas_Object *obj,
56                                                      const char *part);
57 static Evas_Object *_content_unset_hook(Evas_Object *obj,
58                                                        const char *part);
59 static void _item_text_set_hook(Elm_Object_Item *it, const char *part,
60                                 const char *label);
61 static const char *_item_text_get_hook(const Elm_Object_Item *it,
62                                        const char *part);
63 static void _item_content_set_hook(Elm_Object_Item *it, const char *part,
64                                    Evas_Object *content);
65 static Evas_Object *_item_content_unset_hook(const Elm_Object_Item *it,
66                                              const char *part);
67 static Evas_Object *_item_content_get_hook(const Elm_Object_Item *it,
68                                            const char *part);
69 static void _item_disable_hook(Elm_Object_Item *it);
70 static void _item_del_pre_hook(Elm_Object_Item *it);
71 static void _item_signal_emit_hook(Elm_Object_Item *it, const char *emission,
72                                    const char *source);
73 static void _sizing_eval(Evas_Object *obj);
74 static void _block_clicked_cb(void *data, Evas_Object *obj, void *event_info);
75 static void _notify_resize(void *data, Evas *e, Evas_Object *obj,
76                            void *event_info);
77 static void _scroller_resize(void *data, Evas *e, Evas_Object *obj,
78                              void *event_info);
79 static void _timeout(void *data, Evas_Object *obj , void *event_info);
80 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
81 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
82 static void _restack(void *data, Evas *e, Evas_Object *obj, void *event_info);
83 static void _layout_change_cb(void *data, Evas_Object *obj __UNUSED__,
84                               const char *emission __UNUSED__,
85                               const char *source __UNUSED__);
86 static void _item_new(Elm_Popup_Content_Item *item);
87 static void _remove_items(Widget_Data *wd);
88 static void _list_new(Evas_Object *obj);
89 static void _list_del(Widget_Data *wd);
90 static void _item_sizing_eval(Elm_Popup_Content_Item *item);
91 static void _item_select_cb(void *data, Evas_Object *obj __UNUSED__,
92                             const char *emission __UNUSED__,
93                             const char *source __UNUSED__);
94 static void _scroller_size_calc(Evas_Object *obj);
95 static void _action_button_set(Evas_Object *obj, Evas_Object *btn,
96                                unsigned int idx);
97 static Evas_Object *_action_button_get(Evas_Object *obj, unsigned int idx);
98 static Evas_Object *_action_button_unset(Evas_Object *obj, unsigned int idx);
99 static void _button_remove(Evas_Object *obj, Evas_Object *content,
100                            Eina_Bool delete);
101 static void _popup_show(void *data, Evas *e, Evas_Object *obj,
102                         void *event_info);
103 static void _popup_hide(void *data, Evas *e, Evas_Object *obj,
104                         void *event_info);
105 static const char SIG_BLOCK_CLICKED[] = "block,clicked";
106 static const char SIG_TIMEOUT[] = "timeout";
107 static const Evas_Smart_Cb_Description _signals[] = {
108        {SIG_BLOCK_CLICKED, ""},
109        {SIG_TIMEOUT, ""},
110        {NULL, NULL}
111 };
112
113 #define ELM_POPUP_CONTENT_ITEM_CHECK_RETURN(it, ...)                        \
114   ELM_WIDGET_ITEM_CHECK_OR_RETURN((Elm_Widget_Item *)it, __VA_ARGS__); \
115   ELM_CHECK_WIDTYPE(WIDGET(item), widtype) __VA_ARGS__;
116
117 static void
118 _layout_set(Evas_Object *obj)
119 {
120    Widget_Data *wd = elm_widget_data_get(obj);
121
122    if (!wd) return;
123    if ((!(wd->title_text)) && (!(wd->title_icon)))
124      elm_object_signal_emit(wd->base, "elm,state,title_area,hidden", "elm");
125    else
126      elm_object_signal_emit(wd->base, "elm,state,title_area,visible", "elm");
127    if (wd->button_count)
128      elm_object_signal_emit(wd->base, "elm,state,action_area,visible", "elm");
129    else
130      elm_object_signal_emit(wd->base, "elm,state,action_area,hidden", "elm");
131 }
132
133 static void
134 _del_hook(Evas_Object *obj)
135 {
136    Widget_Data *wd = elm_widget_data_get(obj);
137
138    if (!wd) return;
139    free(wd);
140 }
141
142 static void
143 _del_pre_hook(Evas_Object *obj)
144 {
145    unsigned int i;
146    Widget_Data *wd = elm_widget_data_get(obj);
147
148    if (!wd) return;
149    evas_object_smart_callback_del(wd->notify, "block,clicked",
150                                   _block_clicked_cb);
151    evas_object_smart_callback_del(wd->notify, "timeout", _timeout);
152    evas_object_event_callback_del(wd->notify, EVAS_CALLBACK_RESIZE,
153                                   _notify_resize);
154    evas_object_event_callback_del(obj, EVAS_CALLBACK_SHOW, _popup_show);
155    wd->button_count = 0;
156    for (i = 0; i < ELM_POPUP_ACTION_BUTTON_MAX; i++)
157      if (wd->buttons[i])
158        {
159           evas_object_del(wd->buttons[i]->btn);
160           free(wd->buttons[i]);
161           wd->buttons[i] = NULL;
162        }
163    if (wd->items)
164      {
165         _remove_items(wd);
166         _list_del(wd);
167      }
168 }
169
170 static void
171 _theme_hook(Evas_Object *obj)
172 {
173    Eina_List *elist;
174    Elm_Popup_Content_Item *item;
175    char buf[128];
176    unsigned int i = 0;
177    Widget_Data *wd = elm_widget_data_get(obj);
178
179    if (!wd) return;
180    elm_layout_theme_set(wd->base, "popup", "base", elm_widget_style_get(obj));
181    _elm_widget_mirrored_reload(obj);
182    _mirrored_set(obj, elm_widget_mirrored_get(obj));
183    if (wd->button_count)
184      {
185         snprintf(buf, sizeof(buf), "buttons%u", wd->button_count);
186         elm_layout_theme_set(wd->action_area, "popup", buf,
187                              elm_widget_style_get(obj));
188         for (i = 0; i < ELM_POPUP_ACTION_BUTTON_MAX; i++)
189           {
190              if (!wd->buttons[i]) continue;
191              elm_object_style_set(wd->buttons[i]->btn, buf);
192           }
193      }
194    elm_layout_theme_set(wd->content_area, "popup", "content",
195                         elm_widget_style_get(obj));
196    if (wd->content_text_obj)
197      {
198         snprintf(buf, sizeof(buf), "popup/%s", elm_widget_style_get(obj));
199         elm_object_style_set(wd->content_text_obj, buf);
200      }
201    else if (wd->items)
202      {
203         EINA_LIST_FOREACH(wd->items, elist, item)
204           {
205              _elm_theme_object_set(obj, VIEW(item), "popup",
206                                    "item", elm_widget_style_get(obj));
207              if (item->label)
208                {
209                   edje_object_part_text_escaped_set(VIEW(item), "elm.text",
210                                                     item->label);
211                   edje_object_signal_emit(VIEW(item),
212                                           "elm,state,item,text,visible", "elm");
213                }
214              if (item->icon)
215                edje_object_signal_emit(VIEW(item),
216                                        "elm,state,item,icon,visible", "elm");
217              if (item->disabled)
218                edje_object_signal_emit(VIEW(item),
219                                        "elm,state,item,disabled", "elm");
220              evas_object_show(VIEW(item));
221              edje_object_message_signal_process(VIEW(item));
222           }
223         _scroller_size_calc(obj);
224      }
225    if (wd->title_text)
226      {
227         elm_object_part_text_set(wd->base, "elm.text.title", wd->title_text);
228         elm_object_signal_emit(wd->base, "elm,state,title,text,visible", "elm");
229      }
230    if (wd->title_icon)
231      elm_object_signal_emit(wd->base, "elm,state,title,icon,visible", "elm");
232    _layout_set(obj);
233    edje_object_message_signal_process(elm_layout_edje_get(wd->base));
234    _sizing_eval(obj);
235 }
236
237 static void
238 _item_sizing_eval(Elm_Popup_Content_Item *item)
239 {
240    Evas_Coord min_w = -1, min_h = -1, max_w = -1, max_h = -1;
241
242    edje_object_size_min_restricted_calc(VIEW(item), &min_w, &min_h, min_w,
243                                         min_h);
244    evas_object_size_hint_min_set(VIEW(item), min_w, min_h);
245    evas_object_size_hint_max_set(VIEW(item), max_w, max_h);
246 }
247
248 static void
249 _sizing_eval(Evas_Object *obj)
250 {
251    Eina_List *elist;
252    Elm_Popup_Content_Item *item;
253    Evas_Coord w_box = 0, h_box = 0;
254    Evas_Coord minw_box = 0, minh_box = 0;
255    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
256    Widget_Data *wd = elm_widget_data_get(obj);
257    Evas_Coord bx, by, bw, bh;
258
259    if (!wd) return;
260    if (wd->items)
261      {
262         EINA_LIST_FOREACH(wd->items, elist, item)
263           {
264              _item_sizing_eval(item);
265              evas_object_size_hint_min_get(VIEW(item), &minw_box,
266                                            &minh_box);
267              if (minw_box > w_box)
268                w_box = minw_box;
269              if (minh_box != -1)
270                h_box += minh_box;
271           }
272         evas_object_size_hint_min_set(wd->box, w_box, h_box);
273         evas_object_size_hint_min_set(wd->scr, w_box, MIN(h_box, wd->max_sc_h));
274         evas_object_size_hint_max_set(wd->scr, w_box, wd->max_sc_h);
275         evas_object_smart_calculate(wd->scr);
276      }
277    edje_object_size_min_calc(elm_layout_edje_get(wd->base), &minw, &minh);
278    evas_object_size_hint_min_set(wd->base, minw, minh);
279    evas_object_size_hint_max_set(wd->base, maxw, maxh);
280    evas_object_size_hint_min_set(obj, minw, minh);
281    evas_object_size_hint_max_set(obj, maxw, maxh);
282    elm_layout_sizing_eval(wd->base);
283
284    // hack hack hack. this widget needs a ... redo.
285    evas_object_geometry_get(wd->base, &bx, &by, &bw, &bh);
286    evas_object_resize(obj, bw, bh);
287    evas_object_move(obj, bx, by);
288 }
289
290 static void
291 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
292                     void *event_info __UNUSED__)
293 {
294    _sizing_eval(data);
295 }
296
297 static void
298 _sub_del(void *data, Evas_Object *obj, void *event_info)
299 {
300    Elm_Popup_Content_Item *item;
301    unsigned int i;
302    Evas_Object *sub = event_info;
303    Widget_Data *wd = elm_widget_data_get(data);
304
305    if (!wd) return;
306    if (obj == data)
307      {
308         if ((item = evas_object_data_get(sub, "_popup_content_item")) != NULL)
309           {
310              if (sub == item->icon)
311                {
312                   edje_object_part_unswallow(VIEW(item), sub);
313                   edje_object_signal_emit(VIEW(item),
314                                           "elm,state,item,icon,hidden", "elm");
315                   item->icon = NULL;
316                }
317           }
318      }
319    else if (obj == wd->content_area)
320      {
321         if (sub == wd->content)
322           {
323              wd->content = NULL;
324              elm_object_part_content_unset(wd->base, "elm.swallow.content");
325              _sizing_eval(data);
326           }
327         else if (sub == wd->content_text_obj)
328           {
329              wd->content_text_obj = NULL;
330              elm_object_part_content_unset(wd->base, "elm.swallow.content");
331              _sizing_eval(data);
332           }
333         else if (sub == wd->scr)
334           {
335              wd->scr = NULL;
336              wd->box = NULL;
337              elm_object_part_content_unset(wd->base, "elm.swallow.content");
338              _sizing_eval(data);
339           }
340      }
341    else if (obj == wd->action_area)
342      {
343         for (i = 0; i < ELM_POPUP_ACTION_BUTTON_MAX; i++)
344           {
345              if (wd->buttons[i] && sub == wd->buttons[i]->btn &&
346                       wd->buttons[i]->delete_me == EINA_TRUE)
347                {
348                   _button_remove(data, sub, EINA_FALSE);
349                   break;
350                }
351           }
352      }
353    else if (obj == wd->base)
354      {
355         if (sub == wd->title_icon)
356           {
357              elm_object_signal_emit(wd->base, "elm,state,title,icon,hidden",
358                                     "elm");
359              edje_object_message_signal_process(wd->base);
360              wd->title_icon = NULL;
361           }
362      }
363 }
364
365 static void
366 _block_clicked_cb(void *data, Evas_Object *obj __UNUSED__,
367                   void *event_info __UNUSED__)
368 {
369    Widget_Data *wd = elm_widget_data_get(data);
370
371    if (!wd) return;
372    evas_object_smart_callback_call(data, SIG_BLOCK_CLICKED, NULL);
373 }
374
375 static void
376 _timeout(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
377 {
378    evas_object_hide(data);
379    evas_object_smart_callback_call(data, SIG_TIMEOUT, NULL);
380 }
381
382 static void
383 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
384 {
385    Eina_List *elist;
386    Elm_Popup_Content_Item *item;
387    Widget_Data *wd = elm_widget_data_get(obj);
388
389    if (!wd) return;
390    elm_object_mirrored_set(wd->notify, rtl);
391    if (wd->items)
392      EINA_LIST_FOREACH(wd->items, elist, item)
393        edje_object_mirrored_set(VIEW(item), rtl);
394 }
395
396 static void
397 _layout_change_cb(void *data, Evas_Object *obj __UNUSED__,
398                   const char *emission __UNUSED__,
399                   const char *source __UNUSED__)
400 {
401    Widget_Data *wd = elm_widget_data_get((Evas_Object*)data);
402
403    if (!wd) return;
404    if (wd->base)
405      elm_layout_sizing_eval(wd->base);
406 }
407
408 static void
409 _restack(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj,
410          void *event_info __UNUSED__)
411 {
412    Widget_Data *wd = elm_widget_data_get(obj);
413
414    if (!wd) return;
415    evas_object_layer_set(wd->notify, evas_object_layer_get(obj));
416 }
417
418 static void
419 _scroller_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj,
420                  void *event_info __UNUSED__)
421 {
422    Evas_Coord w, h;
423    Widget_Data *wd = elm_widget_data_get(data);
424
425    if (!wd || wd->scr_size_recalc) return;
426    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
427    if (w && h)
428      {
429         if ((w <= wd->max_sc_w) && (h <= wd->max_sc_h))
430           {
431              _sizing_eval(data);
432              wd->scr_size_recalc = EINA_TRUE;
433              return;
434           }
435      }
436    if (wd->max_sc_w < w)
437      wd->max_sc_w = w;
438    if (wd->max_sc_h < h)
439      wd->max_sc_h = h;
440    _sizing_eval(data);
441 }
442
443 static void
444 _list_new(Evas_Object *obj)
445 {
446    Widget_Data *wd = elm_widget_data_get(obj);
447
448    if (!wd) return;
449    //Scroller
450    wd->scr = elm_scroller_add(obj);
451    elm_scroller_bounce_set(wd->scr, EINA_FALSE, EINA_TRUE);
452    elm_object_content_set(wd->scr, wd->box);
453    evas_object_size_hint_weight_set(wd->scr, EVAS_HINT_EXPAND,
454                                     EVAS_HINT_EXPAND);
455    evas_object_size_hint_align_set(wd->scr, EVAS_HINT_FILL, EVAS_HINT_FILL);
456    evas_object_event_callback_add(wd->scr, EVAS_CALLBACK_RESIZE,
457                                   _scroller_resize, obj);
458    evas_object_event_callback_add(wd->scr,
459                                   EVAS_CALLBACK_CHANGED_SIZE_HINTS,
460                                   _changed_size_hints, obj);
461    elm_object_part_content_set(wd->base, "elm.swallow.content", wd->scr);
462
463    //Box
464    wd->box = elm_box_add(obj);
465    evas_object_size_hint_weight_set(wd->box, EVAS_HINT_EXPAND,
466                                     EVAS_HINT_EXPAND);
467    evas_object_size_hint_align_set(wd->box, EVAS_HINT_FILL, EVAS_HINT_FILL);
468
469    elm_object_content_set(wd->scr, wd->box);
470 }
471
472 static void
473 _list_del(Widget_Data *wd)
474 {
475    if (!wd->scr) return;
476    elm_object_part_content_unset(wd->base, "elm.swallow.content");
477    evas_object_event_callback_del(wd->scr, EVAS_CALLBACK_RESIZE,
478                                   _scroller_resize);
479    evas_object_event_callback_del(wd->scr, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
480                                   _changed_size_hints);
481    evas_object_del(wd->scr);
482    wd->scr = NULL;
483    wd->box = NULL;
484 }
485
486 static void
487 _scroller_size_calc(Evas_Object *obj)
488 {
489    Evas_Coord h;
490    Evas_Coord h_title = 0;
491    Evas_Coord h_action_area = 0;
492    Evas_Coord h_content = 0;
493    const char *action_area_height;
494    Widget_Data *wd = elm_widget_data_get(obj);
495
496    if (!wd || !wd->items) return;
497    wd->scr_size_recalc = EINA_FALSE;
498    wd->max_sc_h = -1;
499    wd->max_sc_w = -1;
500    evas_object_geometry_get(wd->notify, NULL, NULL, NULL, &h);
501    if (wd->title_text || wd->title_icon)
502      edje_object_part_geometry_get(elm_layout_edje_get(wd->base),
503                                    "elm.bg.title", NULL, NULL, NULL, &h_title);
504    if (wd->button_count)
505      {
506         action_area_height = edje_object_data_get(
507                  elm_layout_edje_get(wd->action_area), "action_area_height");
508         if (action_area_height) h_action_area = (int)(atoi(action_area_height)
509                  * _elm_config->scale * elm_object_scale_get(obj));
510      }
511    h_content = h - (h_title + h_action_area);
512    wd->max_sc_h = h_content;
513 }
514
515 static void
516 _item_select_cb(void *data, Evas_Object *obj __UNUSED__,
517                 const char *emission __UNUSED__, const char *source __UNUSED__)
518 {
519    Elm_Popup_Content_Item *item = data;
520
521    if (!item || item->disabled) return;
522    if (item->func)
523      item->func((void*)item->base.data, WIDGET(item), data);
524 }
525
526 static void
527 _item_new(Elm_Popup_Content_Item *item)
528 {
529    Widget_Data *wd = elm_widget_data_get(WIDGET(item));
530
531    if (!wd) return;
532    elm_widget_item_text_set_hook_set(item, _item_text_set_hook);
533    elm_widget_item_text_get_hook_set(item, _item_text_get_hook);
534    elm_widget_item_content_set_hook_set(item, _item_content_set_hook);
535    elm_widget_item_content_get_hook_set(item, _item_content_get_hook);
536    elm_widget_item_content_unset_hook_set(item, _item_content_unset_hook);
537    elm_widget_item_disable_hook_set(item, _item_disable_hook);
538    elm_widget_item_del_pre_hook_set(item, _item_del_pre_hook);
539    elm_widget_item_signal_emit_hook_set(item, _item_signal_emit_hook);
540    VIEW(item) = edje_object_add(evas_object_evas_get(wd->base));
541    _elm_theme_object_set(WIDGET(item), VIEW(item), "popup", "item",
542                          elm_widget_style_get(WIDGET(item)));
543    edje_object_mirrored_set(VIEW(item), elm_widget_mirrored_get(WIDGET(item)));
544    edje_object_signal_callback_add(VIEW(item), "elm,action,click", "",
545                                    _item_select_cb, item);
546    evas_object_size_hint_align_set(VIEW(item), EVAS_HINT_FILL,
547                                    EVAS_HINT_FILL);
548    evas_object_show(VIEW(item));
549 }
550
551 static void
552 _remove_items(Widget_Data *wd)
553 {
554    Eina_List *elist;
555    Elm_Popup_Content_Item *item;
556
557    if (!wd->items) return;
558    EINA_LIST_FOREACH(wd->items, elist, item)
559      {
560         if (item->label)
561           eina_stringshare_del(item->label);
562         if (item->icon)
563           {
564              evas_object_del(item->icon);
565              item->icon = NULL;
566           }
567         evas_object_del(VIEW(item));
568         wd->items = eina_list_remove(wd->items, item);
569         free(item);
570      }
571    wd->items = NULL;
572 }
573
574 static void
575 _notify_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
576                void *event_info __UNUSED__)
577 {
578    Widget_Data *wd = elm_widget_data_get(data);
579
580    if (wd->items)
581      _scroller_size_calc(data);
582    _sizing_eval(data);
583 }
584
585 static void
586 _title_text_set(Evas_Object *obj, const char *text)
587 {
588    ELM_CHECK_WIDTYPE(obj, widtype);
589    Eina_Bool title_visibility_old, title_visibility_current;
590    Widget_Data *wd = elm_widget_data_get(obj);
591
592    if (!wd) return;
593    if (wd->title_text == text) return;
594    title_visibility_old = (wd->title_text) || (wd->title_icon);
595    eina_stringshare_replace(&wd->title_text, text);
596    elm_object_part_text_set(wd->base, "elm.text.title", text);
597    if (wd->title_text)
598      elm_object_signal_emit(wd->base, "elm,state,title,text,visible", "elm");
599    else
600      elm_object_signal_emit(wd->base, "elm,state,title,text,hidden", "elm");
601    title_visibility_current = (wd->title_text) || (wd->title_icon);
602    if (title_visibility_old != title_visibility_current)
603      _layout_set(obj);
604    edje_object_message_signal_process(wd->base);
605    _sizing_eval(obj);
606 }
607
608 static void
609 _content_text_set(Evas_Object *obj, const char *text)
610 {
611    ELM_CHECK_WIDTYPE(obj, widtype);
612    Evas_Object *prev_content;
613    char buf[128];
614    Widget_Data *wd = elm_widget_data_get(obj);
615
616    if (!wd) return;
617    if (wd->items)
618      {
619         _remove_items(wd);
620         _list_del(wd);
621      }
622    prev_content = elm_object_part_content_get(wd->content_area,
623                                               "elm.swallow.content");
624    if (prev_content)
625      evas_object_del(prev_content);
626    if (text)
627      {
628         elm_object_part_content_set(wd->base, "elm.swallow.content",
629                                     wd->content_area);
630         wd->content_text_obj = elm_label_add(obj);
631         snprintf(buf, sizeof(buf), "popup/%s",
632                  elm_widget_style_get(obj));
633         elm_object_style_set(wd->content_text_obj, buf);
634         elm_label_line_wrap_set(wd->content_text_obj,
635                                 wd->content_text_wrap_type);
636         elm_object_text_set(wd->content_text_obj, text);
637         evas_object_size_hint_weight_set(wd->content_text_obj, EVAS_HINT_EXPAND,
638                                          0.0);
639         evas_object_size_hint_align_set(wd->content_text_obj, EVAS_HINT_FILL,
640                                         EVAS_HINT_FILL);
641         elm_object_part_content_set(wd->content_area, "elm.swallow.content",
642                                     wd->content_text_obj);
643      }
644    _sizing_eval(obj);
645 }
646
647 static void
648 _text_set_hook(Evas_Object *obj, const char *part,
649                               const char *label)
650 {
651    ELM_CHECK_WIDTYPE(obj, widtype);
652    Widget_Data *wd = elm_widget_data_get(obj);
653
654    if (!wd) return;
655    if (!part || !strcmp(part, "default"))
656      _content_text_set(obj, label);
657    else if (!strcmp(part, "title,text"))
658      _title_text_set(obj, label);
659    else
660      WRN("The part name is invalid! : popup=%p", obj);
661 }
662
663 static const char*
664 _title_text_get(const Evas_Object *obj)
665 {
666    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
667    Widget_Data *wd = elm_widget_data_get(obj);
668
669    if (!wd) return NULL;
670    return wd->title_text;
671 }
672
673 static const char*
674 _content_text_get(const Evas_Object *obj)
675 {
676    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
677    const char *str = NULL;
678    Widget_Data *wd = elm_widget_data_get(obj);
679
680    if (!wd) return NULL;
681    if (wd->content_text_obj)
682      str = elm_object_text_get(wd->content_text_obj);
683    return str;
684 }
685
686 static const char *
687 _text_get_hook(const Evas_Object *obj, const char *part)
688 {
689    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
690    const char *str = NULL;
691    Widget_Data *wd = elm_widget_data_get(obj);
692
693    if (!wd) return NULL;
694    if (!part || !strcmp(part, "default"))
695      str = _content_text_get(obj);
696    else if (!strcmp(part, "title,text"))
697      str = _title_text_get(obj);
698    else
699      WRN("The part name is invalid! : popup=%p", obj);
700    return str;
701 }
702
703 static void
704 _title_icon_set(Evas_Object *obj, Evas_Object *icon)
705 {
706    ELM_CHECK_WIDTYPE(obj, widtype);
707    Eina_Bool title_visibility_old, title_visibility_current;
708    Widget_Data *wd = elm_widget_data_get(obj);
709
710    if (!wd) return;
711    if (wd->title_icon == icon) return;
712    title_visibility_old = (wd->title_text) || (wd->title_icon);
713    if (wd->title_icon) evas_object_del(wd->title_icon);
714
715    wd->title_icon = icon;
716    title_visibility_current = (wd->title_text) || (wd->title_icon);
717    elm_object_part_content_set(wd->base, "elm.swallow.title.icon",
718                                wd->title_icon);
719    if (wd->title_icon)
720      elm_object_signal_emit(wd->base, "elm,state,title,icon,visible", "elm");
721    if (title_visibility_old != title_visibility_current) _layout_set(obj);
722    edje_object_message_signal_process(wd->base);
723    _sizing_eval(obj);
724 }
725
726 static void
727 _content_set(Evas_Object *obj, Evas_Object *content)
728 {
729    ELM_CHECK_WIDTYPE(obj, widtype);
730    Evas_Object *prev_content;
731    Widget_Data *wd = elm_widget_data_get(obj);
732
733    if (!wd) return;
734    if (wd->content && wd->content == content) return;
735    if (wd->items)
736      {
737         _remove_items(wd);
738         _list_del(wd);
739      }
740    prev_content = elm_object_part_content_get(wd->content_area,
741                                               "elm.swallow.content");
742    if (prev_content)
743      evas_object_del(prev_content);
744    wd->content = content;
745    if (content)
746      {
747         elm_object_part_content_set(wd->base, "elm.swallow.content",
748                                     wd->content_area);
749         elm_object_part_content_set(wd->content_area, "elm.swallow.content",
750                                     content);
751         evas_object_show(content);
752      }
753    _sizing_eval(obj);
754 }
755
756 static void
757 _button_remove(Evas_Object *obj, Evas_Object *content, Eina_Bool delete)
758 {
759    unsigned int i = 0, position = 0;
760    char buf[128];
761    Widget_Data *wd = elm_widget_data_get(obj);
762
763    if (!wd->button_count) return;
764    for (i = 0; i < ELM_POPUP_ACTION_BUTTON_MAX; i++)
765     {
766        if (wd->buttons[i])
767          {
768             position++;
769             wd->buttons[i]->delete_me = EINA_FALSE;
770             if (wd->buttons[i]->btn == content)
771               {
772                  snprintf(buf, sizeof(buf), "actionbtn%u", position);
773                  elm_object_part_content_unset(wd->action_area, buf);
774                  evas_object_hide(content);
775                  if (delete) evas_object_del(content);
776                  free(wd->buttons[i]);
777                  wd->buttons[i] = NULL;
778                  wd->button_count -= 1;
779                }
780          }
781     }
782    position = 0;
783    for (i = 0; i < ELM_POPUP_ACTION_BUTTON_MAX; i++)
784     {
785        if (!wd->buttons[i]) continue;
786        position++;
787        snprintf(buf, sizeof(buf), "actionbtn%u", position);
788        elm_object_part_content_unset(wd->action_area, buf);
789        elm_object_part_content_set(wd->action_area, buf,
790                                    wd->buttons[i]->btn);
791        evas_object_show(wd->buttons[i]->btn);
792        wd->buttons[i]->delete_me = EINA_TRUE;
793     }
794    if (!wd->button_count)
795     {
796        _layout_set(obj);
797        elm_object_part_content_unset(wd->base, "elm.swallow.action_area");
798        evas_object_hide(wd->action_area);
799        edje_object_message_signal_process(elm_layout_edje_get(wd->base));
800     }
801    else
802     {
803        snprintf(buf, sizeof(buf), "buttons%u", wd->button_count);
804        elm_layout_theme_set(wd->action_area, "popup", buf,
805                             elm_widget_style_get(obj));
806     }
807 }
808
809 static void
810 _action_button_set(Evas_Object *obj, Evas_Object *btn, unsigned int idx)
811 {
812    Action_Area_Data *adata;
813    char buf[128];
814    unsigned int num = idx - 1, i = 0, position = 0;
815    Widget_Data *wd = elm_widget_data_get(obj);
816
817    if (!wd) return;
818    if (num >= ELM_POPUP_ACTION_BUTTON_MAX) return;
819    if (wd->buttons[num])
820      _button_remove(obj, wd->buttons[num]->btn, EINA_TRUE);
821    if (btn)
822      {
823         wd->button_count++;
824         snprintf(buf, sizeof(buf), "buttons%u", wd->button_count);
825         elm_layout_theme_set(wd->action_area, "popup", buf,
826                              elm_widget_style_get(obj));
827         adata = ELM_NEW(Action_Area_Data);
828         adata->obj = obj;
829         adata->btn = btn;
830         wd->buttons[num] = adata;
831         /* Adding delete_me state inside action data as unset calls _sub_del
832            too and before setting a new content, the previous one needs to
833            be unset in order to avoid unwanted deletion. This way rearrangement
834             of buttons can be achieved in action area.
835          */
836         for (i = 0; i < ELM_POPUP_ACTION_BUTTON_MAX; i++)
837           if (wd->buttons[i])
838             wd->buttons[i]->delete_me = EINA_FALSE;
839         for (i = 0; i < ELM_POPUP_ACTION_BUTTON_MAX; i++)
840           {
841              if (!wd->buttons[i]) continue;
842              position++;
843              snprintf(buf, sizeof(buf), "actionbtn%u", position);
844              elm_object_part_content_unset(wd->action_area, buf);
845              elm_object_part_content_set(wd->action_area, buf,
846                                          wd->buttons[i]->btn);
847              evas_object_show(wd->buttons[i]->btn);
848              /* Setting delete_me to TRUE in order to let _sub_del handle it
849                 if deleted externally and update the buttons array after freeing
850                 action data allocated earlier.
851               */
852              wd->buttons[i]->delete_me = EINA_TRUE;
853           }
854         elm_object_part_content_set(wd->base, "elm.swallow.action_area",
855                                     wd->action_area);
856         evas_object_show(wd->action_area);
857         if (wd->button_count == 1)
858           _layout_set(obj);
859         edje_object_message_signal_process(wd->base);
860         if (wd->items)
861           _scroller_size_calc(obj);
862         _sizing_eval(obj);
863      }
864 }
865
866 static void
867 _content_set_hook(Evas_Object *obj, const char *part,
868                                  Evas_Object *content)
869 {
870    ELM_CHECK_WIDTYPE(obj, widtype);
871    char buff[3];
872    unsigned int i;
873    Widget_Data *wd = elm_widget_data_get(obj);
874
875    if (!wd) return;
876    if (!part || !strcmp(part, "default"))
877      _content_set(obj, content);
878    else if (!strcmp(part, "title,icon"))
879      _title_icon_set(obj, content);
880    else if (!strncmp(part, "button", 6))
881      {
882         part += 6;
883         for (i = 0; i < ELM_POPUP_ACTION_BUTTON_MAX; i++)
884           {
885              snprintf(buff, sizeof(buff), "%u", i+1);
886              if (!strncmp(part, buff, sizeof(buff)))
887                {
888                   _action_button_set(obj, content, i+1);
889                   break;
890                }
891           }
892       }
893    else
894      WRN("The part name is invalid! : popup=%p", obj);
895 }
896
897 static Evas_Object *
898 _title_icon_get(Evas_Object *obj)
899 {
900    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
901    Widget_Data *wd = elm_widget_data_get(obj);
902
903    if (!wd) return NULL;
904    return wd->title_icon;
905 }
906
907 static Evas_Object *
908 _content_get(Evas_Object *obj)
909 {
910    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
911    Widget_Data *wd = elm_widget_data_get(obj);
912
913    if (!wd) return NULL;
914    return wd->content;
915 }
916
917 static Evas_Object *
918 _action_button_get(Evas_Object *obj, unsigned int idx)
919 {
920    unsigned int num = idx - 1;
921    Evas_Object *button = NULL;
922    Widget_Data *wd = elm_widget_data_get(obj);
923
924    if (!wd || !wd->button_count) return NULL;
925    if (wd->buttons[num])
926      button = wd->buttons[num]->btn;
927    return button;
928 }
929
930 static Evas_Object *
931 _content_get_hook(Evas_Object *obj, const char *part)
932 {
933    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
934    Evas_Object *content = NULL;
935    char buff[3];
936    unsigned int i;
937    Widget_Data *wd = elm_widget_data_get(obj);
938
939    if (!wd) return NULL;
940    if (!part || !strcmp(part, "default"))
941      content = _content_get(obj);
942    else if (!strcmp(part, "title,text"))
943      content = _title_icon_get(obj);
944    else if (!strncmp(part, "button", 6))
945      {
946         part += 6;
947         for (i = 0; i < ELM_POPUP_ACTION_BUTTON_MAX; i++)
948           {
949              snprintf(buff, sizeof(buff), "%u", i+1);
950              if (!strncmp(part, buff, sizeof(buff)))
951                {
952                   content = _action_button_get(obj, i+1);
953                   break;
954                }
955           }
956       }
957    else
958      WRN("The part name is invalid! : popup=%p", obj);
959    return content;
960 }
961
962 static Evas_Object *
963 _content_unset(Evas_Object *obj)
964 {
965    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
966    Evas_Object *content;
967    Widget_Data *wd = elm_widget_data_get(obj);
968
969    if (!wd || !wd->content) return NULL;
970    content = elm_object_part_content_unset(wd->content_area,
971                                            "elm.swallow.content");
972    wd->content = NULL;
973    _sizing_eval(obj);
974    return content;
975 }
976
977 static Evas_Object *
978 _title_icon_unset(Evas_Object *obj)
979 {
980    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
981    Evas_Object *icon;
982    Widget_Data *wd = elm_widget_data_get(obj);
983
984    if (!wd || !wd->title_icon) return NULL;
985    icon = elm_object_part_content_unset(wd->base, "elm.swallow.title.icon");
986    wd->title_icon = NULL;
987    return icon;
988 }
989
990 static Evas_Object *
991 _action_button_unset(Evas_Object *obj, unsigned int idx)
992 {
993    unsigned int num = idx -1;
994    Evas_Object *button = NULL;
995    Widget_Data *wd = elm_widget_data_get(obj);
996
997    if (!wd) return NULL;
998    if ((!wd->button_count) || (num >= ELM_POPUP_ACTION_BUTTON_MAX))
999      return NULL;
1000
1001    if (wd->buttons[num])
1002      {
1003         button = wd->buttons[num]->btn;
1004         _button_remove(obj, button, EINA_FALSE);
1005       }
1006    return button;
1007 }
1008
1009 static Evas_Object *
1010 _content_unset_hook(Evas_Object *obj, const char *part)
1011 {
1012    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1013    Evas_Object *content = NULL;
1014    char buff[3];
1015    unsigned int i;
1016    Widget_Data *wd = elm_widget_data_get(obj);
1017
1018    if (!wd) return NULL;
1019    if (!part || !strcmp(part, "default"))
1020      content = _content_unset(obj);
1021    else if (!strcmp(part, "title,icon"))
1022      content = _title_icon_unset(obj);
1023    else if (!strncmp(part, "button", 6))
1024      {
1025         part += 6;
1026         for (i = 0; i < ELM_POPUP_ACTION_BUTTON_MAX; i++)
1027           {
1028              snprintf(buff, sizeof(buff), "%u", i+1);
1029              if (!strncmp(part, buff, sizeof(buff)))
1030                {
1031                   content = _action_button_unset(obj, i+1);
1032                   break;
1033                }
1034           }
1035       }
1036    else
1037      WRN("The part name is invalid! : popup=%p", obj);
1038    return content;
1039 }
1040
1041 static Eina_Bool
1042 _focus_next_hook(const Evas_Object *obj,
1043                  Elm_Focus_Direction dir,
1044                  Evas_Object **next)
1045 {
1046    Widget_Data *wd = elm_widget_data_get(obj);
1047
1048    if (!wd)
1049      return EINA_FALSE;
1050    return elm_widget_focus_next_get(wd->notify, dir, next);
1051 }
1052
1053 static void
1054 _item_text_set(Elm_Popup_Content_Item *item, const char *label)
1055 {
1056    if (!eina_stringshare_replace(&item->label, label)) return;
1057    edje_object_part_text_escaped_set(VIEW(item), "elm.text", label);
1058    if (item->label)
1059      edje_object_signal_emit(VIEW(item),
1060                              "elm,state,item,text,visible", "elm");
1061    else
1062      edje_object_signal_emit(VIEW(item),
1063                              "elm,state,item,text,hidden", "elm");
1064    edje_object_message_signal_process(VIEW(item));
1065 }
1066
1067 static void
1068 _item_text_set_hook(Elm_Object_Item *it, const char *part, const char *label)
1069 {
1070    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
1071    Elm_Popup_Content_Item *item = (Elm_Popup_Content_Item *)it;
1072
1073    if ((!part) || (!strcmp(part, "default")))
1074      {
1075         _item_text_set(item, label);
1076         return;
1077      }
1078    WRN("The part name is invalid! : popup=%p", WIDGET(item));
1079 }
1080
1081 static const char *
1082 _item_text_get_hook(const Elm_Object_Item *it, const char *part)
1083 {
1084    ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL);
1085    Elm_Popup_Content_Item *item = (Elm_Popup_Content_Item *)it;
1086
1087    if ((!part) || (!strcmp(part, "default")))
1088      return item->label;
1089    WRN("The part name is invalid! : popup=%p", WIDGET(item));
1090    return NULL;
1091 }
1092
1093 static void
1094 _item_icon_set(Elm_Popup_Content_Item *item, Evas_Object *icon)
1095 {
1096    if (item->icon == icon) return;
1097    if (item->icon)
1098      {
1099         evas_object_data_del(item->icon, "_popup_content_item");
1100         evas_object_del(item->icon);
1101      }
1102    item->icon = icon;
1103    if (item->icon)
1104      {
1105         elm_widget_sub_object_add(WIDGET(item), item->icon);
1106         evas_object_data_set(item->icon, "_popup_content_item", item);
1107         edje_object_part_swallow(VIEW(item), "elm.swallow.content",
1108                                  item->icon);
1109         edje_object_signal_emit(VIEW(item),
1110                                 "elm,state,item,icon,visible", "elm");
1111      }
1112    else
1113      edje_object_signal_emit(VIEW(item),
1114                              "elm,state,item,icon,hidden", "elm");
1115    edje_object_message_signal_process(item->base.view);
1116 }
1117
1118 static void
1119 _item_content_set_hook(Elm_Object_Item *it, const char *part,
1120                        Evas_Object *content)
1121 {
1122    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
1123    Elm_Popup_Content_Item *item = (Elm_Popup_Content_Item *)it;
1124
1125    if ((!(part)) || (!strcmp(part, "default")))
1126      _item_icon_set(item, content);
1127    else
1128      WRN("The part name is invalid! : popup=%p", WIDGET(item));
1129 }
1130
1131 static Evas_Object *
1132 _item_content_get_hook(const Elm_Object_Item *it,
1133                        const char *part)
1134 {
1135    ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL);
1136    Elm_Popup_Content_Item *item = (Elm_Popup_Content_Item *)it;
1137
1138    if ((!(part)) || (!strcmp(part, "default")))
1139      return item->icon;
1140    WRN("The part name is invalid! : popup=%p", WIDGET(item));
1141    return NULL;
1142 }
1143
1144 static Evas_Object *
1145 _item_icon_unset(Elm_Popup_Content_Item *item)
1146 {
1147    Evas_Object *icon = item->icon;
1148
1149    if (!item->icon) return NULL;
1150    elm_widget_sub_object_del(WIDGET(item), icon);
1151    evas_object_data_del(icon, "_popup_content_item");
1152    edje_object_part_unswallow(item->base.view, icon);
1153    edje_object_signal_emit(VIEW(item),
1154                            "elm,state,item,icon,hidden", "elm");
1155    item->icon = NULL;
1156    return icon;
1157 }
1158
1159 static Evas_Object *
1160 _item_content_unset_hook(const Elm_Object_Item *it,
1161                          const char *part)
1162 {
1163    ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL);
1164    Evas_Object *content = NULL;
1165    Elm_Popup_Content_Item *item = (Elm_Popup_Content_Item *)it;
1166
1167    if ((!(part)) || (!strcmp(part, "default")))
1168      content = _item_icon_unset(item);
1169    else
1170      WRN("The part name is invalid! : popup=%p", WIDGET(item));
1171    return content;
1172 }
1173
1174 static void
1175 _item_disable_hook(Elm_Object_Item *it)
1176 {
1177    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
1178    Elm_Popup_Content_Item *item = (Elm_Popup_Content_Item *)it;
1179    Widget_Data *wd = elm_widget_data_get(WIDGET(item));
1180
1181    if (!wd) return;
1182    if (elm_widget_item_disabled_get(it))
1183      edje_object_signal_emit(VIEW(item), "elm,state,item,disabled", "elm");
1184    else
1185      edje_object_signal_emit(VIEW(item), "elm,state,item,enabled", "elm");
1186 }
1187
1188 static void
1189 _item_del_pre_hook(Elm_Object_Item *it)
1190 {
1191    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
1192    Elm_Popup_Content_Item *item = (Elm_Popup_Content_Item *)it;
1193    Widget_Data *wd = elm_widget_data_get(WIDGET(item));
1194
1195    if (!wd) return;
1196    if (item->icon)
1197      evas_object_del(item->icon);
1198    eina_stringshare_del(item->label);
1199    wd->items = eina_list_remove(wd->items, item);
1200    if (!eina_list_count(wd->items))
1201      {
1202         wd->items = NULL;
1203         _list_del(wd);
1204      }
1205 }
1206
1207 static void
1208 _item_signal_emit_hook(Elm_Object_Item *it, const char *emission,
1209                        const char *source)
1210 {
1211    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
1212    Elm_Popup_Content_Item *item = (Elm_Popup_Content_Item *)it;
1213
1214    edje_object_signal_emit(VIEW(item), emission, source);
1215 }
1216
1217 static void
1218 _popup_show(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj,
1219                void *event_info __UNUSED__)
1220 {
1221    Widget_Data *wd;
1222
1223    wd = elm_widget_data_get(obj);
1224    if (!wd) return;
1225
1226    evas_object_show(wd->notify);
1227 }
1228
1229 static void
1230 _popup_hide(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj,
1231                void *event_info __UNUSED__)
1232 {
1233    Widget_Data *wd;
1234
1235    wd = elm_widget_data_get(obj);
1236    if (!wd) return;
1237
1238    evas_object_hide(wd->notify);
1239 }
1240
1241 EAPI Evas_Object *
1242 elm_popup_add(Evas_Object *parent)
1243 {
1244    Evas_Object *obj;
1245    Evas *e;
1246    int i = 0;
1247    Widget_Data *wd;
1248
1249    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
1250    ELM_SET_WIDTYPE(widtype, "popup");
1251    elm_widget_type_set(obj, widtype);
1252    elm_widget_sub_object_add(parent, obj);
1253    elm_widget_data_set(obj, wd);
1254    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
1255    elm_widget_del_hook_set(obj, _del_hook);
1256    elm_widget_theme_hook_set(obj, _theme_hook);
1257    elm_widget_text_set_hook_set(obj, _text_set_hook);
1258    elm_widget_text_get_hook_set(obj, _text_get_hook);
1259    elm_widget_content_set_hook_set(obj, _content_set_hook);
1260    elm_widget_content_get_hook_set(obj, _content_get_hook);
1261    elm_widget_content_unset_hook_set(obj,_content_unset_hook);
1262    elm_widget_can_focus_set(obj, EINA_FALSE);
1263    elm_widget_focus_next_hook_set(obj, _focus_next_hook);
1264    evas_object_smart_callbacks_descriptions_set(obj, _signals);
1265
1266    wd->notify = elm_notify_add(obj);
1267    elm_notify_parent_set(wd->notify, parent);
1268    elm_notify_orient_set(wd->notify, ELM_NOTIFY_ORIENT_CENTER);
1269    elm_notify_allow_events_set(wd->notify, EINA_FALSE);
1270    evas_object_size_hint_weight_set(wd->notify,
1271                                     EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1272    evas_object_size_hint_align_set(wd->notify, EVAS_HINT_FILL, EVAS_HINT_FILL);
1273    elm_object_style_set(wd->notify, "popup");
1274
1275    evas_object_event_callback_add(wd->notify, EVAS_CALLBACK_RESIZE,
1276                                   _notify_resize, obj);
1277    evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _popup_show,
1278                                   NULL);
1279    evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _popup_hide,
1280                                   NULL);
1281    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESTACK, _restack, NULL);
1282    wd->base = elm_layout_add(obj);
1283    evas_object_size_hint_weight_set(wd->base, EVAS_HINT_EXPAND,
1284                                     EVAS_HINT_EXPAND);
1285    evas_object_size_hint_align_set(wd->base, EVAS_HINT_FILL, EVAS_HINT_FILL);
1286
1287    elm_layout_theme_set(wd->base, "popup", "base", elm_widget_style_get(obj));
1288    elm_object_content_set(wd->notify, wd->base);
1289
1290    elm_object_signal_callback_add(wd->base, "elm,state,title_area,visible",
1291                                   "elm", _layout_change_cb, obj);
1292    elm_object_signal_callback_add(wd->base, "elm,state,title_area,hidden",
1293                                   "elm", _layout_change_cb, obj);
1294    elm_object_signal_callback_add(wd->base, "elm,state,action_area,visible",
1295                                   "elm", _layout_change_cb, obj);
1296    elm_object_signal_callback_add(wd->base, "elm,state,action_area,hidden",
1297                                   "elm", _layout_change_cb, obj);
1298    wd->content_area = elm_layout_add(obj);
1299    elm_layout_theme_set(wd->content_area, "popup", "content",
1300                         elm_widget_style_get(obj));
1301    wd->action_area = elm_layout_add(obj);
1302    evas_object_size_hint_weight_set(wd->action_area, EVAS_HINT_EXPAND,
1303                                     EVAS_HINT_EXPAND);
1304    evas_object_size_hint_align_set(wd->action_area, EVAS_HINT_FILL,
1305                                    EVAS_HINT_FILL);
1306    evas_object_event_callback_add(wd->action_area,
1307                                   EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1308                                   _changed_size_hints, obj);
1309    evas_object_event_callback_add(wd->content_area,
1310                                   EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1311                                   _changed_size_hints, obj);
1312    evas_object_smart_callback_add(wd->base, "sub-object-del",
1313                                   _sub_del, obj);
1314    evas_object_smart_callback_add(wd->content_area, "sub-object-del",
1315                                   _sub_del, obj);
1316    evas_object_smart_callback_add(wd->action_area, "sub-object-del",
1317                                   _sub_del, obj);
1318    evas_object_smart_callback_add(obj, "sub-object-del",
1319                                   _sub_del, obj);
1320
1321    wd->content_text_wrap_type = ELM_WRAP_MIXED;
1322    evas_object_smart_callback_add(wd->notify, "block,clicked",
1323                                   _block_clicked_cb, obj);
1324    evas_object_smart_callback_add(wd->notify, "timeout", _timeout, obj);
1325    for (i = 0; i < ELM_POPUP_ACTION_BUTTON_MAX; i++)
1326      wd->buttons[i] = NULL;
1327    _layout_set(obj);
1328    //TODO: To use scroller for description also
1329    return obj;
1330 }
1331
1332 EAPI void
1333 elm_popup_content_text_wrap_type_set(Evas_Object *obj, Elm_Wrap_Type wrap)
1334 {
1335    ELM_CHECK_WIDTYPE(obj, widtype);
1336    Evas_Object *content_text_obj;
1337    Widget_Data *wd = elm_widget_data_get(obj);
1338
1339    if (!wd) return;
1340    if (wd->content_text_wrap_type == ELM_WRAP_NONE) return;
1341    //Need to wrap the content text, so not allowing ELM_WRAP_NONE
1342    wd->content_text_wrap_type = wrap;
1343    if (wd->content_text_obj)
1344      {
1345         content_text_obj = elm_object_part_content_get(wd->content_area,
1346                                                        "elm.swallow.content");
1347         elm_label_line_wrap_set(content_text_obj, wrap);
1348      }
1349 }
1350
1351 EAPI Elm_Wrap_Type
1352 elm_popup_content_text_wrap_type_get(const Evas_Object *obj)
1353 {
1354    ELM_CHECK_WIDTYPE(obj, widtype) ELM_WRAP_LAST;
1355    Widget_Data *wd = elm_widget_data_get(obj);
1356
1357    if (!wd) return ELM_WRAP_LAST;
1358    return wd->content_text_wrap_type;
1359 }
1360
1361 EAPI void
1362 elm_popup_orient_set(Evas_Object *obj, Elm_Popup_Orient orient)
1363 {
1364    ELM_CHECK_WIDTYPE(obj, widtype);
1365    Widget_Data *wd = elm_widget_data_get(obj);
1366
1367    if (!wd) return;
1368    if (orient >= ELM_POPUP_ORIENT_LAST) return;
1369    elm_notify_orient_set(wd->notify, (Elm_Notify_Orient)orient);
1370 }
1371
1372 EAPI Elm_Popup_Orient
1373 elm_popup_orient_get(const Evas_Object *obj)
1374 {
1375    ELM_CHECK_WIDTYPE(obj, widtype) -1;
1376    Widget_Data *wd = elm_widget_data_get(obj);
1377
1378    if (!wd) return ELM_POPUP_ORIENT_LAST;
1379    return (Elm_Popup_Orient)elm_notify_orient_get(wd->notify);
1380 }
1381
1382 EAPI void
1383 elm_popup_timeout_set(Evas_Object *obj, double timeout)
1384 {
1385    ELM_CHECK_WIDTYPE(obj, widtype);
1386    Widget_Data *wd = elm_widget_data_get(obj);
1387
1388    if (!wd) return;
1389    elm_notify_timeout_set(wd->notify, timeout);
1390 }
1391
1392 EAPI double
1393 elm_popup_timeout_get(const Evas_Object *obj)
1394 {
1395    ELM_CHECK_WIDTYPE(obj, widtype) 0.0;
1396    Widget_Data *wd = elm_widget_data_get(obj);
1397
1398    if (!wd) return 0.0;
1399    return elm_notify_timeout_get(wd->notify);
1400 }
1401
1402 EAPI void
1403 elm_popup_allow_events_set(Evas_Object *obj, Eina_Bool allow)
1404 {
1405    ELM_CHECK_WIDTYPE(obj, widtype);
1406    Eina_Bool allow_events = !!allow;
1407    Widget_Data *wd = elm_widget_data_get(obj);
1408
1409    if (!wd) return;
1410    elm_notify_allow_events_set(wd->notify, allow_events);
1411 }
1412
1413 EAPI Eina_Bool
1414 elm_popup_allow_events_get(const Evas_Object *obj)
1415 {
1416    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1417    Widget_Data *wd = elm_widget_data_get(obj);
1418
1419    if (!wd) return EINA_FALSE;
1420    return elm_notify_allow_events_get(wd->notify);
1421 }
1422
1423 EAPI Elm_Object_Item *
1424 elm_popup_item_append(Evas_Object *obj, const char *label,
1425                               Evas_Object *icon, Evas_Smart_Cb func,
1426                               const void *data)
1427 {
1428    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1429    Evas_Object *prev_content;
1430    Elm_Popup_Content_Item *item;
1431    Widget_Data *wd = elm_widget_data_get(obj);
1432
1433    if (!wd) return NULL;
1434    item = elm_widget_item_new(obj, Elm_Popup_Content_Item);
1435    if (!item) return NULL;
1436    if (wd->content || wd->content_text_obj)
1437      {
1438         prev_content = elm_object_part_content_get(wd->content_area,
1439                                                    "elm.swallow.content");
1440         if (prev_content)
1441           evas_object_del(prev_content);
1442      }
1443
1444    //The first item is appended.
1445    if (!wd->items)
1446      _list_new(obj);
1447
1448    item->func = func;
1449    item->base.data = data;
1450
1451    _item_new(item);
1452    _item_icon_set(item, icon);
1453    _item_text_set(item, label);
1454    elm_box_pack_end(wd->box, VIEW(item));
1455    wd->items = eina_list_append(wd->items, item);
1456
1457    _scroller_size_calc(obj);
1458    _sizing_eval(obj);
1459    return (Elm_Object_Item *)item;
1460 }