557ad1063ca7c8a5c82ac4a378613c6fbb09516b
[framework/uifw/elementary.git] / src / lib / elc_naviframe.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 typedef struct _Widget_Data Widget_Data;
5 typedef struct _Elm_Naviframe_Item Elm_Naviframe_Item;
6 typedef struct _Elm_Naviframe_Content_Item_Pair Elm_Naviframe_Content_Item_Pair;
7 typedef struct _Elm_Naviframe_Text_Item_Pair Elm_Naviframe_Text_Item_Pair;
8
9 struct _Widget_Data
10 {
11    Eina_Inlist  *stack;
12    Evas_Object  *base;
13    Eina_Bool     preserve: 1;
14    Eina_Bool     auto_pushed: 1;
15    Eina_Bool     freeze_events: 1;
16 };
17
18 struct _Elm_Naviframe_Content_Item_Pair
19 {
20    EINA_INLIST;
21    const char *part;
22    Evas_Object *content;
23    Elm_Naviframe_Item *it;
24 };
25
26 struct _Elm_Naviframe_Text_Item_Pair
27 {
28    EINA_INLIST;
29    const char *part;
30    const char *text;
31 };
32
33 struct _Elm_Naviframe_Item
34 {
35    ELM_WIDGET_ITEM;
36    EINA_INLIST;
37    Eina_Inlist       *content_list;
38    Eina_Inlist       *text_list;
39    Evas_Object       *content;
40    Evas_Object       *title_prev_btn;
41    Evas_Object       *title_next_btn;
42    const char        *style;
43    Eina_Bool          back_btn: 1;
44    Eina_Bool          title_visible: 1;
45 };
46
47 static const char *widtype = NULL;
48
49 static const char SIG_TRANSITION_FINISHED[] = "transition,finished";
50 static const char SIG_PUSH_FINISHED[] = "push,finished";
51 static const char SIG_POP_FINISHED[] = "pop,finished";
52 static const char SIG_TITLE_CLICKED[] = "title,clicked";
53
54 static const Evas_Smart_Cb_Description _signals[] = {
55        {SIG_TRANSITION_FINISHED, ""},
56        {SIG_TITLE_CLICKED, ""},
57        {NULL, NULL}
58 };
59
60 static void _del_hook(Evas_Object *obj);
61 static void _theme_hook(Evas_Object *obj);
62 static void _emit_hook(Evas_Object *obj,
63                        const char *emission,
64                        const char *source);
65 static void _disable_hook(Evas_Object *obj);
66 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
67 static void _item_text_set_hook(Elm_Object_Item *it,
68                                 const char *part,
69                                 const char *label);
70 static const char *_item_text_get_hook(const Elm_Object_Item *it,
71                                        const char *part);
72 static void _item_content_set_hook(Elm_Object_Item *it,
73                                    const char *part,
74                                    Evas_Object *content);
75 static Evas_Object *_item_content_get_hook(const Elm_Object_Item *it,
76                                            const char *part);
77 static Evas_Object *_item_content_unset_hook(Elm_Object_Item *it,
78                                              const char *part);
79 static void _item_signal_emit_hook(Elm_Object_Item *it,
80                                    const char *emission,
81                                    const char *source);
82 static void _item_title_visible_update(Elm_Naviframe_Item *navi_it);
83 static void _sizing_eval(Evas_Object *obj);
84 static void _item_sizing_eval(Elm_Naviframe_Item *it);
85 static void _move(void *data, Evas *e, Evas_Object *obj, void *event_info);
86 static void _resize(void *data,
87                     Evas *e,
88                     Evas_Object *obj,
89                     void *event_info);
90 static void _title_clicked(void *data, Evas_Object *obj,
91                            const char *emission,
92                            const char *source);
93 static void _back_btn_clicked(void *data,
94                               Evas_Object *obj,
95                               void *event_info);
96 static Evas_Object *_back_btn_new(Evas_Object *obj);
97 static void _item_content_del(void *data,
98                               Evas *e,
99                               Evas_Object *obj,
100                               void *event_info);
101 static void _title_content_del(void *data,
102                                Evas *e,
103                                Evas_Object *obj,
104                                void *event_info);
105 static void _title_prev_btn_del(void *data,
106                                 Evas *e,
107                                 Evas_Object *obj,
108                                 void *event_info);
109 static void _title_next_btn_del(void *data,
110                                 Evas *e,
111                                 Evas_Object *obj,
112                                 void *event_info);
113 static void _title_content_set(Elm_Naviframe_Item *it,
114                                Elm_Naviframe_Content_Item_Pair *pair,
115                                const char *part,
116                                Evas_Object *content);
117 static void _title_prev_btn_set(Elm_Naviframe_Item *it,
118                                 Evas_Object *btn,
119                                 Eina_Bool back_btn);
120 static void _title_next_btn_set(Elm_Naviframe_Item *it, Evas_Object *btn);
121 static void _item_del(Elm_Naviframe_Item *it);
122 static void _pushed_finished(void *data,
123                              Evas_Object *obj,
124                              const char *emission,
125                              const char *source);
126 static void _popped_finished(void *data,
127                              Evas_Object *obj,
128                              const char *emission,
129                              const char *source);
130 static void _show_finished(void *data,
131                            Evas_Object *obj,
132                            const char *emission,
133                            const char *source);
134 static void _item_content_set(Elm_Naviframe_Item *navi_it,
135                               Evas_Object *content);
136 static void _item_style_set(Elm_Naviframe_Item *navi_it,
137                             const char *item_style);
138
139 static void
140 _del_hook(Evas_Object *obj)
141 {
142    Widget_Data *wd;
143    Elm_Naviframe_Item *it;
144
145    wd = elm_widget_data_get(obj);
146    if (!wd) return;
147
148    if (wd->stack)
149      {
150         while (wd->stack->last)
151           {
152              it = EINA_INLIST_CONTAINER_GET(wd->stack->last,
153                                             Elm_Naviframe_Item);
154              wd->stack = eina_inlist_remove(wd->stack, wd->stack->last);
155              _item_del(it);
156              if (!wd->stack) break;
157           }
158      }
159    free(wd);
160 }
161
162 static void
163 _theme_hook(Evas_Object *obj)
164 {
165    Widget_Data *wd;
166    Elm_Naviframe_Item *it;
167
168    wd  = elm_widget_data_get(obj);
169    if (!wd) return;
170
171    _elm_theme_object_set(obj,
172                          wd->base,
173                          "naviframe",
174                          "base",
175                          elm_widget_style_get(obj));
176
177    EINA_INLIST_FOREACH(wd->stack, it)
178      {
179         _item_style_set(it, it->style);
180         _item_title_visible_update(it);
181      }
182
183    _elm_widget_mirrored_reload(obj);
184    _mirrored_set(obj, elm_widget_mirrored_get(obj));
185 }
186
187 static void _emit_hook(Evas_Object *obj,
188                        const char *emission,
189                        const char *source)
190 {
191    ELM_CHECK_WIDTYPE(obj, widtype);
192
193    Widget_Data *wd = elm_widget_data_get(obj);
194    if (!wd) return;
195
196    edje_object_signal_emit(wd->base, emission, source);
197 }
198
199 static void
200 _disable_hook(Evas_Object *obj __UNUSED__)
201 {
202    //FIXME:
203 }
204
205 static void
206 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
207 {
208    Widget_Data *wd;
209    Elm_Naviframe_Item *it;
210
211    wd  = elm_widget_data_get(obj);
212    if (!wd) return;
213
214    EINA_INLIST_FOREACH(wd->stack, it)
215      edje_object_mirrored_set(VIEW(it), rtl);
216    edje_object_mirrored_set(wd->base, rtl);
217 }
218
219 static void
220 _item_text_set_hook(Elm_Object_Item *it,
221                     const char *part,
222                     const char *label)
223 {
224    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
225
226    Elm_Naviframe_Text_Item_Pair *pair = NULL;
227    Elm_Naviframe_Item *navi_it = (Elm_Naviframe_Item *) it;
228    char buf[1024];
229
230    if (!part)
231      snprintf(buf, sizeof(buf), "elm.text.title");
232    else
233      snprintf(buf, sizeof(buf), "%s", part);
234
235    EINA_INLIST_FOREACH(navi_it->text_list, pair)
236      if (!strcmp(buf, pair->part)) break;
237
238    if (!pair)
239      {
240         pair = ELM_NEW(Elm_Naviframe_Text_Item_Pair);
241         if (!pair)
242           {
243              ERR("Failed to allocate new text part of the item! : naviframe=%p",
244              WIDGET(navi_it));
245              return;
246           }
247         eina_stringshare_replace(&pair->part, buf);
248         navi_it->text_list = eina_inlist_append(navi_it->text_list,
249                                                 EINA_INLIST_GET(pair));
250      }
251
252    eina_stringshare_replace(&pair->text, label);
253    edje_object_part_text_set(VIEW(navi_it), buf, label);
254
255    if (label)
256      {
257         snprintf(buf, sizeof(buf), "elm,state,%s,show", buf);
258         edje_object_signal_emit(VIEW(navi_it), buf, "elm");
259      }
260    else
261      {
262         snprintf(buf, sizeof(buf), "elm,state,%s,hide", buf);
263         edje_object_signal_emit(VIEW(navi_it), buf, "elm");
264      }
265
266    _item_sizing_eval(navi_it);
267 }
268
269 static const char *
270 _item_text_get_hook(const Elm_Object_Item *it, const char *part)
271 {
272    ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL);
273    Elm_Naviframe_Text_Item_Pair *pair = NULL;
274    Elm_Naviframe_Item *navi_it = (Elm_Naviframe_Item *) it;
275    char buf[1024];
276
277    if (!part)
278      snprintf(buf, sizeof(buf), "elm.text.title");
279    else
280      snprintf(buf, sizeof(buf), "%s", part);
281
282    EINA_INLIST_FOREACH(navi_it->text_list, pair)
283      {
284         if (!strcmp(buf, pair->part))
285           return pair->text;
286      }
287    return NULL;
288 }
289
290 static void
291 _item_content_set_hook(Elm_Object_Item *it,
292                        const char *part,
293                        Evas_Object *content)
294 {
295    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
296
297    Elm_Naviframe_Content_Item_Pair *pair = NULL;
298    Elm_Naviframe_Item *navi_it = (Elm_Naviframe_Item *) it;
299
300    //specified parts
301    if ((!part) || (!strcmp(part, "elm.swallow.content")))
302      {
303         _item_content_set(navi_it, content);
304         return;
305      }
306    else if (!strcmp(part, "elm.swallow.prev_btn"))
307      {
308         _title_prev_btn_set(navi_it, content, EINA_FALSE);
309         return;
310      }
311    else if(!strcmp(part, "elm.swallow.next_btn"))
312      {
313         _title_next_btn_set(navi_it, content);
314         return;
315      }
316
317    //common part
318    _title_content_set(navi_it, pair, part, content);
319 }
320
321 static Evas_Object *
322 _item_content_get_hook(const Elm_Object_Item *it, const char *part)
323 {
324    ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL);
325    Elm_Naviframe_Content_Item_Pair *pair = NULL;
326    Elm_Naviframe_Item *navi_it = (Elm_Naviframe_Item *) it;
327
328    //specified parts
329    if ((!part) || (!strcmp(part, "elm.swallow.content")))
330      return navi_it->content;
331    else if (!strcmp(part, "elm.swallow.prev_btn"))
332      return navi_it->title_prev_btn;
333    else if(!strcmp(part, "elm.swallow.next_btn"))
334      return navi_it->title_next_btn;
335
336    //common parts
337    EINA_INLIST_FOREACH(navi_it->content_list, pair)
338      {
339         if (!strcmp(part, pair->part))
340           return pair->content;
341      }
342    return NULL;
343 }
344
345 static Evas_Object *
346 _item_content_unset_hook(Elm_Object_Item *it, const char *part)
347 {
348    ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL);
349    Elm_Naviframe_Content_Item_Pair *pair = NULL;
350    Elm_Naviframe_Item *navi_it = (Elm_Naviframe_Item *) it;
351    Evas_Object *content = NULL;
352    char buf[1028];
353
354    //specified parts
355    //FIXME: could be unset the below specified contents also.
356    if (!part ||
357        !strcmp(part, "elm.swallow.content") ||
358        !strcmp(part, "elm.swallow.prev_btn") ||
359        !strcmp(part, "elm.swallow.next_btn"))
360      {
361         WRN("You can not unset the content! : naviframe=%p",
362             WIDGET(navi_it));
363         return NULL;
364      }
365
366    //common parts
367    EINA_INLIST_FOREACH(navi_it->content_list, pair)
368      {
369         if (!strcmp(part, pair->part))
370           {
371              content = pair->content;
372              eina_stringshare_del(pair->part);
373              navi_it->content_list = eina_inlist_remove(navi_it->content_list,
374                                                         EINA_INLIST_GET(pair));
375              free(pair);
376              break;
377           }
378      }
379
380    if (!content) return NULL;
381
382    elm_widget_sub_object_del(WIDGET(navi_it), content);
383    edje_object_part_unswallow(VIEW(navi_it), content);
384    snprintf(buf, sizeof(buf), "elm,state,%s,hide", part);
385    edje_object_signal_emit(VIEW(navi_it), buf, "elm");
386    evas_object_event_callback_del(content,
387                                   EVAS_CALLBACK_DEL,
388                                   _title_content_del);
389    _item_sizing_eval(navi_it);
390
391    return content;
392 }
393
394 static void
395 _item_signal_emit_hook(Elm_Object_Item *it,
396                        const char *emission,
397                        const char *source)
398 {
399    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
400    Elm_Naviframe_Item *navi_it = (Elm_Naviframe_Item *) it;
401    edje_object_signal_emit(VIEW(navi_it), emission, source);
402 }
403
404 static void
405 _item_title_visible_update(Elm_Naviframe_Item *navi_it)
406 {
407    if (navi_it->title_visible)
408      edje_object_signal_emit(VIEW(navi_it), "elm,state,title,show", "elm");
409    else
410      edje_object_signal_emit(VIEW(navi_it), "elm,state,title,hide", "elm");
411 }
412
413 static void
414 _sizing_eval(Evas_Object *obj)
415 {
416    Widget_Data *wd;
417    Elm_Naviframe_Item *it;
418    wd  = elm_widget_data_get(obj);
419    if (!wd) return;
420
421    EINA_INLIST_FOREACH(wd->stack, it)
422      _item_sizing_eval(it);
423 }
424
425 static void
426 _item_sizing_eval(Elm_Naviframe_Item *it)
427 {
428    Widget_Data *wd;
429    Evas_Coord x, y, w, h;
430    if (!it) return;
431
432    wd = elm_widget_data_get(WIDGET(it));
433    if (!wd) return;
434
435    evas_object_geometry_get(WIDGET(it), &x, &y, &w, &h);
436    evas_object_move(VIEW(it), x, y);
437    evas_object_resize(VIEW(it), w, h);
438 }
439
440 static void
441 _move(void *data __UNUSED__,
442       Evas *e __UNUSED__,
443       Evas_Object *obj,
444       void *event_info __UNUSED__)
445 {
446    _sizing_eval(obj);
447 }
448
449 static void
450 _resize(void *data __UNUSED__,
451         Evas *e __UNUSED__,
452         Evas_Object *obj,
453         void *event_info __UNUSED__)
454 {
455    _sizing_eval(obj);
456 }
457
458 static void
459 _title_clicked(void *data,
460                Evas_Object *obj __UNUSED__,
461                const char *emission __UNUSED__,
462                const char *source __UNUSED__)
463 {
464    Elm_Naviframe_Item *it = data;
465    evas_object_smart_callback_call(WIDGET(it), SIG_TITLE_CLICKED, it);
466 }
467
468 static void
469 _back_btn_clicked(void *data,
470                   Evas_Object *obj,
471                   void *event_info __UNUSED__)
472 {
473 /* Since edje has the event queue, clicked event could be happend multiple times
474    on some heavy environment. This callback del will prevent those  scenario and
475    guarantee only one clicked for it's own page. */
476    evas_object_smart_callback_del(obj, "clicked", _back_btn_clicked);
477    elm_naviframe_item_pop(data);
478 }
479
480 static Evas_Object *
481 _back_btn_new(Evas_Object *obj)
482 {
483    Evas_Object *btn;
484    char buf[1024];
485    btn = elm_button_add(obj);
486    if (!btn) return NULL;
487    evas_object_smart_callback_add(btn, "clicked", _back_btn_clicked, obj);
488    snprintf(buf, sizeof(buf), "naviframe/back_btn/%s", elm_widget_style_get(obj));
489    elm_object_style_set(btn, buf);
490    return btn;
491 }
492
493 static void
494 _title_content_del(void *data,
495                    Evas *e __UNUSED__,
496                    Evas_Object *obj __UNUSED__,
497                    void *event_info __UNUSED__)
498 {
499    char buf[1024];
500    Elm_Naviframe_Content_Item_Pair *pair = data;
501    Elm_Naviframe_Item *it = pair->it;
502    snprintf(buf, sizeof(buf), "elm,state,%s,hide", pair->part);
503    edje_object_signal_emit(VIEW(it), buf, "elm");
504    it->content_list = eina_inlist_remove(it->content_list,
505                                          EINA_INLIST_GET(pair));
506    eina_stringshare_del(pair->part);
507    free(pair);
508 }
509
510 static void
511 _title_prev_btn_del(void *data,
512                     Evas *e __UNUSED__,
513                     Evas_Object *obj __UNUSED__,
514                     void *event_info __UNUSED__)
515 {
516    Elm_Naviframe_Item *it = data;
517    it->back_btn = EINA_FALSE;
518    it->title_prev_btn = NULL;
519    edje_object_signal_emit(VIEW(it), "elm,state,prev_btn,hide", "elm");
520 }
521
522 static void
523 _title_next_btn_del(void *data,
524                     Evas *e __UNUSED__,
525                     Evas_Object *obj __UNUSED__,
526                     void *event_info __UNUSED__)
527 {
528    Elm_Naviframe_Item *it = data;
529    it->title_next_btn = NULL;
530    edje_object_signal_emit(VIEW(it), "elm,state,next_btn,hide", "elm");
531 }
532
533 static void
534 _item_content_del(void *data,
535                   Evas *e __UNUSED__,
536                   Evas_Object *obj __UNUSED__,
537                   void *event_info __UNUSED__)
538 {
539    Elm_Naviframe_Item *it = data;
540    it->content = NULL;
541    edje_object_signal_emit(VIEW(it), "elm,state,content,hide", "elm");
542 }
543
544 static void
545 _title_content_set(Elm_Naviframe_Item *it,
546                    Elm_Naviframe_Content_Item_Pair *pair,
547                    const char *part,
548                    Evas_Object *content)
549 {
550    char buf[1024];
551
552    EINA_INLIST_FOREACH(it->content_list, pair)
553      if (!strcmp(part, pair->part)) break;
554
555    if (!pair)
556      {
557         pair = ELM_NEW(Elm_Naviframe_Content_Item_Pair);
558         if (!pair)
559           {
560              ERR("Failed to allocate new content part of the item! : naviframe=%p", WIDGET(it));
561              return;
562           }
563         pair->it = it;
564         eina_stringshare_replace(&pair->part, part);
565         it->content_list = eina_inlist_append(it->content_list,
566                                               EINA_INLIST_GET(pair));
567      }
568
569    if (pair->content == content) return;
570
571    if (pair->content)
572      {
573         evas_object_event_callback_del(pair->content,
574                                        EVAS_CALLBACK_DEL,
575                                        _title_content_del);
576         evas_object_del(pair->content);
577      }
578    if (content)
579      {
580         elm_widget_sub_object_add(WIDGET(it), content);
581         evas_object_event_callback_add(content,
582                                        EVAS_CALLBACK_DEL,
583                                        _title_content_del,
584                                        pair);
585         edje_object_part_swallow(it->base.view, part, content);
586         snprintf(buf, sizeof(buf), "elm,state,%s,show", part);
587         edje_object_signal_emit(it->base.view, buf, "elm");
588         pair->content = content;
589         _item_sizing_eval(it);
590      }
591    else
592      {
593         snprintf(buf, sizeof(buf), "elm,state,%s,hide", part);
594         edje_object_signal_emit(it->base.view, buf, "elm");
595         pair->content = NULL;
596      }
597 }
598
599 static void
600 _title_prev_btn_set(Elm_Naviframe_Item *it,
601                     Evas_Object *btn,
602                     Eina_Bool back_btn)
603 {
604    if (it->title_prev_btn == btn) return;
605
606    if (it->title_prev_btn)
607      evas_object_del(it->title_prev_btn);
608
609    it->title_prev_btn = btn;
610
611    if (!btn)
612      {
613         edje_object_signal_emit(VIEW(it),
614                                 "elm,state,prev_btn,hide",
615                                 "elm");
616         return;
617      }
618
619    elm_widget_sub_object_add(WIDGET(it), btn);
620    evas_object_event_callback_add(btn,
621                                   EVAS_CALLBACK_DEL,
622                                   _title_prev_btn_del,
623                                   it);
624    edje_object_part_swallow(VIEW(it), "elm.swallow.prev_btn", btn);
625    edje_object_signal_emit(VIEW(it), "elm,state,prev_btn,show", "elm");
626    it->back_btn = back_btn;
627
628    _item_sizing_eval(it);
629 }
630
631 static void
632 _title_next_btn_set(Elm_Naviframe_Item *it, Evas_Object *btn)
633 {
634    if (it->title_next_btn == btn) return;
635
636    if (it->title_next_btn)
637      evas_object_del(it->title_next_btn);
638
639    it->title_next_btn = btn;
640
641    if (!btn)
642      {
643         edje_object_signal_emit(VIEW(it),
644                                 "elm,state,next_btn,hide",
645                                 "elm");
646         return;
647      }
648
649    elm_widget_sub_object_add(WIDGET(it), btn);
650    evas_object_event_callback_add(btn,
651                                   EVAS_CALLBACK_DEL,
652                                   _title_next_btn_del,
653                                   it);
654    edje_object_part_swallow(VIEW(it), "elm.swallow.next_btn", btn);
655    edje_object_signal_emit(VIEW(it), "elm,state,next_btn,show", "elm");
656
657    _item_sizing_eval(it);
658 }
659
660 static void
661 _item_del(Elm_Naviframe_Item *it)
662 {
663    Widget_Data *wd;
664    Elm_Naviframe_Content_Item_Pair *content_pair;
665    Elm_Naviframe_Text_Item_Pair *text_pair;
666
667    if (!it) return;
668
669    wd = elm_widget_data_get(WIDGET(it));
670    if (!wd) return;
671
672    if (it->title_prev_btn)
673      evas_object_del(it->title_prev_btn);
674    if (it->title_next_btn)
675      evas_object_del(it->title_next_btn);
676    if ((it->content) && (!wd->preserve))
677      evas_object_del(it->content);
678
679    while (it->content_list)
680      {
681         content_pair = EINA_INLIST_CONTAINER_GET(it->content_list,
682                                                  Elm_Naviframe_Content_Item_Pair);
683         evas_object_event_callback_del(content_pair->content,
684                                        EVAS_CALLBACK_DEL,
685                                        _title_content_del);
686         evas_object_del(content_pair->content);
687         eina_stringshare_del(content_pair->part);
688         it->content_list = eina_inlist_remove(it->content_list,
689                                               it->content_list);
690         free(content_pair);
691      }
692
693    while (it->text_list)
694      {
695         text_pair = EINA_INLIST_CONTAINER_GET(it->text_list,
696                                               Elm_Naviframe_Text_Item_Pair);
697         eina_stringshare_del(text_pair->part);
698         eina_stringshare_del(text_pair->text);
699         it->text_list = eina_inlist_remove(it->text_list,
700                                            it->text_list);
701         free(text_pair);
702      }
703
704    eina_stringshare_del(it->style);
705
706    elm_widget_item_del(it);
707 }
708
709 static void
710 _pushed_finished(void *data,
711                  Evas_Object *obj __UNUSED__,
712                  const char *emission __UNUSED__,
713                  const char *source __UNUSED__)
714 {
715    Widget_Data *wd;
716    Elm_Naviframe_Item *it = data;
717    if (!it) return;
718
719    wd = elm_widget_data_get(WIDGET(it));
720    if (!wd) return;
721
722    evas_object_hide(VIEW(it));
723    evas_object_smart_callback_call(WIDGET(it),
724                                    SIG_PUSH_FINISHED,
725                                    data);
726    if (wd->freeze_events)
727      evas_object_freeze_events_set(VIEW(it), EINA_FALSE);
728 }
729
730 static void
731 _popped_finished(void *data,
732                  Evas_Object *obj __UNUSED__,
733                  const char *emission __UNUSED__,
734                  const char *source __UNUSED__)
735 {
736    Elm_Naviframe_Item *it = data;
737    if (!it) return;
738    evas_object_smart_callback_call(WIDGET(it),
739                                    SIG_POP_FINISHED,
740                                    data);
741    _item_del(data);
742 }
743
744 static void
745 _show_finished(void *data,
746                Evas_Object *obj __UNUSED__,
747                const char *emission __UNUSED__,
748                const char *source __UNUSED__)
749 {
750    Elm_Naviframe_Item *it;
751    Widget_Data *wd;
752
753    it = data;
754    if (!it) return;
755    wd =  elm_widget_data_get(WIDGET(it));
756    if (!wd) return;
757
758    evas_object_smart_callback_call(WIDGET(it),
759                                    SIG_TRANSITION_FINISHED,
760                                    data);
761    if (wd->freeze_events)
762      evas_object_freeze_events_set(VIEW(it), EINA_FALSE);
763 }
764
765 static void
766 _item_content_set(Elm_Naviframe_Item *navi_it, Evas_Object *content)
767 {
768    if (navi_it->content == content) return;
769    if (navi_it->content) evas_object_del(navi_it->content);
770    elm_widget_sub_object_add(WIDGET(navi_it), content);
771    edje_object_part_swallow(VIEW(navi_it),
772                             "elm.swallow.content",
773                             content);
774    if (content)
775      edje_object_signal_emit(VIEW(navi_it),
776                              "elm,state,content,show",
777                              "elm");
778    else
779      edje_object_signal_emit(VIEW(navi_it),
780                              "elm,state,content,hide",
781                              "elm");
782    evas_object_event_callback_add(content,
783                                   EVAS_CALLBACK_DEL,
784                                   _item_content_del,
785                                   navi_it);
786    navi_it->content = content;
787    _item_sizing_eval(navi_it);
788 }
789
790 //FIXME: need to handle if this function is called while transition
791 static void
792 _item_style_set(Elm_Naviframe_Item *navi_it, const char *item_style)
793 {
794    Elm_Naviframe_Content_Item_Pair *content_pair;
795    Elm_Naviframe_Text_Item_Pair *text_pair;
796    Widget_Data *wd;
797
798    char buf[256];
799
800    if (!item_style)
801      {
802         sprintf(buf, "item/basic");
803         eina_stringshare_replace(&navi_it->style, "basic");
804      }
805    else
806      {
807         if (strlen(item_style) > sizeof(buf))
808           WRN("too much long style name! : naviframe=%p", WIDGET(navi_it));
809         sprintf(buf, "item/%s", item_style);
810         eina_stringshare_replace(&navi_it->style, item_style);
811      }
812    _elm_theme_object_set(WIDGET(navi_it),
813                          VIEW(navi_it),
814                          "naviframe",
815                          buf,
816                          elm_widget_style_get(WIDGET(navi_it)));
817    //recover item
818    EINA_INLIST_FOREACH(navi_it->text_list, text_pair)
819       _item_text_set_hook((Elm_Object_Item *) navi_it,
820                           text_pair->part,
821                           text_pair->text);
822
823    EINA_INLIST_FOREACH(navi_it->content_list, content_pair)
824       _item_content_set_hook((Elm_Object_Item *) navi_it,
825                              content_pair->part,
826                              content_pair->content);
827
828    //content
829    if (navi_it->content)
830      {
831         edje_object_part_swallow(VIEW(navi_it),
832                                  "elm.swallow.content",
833                                  navi_it->content);
834         edje_object_signal_emit(VIEW(navi_it),
835                                 "elm,state,content,show",
836                                 "elm");
837      }
838
839    //prev button
840    if (navi_it->title_prev_btn)
841      {
842         edje_object_part_swallow(VIEW(navi_it),
843                                  "elm.swallow.prev_btn",
844                                  navi_it->title_prev_btn);
845         edje_object_signal_emit(VIEW(navi_it),
846                                 "elm,state,prev_btn,show",
847                                 "elm");
848      }
849
850    //next button
851    if (navi_it->title_next_btn)
852      {
853         edje_object_part_swallow(VIEW(navi_it),
854                                  "elm.swallow.next_btn",
855                                  navi_it->title_next_btn);
856         edje_object_signal_emit(VIEW(navi_it),
857                                 "elm,state,next_btn,show",
858                                 "elm");
859      }
860
861    navi_it->title_visible = EINA_TRUE;
862    _item_sizing_eval(navi_it);
863
864    wd = elm_widget_data_get(WIDGET(navi_it));
865    if (!wd) return;
866
867    if (wd->freeze_events)
868      evas_object_freeze_events_set(VIEW(navi_it), EINA_FALSE);
869 }
870
871 EAPI Evas_Object *
872 elm_naviframe_add(Evas_Object *parent)
873 {
874    Evas_Object *obj;
875    Evas *e;
876    Widget_Data *wd;
877
878    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
879    ELM_SET_WIDTYPE(widtype, "naviframe");
880    elm_widget_type_set(obj, "naviframe");
881    elm_widget_sub_object_add(parent, obj);
882    elm_widget_data_set(obj, wd);
883    elm_widget_del_hook_set(obj, _del_hook);
884    elm_widget_disable_hook_set(obj, _disable_hook);
885    elm_widget_theme_hook_set(obj, _theme_hook);
886    elm_widget_signal_emit_hook_set(obj, _emit_hook);
887
888    //base
889    wd->base = edje_object_add(e);
890    edje_object_mirrored_set(wd->base, elm_widget_mirrored_get(obj));
891    elm_widget_resize_object_set(obj, wd->base);
892    _elm_theme_object_set(obj, wd->base, "naviframe", "base", "default");
893
894    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _move, obj);
895    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize, obj);
896    evas_object_smart_callbacks_descriptions_set(obj, _signals);
897
898    wd->auto_pushed = EINA_TRUE;
899    wd->freeze_events = EINA_TRUE;
900
901    return obj;
902 }
903
904 EAPI Elm_Object_Item *
905 elm_naviframe_item_push(Evas_Object *obj,
906                         const char *title_label,
907                         Evas_Object *prev_btn,
908                         Evas_Object *next_btn,
909                         Evas_Object *content,
910                         const char *item_style)
911 {
912    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
913    Widget_Data *wd;
914    Elm_Naviframe_Item *prev_it, *it;
915
916    wd = elm_widget_data_get(obj);
917    if (!wd) return NULL;
918
919    //create item
920    it = elm_widget_item_new(obj, Elm_Naviframe_Item);
921    if (!it)
922      {
923         ERR("Failed to allocate new item! : naviframe=%p", obj);
924         return NULL;
925      }
926
927    elm_widget_item_text_set_hook_set(it, _item_text_set_hook);
928    elm_widget_item_text_get_hook_set(it, _item_text_get_hook);
929    elm_widget_item_content_set_hook_set(it, _item_content_set_hook);
930    elm_widget_item_content_get_hook_set(it, _item_content_get_hook);
931    elm_widget_item_content_unset_hook_set(it, _item_content_unset_hook);
932    elm_widget_item_signal_emit_hook_set(it, _item_signal_emit_hook);
933
934    //item base layout
935    VIEW(it) = edje_object_add(evas_object_evas_get(obj));
936    edje_object_mirrored_set(VIEW(it), elm_widget_mirrored_get(obj));
937    evas_object_smart_member_add(VIEW(it), wd->base);
938    elm_widget_sub_object_add(obj, VIEW(it));
939    edje_object_signal_callback_add(VIEW(it),
940                                    "elm,action,show,finished",
941                                    "",
942                                    _show_finished, it);
943    edje_object_signal_callback_add(VIEW(it),
944                                    "elm,action,pushed,finished",
945                                    "",
946                                    _pushed_finished, it);
947    edje_object_signal_callback_add(VIEW(it),
948                                    "elm,action,popped,finished",
949                                    "",
950                                    _popped_finished, it);
951    edje_object_signal_callback_add(VIEW(it),
952                                    "elm,action,title,clicked",
953                                    "",
954                                    _title_clicked, it);
955
956    _item_style_set(it, item_style);
957
958    _item_text_set_hook((Elm_Object_Item *) it, "elm.text.title", title_label);
959
960    //title buttons
961    if ((!prev_btn) && wd->auto_pushed && eina_inlist_count(wd->stack))
962      {
963         prev_btn = _back_btn_new(obj);
964         _title_prev_btn_set(it, prev_btn, EINA_TRUE);
965      }
966    else
967      _title_prev_btn_set(it, prev_btn, EINA_FALSE);
968
969    _title_next_btn_set(it, next_btn);
970
971    _item_content_set(it, content);
972
973    _item_sizing_eval(it);
974    evas_object_show(VIEW(it));
975
976    prev_it = (Elm_Naviframe_Item *) elm_naviframe_top_item_get(obj);
977    if (prev_it)
978      {
979         if (wd->freeze_events)
980           {
981              evas_object_freeze_events_set(VIEW(it), EINA_TRUE);
982              evas_object_freeze_events_set(VIEW(prev_it), EINA_TRUE);
983           }
984         edje_object_signal_emit(VIEW(prev_it),
985                                 "elm,state,cur,pushed",
986                                 "elm");
987         edje_object_signal_emit(VIEW(it),
988                                 "elm,state,new,pushed",
989                                 "elm");
990      }
991    it->title_visible = EINA_TRUE;
992    wd->stack = eina_inlist_append(wd->stack, EINA_INLIST_GET(it));
993    return (Elm_Object_Item *) it;
994 }
995
996 EAPI Evas_Object *
997 elm_naviframe_item_pop(Evas_Object *obj)
998 {
999    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1000    Elm_Naviframe_Item *it, *prev_it = NULL;
1001    Widget_Data *wd;
1002    Evas_Object *content = NULL;
1003
1004    wd = elm_widget_data_get(obj);
1005    if (!wd) return NULL;
1006
1007    it = (Elm_Naviframe_Item *) elm_naviframe_top_item_get(obj);
1008    if (!it) return NULL;
1009    elm_widget_tree_unfocusable_set(it->content, EINA_TRUE);
1010    if (wd->preserve)
1011      content = it->content;
1012
1013    if (wd->stack->last->prev)
1014      prev_it = EINA_INLIST_CONTAINER_GET(wd->stack->last->prev,
1015                                          Elm_Naviframe_Item);
1016    wd->stack = eina_inlist_remove(wd->stack, EINA_INLIST_GET(it));
1017    if (prev_it)
1018      {
1019         edje_object_signal_emit(VIEW(it), "elm,state,cur,popped", "elm");
1020         evas_object_show(VIEW(prev_it));
1021         evas_object_raise(VIEW(prev_it));
1022         edje_object_signal_emit(VIEW(prev_it),
1023                                 "elm,state,prev,popped",
1024                                 "elm");
1025      }
1026    else
1027      _item_del(it);
1028
1029    return content;
1030 }
1031
1032 EAPI void
1033 elm_naviframe_item_pop_to(Elm_Object_Item *it)
1034 {
1035    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
1036    Elm_Naviframe_Item *navi_it;
1037    Widget_Data *wd;
1038    Eina_Inlist *l, *prev_l;
1039
1040    navi_it = (Elm_Naviframe_Item *) it;
1041    wd = elm_widget_data_get(WIDGET(navi_it));
1042    if (!wd) return;
1043
1044    if (it == elm_naviframe_top_item_get(WIDGET(navi_it))) return;
1045
1046    l = wd->stack->last->prev;
1047
1048    while(l)
1049      {
1050         if (EINA_INLIST_CONTAINER_GET(l, Elm_Naviframe_Item) ==
1051             ((Elm_Naviframe_Item *) it)) break;
1052         prev_l = l->prev;
1053         wd->stack = eina_inlist_remove(wd->stack, l);
1054         _item_del(EINA_INLIST_CONTAINER_GET(l, Elm_Naviframe_Item));
1055         l = prev_l;
1056      }
1057    elm_naviframe_item_pop(WIDGET(navi_it));
1058 }
1059
1060 EAPI void
1061 elm_naviframe_item_promote(Elm_Object_Item *it)
1062 {
1063    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
1064    Elm_Naviframe_Item *navi_it;
1065    Elm_Naviframe_Item *prev_it;
1066    Widget_Data *wd;
1067
1068    navi_it = (Elm_Naviframe_Item *) it;
1069    wd = elm_widget_data_get(navi_it->base.widget);
1070    if (!wd) return;
1071
1072    if (it == elm_naviframe_top_item_get(navi_it->base.widget)) return;
1073    wd->stack = eina_inlist_demote(wd->stack, EINA_INLIST_GET(navi_it));
1074    prev_it = EINA_INLIST_CONTAINER_GET(wd->stack->last->prev,
1075                                          Elm_Naviframe_Item);
1076    if (wd->freeze_events)
1077      {
1078         evas_object_freeze_events_set(VIEW(it), EINA_TRUE);
1079         evas_object_freeze_events_set(VIEW(prev_it), EINA_TRUE);
1080      }
1081    edje_object_signal_emit(prev_it->base.view,
1082                            "elm,state,cur,pushed",
1083                            "elm");
1084    evas_object_show(navi_it->base.view);
1085    evas_object_raise(navi_it->base.view);
1086    edje_object_signal_emit(navi_it->base.view,
1087                            "elm,state,new,pushed",
1088                            "elm");
1089
1090 }
1091
1092 EAPI void
1093 elm_naviframe_item_del(Elm_Object_Item *it)
1094 {
1095    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
1096    Elm_Naviframe_Item *navi_it;
1097    Widget_Data *wd;
1098
1099    navi_it =(Elm_Naviframe_Item *) it;
1100    wd = elm_widget_data_get(WIDGET(navi_it));
1101    if (!wd) return;
1102
1103    if (it == elm_naviframe_top_item_get(WIDGET(navi_it)))
1104      {
1105         wd->stack = eina_inlist_remove(wd->stack, EINA_INLIST_GET(navi_it));
1106         _item_del(navi_it);
1107         navi_it = EINA_INLIST_CONTAINER_GET(wd->stack->last,
1108                                             Elm_Naviframe_Item);
1109         evas_object_show(VIEW(navi_it));
1110         evas_object_raise(VIEW(navi_it));
1111         edje_object_signal_emit(VIEW(navi_it), "elm,state,visible", "elm");
1112      }
1113    else
1114      {
1115         wd->stack = eina_inlist_remove(wd->stack, EINA_INLIST_GET(navi_it));
1116         _item_del(navi_it);
1117      }
1118 }
1119
1120 EAPI void
1121 elm_naviframe_content_preserve_on_pop_set(Evas_Object *obj, Eina_Bool preserve)
1122 {
1123    ELM_CHECK_WIDTYPE(obj, widtype);
1124    Widget_Data *wd = elm_widget_data_get(obj);
1125    if (!wd) return;
1126    wd->preserve = !!preserve;
1127 }
1128
1129 EAPI Eina_Bool
1130 elm_naviframe_content_preserve_on_pop_get(const Evas_Object *obj)
1131 {
1132    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1133    Widget_Data *wd = elm_widget_data_get(obj);
1134    if (!wd) return EINA_FALSE;
1135    return wd->preserve;
1136 }
1137
1138 EAPI Elm_Object_Item*
1139 elm_naviframe_top_item_get(const Evas_Object *obj)
1140 {
1141    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1142    Widget_Data *wd = elm_widget_data_get(obj);
1143    if ((!wd) || (!wd->stack)) return NULL;
1144    return (Elm_Object_Item *) (EINA_INLIST_CONTAINER_GET(wd->stack->last,
1145                                                          Elm_Naviframe_Item));
1146 }
1147
1148 EAPI Elm_Object_Item*
1149 elm_naviframe_bottom_item_get(const Evas_Object *obj)
1150 {
1151    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1152    Widget_Data *wd = elm_widget_data_get(obj);
1153    if ((!wd) || (!wd->stack)) return NULL;
1154    return (Elm_Object_Item *) (EINA_INLIST_CONTAINER_GET(wd->stack,
1155                                                          Elm_Naviframe_Item));
1156 }
1157
1158 EAPI void
1159 elm_naviframe_item_style_set(Elm_Object_Item *it, const char *item_style)
1160 {
1161    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
1162    Elm_Naviframe_Item *navi_it = (Elm_Naviframe_Item *) it;
1163
1164    //Return if new style is exsiting one.
1165    if (item_style)
1166      if (!strcmp(item_style, navi_it->style)) return;
1167
1168    if (!item_style)
1169      if (!strcmp("basic", navi_it->style)) return;
1170
1171    _item_style_set(navi_it, item_style);
1172 }
1173
1174 EAPI const char *
1175 elm_naviframe_item_style_get(const Elm_Object_Item *it)
1176 {
1177    ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL);
1178    Elm_Naviframe_Item *navi_it = (Elm_Naviframe_Item *) it;
1179    return navi_it->style;
1180 }
1181
1182 EAPI void
1183 elm_naviframe_item_title_visible_set(Elm_Object_Item *it, Eina_Bool visible)
1184 {
1185    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
1186    Elm_Naviframe_Item *navi_it = (Elm_Naviframe_Item *) it;
1187
1188    visible = !!visible;
1189    if (navi_it->title_visible == visible) return;
1190
1191    navi_it->title_visible = visible;
1192    _item_title_visible_update(navi_it);
1193 }
1194
1195 EAPI Eina_Bool
1196 elm_naviframe_item_title_visible_get(const Elm_Object_Item *it)
1197 {
1198    ELM_OBJ_ITEM_CHECK_OR_RETURN(it, EINA_FALSE);
1199    Elm_Naviframe_Item *navi_it = (Elm_Naviframe_Item *) it;
1200    return navi_it->title_visible;
1201 }
1202
1203 EAPI void
1204 elm_naviframe_prev_btn_auto_pushed_set(Evas_Object *obj, Eina_Bool auto_pushed)
1205 {
1206    ELM_CHECK_WIDTYPE(obj, widtype);
1207    Widget_Data *wd = elm_widget_data_get(obj);
1208    if (!wd) return;
1209    wd->auto_pushed = !!auto_pushed;
1210 }
1211
1212 EAPI Eina_Bool
1213 elm_naviframe_prev_btn_auto_pushed_get(const Evas_Object *obj)
1214 {
1215    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1216    Widget_Data *wd = elm_widget_data_get(obj);
1217    if (!wd) return EINA_FALSE;
1218    return wd->auto_pushed;
1219 }
1220