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