Initialize Tizen 2.3
[framework/uifw/elementary.git] / mobile / src / lib / elc_popup.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_widget_popup.h"
4
5 #define ELM_POPUP_ACTION_BUTTON_MAX 3
6 #define OUTLINE_TEXT "Center popup is opened, double tap to close the popup"
7
8 EAPI const char ELM_POPUP_SMART_NAME[] = "elm_popup";
9
10 static void _button_remove(Evas_Object *, int, Eina_Bool);
11
12 static const char ACCESS_TITLE_PART[] = "access.title";
13 static const char ACCESS_BODY_PART[] = "access.body";
14 static const char ACCESS_BASE_PART[] = "access.base";
15
16 static const char SIG_BLOCK_CLICKED[] = "block,clicked";
17 static const char SIG_TIMEOUT[] = "timeout";
18 static const char SIG_ACCESS_CHANGED[] = "access,changed";
19 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
20    {SIG_BLOCK_CLICKED, ""},
21    {SIG_TIMEOUT, ""},
22    {SIG_ACCESS_CHANGED, ""},
23    {NULL, NULL}
24 };
25
26 EVAS_SMART_SUBCLASS_NEW
27   (ELM_POPUP_SMART_NAME, _elm_popup, Elm_Popup_Smart_Class,
28   Elm_Layout_Smart_Class, elm_layout_smart_class_get, _smart_callbacks);
29
30 static void  _on_content_del(void *data, Evas *e, Evas_Object *obj, void *event_info);
31
32 static Eina_Bool
33 _elm_popup_smart_translate(Evas_Object *obj)
34 {
35    ELM_POPUP_DATA_GET(obj, sd);
36    Elm_Popup_Item *it;
37    Eina_List *l;
38
39    EINA_LIST_FOREACH(sd->items, l, it)
40      elm_widget_item_translate(it);
41
42    return EINA_TRUE;
43 }
44
45 static void
46 _visuals_set(Evas_Object *obj)
47 {
48    ELM_POPUP_DATA_GET(obj, sd);
49
50    if (!sd->title_text && !sd->title_icon)
51      elm_layout_signal_emit(obj, "elm,state,title_area,hidden", "elm");
52    else
53      elm_layout_signal_emit(obj, "elm,state,title_area,visible", "elm");
54
55    if (sd->button_count)
56      elm_layout_signal_emit(obj, "elm,state,action_area,visible", "elm");
57    else
58      elm_layout_signal_emit(obj, "elm,state,action_area,hidden", "elm");
59 }
60
61
62 static void
63 _item_update(Elm_Popup_Item *item)
64 {
65    if (item->label)
66      {
67         edje_object_part_text_escaped_set
68            (VIEW(item), "elm.text", item->label);
69         edje_object_signal_emit
70            (VIEW(item), "elm,state,item,text,visible", "elm");
71      }
72    if (item->icon)
73       edje_object_signal_emit
74          (VIEW(item), "elm,state,item,icon,visible", "elm");
75    if (item->base.disabled)
76       edje_object_signal_emit
77          (VIEW(item), "elm,state,item,disabled", "elm");
78    evas_object_show(VIEW(item));
79    edje_object_message_signal_process(VIEW(item));
80 }
81
82 static void
83 _block_clicked_cb(void *data,
84                   Evas_Object *obj __UNUSED__,
85                   void *event_info __UNUSED__)
86 {
87    evas_object_smart_callback_call(data, SIG_BLOCK_CLICKED, NULL);
88 }
89
90 static void
91 _timeout_cb(void *data,
92             Evas_Object *obj __UNUSED__,
93             void *event_info __UNUSED__)
94 {
95    evas_object_hide(data);
96    evas_object_smart_callback_call(data, SIG_TIMEOUT, NULL);
97 }
98
99 static Evas_Object *
100 _access_object_get(const Evas_Object *obj, const char* part)
101 {
102    Evas_Object *po, *ao;
103    ELM_POPUP_DATA_GET(obj, sd);
104
105    po = (Evas_Object *)edje_object_part_object_get(ELM_WIDGET_DATA(sd)->resize_obj, part);
106    ao = evas_object_data_get(po, "_part_access_obj");
107
108    return ao;
109 }
110
111 static void
112 _on_show(void *data __UNUSED__,
113          Evas *e __UNUSED__,
114          Evas_Object *obj,
115          void *event_info __UNUSED__)
116 {
117    ELM_POPUP_DATA_GET(obj, sd);
118
119    evas_object_show(sd->notify);
120
121    // FIX ME (WooHyun Jung) : This code is for arranging child-parent relation well.
122    // Without this code, Popup't top parent will be notify.(and there will be no parent for notify)
123    elm_widget_sub_object_add(elm_widget_parent_get(obj), sd->notify);
124    /* yeah, ugly, but again, this widget needs a rewrite */
125    elm_object_content_set(sd->notify, obj);
126
127    elm_object_focus_set(obj, EINA_TRUE);
128 }
129
130 static void
131 _on_hide(void *data __UNUSED__,
132             Evas *e __UNUSED__,
133             Evas_Object *obj,
134             void *event_info __UNUSED__)
135 {
136    ELM_POPUP_DATA_GET(obj, sd);
137
138    evas_object_hide(sd->notify);
139
140    elm_object_content_unset(sd->notify);
141
142 /* FIXME:elm_object_content_unset(notify) deletes callback to revert focus status. */
143    elm_object_focus_set(obj, EINA_FALSE);
144 }
145
146 static void
147 _scroller_size_calc(Evas_Object *obj)
148 {
149    Evas_Coord h;
150    Evas_Coord h_title = 0;
151    Evas_Coord h_content = 0;
152    Evas_Coord h_action_area = 0;
153    const char *action_area_height;
154
155    ELM_POPUP_DATA_GET(obj, sd);
156
157    if (!sd->items) return;
158
159    sd->scr_size_recalc = EINA_FALSE;
160    sd->max_sc_h = -1;
161    sd->max_sc_w = -1;
162    evas_object_geometry_get(sd->notify, NULL, NULL, NULL, &h);
163    if (sd->title_text || sd->title_icon)
164      edje_object_part_geometry_get(ELM_WIDGET_DATA(sd)->resize_obj,
165                                    "elm.bg.title", NULL, NULL, NULL, &h_title);
166    if (sd->button_count)
167      {
168         action_area_height = edje_object_data_get(
169             elm_layout_edje_get(sd->action_area), "action_area_height");
170         if (action_area_height)
171           h_action_area =
172             (int)(atoi(action_area_height)
173                   * elm_config_scale_get() * elm_object_scale_get(obj));
174      }
175
176    h_content = h - (h_title + h_action_area);
177    sd->max_sc_h = h_content;
178 }
179
180 static void
181 _size_hints_changed_cb(void *data,
182                        Evas *e __UNUSED__,
183                        Evas_Object *obj __UNUSED__,
184                        void *event_info __UNUSED__)
185 {
186    elm_layout_sizing_eval(data);
187 }
188
189 static void
190 _list_del(Elm_Popup_Smart_Data *sd)
191 {
192    if (!sd->scr) return;
193
194    evas_object_event_callback_del
195      (sd->scr, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _size_hints_changed_cb);
196
197    evas_object_del(sd->tbl);
198    sd->scr = NULL;
199    sd->box = NULL;
200    sd->spacer = NULL;
201    sd->tbl = NULL;
202 }
203
204 static void
205 _items_remove(Elm_Popup_Smart_Data *sd)
206 {
207    Elm_Popup_Item *item;
208
209    if (!sd->items) return;
210
211    EINA_LIST_FREE (sd->items, item)
212      elm_widget_item_del(item);
213
214    sd->items = NULL;
215 }
216
217 static void
218 _elm_popup_smart_del(Evas_Object *obj)
219 {
220    Evas_Object *notify = NULL;
221    unsigned int i;
222
223    ELM_POPUP_DATA_GET(obj, sd);
224
225    evas_object_smart_callback_del
226      (sd->notify, "block,clicked", _block_clicked_cb);
227    evas_object_smart_callback_del(sd->notify, "timeout", _timeout_cb);
228    evas_object_event_callback_del
229      (sd->content, EVAS_CALLBACK_DEL, _on_content_del);
230    evas_object_event_callback_del(obj, EVAS_CALLBACK_SHOW, _on_show);
231    sd->button_count = 0;
232
233    for (i = 0; i < ELM_POPUP_ACTION_BUTTON_MAX; i++)
234      {
235         if (sd->buttons[i])
236           {
237              evas_object_del(sd->buttons[i]->btn);
238              free(sd->buttons[i]);
239              sd->buttons[i] = NULL;
240           }
241      }
242    if (sd->items)
243      {
244         _items_remove(sd);
245         _list_del(sd);
246      }
247
248    if (elm_widget_parent_get(obj) == sd->notify)
249      {
250         notify = sd->notify;
251      }
252
253    ELM_WIDGET_CLASS(_elm_popup_parent_sc)->base.del(obj);
254
255    if (notify)
256      {
257         evas_object_del(notify);
258      }
259 }
260
261 static void
262 _mirrored_set(Evas_Object *obj,
263               Eina_Bool rtl)
264 {
265    Eina_List *elist;
266    Elm_Popup_Item *item;
267
268    ELM_POPUP_DATA_GET(obj, sd);
269
270    elm_object_mirrored_set(sd->notify, rtl);
271    if (sd->items)
272      EINA_LIST_FOREACH(sd->items, elist, item)
273        edje_object_mirrored_set(VIEW(item), rtl);
274 }
275
276 static void
277 _access_base_activate_cb(void *data,
278                         Evas_Object *part_obj __UNUSED__,
279                         Elm_Object_Item *item __UNUSED__)
280 {
281    evas_object_del(data);
282 }
283
284 static void
285 _access_obj_process(Evas_Object *obj, Eina_Bool is_access)
286 {
287    Evas_Object *ao;
288
289    ELM_POPUP_DATA_GET(obj, sd);
290
291    if (is_access)
292      {
293         if (sd->title_text)
294           {
295              ao = _elm_access_edje_object_part_object_register
296                     (obj, ELM_WIDGET_DATA(sd)->resize_obj, ACCESS_TITLE_PART);
297              _elm_access_text_set(_elm_access_object_get(ao),
298                                   ELM_ACCESS_TYPE, E_("Popup Title"));
299              _elm_access_text_set(_elm_access_object_get(ao),
300                                   ELM_ACCESS_INFO, sd->title_text);
301           }
302
303         if (sd->text_content_obj)
304           {
305              ao = _elm_access_edje_object_part_object_register
306                     (obj, ELM_WIDGET_DATA(sd)->resize_obj, ACCESS_BODY_PART);
307              _elm_access_text_set(_elm_access_object_get(ao),
308                                   ELM_ACCESS_TYPE, E_("Popup Body Text"));
309              _elm_access_text_set(_elm_access_object_get(ao),
310                ELM_ACCESS_INFO, elm_object_text_get(sd->text_content_obj));
311           }
312
313         /* register outline */
314         if (!sd->button_count)
315           {
316              ao = _elm_access_edje_object_part_object_register
317                     (obj, ELM_WIDGET_DATA(sd)->resize_obj, ACCESS_BASE_PART);
318              _elm_access_text_set(_elm_access_object_get(ao),
319                                   ELM_ACCESS_TYPE, E_(OUTLINE_TEXT));
320              _elm_access_activate_callback_set
321                (_elm_access_object_get(ao), _access_base_activate_cb, obj);
322           }
323      }
324    else
325      {
326         if (sd->title_text)
327           {
328              _elm_access_edje_object_part_object_unregister
329                     (obj, ELM_WIDGET_DATA(sd)->resize_obj, ACCESS_TITLE_PART);
330           }
331
332         if (sd->text_content_obj)
333           {
334              _elm_access_edje_object_part_object_unregister
335                     (obj, ELM_WIDGET_DATA(sd)->resize_obj, ACCESS_BODY_PART);
336           }
337
338         /* unregister outline */
339         if (!sd->button_count)
340           _elm_access_edje_object_part_object_unregister
341                  (obj, ELM_WIDGET_DATA(sd)->resize_obj, ACCESS_BASE_PART);
342      }
343 }
344
345 static Eina_Bool
346 _elm_popup_smart_theme(Evas_Object *obj)
347 {
348    Elm_Popup_Item *item;
349    Eina_List *elist;
350    char buf[128];
351
352    ELM_POPUP_DATA_GET(obj, sd);
353
354    if (!ELM_WIDGET_CLASS(_elm_popup_parent_sc)->theme(obj))
355      return EINA_FALSE;
356
357    _mirrored_set(obj, elm_widget_mirrored_get(obj));
358
359    elm_object_style_set(sd->notify, elm_widget_style_get(obj));
360
361    if (sd->button_count)
362      {
363         snprintf(buf, sizeof(buf), "buttons%u", sd->button_count);
364         elm_layout_theme_set(sd->action_area, "popup", buf,
365                              elm_widget_style_get(obj));
366      }
367    elm_layout_theme_set(sd->content_area, "popup", "content",
368                         elm_widget_style_get(obj));
369    if (sd->text_content_obj)
370      {
371         snprintf(buf, sizeof(buf), "popup/%s", elm_widget_style_get(obj));
372         elm_object_style_set(sd->text_content_obj, buf);
373      }
374    else if (sd->items)
375      {
376         EINA_LIST_FOREACH(sd->items, elist, item)
377           {
378              elm_widget_theme_object_set
379                (obj, VIEW(item), "popup", "item", elm_widget_style_get(obj));
380              _item_update(item);
381           }
382         _scroller_size_calc(obj);
383      }
384    if (sd->title_text)
385      {
386         elm_layout_text_set(obj, "elm.text.title", sd->title_text);
387         elm_layout_signal_emit(obj, "elm,state,title,text,visible", "elm");
388      }
389    if (sd->title_icon)
390      elm_layout_signal_emit(obj, "elm,state,title,icon,visible", "elm");
391
392    _visuals_set(obj);
393    edje_object_message_signal_process(ELM_WIDGET_DATA(sd)->resize_obj);
394    elm_layout_sizing_eval(obj);
395
396    /* access */
397    if (_elm_config->access_mode) _access_obj_process(obj, EINA_TRUE);
398
399    return EINA_TRUE;
400 }
401
402 static void
403 _item_sizing_eval(Elm_Popup_Item *item)
404 {
405    Evas_Coord min_w = -1, min_h = -1, max_w = -1, max_h = -1;
406
407    edje_object_size_min_restricted_calc
408      (VIEW(item), &min_w, &min_h, min_w, min_h);
409    evas_object_size_hint_min_set(VIEW(item), min_w, min_h);
410    evas_object_size_hint_max_set(VIEW(item), max_w, max_h);
411 }
412
413 static void
414 _elm_popup_smart_sizing_eval(Evas_Object *obj)
415 {
416    Eina_List *elist;
417    Elm_Popup_Item *item;
418    Evas_Coord h_box = 0, minh_box = 0;
419    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
420
421    ELM_POPUP_DATA_GET(obj, sd);
422
423    if (sd->items)
424      {
425         EINA_LIST_FOREACH(sd->items, elist, item)
426           {
427              _item_sizing_eval(item);
428              evas_object_size_hint_min_get(VIEW(item), NULL, &minh_box);
429              if (minh_box != -1) h_box += minh_box;
430           }
431         evas_object_size_hint_min_set(sd->spacer, 0, MIN(h_box, sd->max_sc_h));
432         evas_object_size_hint_max_set(sd->spacer, -1, sd->max_sc_h);
433
434         evas_object_size_hint_min_get(sd->scr, &minw, &minh);
435         evas_object_size_hint_max_get(sd->scr, &minw, &minh);
436      }
437
438    edje_object_size_min_calc(ELM_WIDGET_DATA(sd)->resize_obj, &minw, &minh);
439
440    evas_object_size_hint_min_set(obj, minw, minh);
441    evas_object_size_hint_max_set(obj, maxw, maxh);
442 }
443
444 static Eina_Bool
445 _elm_popup_smart_sub_object_del(Evas_Object *obj,
446                                 Evas_Object *sobj)
447 {
448    Elm_Popup_Item *item;
449
450    ELM_POPUP_DATA_GET(obj, sd);
451
452    if (!ELM_WIDGET_CLASS(_elm_popup_parent_sc)->sub_object_del(obj, sobj))
453      return EINA_FALSE;
454
455    if (sobj == sd->title_icon)
456      {
457         elm_layout_signal_emit(obj, "elm,state,title,icon,hidden", "elm");
458         edje_object_message_signal_process(ELM_WIDGET_DATA(sd)->resize_obj);
459         sd->title_icon = NULL;
460      }
461    else if ((item =
462                evas_object_data_get(sobj, "_popup_icon_parent_item")) != NULL)
463      {
464         if (sobj == item->icon)
465           {
466              edje_object_part_unswallow(VIEW(item), sobj);
467              edje_object_signal_emit
468                (VIEW(item), "elm,state,item,icon,hidden", "elm");
469              item->icon = NULL;
470           }
471      }
472
473    return EINA_TRUE;
474 }
475
476 static void
477 _on_content_del(void *data,
478                 Evas *e __UNUSED__,
479                 Evas_Object *obj __UNUSED__,
480                 void *event_info __UNUSED__)
481 {
482    ELM_POPUP_DATA_GET(data, sd);
483
484    sd->content = NULL;
485    edje_object_part_unswallow
486        (data, edje_object_part_swallow_get(data, "elm.swallow.content"));
487    elm_layout_sizing_eval(data);
488 }
489
490 static void
491 _on_text_content_del(void *data,
492                      Evas *e __UNUSED__,
493                      Evas_Object *obj __UNUSED__,
494                      void *event_info __UNUSED__)
495 {
496    ELM_POPUP_DATA_GET(data, sd);
497
498    sd->text_content_obj = NULL;
499    edje_object_part_unswallow
500        (data, edje_object_part_swallow_get(data, "elm.swallow.content"));
501    elm_layout_sizing_eval(data);
502 }
503
504 static void
505 _on_table_del(void *data,
506               Evas *e __UNUSED__,
507               Evas_Object *obj __UNUSED__,
508               void *event_info __UNUSED__)
509 {
510    ELM_POPUP_DATA_GET(data, sd);
511
512    sd->tbl = NULL;
513    sd->spacer = NULL;
514    sd->scr = NULL;
515    sd->box = NULL;
516    elm_layout_sizing_eval(data);
517 }
518
519 static void
520 _on_button_del(void *data,
521                Evas *e __UNUSED__,
522                Evas_Object *obj,
523                void *event_info __UNUSED__)
524 {
525    int i;
526
527    ELM_POPUP_DATA_GET(data, sd);
528
529    for (i = 0; i < ELM_POPUP_ACTION_BUTTON_MAX; i++)
530      {
531         if (sd->buttons[i] && obj == sd->buttons[i]->btn &&
532             sd->buttons[i]->delete_me == EINA_TRUE)
533           {
534              _button_remove(data, i, EINA_FALSE);
535              break;
536           }
537      }
538 }
539
540 static void
541 _button_remove(Evas_Object *obj,
542                int pos,
543                Eina_Bool delete)
544 {
545    int i = 0;
546    char buf[128];
547
548    ELM_POPUP_DATA_GET(obj, sd);
549
550    if (!sd->button_count) return;
551
552    if (!sd->buttons[pos]) return;
553
554    if (delete) evas_object_del(sd->buttons[pos]->btn);
555
556    evas_object_event_callback_del
557      (sd->buttons[pos]->btn, EVAS_CALLBACK_DEL, _on_button_del);
558    free(sd->buttons[pos]);
559
560    sd->buttons[pos] = NULL;
561    sd->button_count -= 1;
562
563    if (!sd->no_shift)
564      {
565         /* shift left the remaining buttons */
566         for (i = pos; i < ELM_POPUP_ACTION_BUTTON_MAX - 1; i++)
567           {
568              sd->buttons[i] = sd->buttons[i + 1];
569
570              snprintf(buf, sizeof(buf), "actionbtn%d", pos + 1);
571              elm_object_part_content_unset(sd->action_area, buf);
572              snprintf(buf, sizeof(buf), "actionbtn%d", pos);
573              elm_object_part_content_set
574                (sd->action_area, buf, sd->buttons[i]->btn);
575           }
576      }
577
578    if (!sd->button_count)
579      {
580         _visuals_set(obj);
581         edje_object_part_unswallow
582           (obj, edje_object_part_swallow_get(obj, "elm.swallow.action_area"));
583         evas_object_hide(sd->action_area);
584         edje_object_message_signal_process(ELM_WIDGET_DATA(sd)->resize_obj);
585      }
586    else
587      {
588         snprintf(buf, sizeof(buf), "buttons%u", sd->button_count);
589         elm_layout_theme_set
590           (sd->action_area, "popup", buf, elm_widget_style_get(obj));
591      }
592 }
593
594 static void
595 _layout_change_cb(void *data,
596                   Evas_Object *obj __UNUSED__,
597                   const char *emission __UNUSED__,
598                   const char *source __UNUSED__)
599 {
600    elm_layout_sizing_eval(data);
601 }
602
603 static void
604 _restack_cb(void *data __UNUSED__,
605             Evas *e __UNUSED__,
606             Evas_Object *obj,
607             void *event_info __UNUSED__)
608 {
609    ELM_POPUP_DATA_GET(obj, sd);
610
611    evas_object_layer_set(sd->notify, evas_object_layer_get(obj));
612 }
613
614 static void
615 _list_add(Evas_Object *obj)
616 {
617    ELM_POPUP_DATA_GET(obj, sd);
618
619    sd->tbl = elm_table_add(obj);
620
621    evas_object_event_callback_add
622      (sd->tbl, EVAS_CALLBACK_DEL, _on_table_del, obj);
623
624    edje_object_part_swallow
625      (ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.content", sd->tbl);
626    evas_object_size_hint_weight_set
627      (sd->tbl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
628    evas_object_size_hint_align_set(sd->tbl, EVAS_HINT_FILL, EVAS_HINT_FILL);
629    evas_object_show(sd->tbl);
630
631    sd->spacer = evas_object_rectangle_add(evas_object_evas_get(obj));
632    evas_object_color_set(sd->spacer, 0, 0, 0, 0);
633    elm_table_pack(sd->tbl, sd->spacer, 0, 0, 1, 1);
634
635    //Scroller
636    sd->scr = elm_scroller_add(obj);
637    elm_scroller_content_min_limit(sd->scr, EINA_TRUE, EINA_FALSE);
638    elm_scroller_bounce_set(sd->scr, EINA_FALSE, EINA_TRUE);
639    evas_object_size_hint_weight_set
640      (sd->scr, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
641    evas_object_size_hint_align_set(sd->scr, EVAS_HINT_FILL, EVAS_HINT_FILL);
642    evas_object_event_callback_add
643      (sd->scr, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _size_hints_changed_cb,
644      obj);
645    elm_table_pack(sd->tbl, sd->scr, 0, 0, 1, 1);
646    evas_object_show(sd->scr);
647
648    //Box
649    sd->box = elm_box_add(obj);
650    evas_object_size_hint_weight_set(sd->box, EVAS_HINT_EXPAND, 0.0);
651    evas_object_size_hint_align_set(sd->box, EVAS_HINT_FILL, 0.0);
652    elm_object_content_set(sd->scr, sd->box);
653    evas_object_show(sd->box);
654 }
655
656 static void
657 _item_select_cb(void *data,
658                 Evas_Object *obj __UNUSED__,
659                 const char *emission __UNUSED__,
660                 const char *source __UNUSED__)
661 {
662    Elm_Popup_Item *item = data;
663
664    if (!item || item->disabled) return;
665    if (item->func)
666      item->func((void *)item->base.data, WIDGET(item), data);
667 }
668
669 static void
670 _item_text_set(Elm_Popup_Item *item,
671                const char *label)
672 {
673    if (!eina_stringshare_replace(&item->label, label)) return;
674
675    edje_object_part_text_escaped_set(VIEW(item), "elm.text", label);
676
677    if (item->label)
678      edje_object_signal_emit
679        (VIEW(item), "elm,state,item,text,visible", "elm");
680    else
681      edje_object_signal_emit
682        (VIEW(item), "elm,state,item,text,hidden", "elm");
683
684    edje_object_message_signal_process(VIEW(item));
685 }
686
687 static void
688 _item_text_set_hook(Elm_Object_Item *it,
689                     const char *part,
690                     const char *label)
691 {
692    Elm_Popup_Item *item = (Elm_Popup_Item *)it;
693
694    ELM_POPUP_ITEM_CHECK_OR_RETURN(it);
695
696    if ((!part) || (!strcmp(part, "default")))
697      {
698         _item_text_set(item, label);
699         return;
700      }
701
702    WRN("The part name is invalid! : popup=%p", WIDGET(item));
703 }
704
705 static const char *
706 _item_text_get_hook(const Elm_Object_Item *it,
707                     const char *part)
708 {
709    Elm_Popup_Item *item = (Elm_Popup_Item *)it;
710
711    ELM_POPUP_ITEM_CHECK_OR_RETURN(it, NULL);
712
713    if ((!part) || (!strcmp(part, "default")))
714      return item->label;
715
716    WRN("The part name is invalid! : popup=%p", WIDGET(item));
717
718    return NULL;
719 }
720
721 static void
722 _item_icon_set(Elm_Popup_Item *item,
723                Evas_Object *icon)
724 {
725    if (item->icon == icon) return;
726
727    if (item->icon)
728      evas_object_del(item->icon);
729
730    item->icon = icon;
731    if (item->icon)
732      {
733         elm_widget_sub_object_add(WIDGET(item), item->icon);
734         evas_object_data_set(item->icon, "_popup_icon_parent_item", item);
735         edje_object_part_swallow
736           (VIEW(item), "elm.swallow.content", item->icon);
737         edje_object_signal_emit
738           (VIEW(item), "elm,state,item,icon,visible", "elm");
739      }
740    else
741      edje_object_signal_emit(VIEW(item), "elm,state,item,icon,hidden", "elm");
742
743    edje_object_message_signal_process(item->base.view);
744 }
745
746 static void
747 _item_content_set_hook(Elm_Object_Item *it,
748                        const char *part,
749                        Evas_Object *content)
750 {
751    Elm_Popup_Item *item = (Elm_Popup_Item *)it;
752
753    ELM_POPUP_ITEM_CHECK_OR_RETURN(it);
754
755    if ((!(part)) || (!strcmp(part, "default")))
756      _item_icon_set(item, content);
757    else
758      WRN("The part name is invalid! : popup=%p", WIDGET(item));
759 }
760
761 static Evas_Object *
762 _item_content_get_hook(const Elm_Object_Item *it,
763                        const char *part)
764 {
765    Elm_Popup_Item *item = (Elm_Popup_Item *)it;
766
767    ELM_POPUP_ITEM_CHECK_OR_RETURN(it, NULL);
768
769    if ((!(part)) || (!strcmp(part, "default")))
770      return item->icon;
771
772    WRN("The part name is invalid! : popup=%p", WIDGET(item));
773
774    return NULL;
775 }
776
777 static Evas_Object *
778 _item_icon_unset(Elm_Popup_Item *item)
779 {
780    Evas_Object *icon = item->icon;
781
782    if (!item->icon) return NULL;
783    elm_widget_sub_object_del(WIDGET(item), icon);
784    evas_object_data_del(icon, "_popup_icon_parent_item");
785    edje_object_part_unswallow(item->base.view, icon);
786    edje_object_signal_emit(VIEW(item), "elm,state,item,icon,hidden", "elm");
787    item->icon = NULL;
788
789    return icon;
790 }
791
792 static Evas_Object *
793 _item_content_unset_hook(const Elm_Object_Item *it,
794                          const char *part)
795 {
796    Evas_Object *content = NULL;
797    Elm_Popup_Item *item = (Elm_Popup_Item *)it;
798
799    ELM_POPUP_ITEM_CHECK_OR_RETURN(it, NULL);
800
801    if ((!(part)) || (!strcmp(part, "default")))
802      content = _item_icon_unset(item);
803    else
804      WRN("The part name is invalid! : popup=%p", WIDGET(item));
805
806    return content;
807 }
808
809 static void
810 _item_disable_hook(Elm_Object_Item *it)
811 {
812    Elm_Popup_Item *item = (Elm_Popup_Item *)it;
813
814    ELM_POPUP_ITEM_CHECK_OR_RETURN(it);
815
816    if (elm_widget_item_disabled_get(it))
817      edje_object_signal_emit(VIEW(item), "elm,state,item,disabled", "elm");
818    else
819      edje_object_signal_emit(VIEW(item), "elm,state,item,enabled", "elm");
820 }
821
822 static void
823 _item_del_pre_hook(Elm_Object_Item *it)
824 {
825    Elm_Popup_Item *item = (Elm_Popup_Item *)it;
826
827    ELM_POPUP_ITEM_CHECK_OR_RETURN(it);
828    ELM_POPUP_DATA_GET(WIDGET(item), sd);
829
830    if (item->icon)
831      evas_object_del(item->icon);
832
833    eina_stringshare_del(item->label);
834    sd->items = eina_list_remove(sd->items, item);
835    if (!eina_list_count(sd->items))
836      {
837         sd->items = NULL;
838         _list_del(sd);
839      }
840 }
841
842 static void
843 _item_signal_emit_hook(Elm_Object_Item *it,
844                        const char *emission,
845                        const char *source)
846 {
847    Elm_Popup_Item *item = (Elm_Popup_Item *)it;
848
849    ELM_POPUP_ITEM_CHECK_OR_RETURN(it);
850
851    edje_object_signal_emit(VIEW(item), emission, source);
852 }
853
854 static void
855 _access_activate_cb(void *data __UNUSED__,
856                     Evas_Object *part_obj __UNUSED__,
857                     Elm_Object_Item *item)
858 {
859    _item_select_cb(item, NULL, NULL, NULL);
860 }
861
862 static char *
863 _access_state_cb(void *data, Evas_Object *obj __UNUSED__)
864 {
865    Elm_Popup_Item *it = (Elm_Popup_Item *)data;
866    if (!it) return NULL;
867
868    if (it->base.disabled)
869      return strdup(E_("State: Disabled"));
870
871    return NULL;
872 }
873
874 static char *
875 _access_info_cb(void *data, Evas_Object *obj __UNUSED__)
876 {
877    Elm_Popup_Item *it = (Elm_Popup_Item *)data;
878    const char *txt = NULL;
879    Evas_Object *icon = NULL;
880    Eina_Strbuf *buf = NULL;
881    char *str = NULL;
882
883    if (!it) return NULL;
884
885    txt = it->label;
886    icon = it->icon;
887
888    if (txt && icon)
889      {
890         buf = eina_strbuf_new();
891         eina_strbuf_append(buf, E_("icon "));
892         eina_strbuf_append(buf, txt);
893         str = eina_strbuf_string_steal(buf);
894         eina_strbuf_free(buf);
895         return str;
896      }
897    else if ((!txt) && icon) return strdup(E_("icon"));
898    else if (txt && (!icon)) return strdup(txt);
899
900    return NULL;
901 }
902
903 static void
904 _access_widget_item_register(Elm_Popup_Item *it)
905 {
906    Elm_Access_Info *ao;
907
908    _elm_access_widget_item_register((Elm_Widget_Item *)it);
909    ao = _elm_access_object_get(it->base.access_obj);
910    _elm_access_callback_set(ao, ELM_ACCESS_INFO, _access_info_cb, it);
911    _elm_access_callback_set(ao, ELM_ACCESS_STATE, _access_state_cb, it);
912    _elm_access_text_set(ao, ELM_ACCESS_TYPE, E_("Popup_list"));
913    _elm_access_activate_callback_set(ao, _access_activate_cb, it);
914
915 }
916
917 static void
918 _item_new(Elm_Popup_Item *item)
919 {
920    int orientation = -1;
921
922    ELM_POPUP_DATA_GET(WIDGET(item), sd);
923
924    elm_widget_item_text_set_hook_set(item, _item_text_set_hook);
925    elm_widget_item_text_get_hook_set(item, _item_text_get_hook);
926    elm_widget_item_content_set_hook_set(item, _item_content_set_hook);
927    elm_widget_item_content_get_hook_set(item, _item_content_get_hook);
928    elm_widget_item_content_unset_hook_set(item, _item_content_unset_hook);
929    elm_widget_item_disable_hook_set(item, _item_disable_hook);
930    elm_widget_item_del_pre_hook_set(item, _item_del_pre_hook);
931    elm_widget_item_signal_emit_hook_set(item, _item_signal_emit_hook);
932    VIEW(item) = edje_object_add
933        (evas_object_evas_get(ELM_WIDGET_DATA(sd)->obj));
934
935    orientation = sd->orientation;
936    if (orientation == 90 || orientation == 270)
937       elm_widget_theme_object_set
938          (WIDGET(item), VIEW(item), "popup", "item/landscape", elm_widget_style_get(WIDGET(item)));
939    else
940       elm_widget_theme_object_set
941          (WIDGET(item), VIEW(item), "popup", "item", elm_widget_style_get(WIDGET(item)));
942    edje_object_mirrored_set(VIEW(item), elm_widget_mirrored_get(WIDGET(item)));
943    edje_object_signal_callback_add
944      (VIEW(item), "elm,action,click", "", _item_select_cb, item);
945    evas_object_size_hint_align_set
946      (VIEW(item), EVAS_HINT_FILL, EVAS_HINT_FILL);
947
948    /* access */
949    if (_elm_config->access_mode) _access_widget_item_register(item);
950
951    evas_object_show(VIEW(item));
952 }
953
954 static Eina_Bool
955 _title_text_set(Evas_Object *obj,
956                 const char *text)
957 {
958    Evas_Object *ao;
959    Eina_Bool title_visibility_old, title_visibility_current;
960
961    ELM_POPUP_DATA_GET(obj, sd);
962
963    if (sd->title_text == text) return EINA_TRUE;
964
965    title_visibility_old = (sd->title_text) || (sd->title_icon);
966    eina_stringshare_replace(&sd->title_text, text);
967
968    //bare edje here because we're inside the hook, already
969    edje_object_part_text_escaped_set
970      (ELM_WIDGET_DATA(sd)->resize_obj, "elm.text.title", text);
971
972    /* access */
973    if (_elm_config->access_mode)
974      {
975         ao = _access_object_get(obj, ACCESS_TITLE_PART);
976         if (!ao)
977           {
978              ao = _elm_access_edje_object_part_object_register
979                     (obj, ELM_WIDGET_DATA(sd)->resize_obj, ACCESS_TITLE_PART);
980              _elm_access_text_set(_elm_access_object_get(ao),
981                                   ELM_ACCESS_TYPE, E_("Popup Title"));
982           }
983         _elm_access_text_set(_elm_access_object_get(ao), ELM_ACCESS_INFO, text);
984      }
985
986    if (sd->title_text)
987      elm_layout_signal_emit(obj, "elm,state,title,text,visible", "elm");
988    else
989      elm_layout_signal_emit(obj, "elm,state,title,text,hidden", "elm");
990
991    title_visibility_current = (sd->title_text) || (sd->title_icon);
992
993    if (title_visibility_old != title_visibility_current)
994      _visuals_set(obj);
995
996    edje_object_message_signal_process(ELM_WIDGET_DATA(sd)->resize_obj);
997    elm_layout_sizing_eval(obj);
998
999    return EINA_TRUE;
1000 }
1001
1002 static Eina_Bool
1003 _content_text_set(Evas_Object *obj,
1004                   const char *text)
1005 {
1006    Evas_Object *prev_content, *ao;
1007    char buf[128];
1008
1009    ELM_POPUP_DATA_GET(obj, sd);
1010
1011    if (sd->items)
1012      {
1013         _items_remove(sd);
1014         _list_del(sd);
1015      }
1016
1017    prev_content = elm_layout_content_get
1018        (sd->content_area, "elm.swallow.content");
1019
1020    if (prev_content)
1021      evas_object_del(prev_content);
1022
1023    if (!text) goto end;
1024
1025    edje_object_part_swallow
1026      (ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.content",
1027      sd->content_area);
1028    sd->text_content_obj = elm_label_add(obj);
1029
1030    evas_object_event_callback_add
1031      (sd->text_content_obj, EVAS_CALLBACK_DEL, _on_text_content_del, obj);
1032
1033    snprintf(buf, sizeof(buf), "popup/%s", elm_widget_style_get(obj));
1034    elm_object_style_set(sd->text_content_obj, buf);
1035    elm_label_line_wrap_set(sd->text_content_obj, sd->content_text_wrap_type);
1036    elm_object_text_set(sd->text_content_obj, text);
1037    evas_object_size_hint_weight_set
1038      (sd->text_content_obj, EVAS_HINT_EXPAND, 0.0);
1039    evas_object_size_hint_align_set
1040      (sd->text_content_obj, EVAS_HINT_FILL, EVAS_HINT_FILL);
1041    elm_layout_content_set
1042      (sd->content_area, "elm.swallow.content", sd->text_content_obj);
1043
1044    /* access */
1045    if (_elm_config->access_mode)
1046      {
1047         /* unregister label, ACCESS_BODY_PART will register */
1048         elm_access_object_unregister(sd->text_content_obj);
1049
1050         ao = _access_object_get(obj, ACCESS_BODY_PART);
1051         if (!ao)
1052           {
1053              ao = _elm_access_edje_object_part_object_register
1054                     (obj, ELM_WIDGET_DATA(sd)->resize_obj, ACCESS_BODY_PART);
1055              _elm_access_text_set(_elm_access_object_get(ao),
1056                                   ELM_ACCESS_TYPE, E_("Popup Body Text"));
1057           }
1058         _elm_access_text_set(_elm_access_object_get(ao), ELM_ACCESS_INFO, text);
1059      }
1060
1061 end:
1062    elm_layout_sizing_eval(obj);
1063
1064    return EINA_TRUE;
1065 }
1066
1067 static Eina_Bool
1068 _elm_popup_smart_text_set(Evas_Object *obj,
1069                           const char *part,
1070                           const char *label)
1071 {
1072    if (!part || !strcmp(part, "default"))
1073      return _content_text_set(obj, label);
1074    else if (!strcmp(part, "title,text"))
1075      return _title_text_set(obj, label);
1076    else
1077      return _elm_popup_parent_sc->text_set(obj, part, label);
1078 }
1079
1080 static const char *
1081 _title_text_get(const Evas_Object *obj)
1082 {
1083    ELM_POPUP_DATA_GET(obj, sd);
1084
1085    return sd->title_text;
1086 }
1087
1088 static const char *
1089 _content_text_get(const Evas_Object *obj)
1090 {
1091    const char *str = NULL;
1092
1093    ELM_POPUP_DATA_GET(obj, sd);
1094
1095    if (sd->text_content_obj)
1096      str = elm_object_text_get(sd->text_content_obj);
1097
1098    return str;
1099 }
1100
1101 static const char *
1102 _elm_popup_smart_text_get(const Evas_Object *obj,
1103                           const char *part)
1104 {
1105    const char *str = NULL;
1106
1107    if (!part || !strcmp(part, "default"))
1108      str = _content_text_get(obj);
1109    else if (!strcmp(part, "title,text"))
1110      str = _title_text_get(obj);
1111    else
1112      str = _elm_popup_parent_sc->text_get(obj, part);
1113
1114    return str;
1115 }
1116
1117 static Eina_Bool
1118 _title_icon_set(Evas_Object *obj,
1119                 Evas_Object *icon)
1120 {
1121    Eina_Bool title_visibility_old, title_visibility_current;
1122
1123    ELM_POPUP_DATA_GET(obj, sd);
1124
1125    if (sd->title_icon == icon) return EINA_TRUE;
1126    title_visibility_old = (sd->title_text) || (sd->title_icon);
1127    if (sd->title_icon) evas_object_del(sd->title_icon);
1128
1129    sd->title_icon = icon;
1130    title_visibility_current = (sd->title_text) || (sd->title_icon);
1131
1132    //bare edje here because we're already in content_set virtual
1133    edje_object_part_swallow
1134      (ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.title.icon",
1135      sd->title_icon);
1136
1137    if (sd->title_icon)
1138      elm_layout_signal_emit(obj, "elm,state,title,icon,visible", "elm");
1139    if (title_visibility_old != title_visibility_current) _visuals_set(obj);
1140
1141    edje_object_message_signal_process(ELM_WIDGET_DATA(sd)->resize_obj);
1142    elm_layout_sizing_eval(obj);
1143
1144    return EINA_TRUE;
1145 }
1146
1147 static Eina_Bool
1148 _content_set(Evas_Object *obj,
1149              Evas_Object *content)
1150 {
1151    Evas_Object *prev_content;
1152
1153    ELM_POPUP_DATA_GET(obj, sd);
1154
1155    if (sd->content && sd->content == content) return EINA_TRUE;
1156    if (sd->items)
1157      {
1158         _items_remove(sd);
1159         _list_del(sd);
1160      }
1161    prev_content =
1162      elm_layout_content_get(sd->content_area, "elm.swallow.content");
1163    if (prev_content)
1164      evas_object_del(prev_content);
1165
1166    sd->content = content;
1167    if (content)
1168      {
1169         //bare edje as to avoid loop
1170         edje_object_part_swallow
1171           (ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.content",
1172           sd->content_area);
1173
1174         elm_layout_content_set
1175           (sd->content_area, "elm.swallow.content", content);
1176         evas_object_show(content);
1177
1178         evas_object_event_callback_add
1179           (content, EVAS_CALLBACK_DEL, _on_content_del, obj);
1180      }
1181    elm_layout_sizing_eval(obj);
1182
1183    return EINA_TRUE;
1184 }
1185
1186 static void
1187 _action_button_set(Evas_Object *obj,
1188                    Evas_Object *btn,
1189                    unsigned int idx)
1190 {
1191    int i = 0;
1192    Action_Area_Data *adata;
1193    char buf[128];
1194    Evas_Object *ao;
1195
1196    ELM_POPUP_DATA_GET(obj, sd);
1197
1198    if (idx >= ELM_POPUP_ACTION_BUTTON_MAX) return;
1199
1200    if (!btn)
1201      {
1202         _button_remove(obj, idx, EINA_TRUE);
1203         return;
1204      }
1205
1206    if (!sd->buttons[idx]) sd->button_count++;
1207    else
1208      {
1209         sd->no_shift = EINA_TRUE;
1210         evas_object_del(sd->buttons[idx]->btn);
1211         sd->no_shift = EINA_FALSE;
1212      }
1213
1214    if (_elm_config->access_mode)
1215      {
1216         /* if popup has a button, popup should be closed by the button
1217            so outline(ACCESS_BASE_PART) is not necessary any more */
1218         ao = _access_object_get(obj, ACCESS_BASE_PART);
1219
1220         if (ao && sd->button_count)
1221           _elm_access_edje_object_part_object_unregister
1222             (obj, ELM_WIDGET_DATA(sd)->resize_obj, ACCESS_BASE_PART);
1223      }
1224
1225    snprintf(buf, sizeof(buf), "buttons%u", sd->button_count);
1226    elm_layout_theme_set
1227      (sd->action_area, "popup", buf, elm_widget_style_get(obj));
1228
1229    adata = ELM_NEW(Action_Area_Data);
1230    adata->obj = obj;
1231    adata->btn = btn;
1232
1233    evas_object_event_callback_add
1234      (btn, EVAS_CALLBACK_DEL, _on_button_del, obj);
1235
1236    sd->buttons[idx] = adata;
1237
1238    snprintf(buf, sizeof(buf), "actionbtn%u", idx + 1);
1239    elm_object_part_content_set
1240      (sd->action_area, buf, sd->buttons[idx]->btn);
1241    evas_object_show(sd->buttons[i]->btn);
1242
1243    edje_object_part_swallow
1244      (ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.action_area",
1245      sd->action_area);
1246    if (sd->button_count == 1) _visuals_set(obj);
1247
1248    edje_object_message_signal_process(ELM_WIDGET_DATA(sd)->resize_obj);
1249    if (sd->items) _scroller_size_calc(obj);
1250
1251    elm_layout_sizing_eval(obj);
1252 }
1253
1254 static Eina_Bool
1255 _elm_popup_smart_content_set(Evas_Object *obj,
1256                              const char *part,
1257                              Evas_Object *content)
1258 {
1259    unsigned int i;
1260
1261    if (!part || !strcmp(part, "default"))
1262      return _content_set(obj, content);
1263    else if (!strcmp(part, "title,icon"))
1264      return _title_icon_set(obj, content);
1265    else if (!strncmp(part, "button", 6))
1266      {
1267         i = atoi(part + 6) - 1;
1268
1269         if (i >= ELM_POPUP_ACTION_BUTTON_MAX)
1270           goto err;
1271
1272         _action_button_set(obj, content, i);
1273
1274         return EINA_TRUE;
1275      }
1276
1277 err:
1278    ERR("The part name is invalid! : popup=%p", obj);
1279
1280    return EINA_FALSE;
1281 }
1282
1283 static Evas_Object *
1284 _title_icon_get(const Evas_Object *obj)
1285 {
1286    ELM_POPUP_DATA_GET(obj, sd);
1287
1288    return sd->title_icon;
1289 }
1290
1291 static Evas_Object *
1292 _content_get(const Evas_Object *obj)
1293 {
1294    ELM_POPUP_DATA_GET(obj, sd);
1295
1296    return sd->content;
1297 }
1298
1299 static Evas_Object *
1300 _action_button_get(const Evas_Object *obj,
1301                    unsigned int idx)
1302 {
1303    Evas_Object *button = NULL;
1304
1305    ELM_POPUP_DATA_GET(obj, sd);
1306    if (!sd->button_count) return NULL;
1307
1308    if (sd->buttons[idx])
1309      button = sd->buttons[idx]->btn;
1310
1311    return button;
1312 }
1313
1314 static Evas_Object *
1315 _elm_popup_smart_content_get(const Evas_Object *obj,
1316                              const char *part)
1317 {
1318    Evas_Object *content = NULL;
1319    unsigned int i;
1320
1321    if (!part || !strcmp(part, "default"))
1322      content = _content_get(obj);
1323    else if (!strcmp(part, "title,text"))
1324      content = _title_icon_get(obj);
1325    else if (!strncmp(part, "button", 6))
1326      {
1327         i = atoi(part + 6) - 1;
1328
1329         if (i >= ELM_POPUP_ACTION_BUTTON_MAX)
1330           goto err;
1331
1332         content = _action_button_get(obj, i);
1333      }
1334    else
1335      goto err;
1336
1337    return content;
1338
1339 err:
1340    WRN("The part name is invalid! : popup=%p", obj);
1341    return content;
1342 }
1343
1344 static Evas_Object *
1345 _content_unset(Evas_Object *obj)
1346 {
1347    Evas_Object *content;
1348
1349    ELM_POPUP_DATA_GET(obj, sd);
1350
1351    if (!sd->content) return NULL;
1352
1353    evas_object_event_callback_del
1354      (sd->content, EVAS_CALLBACK_DEL, _on_content_del);
1355
1356    content = elm_layout_content_unset(sd->content_area, "elm.swallow.content");
1357    sd->content = NULL;
1358
1359    elm_layout_sizing_eval(obj);
1360
1361    return content;
1362 }
1363
1364 static Evas_Object *
1365 _title_icon_unset(Evas_Object *obj)
1366 {
1367    Evas_Object *icon;
1368
1369    ELM_POPUP_DATA_GET(obj, sd);
1370
1371    if (!sd->title_icon) return NULL;
1372
1373    icon = sd->title_icon;
1374    edje_object_part_unswallow(ELM_WIDGET_DATA(sd)->resize_obj, sd->title_icon);
1375    sd->title_icon = NULL;
1376
1377    return icon;
1378 }
1379
1380 static Evas_Object *
1381 _elm_popup_smart_content_unset(Evas_Object *obj,
1382                                const char *part)
1383 {
1384    Evas_Object *content = NULL;
1385    unsigned int i;
1386
1387    if (!part || !strcmp(part, "default"))
1388      content = _content_unset(obj);
1389    else if (!strcmp(part, "title,icon"))
1390      content = _title_icon_unset(obj);
1391    else if (!strncmp(part, "button", 6))
1392      {
1393         i = atoi(part + 6) - 1;
1394
1395         if (i >= ELM_POPUP_ACTION_BUTTON_MAX)
1396           goto err;
1397
1398         _button_remove(obj, i, EINA_FALSE);
1399      }
1400    else
1401      goto err;
1402
1403    return content;
1404
1405 err:
1406    ERR("The part name is invalid! : popup=%p", obj);
1407
1408    return content;
1409 }
1410
1411 static Eina_Bool
1412 _elm_popup_smart_focus_next(const Evas_Object *obj,
1413                             Elm_Focus_Direction dir,
1414                             Evas_Object **next)
1415 {
1416    Evas_Object *ao;
1417    Eina_List *items = NULL;
1418    Elm_Popup_Item * it = NULL;
1419    Eina_List *l;
1420
1421    ELM_POPUP_DATA_GET(obj, sd);
1422
1423    /* access */
1424    if (_elm_config->access_mode)
1425      {
1426         ao = _access_object_get(obj, ACCESS_BASE_PART);
1427         if (ao) items = eina_list_append(items, ao);
1428
1429         if (sd->title_text)
1430           {
1431              ao = _access_object_get(obj, ACCESS_TITLE_PART);
1432              items = eina_list_append(items, ao);
1433           }
1434
1435         ao = _access_object_get(obj, ACCESS_BODY_PART);
1436         if (ao) items = eina_list_append(items, ao);
1437      }
1438
1439    /* content area */
1440    if (sd->content) items = eina_list_append(items, sd->content_area);
1441
1442    EINA_LIST_FOREACH(sd->items, l, it)
1443      items = eina_list_append(items, it->base.access_obj);
1444    /* action area */
1445    if (sd->button_count) items = eina_list_append(items, sd->action_area);
1446
1447    if (_elm_config->access_mode)
1448      return elm_widget_focus_list_next_get(obj, items, eina_list_data_get, dir, next);
1449
1450    if (!elm_widget_focus_list_next_get(obj, items, eina_list_data_get, dir, next))
1451      *next = (Evas_Object *)obj;
1452
1453    return EINA_TRUE;
1454 }
1455
1456 static Eina_Bool
1457 _elm_popup_smart_focus_direction(const Evas_Object *obj,
1458                                  const Evas_Object *base,
1459                                  double degree,
1460                                  Evas_Object **direction,
1461                                  double *weight)
1462 {
1463    Evas_Object *ao;
1464    Eina_List *items = NULL;
1465    Elm_Popup_Item * it = NULL;
1466    Eina_List *l;
1467
1468    ELM_POPUP_DATA_GET(obj, sd);
1469
1470    /* access */
1471    if (_elm_config->access_mode)
1472      {
1473         ao = _access_object_get(obj, ACCESS_BASE_PART);
1474         if (ao) items = eina_list_append(items, ao);
1475
1476         if (sd->title_text)
1477           {
1478              ao = _access_object_get(obj, ACCESS_TITLE_PART);
1479              items = eina_list_append(items, ao);
1480           }
1481
1482         ao = _access_object_get(obj, ACCESS_BODY_PART);
1483         if (ao) items = eina_list_append(items, ao);
1484      }
1485
1486    /* content area */
1487    if (sd->content) items = eina_list_append(items, sd->content_area);
1488
1489    EINA_LIST_FOREACH(sd->items, l, it)
1490      items = eina_list_append(items, it->base.access_obj);
1491
1492    /* action area */
1493    if (sd->button_count) items = eina_list_append(items, sd->action_area);
1494
1495    elm_widget_focus_list_direction_get
1496      (obj, base, items, eina_list_data_get, degree, direction, weight);
1497
1498    return EINA_TRUE;
1499 }
1500
1501 static void _rotation_changed_cb(void *data,
1502                                Evas_Object *o __UNUSED__,
1503                                const char *emission __UNUSED__,
1504                                const char *source __UNUSED__)
1505 {
1506    int rotation = -1;
1507    Eina_List *elist;
1508    Evas_Object *popup = data;
1509    Elm_Popup_Item *item;
1510
1511    ELM_POPUP_CHECK(popup);
1512    ELM_POPUP_DATA_GET(popup, sd);
1513
1514    rotation = ELM_WIDGET_DATA(sd)->orient_mode;
1515
1516    if (sd->orientation == rotation) return;
1517
1518    sd->orientation = rotation;
1519
1520    if (sd->items)
1521      {
1522         EINA_LIST_FOREACH(sd->items, elist, item)
1523         {
1524            if (rotation == 90 || rotation == 270)
1525               elm_widget_theme_object_set
1526                  (WIDGET(item), VIEW(item), "popup", "item/landscape", elm_widget_style_get(WIDGET(item)));
1527            else
1528               elm_widget_theme_object_set
1529                  (WIDGET(item), VIEW(item), "popup", "item", elm_widget_style_get(WIDGET(item)));
1530            _item_update(item);
1531         }
1532       _scroller_size_calc(popup);
1533       elm_layout_sizing_eval(popup);
1534    }
1535 }
1536
1537 static void
1538 _elm_popup_smart_add(Evas_Object *obj)
1539 {
1540    Evas_Object *ao;
1541
1542    EVAS_SMART_DATA_ALLOC(obj, Elm_Popup_Smart_Data);
1543
1544    ELM_WIDGET_CLASS(_elm_popup_parent_sc)->base.add(obj);
1545
1546    evas_object_size_hint_weight_set
1547      (ELM_WIDGET_DATA(priv)->resize_obj, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1548    evas_object_size_hint_align_set
1549      (ELM_WIDGET_DATA(priv)->resize_obj, EVAS_HINT_FILL, EVAS_HINT_FILL);
1550
1551    elm_layout_theme_set(obj, "popup", "base", elm_widget_style_get(obj));
1552
1553    priv->notify = elm_notify_add(obj);
1554    elm_notify_align_set(priv->notify, 0.5, 0.5);
1555    elm_notify_allow_events_set(priv->notify, EINA_FALSE);
1556    evas_object_size_hint_weight_set
1557      (priv->notify, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1558    evas_object_size_hint_align_set
1559      (priv->notify, EVAS_HINT_FILL, EVAS_HINT_FILL);
1560
1561    elm_object_style_set(priv->notify, "popup");
1562
1563    evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _on_show, NULL);
1564    evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _on_hide, NULL);
1565
1566    evas_object_event_callback_add
1567      (obj, EVAS_CALLBACK_RESTACK, _restack_cb, NULL);
1568
1569    elm_layout_signal_callback_add
1570      (obj, "elm,state,title_area,visible", "elm", _layout_change_cb, obj);
1571    elm_layout_signal_callback_add
1572      (obj, "elm,state,title_area,hidden", "elm", _layout_change_cb, obj);
1573    elm_layout_signal_callback_add
1574      (obj, "elm,state,action_area,visible", "elm", _layout_change_cb, obj);
1575    elm_layout_signal_callback_add
1576      (obj, "elm,state,action_area,hidden", "elm", _layout_change_cb, obj);
1577
1578    priv->content_area = elm_layout_add(obj);
1579    elm_layout_theme_set
1580      (priv->content_area, "popup", "content", elm_widget_style_get(obj));
1581    priv->action_area = elm_layout_add(obj);
1582    evas_object_size_hint_weight_set(priv->action_area, EVAS_HINT_EXPAND,
1583                                     EVAS_HINT_EXPAND);
1584    evas_object_size_hint_align_set(priv->action_area, EVAS_HINT_FILL,
1585                                    EVAS_HINT_FILL);
1586    evas_object_event_callback_add
1587      (priv->action_area, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1588      _size_hints_changed_cb, obj);
1589    evas_object_event_callback_add
1590      (priv->content_area, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1591      _size_hints_changed_cb, obj);
1592
1593    priv->content_text_wrap_type = ELM_WRAP_MIXED;
1594    evas_object_smart_callback_add
1595      (priv->notify, "block,clicked", _block_clicked_cb, obj);
1596
1597    evas_object_smart_callback_add(priv->notify, "timeout", _timeout_cb, obj);
1598
1599    elm_widget_can_focus_set(obj, EINA_TRUE);
1600
1601    _visuals_set(obj);
1602
1603    /* access */
1604    if (_elm_config->access_mode)
1605      {
1606         ao = _elm_access_edje_object_part_object_register
1607                (obj, ELM_WIDGET_DATA(priv)->resize_obj, ACCESS_BASE_PART);
1608         _elm_access_text_set(_elm_access_object_get(ao),
1609                              ELM_ACCESS_TYPE, E_(OUTLINE_TEXT));
1610         _elm_access_activate_callback_set
1611           (_elm_access_object_get(ao), _access_base_activate_cb, obj);
1612      }
1613 }
1614
1615 static void
1616 _elm_popup_smart_parent_set(Evas_Object *obj,
1617                             Evas_Object *parent)
1618 {
1619    ELM_POPUP_DATA_GET(obj, sd);
1620
1621    elm_notify_parent_set(sd->notify, parent);
1622 }
1623
1624 static void
1625 _elm_popup_smart_access(Evas_Object *obj, Eina_Bool is_access)
1626 {
1627    _access_obj_process(obj, is_access);
1628
1629    evas_object_smart_callback_call(obj, SIG_ACCESS_CHANGED, NULL);
1630 }
1631
1632 static Eina_Bool
1633 _elm_popup_smart_event(Evas_Object *obj,
1634                        Evas_Object *src __UNUSED__,
1635                        Evas_Callback_Type type,
1636                        void *event_info)
1637 {
1638    Evas_Event_Key_Down *ev = event_info;
1639
1640    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
1641    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
1642    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
1643
1644    if (!strcmp(ev->keyname, "Tab"))
1645      {
1646         if (evas_key_modifier_is_set(ev->modifiers, "Shift"))
1647           elm_widget_focus_cycle(obj, ELM_FOCUS_PREVIOUS);
1648         else
1649           elm_widget_focus_cycle(obj, ELM_FOCUS_NEXT);
1650
1651         goto success;
1652      }
1653    else if ((!strcmp(ev->keyname, "Left")) ||
1654             ((!strcmp(ev->keyname, "KP_Left")) && (!ev->string)))
1655      {
1656         elm_widget_focus_direction_go(obj, 270.0);
1657         goto success;
1658      }
1659    else if ((!strcmp(ev->keyname, "Right")) ||
1660             ((!strcmp(ev->keyname, "KP_Right")) && (!ev->string)))
1661      {
1662         elm_widget_focus_direction_go(obj, 90.0);
1663         goto success;
1664      }
1665    else if ((!strcmp(ev->keyname, "Up")) ||
1666             ((!strcmp(ev->keyname, "KP_Up")) && (!ev->string)))
1667      {
1668         elm_widget_focus_direction_go(obj, 0.0);
1669         goto success;
1670      }
1671    else if ((!strcmp(ev->keyname, "Down")) ||
1672             ((!strcmp(ev->keyname, "KP_Down")) && (!ev->string)))
1673      {
1674         elm_widget_focus_direction_go(obj, 180.0);
1675         goto success;
1676      }
1677
1678    return EINA_FALSE;
1679
1680 success:
1681    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1682    return EINA_TRUE;
1683 }
1684
1685 static void
1686 _elm_popup_smart_set_user(Elm_Popup_Smart_Class *sc)
1687 {
1688    ELM_WIDGET_CLASS(sc)->base.add = _elm_popup_smart_add;
1689    ELM_WIDGET_CLASS(sc)->base.del = _elm_popup_smart_del;
1690
1691    ELM_WIDGET_CLASS(sc)->parent_set = _elm_popup_smart_parent_set;
1692    ELM_WIDGET_CLASS(sc)->event = _elm_popup_smart_event;
1693    ELM_WIDGET_CLASS(sc)->theme = _elm_popup_smart_theme;
1694    ELM_WIDGET_CLASS(sc)->translate = _elm_popup_smart_translate;
1695    ELM_WIDGET_CLASS(sc)->focus_next = _elm_popup_smart_focus_next;
1696    ELM_WIDGET_CLASS(sc)->access = _elm_popup_smart_access;
1697    ELM_WIDGET_CLASS(sc)->focus_direction = _elm_popup_smart_focus_direction;
1698    ELM_WIDGET_CLASS(sc)->sub_object_del = _elm_popup_smart_sub_object_del;
1699
1700    ELM_CONTAINER_CLASS(sc)->content_set = _elm_popup_smart_content_set;
1701    ELM_CONTAINER_CLASS(sc)->content_get = _elm_popup_smart_content_get;
1702    ELM_CONTAINER_CLASS(sc)->content_unset = _elm_popup_smart_content_unset;
1703
1704    ELM_LAYOUT_CLASS(sc)->text_set = _elm_popup_smart_text_set;
1705    ELM_LAYOUT_CLASS(sc)->text_get = _elm_popup_smart_text_get;
1706    ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_popup_smart_sizing_eval;
1707 }
1708
1709 EAPI const Elm_Popup_Smart_Class *
1710 elm_popup_smart_class_get(void)
1711 {
1712    static Elm_Popup_Smart_Class _sc =
1713      ELM_POPUP_SMART_CLASS_INIT_NAME_VERSION(ELM_POPUP_SMART_NAME);
1714    static const Elm_Popup_Smart_Class *class = NULL;
1715    Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
1716
1717    if (class)
1718      return class;
1719
1720    _elm_popup_smart_set(&_sc);
1721    esc->callbacks = _smart_callbacks;
1722    class = &_sc;
1723
1724    return class;
1725 }
1726
1727 EAPI Evas_Object *
1728 elm_popup_add(Evas_Object *parent)
1729 {
1730    Evas_Object *obj;
1731
1732    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1733
1734    obj = elm_widget_add(_elm_popup_smart_class_new(), parent);
1735    if (!obj) return NULL;
1736
1737    if (!elm_widget_sub_object_add(parent, obj))
1738      ERR("could not add %p as sub object of %p", obj, parent);
1739
1740    /* access: parent could be any object such as elm_list which does
1741       not know elc_popup as its child object in the focus_next();    */
1742    ELM_WIDGET_DATA_GET(obj, sd);
1743    ELM_POPUP_DATA_GET(obj, sd1);
1744
1745    sd->highlight_root = EINA_TRUE;
1746    sd1->orientation = sd->orient_mode;
1747
1748    _elm_widget_orient_signal_emit(obj);
1749
1750    elm_layout_signal_callback_add
1751      (obj, "elm,state,orientation,changed", "", _rotation_changed_cb, obj);
1752
1753    return obj;
1754 }
1755
1756 EAPI void
1757 elm_popup_content_text_wrap_type_set(Evas_Object *obj,
1758                                      Elm_Wrap_Type wrap)
1759 {
1760    ELM_POPUP_CHECK(obj);
1761    ELM_POPUP_DATA_GET(obj, sd);
1762
1763    //Need to wrap the content text, so not allowing ELM_WRAP_NONE
1764    if (sd->content_text_wrap_type == ELM_WRAP_NONE) return;
1765
1766    sd->content_text_wrap_type = wrap;
1767    if (sd->text_content_obj)
1768      elm_label_line_wrap_set(sd->text_content_obj, wrap);
1769 }
1770
1771 EAPI Elm_Wrap_Type
1772 elm_popup_content_text_wrap_type_get(const Evas_Object *obj)
1773 {
1774    ELM_POPUP_CHECK(obj) ELM_WRAP_LAST;
1775    ELM_POPUP_DATA_GET(obj, sd);
1776
1777    return sd->content_text_wrap_type;
1778 }
1779
1780 EAPI void
1781 elm_popup_orient_set(Evas_Object *obj,
1782                      Elm_Popup_Orient orient)
1783 {
1784    ELM_POPUP_CHECK(obj);
1785    ELM_POPUP_DATA_GET(obj, sd);
1786
1787    if (orient >= ELM_POPUP_ORIENT_LAST) return;
1788    double horizontal = 0, vertical = 0;
1789
1790       switch (orient)
1791         {
1792          case ELM_POPUP_ORIENT_TOP:
1793             horizontal = 0.5; vertical = 0.0;
1794            break;
1795
1796          case ELM_POPUP_ORIENT_CENTER:
1797             horizontal = 0.5; vertical = 0.5;
1798            break;
1799
1800          case ELM_POPUP_ORIENT_BOTTOM:
1801             horizontal = 0.5; vertical = 1.0;
1802            break;
1803
1804          case ELM_POPUP_ORIENT_LEFT:
1805             horizontal = 0.0; vertical = 0.5;
1806            break;
1807
1808          case ELM_POPUP_ORIENT_RIGHT:
1809             horizontal = 1.0; vertical = 0.5;
1810            break;
1811
1812          case ELM_POPUP_ORIENT_TOP_LEFT:
1813             horizontal = 0.0; vertical = 0.0;
1814            break;
1815
1816          case ELM_POPUP_ORIENT_TOP_RIGHT:
1817             horizontal = 1.0; vertical = 0.0;
1818            break;
1819
1820          case ELM_POPUP_ORIENT_BOTTOM_LEFT:
1821             horizontal = 0.0; vertical = 1.0;
1822            break;
1823
1824          case ELM_POPUP_ORIENT_BOTTOM_RIGHT:
1825             horizontal = 1.0; vertical = 1.0;
1826            break;
1827         }
1828    elm_notify_align_set(sd->notify, horizontal, vertical);
1829 }
1830
1831 EAPI Elm_Popup_Orient
1832 elm_popup_orient_get(const Evas_Object *obj)
1833 {
1834    ELM_POPUP_CHECK(obj) - 1;
1835    ELM_POPUP_DATA_GET(obj, sd);
1836
1837    return (Elm_Popup_Orient)elm_notify_orient_get(sd->notify);
1838 }
1839
1840 EAPI void
1841 elm_popup_timeout_set(Evas_Object *obj,
1842                       double timeout)
1843 {
1844    ELM_POPUP_CHECK(obj);
1845    ELM_POPUP_DATA_GET(obj, sd);
1846
1847    elm_notify_timeout_set(sd->notify, timeout);
1848 }
1849
1850 EAPI double
1851 elm_popup_timeout_get(const Evas_Object *obj)
1852 {
1853    ELM_POPUP_CHECK(obj) 0.0;
1854    ELM_POPUP_DATA_GET(obj, sd);
1855
1856    return elm_notify_timeout_get(sd->notify);
1857 }
1858
1859 EAPI void
1860 elm_popup_allow_events_set(Evas_Object *obj,
1861                            Eina_Bool allow)
1862 {
1863    Eina_Bool allow_events = !!allow;
1864
1865    ELM_POPUP_CHECK(obj);
1866    ELM_POPUP_DATA_GET(obj, sd);
1867
1868    elm_notify_allow_events_set(sd->notify, allow_events);
1869 }
1870
1871 EAPI Eina_Bool
1872 elm_popup_allow_events_get(const Evas_Object *obj)
1873 {
1874    ELM_POPUP_CHECK(obj) EINA_FALSE;
1875    ELM_POPUP_DATA_GET(obj, sd);
1876
1877    return elm_notify_allow_events_get(sd->notify);
1878 }
1879
1880 EAPI Elm_Object_Item *
1881 elm_popup_item_append(Evas_Object *obj,
1882                       const char *label,
1883                       Evas_Object *icon,
1884                       Evas_Smart_Cb func,
1885                       const void *data)
1886 {
1887    Evas_Object *prev_content;
1888    Elm_Popup_Item *item;
1889
1890    ELM_POPUP_CHECK(obj) NULL;
1891    ELM_POPUP_DATA_GET(obj, sd);
1892
1893    item = elm_widget_item_new(obj, Elm_Popup_Item);
1894    if (!item) return NULL;
1895    if (sd->content || sd->text_content_obj)
1896      {
1897         prev_content = elm_layout_content_get
1898             (sd->content_area, "elm.swallow.content");
1899         if (prev_content)
1900           evas_object_del(prev_content);
1901      }
1902
1903    //The first item is appended.
1904    if (!sd->items)
1905      _list_add(obj);
1906
1907    item->func = func;
1908    item->base.data = data;
1909
1910    _item_new(item);
1911    _item_icon_set(item, icon);
1912    _item_text_set(item, label);
1913
1914    elm_box_pack_end(sd->box, VIEW(item));
1915    sd->items = eina_list_append(sd->items, item);
1916
1917    _scroller_size_calc(obj);
1918    elm_layout_sizing_eval(obj);
1919
1920    return (Elm_Object_Item *)item;
1921 }