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