naviframe - support escape key event
[framework/uifw/elementary.git] / src / lib / elc_naviframe.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_widget_naviframe.h"
4
5 EAPI const char ELM_NAVIFRAME_SMART_NAME[] = "elm_naviframe";
6
7 static const char CONTENT_PART[] = "elm.swallow.content";
8 static const char PREV_BTN_PART[] = "elm.swallow.prev_btn";
9 static const char NEXT_BTN_PART[] = "elm.swallow.next_btn";
10 static const char ICON_PART[] = "elm.swallow.icon";
11 static const char TITLE_PART[] = "elm.text.title";
12 static const char SUBTITLE_PART[] = "elm.text.subtitle";
13 static const char TITLE_ACCESS_PART[] = "access.title";
14
15 static const char SIG_TRANSITION_FINISHED[] = "transition,finished";
16 static const char SIG_TITLE_CLICKED[] = "title,clicked";
17 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
18    {SIG_TRANSITION_FINISHED, ""},
19    {SIG_TITLE_CLICKED, ""},
20    {NULL, NULL}
21 };
22
23 EVAS_SMART_SUBCLASS_NEW
24   (ELM_NAVIFRAME_SMART_NAME, _elm_naviframe, Elm_Naviframe_Smart_Class,
25   Elm_Layout_Smart_Class, elm_layout_smart_class_get, _smart_callbacks);
26
27 static const char SIG_CLICKED[] = "clicked";
28
29 static void
30 _item_content_del_cb(void *data,
31                      Evas *e __UNUSED__,
32                      Evas_Object *obj __UNUSED__,
33                      void *event_info __UNUSED__)
34 {
35    Elm_Naviframe_Item *it = data;
36
37    it->content = NULL;
38    elm_object_signal_emit(VIEW(it), "elm,state,content,hide", "elm");
39 }
40
41 static void
42 _item_title_prev_btn_del_cb(void *data,
43                             Evas *e __UNUSED__,
44                             Evas_Object *obj __UNUSED__,
45                             void *event_info __UNUSED__)
46 {
47    Elm_Naviframe_Item *it = data;
48
49    it->title_prev_btn = NULL;
50    elm_object_signal_emit(VIEW(it), "elm,state,prev_btn,hide", "elm");
51 }
52
53 static void
54 _item_title_next_btn_del_cb(void *data,
55                             Evas *e __UNUSED__,
56                             Evas_Object *obj __UNUSED__,
57                             void *event_info __UNUSED__)
58 {
59    Elm_Naviframe_Item *it = data;
60
61    it->title_next_btn = NULL;
62    elm_object_signal_emit(VIEW(it), "elm,state,next_btn,hide", "elm");
63 }
64
65 static void
66 _item_title_icon_del_cb(void *data,
67                         Evas *e __UNUSED__,
68                         Evas_Object *obj __UNUSED__,
69                         void *event_info __UNUSED__)
70 {
71    Elm_Naviframe_Item *it = data;
72
73    it->title_icon = NULL;
74    elm_object_signal_emit(VIEW(it), "elm,state,icon,hide", "elm");
75 }
76
77 static void
78 _title_content_del(void *data,
79                    Evas *e __UNUSED__,
80                    Evas_Object *obj __UNUSED__,
81                    void *event_info __UNUSED__)
82 {
83    char buf[1024];
84    Elm_Naviframe_Content_Item_Pair *pair = data;
85    Elm_Naviframe_Item *it = pair->it;
86    snprintf(buf, sizeof(buf), "elm,state,%s,hide", pair->part);
87    elm_object_signal_emit(VIEW(it), buf, "elm");
88    it->content_list = eina_inlist_remove(it->content_list,
89                                          EINA_INLIST_GET(pair));
90    eina_stringshare_del(pair->part);
91    free(pair);
92 }
93
94 static void
95 _item_free(Elm_Naviframe_Item *it)
96 {
97    Eina_Inlist *l;
98    Elm_Naviframe_Content_Item_Pair *content_pair;
99    Elm_Naviframe_Text_Item_Pair *text_pair;
100
101    ELM_NAVIFRAME_DATA_GET(WIDGET(it), sd);
102
103    eina_stringshare_del(it->style);
104    eina_stringshare_del(it->title_label);
105    eina_stringshare_del(it->subtitle_label);
106
107    EINA_INLIST_FOREACH_SAFE(it->content_list, l, content_pair)
108      {
109         if (content_pair->content)
110           {
111              evas_object_event_callback_del(content_pair->content,
112                                             EVAS_CALLBACK_DEL,
113                                             _title_content_del);
114              evas_object_del(content_pair->content);
115           }
116         eina_stringshare_del(content_pair->part);
117         free(content_pair);
118      }
119    EINA_INLIST_FOREACH_SAFE(it->text_list, l, text_pair)
120      {
121         eina_stringshare_del(text_pair->part);
122         free(text_pair);
123      }
124
125    if (it->content)
126      {
127         if ((sd->preserve) && (!sd->on_deletion))
128           {
129              /* so that elm does not delete the contents with the item's
130               * view after the del_pre_hook */
131              elm_object_part_content_unset(VIEW(it), CONTENT_PART);
132              evas_object_event_callback_del
133                 (it->content, EVAS_CALLBACK_DEL, _item_content_del_cb);
134           }
135      }
136 }
137
138 static void
139 _item_content_signals_emit(Elm_Naviframe_Item *it)
140 {
141    Elm_Naviframe_Content_Item_Pair *content_pair;
142    char buf[1024];
143    //content
144    if (it->content)
145      elm_object_signal_emit(VIEW(it), "elm,state,content,show", "elm");
146    else
147      elm_object_signal_emit(VIEW(it), "elm,state,content,hide", "elm");
148
149    //prev button
150    if (it->title_prev_btn)
151      elm_object_signal_emit(VIEW(it), "elm,state,prev_btn,show", "elm");
152    else
153      elm_object_signal_emit(VIEW(it), "elm,state,prev_btn,hide", "elm");
154
155    //next button
156    if (it->title_next_btn)
157      elm_object_signal_emit(VIEW(it), "elm,state,next_btn,show", "elm");
158    else
159      elm_object_signal_emit(VIEW(it), "elm,state,next_btn,hide", "elm");
160
161    if (it->title_icon)
162      elm_object_signal_emit(VIEW(it), "elm,state,icon,show", "elm");
163    else
164      elm_object_signal_emit(VIEW(it), "elm,state,icon,hide", "elm");
165
166    EINA_INLIST_FOREACH(it->content_list, content_pair)
167      {
168         if (content_pair->content)
169           snprintf(buf, sizeof(buf), "elm,state,%s,show", content_pair->part);
170         else
171           snprintf(buf, sizeof(buf), "elm,state,%s,hide", content_pair->part);
172         elm_object_signal_emit(VIEW(it), buf, "elm");
173      }
174 }
175
176 static void
177 _item_text_signals_emit(Elm_Naviframe_Item *it)
178 {
179    Elm_Naviframe_Text_Item_Pair *text_pair;
180    char buf[1024];
181
182    if ((it->title_label) && (it->title_label[0]))
183      elm_object_signal_emit(VIEW(it), "elm,state,title_label,show", "elm");
184    else
185      elm_object_signal_emit(VIEW(it), "elm,state,title_label,hide", "elm");
186
187    if ((it->subtitle_label) && (it->subtitle_label[0]))
188      elm_object_signal_emit(VIEW(it), "elm,state,subtitle,show", "elm");
189    else
190      elm_object_signal_emit(VIEW(it), "elm,state,subtitle,hide", "elm");
191
192    EINA_INLIST_FOREACH(it->text_list, text_pair)
193      {
194         if (elm_object_part_text_get(VIEW(it), text_pair->part))
195           snprintf(buf, sizeof(buf), "elm,state,%s,show", text_pair->part);
196         else
197           snprintf(buf, sizeof(buf), "elm,state,%s,hide", text_pair->part);
198         elm_object_signal_emit(VIEW(it), buf, "elm");
199      }
200 }
201
202 static Evas_Object *
203 _access_object_get(Elm_Naviframe_Item *it, const char* part)
204 {
205    Evas_Object *po, *ao;
206
207    po = (Evas_Object *)edje_object_part_object_get
208           (elm_layout_edje_get(VIEW(it)), part);
209    ao = evas_object_data_get(po, "_part_access_obj");
210
211    return ao;
212 }
213
214 static void
215 _access_focus_set(Elm_Naviframe_Item *it)
216 {
217    Evas_Object *ao;
218
219    if (!it->title_visible)
220      {
221         elm_object_focus_set(it->content, EINA_TRUE);
222         return;
223      }
224
225    ao =_access_object_get(it, TITLE_ACCESS_PART);
226    if (ao) elm_object_focus_set(ao, EINA_TRUE);
227    else if ((it->title_icon) &&
228             (elm_widget_can_focus_get(it->title_icon) ||
229              elm_widget_child_can_focus_get(it->title_icon)))
230      elm_object_focus_set(it->title_icon, EINA_TRUE);
231 }
232
233 static void
234 _item_signals_emit(Elm_Naviframe_Item *it)
235 {
236    _item_text_signals_emit(it);
237    _item_content_signals_emit(it);
238 }
239
240 /* FIXME: we need to handle the case when this function is called
241  * during a transition */
242 static void
243 _item_style_set(Elm_Naviframe_Item *it,
244                 const char *item_style)
245 {
246    char buf[256];
247
248    ELM_NAVIFRAME_DATA_GET(WIDGET(it), sd);
249
250    if (!item_style)
251      {
252         strcpy(buf, "item/basic");
253         eina_stringshare_replace(&it->style, "basic");
254      }
255    else
256      {
257         snprintf(buf, sizeof(buf), "item/%s", item_style);
258         eina_stringshare_replace(&it->style, item_style);
259      }
260
261    elm_layout_theme_set(VIEW(it), "naviframe", buf,
262                         elm_widget_style_get(WIDGET(it)));
263
264    if (sd->freeze_events)
265      evas_object_freeze_events_set(VIEW(it), EINA_FALSE);
266 }
267
268 static void
269 _item_title_visible_update(Elm_Naviframe_Item *nit)
270 {
271    /* access */
272    if (_elm_config->access_mode) _access_focus_set(nit);
273
274    if (nit->title_visible)
275      elm_object_signal_emit(VIEW(nit), "elm,state,title,show", "elm");
276    else
277      elm_object_signal_emit(VIEW(nit), "elm,state,title,hide", "elm");
278 }
279
280 static Eina_Bool
281 _elm_naviframe_smart_theme(Evas_Object *obj)
282 {
283    Elm_Naviframe_Item *it;
284    const char *style, *sstyle;
285
286    ELM_NAVIFRAME_DATA_GET(obj, sd);
287
288    style = elm_widget_style_get(obj);
289
290    EINA_INLIST_FOREACH(sd->stack, it)
291      {
292         /* FIXME: Need to merge with opensource later. smart_theme() is called
293            multiple timese since the elm_widget.c is inefficient. If the
294            elm_widget is merged with the latest opensouce, it's ok to sync with
295            opensource here also */
296         sstyle = elm_widget_style_get(VIEW(it));
297         if ((style && sstyle) && strcmp(style, sstyle))
298           {
299              _item_style_set(it, it->style);
300              _item_signals_emit(it);
301              _item_title_visible_update(it);
302           }
303      }
304
305    elm_layout_sizing_eval(obj);
306
307    return EINA_TRUE;
308 }
309
310 static char *
311 _access_info_cb(void *data, Evas_Object *obj __UNUSED__)
312 {
313    Evas_Object *layout;
314    Eina_Strbuf *buf;
315    const char *info;
316    char *ret;
317
318    layout = (Evas_Object *)data;
319    info = elm_object_part_text_get(layout, TITLE_PART);
320    if (!info) return NULL;
321
322    buf = eina_strbuf_new();
323    eina_strbuf_append(buf, info);
324
325    info = elm_object_part_text_get(layout, SUBTITLE_PART);
326    if (!info) goto end;
327
328    eina_strbuf_append_printf(buf, ", %s", info);
329
330 end:
331    ret = eina_strbuf_string_steal(buf);
332    eina_strbuf_free(buf);
333    return ret;
334 }
335
336 static void
337 _access_obj_process(Elm_Naviframe_Item *it, Eina_Bool is_access)
338 {
339    Evas_Object *ao, *eo;
340
341    if (is_access)
342      {
343         if (!_access_object_get(it, TITLE_ACCESS_PART))
344           {
345              eo = elm_layout_edje_get(VIEW(it));
346              ao =_elm_access_edje_object_part_object_register(WIDGET(it), eo,
347                                                               TITLE_ACCESS_PART);
348             _elm_access_text_set(_elm_access_object_get(ao),
349                                 ELM_ACCESS_TYPE, E_("title"));
350             _elm_access_callback_set(_elm_access_object_get(ao),
351                                      ELM_ACCESS_INFO, _access_info_cb, VIEW(it));
352
353             /* to access title access object, any idea? */
354             ((Elm_Widget_Item *)it)->access_obj = ao;
355          }
356      }
357    else
358      {
359         if (it->title_label)
360           _elm_access_edje_object_part_object_unregister
361                 (WIDGET(it), elm_layout_edje_get(VIEW(it)), TITLE_ACCESS_PART);
362
363         /* to access title access object, any idea? */
364         ao = ((Elm_Widget_Item *)it)->access_obj;
365         if (!ao) return;
366         evas_object_del(ao);
367      }
368 }
369
370 static void
371 _item_text_set_hook(Elm_Object_Item *it,
372                     const char *part,
373                     const char *label)
374 {
375    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
376    Elm_Naviframe_Text_Item_Pair *pair = NULL;
377    char buf[1024];
378
379    if ((!part) || (!strcmp(part, "default")) ||
380        (!strcmp(part, TITLE_PART)))
381      {
382         eina_stringshare_replace(&nit->title_label, label);
383         if (label)
384           elm_object_signal_emit(VIEW(it), "elm,state,title_label,show", "elm");
385         else
386           elm_object_signal_emit(VIEW(it), "elm,state,title_label,hide", "elm");
387         elm_object_part_text_set(VIEW(it), TITLE_PART, label);
388      }
389    else if (!strcmp("subtitle", part))
390      {
391         eina_stringshare_replace(&nit->subtitle_label, label);
392         if (label)
393           elm_object_signal_emit(VIEW(it), "elm,state,subtitle,show", "elm");
394         else
395           elm_object_signal_emit(VIEW(it), "elm,state,subtitle,hide", "elm");
396         elm_object_part_text_set(VIEW(it), SUBTITLE_PART, label);
397      }
398    else
399      {
400         EINA_INLIST_FOREACH(nit->text_list, pair)
401           if (!strcmp(part, pair->part)) break;
402
403         if (!pair)
404           {
405              pair = ELM_NEW(Elm_Naviframe_Text_Item_Pair);
406              if (!pair)
407                {
408                   ERR("Failed to allocate new text part of the item! : naviframe=%p",
409                   WIDGET(it));
410                   return;
411                }
412              eina_stringshare_replace(&pair->part, part);
413              nit->text_list = eina_inlist_append(nit->text_list,
414                                                  EINA_INLIST_GET(pair));
415           }
416         if (label)
417           snprintf(buf, sizeof(buf), "elm,state,%s,show", part);
418         else
419           snprintf(buf, sizeof(buf), "elm,state,%s,hide", part);
420         elm_object_signal_emit(VIEW(it), buf, "elm");
421         elm_object_part_text_set(VIEW(it), part, label);
422      }
423
424    /* access */
425    if (_elm_config->access_mode)
426      _access_obj_process(nit, EINA_TRUE);
427
428    elm_layout_sizing_eval(WIDGET(nit));
429 }
430
431 static const char *
432 _item_text_get_hook(const Elm_Object_Item *it,
433                     const char *part)
434 {
435    char buf[1024];
436
437    if (!part || !strcmp(part, "default"))
438      snprintf(buf, sizeof(buf), TITLE_PART);
439    else if (!strcmp("subtitle", part))
440      snprintf(buf, sizeof(buf), SUBTITLE_PART);
441    else
442      snprintf(buf, sizeof(buf), "%s", part);
443
444    return elm_object_part_text_get(VIEW(it), buf);
445 }
446
447 static Eina_Bool
448 _item_del_pre_hook(Elm_Object_Item *it)
449 {
450    Elm_Naviframe_Item *nit, *prev_it = NULL;
451    Eina_Bool top;
452
453    nit = (Elm_Naviframe_Item *)it;
454    ELM_NAVIFRAME_DATA_GET(WIDGET(nit), sd);
455
456    if (nit->animator) ecore_animator_del(nit->animator);
457
458    top = (it == elm_naviframe_top_item_get(WIDGET(nit)));
459    if (evas_object_data_get(VIEW(nit), "out_of_list"))
460      goto end;
461
462    if (!sd->on_deletion)
463      {
464         nit->unfocusable = elm_widget_tree_unfocusable_get(VIEW(nit));
465         elm_widget_tree_unfocusable_set(VIEW(nit), EINA_TRUE);
466      }
467
468    if (sd->stack->last->prev)
469      prev_it = EINA_INLIST_CONTAINER_GET
470          (sd->stack->last->prev, Elm_Naviframe_Item);
471
472    sd->stack = eina_inlist_remove(sd->stack, EINA_INLIST_GET(nit));
473    if (!sd->stack) elm_widget_resize_object_set(WIDGET(it), sd->dummy_edje);
474
475    if (top && !sd->on_deletion) /* must raise another one */
476      {
477         if (!prev_it) goto end;
478
479         if (sd->freeze_events)
480           {
481              evas_object_freeze_events_set(VIEW(prev_it), EINA_FALSE);
482           }
483         elm_widget_resize_object_set(WIDGET(prev_it), VIEW(prev_it));
484         evas_object_show(VIEW(prev_it));
485         evas_object_raise(VIEW(prev_it));
486
487         elm_object_signal_emit(VIEW(prev_it), "elm,state,visible", "elm");
488      }
489
490 end:
491
492    _item_free(nit);
493
494    return EINA_TRUE;
495 }
496
497 static void
498 _item_content_set(Elm_Naviframe_Item *it,
499                   Evas_Object *content)
500 {
501    if (it->content == content) return;
502
503    if (it->content) evas_object_del(it->content);
504    it->content = content;
505
506    if (!content) return;
507
508    elm_object_part_content_set(VIEW(it), CONTENT_PART, content);
509    elm_object_signal_emit(VIEW(it), "elm,state,content,show", "elm");
510
511    evas_object_event_callback_add
512      (content, EVAS_CALLBACK_DEL, _item_content_del_cb, it);
513 }
514
515 static void
516 _item_title_prev_btn_set(Elm_Naviframe_Item *it,
517                          Evas_Object *btn)
518 {
519    if (it->title_prev_btn == btn) return;
520    if (it->title_prev_btn) evas_object_del(it->title_prev_btn);
521    it->title_prev_btn = btn;
522    if (!btn) return;
523
524    elm_object_part_content_set(VIEW(it), PREV_BTN_PART, btn);
525    elm_object_signal_emit(VIEW(it), "elm,state,prev_btn,show", "elm");
526    evas_object_event_callback_add
527      (btn, EVAS_CALLBACK_DEL, _item_title_prev_btn_del_cb, it);
528 }
529
530 static void
531 _item_title_next_btn_set(Elm_Naviframe_Item *it,
532                          Evas_Object *btn)
533 {
534    if (it->title_next_btn == btn) return;
535    if (it->title_next_btn) evas_object_del(it->title_next_btn);
536    it->title_next_btn = btn;
537    if (!btn) return;
538
539    elm_object_part_content_set(VIEW(it), NEXT_BTN_PART, btn);
540    elm_object_signal_emit(VIEW(it), "elm,state,next_btn,show", "elm");
541
542    evas_object_event_callback_add
543      (btn, EVAS_CALLBACK_DEL, _item_title_next_btn_del_cb, it);
544 }
545
546 static void
547 _item_title_icon_set(Elm_Naviframe_Item *it,
548                      Evas_Object *icon)
549 {
550    if (it->title_icon == icon) return;
551    if (it->title_icon) evas_object_del(it->title_icon);
552    it->title_icon = icon;
553    if (!icon) return;
554
555    elm_object_part_content_set(VIEW(it), ICON_PART, icon);
556    elm_object_signal_emit(VIEW(it), "elm,state,icon,show", "elm");
557
558    evas_object_event_callback_add
559      (icon, EVAS_CALLBACK_DEL, _item_title_icon_del_cb, it);
560 }
561
562 static Evas_Object *
563 _item_content_unset(Elm_Naviframe_Item *it)
564 {
565    Evas_Object *content = it->content;
566
567    if (!content) return NULL;
568
569    elm_object_part_content_unset(VIEW(it), CONTENT_PART);
570    elm_object_signal_emit(VIEW(it), "elm,state,content,hide", "elm");
571
572    evas_object_event_callback_del
573      (content, EVAS_CALLBACK_DEL, _item_content_del_cb);
574
575    it->content = NULL;
576    return content;
577 }
578
579 static Evas_Object *
580 _item_title_prev_btn_unset(Elm_Naviframe_Item *it)
581 {
582    Evas_Object *content = it->title_prev_btn;
583
584    if (!content) return NULL;
585
586    elm_object_part_content_unset(VIEW(it), PREV_BTN_PART);
587    elm_object_signal_emit(VIEW(it), "elm,state,prev_btn,hide", "elm");
588
589    evas_object_event_callback_del
590      (content, EVAS_CALLBACK_DEL, _item_title_prev_btn_del_cb);
591
592    it->title_prev_btn = NULL;
593    return content;
594 }
595
596 static Evas_Object *
597 _item_title_next_btn_unset(Elm_Naviframe_Item *it)
598 {
599    Evas_Object *content = it->title_next_btn;
600
601    if (!content) return NULL;
602
603    elm_object_part_content_unset(VIEW(it), NEXT_BTN_PART);
604    elm_object_signal_emit(VIEW(it), "elm,state,next_btn,hide", "elm");
605
606    evas_object_event_callback_del
607      (content, EVAS_CALLBACK_DEL, _item_title_next_btn_del_cb);
608
609    it->title_next_btn = NULL;
610    return content;
611 }
612
613 static Evas_Object *
614 _item_title_icon_unset(Elm_Naviframe_Item *it)
615 {
616    Evas_Object *content = it->title_icon;
617
618    if (!content) return NULL;
619
620    elm_object_part_content_unset(VIEW(it), ICON_PART);
621    elm_object_signal_emit(VIEW(it), "elm,state,icon,hide", "elm");
622
623    evas_object_event_callback_del
624      (content, EVAS_CALLBACK_DEL, _item_title_icon_del_cb);
625
626    it->title_icon = NULL;
627    return content;
628 }
629
630 /* since we have each item as layout, we can't reusing the layout's
631  * aliasing, so let's do it ourselves */
632 static void
633 _part_aliasing_eval(const char **part)
634 {
635    if (!*part || !strcmp("default", *part))
636      *part = CONTENT_PART;
637    else if (!strcmp(*part, "prev_btn"))
638      *part = PREV_BTN_PART;
639    else if (!strcmp(*part, "next_btn"))
640      *part = NEXT_BTN_PART;
641    else if (!strcmp(*part, "icon"))
642      *part = ICON_PART;
643 }
644
645 static void
646 _title_content_set(Elm_Naviframe_Item *it,
647                    const char *part,
648                    Evas_Object *content)
649 {
650    Elm_Naviframe_Content_Item_Pair *pair = NULL;
651    char buf[1024];
652
653    EINA_INLIST_FOREACH(it->content_list, pair)
654      if (!strcmp(part, pair->part)) break;
655    if (pair)
656      {
657         if (pair->content == content) return;
658         if (pair->content)
659           evas_object_event_callback_del(pair->content,
660                                          EVAS_CALLBACK_DEL,
661                                          _title_content_del);
662        if (content) elm_object_part_content_set(VIEW(it), part, content);
663      }
664    else
665      {
666         if (!content) return;
667
668         //Remove the pair if new content was swallowed into other part.
669         EINA_INLIST_FOREACH(it->content_list, pair)
670           {
671              if (pair->content == content)
672                {
673                   eina_stringshare_del(pair->part);
674                   it->content_list = eina_inlist_remove(it->content_list,
675                                                         EINA_INLIST_GET(pair));
676                   evas_object_event_callback_del(pair->content,
677                                                  EVAS_CALLBACK_DEL,
678                                                  _title_content_del);
679                   free(pair);
680                   break;
681                }
682           }
683
684         //New pair
685         pair = ELM_NEW(Elm_Naviframe_Content_Item_Pair);
686         if (!pair)
687           {
688              ERR("Failed to allocate new content part of the item! : naviframe=%p",
689              WIDGET(it));
690              return;
691           }
692         pair->it = it;
693         eina_stringshare_replace(&pair->part, part);
694         it->content_list = eina_inlist_append(it->content_list,
695                                               EINA_INLIST_GET(pair));
696         elm_object_part_content_set(VIEW(it), part, content);
697         snprintf(buf, sizeof(buf), "elm,state,%s,show", part);
698         elm_object_signal_emit(VIEW(it), buf, "elm");
699      }
700    pair->content = content;
701    evas_object_event_callback_add(content,
702                                   EVAS_CALLBACK_DEL,
703                                   _title_content_del,
704                                   pair);
705
706    /* access */
707    if (_elm_config->access_mode)
708      _access_obj_process(it, EINA_TRUE);
709 }
710
711 static void
712 _item_content_set_hook(Elm_Object_Item *it,
713                        const char *part,
714                        Evas_Object *content)
715 {
716    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
717
718    _part_aliasing_eval(&part);
719
720    //specified parts
721    if (!part || !strcmp(CONTENT_PART, part))
722      _item_content_set(nit, content);
723    else if (!strcmp(part, PREV_BTN_PART))
724      _item_title_prev_btn_set(nit, content);
725    else if (!strcmp(part, NEXT_BTN_PART))
726      _item_title_next_btn_set(nit, content);
727    else if (!strcmp(part, ICON_PART))
728      _item_title_icon_set(nit, content);
729    else
730      _title_content_set(nit, part, content);
731
732    elm_layout_sizing_eval(WIDGET(it));
733 }
734
735 static Evas_Object *
736 _item_content_get_hook(const Elm_Object_Item *it,
737                        const char *part)
738 {
739    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
740
741    _part_aliasing_eval(&part);
742
743    //specified parts
744    if (!part || !strcmp(CONTENT_PART, part))
745      return nit->content;
746    else if (!strcmp(part, PREV_BTN_PART))
747      return nit->title_prev_btn;
748    else if (!strcmp(part, NEXT_BTN_PART))
749      return nit->title_next_btn;
750    else if (!strcmp(part, ICON_PART))
751      return nit->title_icon;
752
753    //common parts
754    return elm_object_part_content_get(VIEW(nit), part);
755 }
756
757 static Evas_Object *
758 _title_content_unset(Elm_Naviframe_Item *it, const char *part)
759 {
760    Elm_Naviframe_Content_Item_Pair *pair = NULL;
761    char buf[1028];
762    Evas_Object *content = NULL;
763
764    EINA_INLIST_FOREACH(it->content_list, pair)
765      {
766         if (!strcmp(part, pair->part))
767           {
768              content = pair->content;
769              eina_stringshare_del(pair->part);
770              it->content_list = eina_inlist_remove(it->content_list,
771                                                    EINA_INLIST_GET(pair));
772              free(pair);
773              break;
774           }
775      }
776
777    if (!content) return NULL;
778
779    elm_object_part_content_unset(VIEW(it), part);
780    snprintf(buf, sizeof(buf), "elm,state,%s,hide", part);
781    elm_object_signal_emit(VIEW(it), buf, "elm");
782    evas_object_event_callback_del(content,
783                                   EVAS_CALLBACK_DEL,
784                                   _title_content_del);
785    return content;
786 }
787
788 static Evas_Object *
789 _item_content_unset_hook(Elm_Object_Item *it,
790                          const char *part)
791 {
792    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
793    Evas_Object *o = NULL;
794
795    _part_aliasing_eval(&part);
796
797    //specified parts
798    if (!part || !strcmp(CONTENT_PART, part))
799      o = _item_content_unset(nit);
800    else if (!strcmp(part, PREV_BTN_PART))
801      o = _item_title_prev_btn_unset(nit);
802    else if (!strcmp(part, NEXT_BTN_PART))
803      o = _item_title_next_btn_unset(nit);
804    else if (!strcmp(part, ICON_PART))
805      o = _item_title_icon_unset(nit);
806    else
807      o = _title_content_unset(nit, part);
808
809    elm_layout_sizing_eval(WIDGET(it));
810
811    return o;
812 }
813
814 static void
815 _item_signal_emit_hook(Elm_Object_Item *it,
816                        const char *emission,
817                        const char *source)
818 {
819    elm_object_signal_emit(VIEW(it), emission, source);
820 }
821
822 static void
823 _elm_naviframe_smart_sizing_eval(Evas_Object *obj)
824 {
825    Evas_Coord minw = -1, minh = -1;
826    Elm_Naviframe_Item *it;
827    Evas_Coord x, y, w, h;
828
829    ELM_NAVIFRAME_DATA_GET(obj, sd);
830
831    if (sd->on_deletion) return;
832
833    evas_object_geometry_get(obj, &x, &y, &w, &h);
834    EINA_INLIST_FOREACH(sd->stack, it)
835      {
836         evas_object_move(VIEW(it), x, y);
837         evas_object_resize(VIEW(it), w, h);
838         edje_object_size_min_calc(elm_layout_edje_get(VIEW(it)),
839                                   &it->minw, &it->minh);
840         if (it->minw > minw) minw = it->minw;
841         if (it->minh > minh) minh = it->minh;
842      }
843
844    evas_object_size_hint_min_set(obj, minw, minh);
845    evas_object_size_hint_max_set(obj, -1, -1);
846 }
847
848 static void
849 _on_item_back_btn_clicked(void *data,
850                           Evas_Object *obj,
851                           void *event_info __UNUSED__)
852 {
853    /* Since edje has the event queue, clicked event could be happend
854       multiple times on some heavy environment. This callback del will
855       prevent those scenario and guarantee only one clicked for it's own
856       page. */
857    evas_object_smart_callback_del(obj, SIG_CLICKED, _on_item_back_btn_clicked);
858    elm_naviframe_item_pop(data);
859 }
860
861 static Evas_Object *
862 _back_btn_new(Evas_Object *obj, const char *title_label)
863 {
864    Evas_Object *btn, *ed;
865    char buf[1024];
866
867    btn = elm_button_add(obj);
868
869    if (!btn) return NULL;
870    evas_object_smart_callback_add
871      (btn, SIG_CLICKED, _on_item_back_btn_clicked, obj);
872    snprintf
873      (buf, sizeof(buf), "naviframe/back_btn/%s", elm_widget_style_get(obj));
874    elm_object_style_set(btn, buf);
875    if (title_label)
876      elm_layout_text_set(btn, NULL, title_label);
877    else
878      elm_object_domain_translatable_text_set(btn, PACKAGE, N_("Back"));
879
880    /* HACK NOTE: this explicit check only exists to avoid an ERR()
881     * message from elm_layout_content_set().
882     *
883     * The button was ALWAYS supposed to support an elm.swallow.content, but
884     * default naviframe/back_btn/default theme did not provide such, then
885     * old themes would emit such error message.
886     *
887     * Once we can break the theme API, remove this check and always
888     * set an icon.
889     */
890    ed = elm_layout_edje_get(btn);
891    if (edje_object_part_exists(ed, CONTENT_PART))
892      {
893         Evas_Object *ico = elm_icon_add(btn);
894         elm_icon_standard_set(ico, "arrow_left");
895         elm_layout_content_set(btn, CONTENT_PART, ico);
896      }
897
898    return btn;
899 }
900
901 static void
902 _elm_naviframe_smart_signal_callback_add(Evas_Object *obj,
903                                   const char *emission,
904                                   const char *source,
905                                   Edje_Signal_Cb func_cb,
906                                   void *data)
907 {
908    ELM_NAVIFRAME_DATA_GET(obj, sd);
909    Elm_Object_Item *it;
910
911    if (!sd->stack) return;
912
913    _elm_naviframe_parent_sc->callback_add(obj, emission, source, func_cb, data);
914
915    it = elm_naviframe_top_item_get(obj);
916    if (!it) return EINA_FALSE;
917
918    elm_object_signal_callback_add(VIEW(it), emission, source, func_cb, data);
919 }
920
921 static void
922 _elm_naviframe_smart_signal(Evas_Object *obj,
923                             const char *emission,
924                             const char *source)
925 {
926    ELM_NAVIFRAME_DATA_GET(obj, sd);
927
928    if (!sd->stack) return;
929
930    _elm_naviframe_parent_sc->signal(obj, emission, source);
931 }
932
933 /* content/text smart functions proxying things to the top item, which
934  * is the resize object of the layout */
935 static Eina_Bool
936 _elm_naviframe_smart_text_set(Evas_Object *obj,
937                               const char *part,
938                               const char *label)
939 {
940    Elm_Object_Item *it;
941
942    it = elm_naviframe_top_item_get(obj);
943    if (!it) return EINA_FALSE;
944
945    elm_object_item_part_text_set(it, part, label);
946
947    return !strcmp(elm_object_item_part_text_get(it, part), label);
948 }
949
950 static const char *
951 _elm_naviframe_smart_text_get(const Evas_Object *obj,
952                               const char *part)
953 {
954    Elm_Object_Item *it = elm_naviframe_top_item_get(obj);
955
956    if (!it) return NULL;
957
958    return elm_object_item_part_text_get(it, part);
959 }
960
961 /* we have to keep a "manual" set here because of the callbacks on the
962  * children */
963 static Eina_Bool
964 _elm_naviframe_smart_content_set(Evas_Object *obj,
965                                  const char *part,
966                                  Evas_Object *content)
967 {
968    Elm_Object_Item *it;
969
970    it = elm_naviframe_top_item_get(obj);
971    if (!it) return EINA_FALSE;
972
973    elm_object_item_part_content_set(it, part, content);
974
975    return content == elm_object_item_part_content_get(it, part);
976 }
977
978 static Evas_Object *
979 _elm_naviframe_smart_content_get(const Evas_Object *obj,
980                                  const char *part)
981 {
982    Elm_Object_Item *it = elm_naviframe_top_item_get(obj);
983
984    if (!it) return NULL;
985
986    return elm_object_item_part_content_get(it, part);
987 }
988
989 static Evas_Object *
990 _elm_naviframe_smart_content_unset(Evas_Object *obj,
991                                    const char *part)
992 {
993    Elm_Object_Item *it = elm_naviframe_top_item_get(obj);
994
995    if (!it) return NULL;
996
997    return elm_object_item_part_content_unset(it, part);
998 }
999
1000 static void
1001 _on_item_title_clicked(void *data,
1002                        Evas_Object *obj __UNUSED__,
1003                        const char *emission __UNUSED__,
1004                        const char *source __UNUSED__)
1005 {
1006    Elm_Naviframe_Item *it = data;
1007
1008    evas_object_smart_callback_call(WIDGET(it), SIG_TITLE_CLICKED, it);
1009 }
1010
1011 /* "elm,state,cur,pushed"
1012  */
1013 static void
1014 _on_item_push_finished(void *data,
1015                        Evas_Object *obj __UNUSED__,
1016                        const char *emission __UNUSED__,
1017                        const char *source __UNUSED__)
1018 {
1019    Elm_Naviframe_Item *it = data;
1020
1021    if (!it) return;
1022
1023    ELM_NAVIFRAME_DATA_GET(WIDGET(it), sd);
1024
1025    evas_object_hide(VIEW(it));
1026
1027    elm_widget_tree_unfocusable_set(VIEW(it), it->unfocusable);
1028
1029    if (sd->freeze_events)
1030      evas_object_freeze_events_set(VIEW(it), EINA_FALSE);
1031 }
1032
1033 /* "elm,state,cur,popped"
1034  */
1035 static void
1036 _on_item_pop_finished(void *data,
1037                       Evas_Object *obj __UNUSED__,
1038                       const char *emission __UNUSED__,
1039                       const char *source __UNUSED__)
1040 {
1041    Elm_Naviframe_Item *it = data;
1042
1043    ELM_NAVIFRAME_DATA_GET(WIDGET(it), sd);
1044
1045    if (sd->preserve)
1046      elm_widget_tree_unfocusable_set(VIEW(it), it->unfocusable);
1047    sd->popping = eina_list_remove(sd->popping, it);
1048
1049    elm_widget_item_del(data);
1050 }
1051
1052 /* "elm,state,new,pushed",
1053  * "elm,state,prev,popped
1054  */
1055 static void
1056 _on_item_show_finished(void *data,
1057                        Evas_Object *obj __UNUSED__,
1058                        const char *emission __UNUSED__,
1059                        const char *source __UNUSED__)
1060 {
1061    Elm_Naviframe_Item *it = data;
1062    unsigned int order = 0;
1063    Evas_Object *newest;
1064
1065    ELM_NAVIFRAME_DATA_GET(WIDGET(it), sd);
1066
1067    elm_object_signal_emit(VIEW(it), "elm,state,visible", "elm");
1068
1069    elm_widget_tree_unfocusable_set(VIEW(it), it->unfocusable);
1070
1071    newest = elm_widget_newest_focus_order_get(VIEW(it), &order, EINA_TRUE);
1072    if (newest)
1073      elm_object_focus_set(newest, EINA_TRUE);
1074    else
1075      elm_object_focus_set(VIEW(it), EINA_TRUE);
1076
1077    if (sd->freeze_events)
1078      evas_object_freeze_events_set(VIEW(it), EINA_FALSE);
1079
1080    evas_object_smart_callback_call(WIDGET(it), SIG_TRANSITION_FINISHED, data);
1081 }
1082
1083 static void
1084 _on_item_size_hints_changed(void *data,
1085                             Evas *e __UNUSED__,
1086                             Evas_Object *obj __UNUSED__,
1087                             void *event_info __UNUSED__)
1088 {
1089    elm_layout_sizing_eval(data);
1090 }
1091
1092 static void
1093 _item_dispmode_set(Elm_Naviframe_Item *it, Evas_Display_Mode dispmode)
1094 {
1095    if (it->dispmode == dispmode) return;
1096    switch (dispmode)
1097      {
1098       case EVAS_DISPLAY_MODE_COMPRESS:
1099          elm_object_signal_emit(VIEW(it), "display,mode,compress", "");
1100          break;
1101       default:
1102          elm_object_signal_emit(VIEW(it), "display,mode,default", "");
1103          break;
1104      }
1105    it->dispmode = dispmode;
1106 }
1107
1108 static Elm_Naviframe_Item *
1109 _item_new(Evas_Object *obj,
1110           const Elm_Naviframe_Item *prev_it,
1111           const char *title_label,
1112           Evas_Object *prev_btn,
1113           Evas_Object *next_btn,
1114           Evas_Object *content,
1115           const char *item_style)
1116 {
1117    Elm_Naviframe_Item *it;
1118
1119    ELM_NAVIFRAME_DATA_GET(obj, sd);
1120
1121    it = elm_widget_item_new(obj, Elm_Naviframe_Item);
1122    if (!it)
1123      {
1124         ERR("Failed to allocate new item! : naviframe=%p", obj);
1125         return NULL;
1126      }
1127
1128    elm_widget_item_del_pre_hook_set(it, _item_del_pre_hook);
1129    elm_widget_item_text_set_hook_set(it, _item_text_set_hook);
1130    elm_widget_item_text_get_hook_set(it, _item_text_get_hook);
1131    elm_widget_item_content_set_hook_set(it, _item_content_set_hook);
1132    elm_widget_item_content_get_hook_set(it, _item_content_get_hook);
1133    elm_widget_item_content_unset_hook_set(it, _item_content_unset_hook);
1134    elm_widget_item_signal_emit_hook_set(it, _item_signal_emit_hook);
1135
1136    //item base layout
1137    VIEW(it) = elm_layout_add(obj);
1138    evas_object_smart_member_add(VIEW(it), obj);
1139
1140    evas_object_event_callback_add
1141      (VIEW(it), EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1142      _on_item_size_hints_changed, obj);
1143
1144    elm_object_signal_callback_add
1145      (VIEW(it), "elm,action,show,finished", "", _on_item_show_finished, it);
1146    elm_object_signal_callback_add
1147      (VIEW(it), "elm,action,pushed,finished", "", _on_item_push_finished, it);
1148    elm_object_signal_callback_add
1149      (VIEW(it), "elm,action,popped,finished", "", _on_item_pop_finished, it);
1150    elm_object_signal_callback_add
1151      (VIEW(it), "elm,action,title,clicked", "", _on_item_title_clicked, it);
1152
1153    _item_style_set(it, item_style);
1154
1155    if (title_label)
1156      _item_text_set_hook((Elm_Object_Item *)it, TITLE_PART, title_label);
1157
1158    //title buttons
1159    if ((!prev_btn) && sd->auto_pushed && prev_it)
1160      {
1161         const char *prev_title = prev_it->title_label;
1162         prev_btn = _back_btn_new(obj, prev_title);
1163      }
1164
1165    if (prev_btn)
1166      {
1167         _item_content_set_hook((Elm_Object_Item *)it, PREV_BTN_PART, prev_btn);
1168
1169         if (!elm_layout_text_get(prev_btn, NULL))
1170           _elm_access_text_set
1171             (_elm_access_object_get(prev_btn), ELM_ACCESS_INFO, E_("Back"));
1172      }
1173
1174    if (next_btn)
1175      {
1176         _item_content_set_hook((Elm_Object_Item *)it, NEXT_BTN_PART, next_btn);
1177
1178         if (!elm_layout_text_get(next_btn, NULL))
1179           _elm_access_text_set
1180             (_elm_access_object_get(next_btn), ELM_ACCESS_INFO, E_("Next"));
1181      }
1182
1183    _item_content_set(it, content);
1184    _item_dispmode_set(it, sd->dispmode);
1185
1186    it->title_visible = EINA_TRUE;
1187
1188    return it;
1189 }
1190
1191 static void
1192 _on_obj_size_hints_changed(void *data __UNUSED__, Evas *e __UNUSED__,
1193                            Evas_Object *obj, void *event_info __UNUSED__)
1194 {
1195    Elm_Naviframe_Item *it;
1196    Evas_Display_Mode dispmode;
1197
1198    ELM_NAVIFRAME_DATA_GET(obj, sd);
1199
1200    dispmode = evas_object_size_hint_display_mode_get(obj);
1201    if (sd->dispmode == dispmode) return;
1202
1203    sd->dispmode = dispmode;
1204
1205    EINA_INLIST_FOREACH(sd->stack, it)
1206      _item_dispmode_set(it, dispmode);
1207 }
1208
1209 static Eina_Bool
1210 _elm_naviframe_smart_focus_next(const Evas_Object *obj,
1211                                 Elm_Focus_Direction dir,
1212                                 Evas_Object **next)
1213 {
1214    Evas_Object *ao;
1215    Eina_Bool ret;
1216    Eina_List *l = NULL;
1217    Elm_Naviframe_Item *top_it;
1218    void *(*list_data_get)(const Eina_List *list);
1219
1220    top_it = (Elm_Naviframe_Item *)elm_naviframe_top_item_get(obj);
1221    if (!top_it) return EINA_FALSE;
1222
1223    list_data_get = eina_list_data_get;
1224
1225    l = eina_list_append(l, VIEW(top_it));
1226
1227    /* access */
1228    if (_elm_config->access_mode)
1229      {
1230         ao = _access_object_get(top_it, TITLE_ACCESS_PART);
1231         if (ao) l = eina_list_append(l, ao);
1232      }
1233
1234    ret = elm_widget_focus_list_next_get(obj, l, list_data_get, dir, next);
1235    eina_list_free(l);
1236
1237    return ret;
1238 }
1239
1240 static Eina_Bool
1241 _elm_naviframe_smart_focus_direction(const Evas_Object *obj,
1242                                      const Evas_Object *base,
1243                                      double degree,
1244                                      Evas_Object **direction,
1245                                      double *weight)
1246 {
1247    Eina_Bool ret;
1248    Eina_List *l = NULL;
1249    Elm_Naviframe_Item *top_it;
1250    void *(*list_data_get)(const Eina_List *list);
1251
1252    top_it = (Elm_Naviframe_Item *)elm_naviframe_top_item_get(obj);
1253    if (!top_it) return EINA_FALSE;
1254
1255    list_data_get = eina_list_data_get;
1256
1257    l = eina_list_append(l, VIEW(top_it));
1258    ret = elm_widget_focus_list_direction_get
1259       (obj, base, l, list_data_get, degree, direction, weight);
1260    eina_list_free(l);
1261
1262    return ret;
1263 }
1264
1265 static void
1266 _elm_naviframe_smart_add(Evas_Object *obj)
1267 {
1268    EVAS_SMART_DATA_ALLOC(obj, Elm_Naviframe_Smart_Data);
1269
1270    ELM_WIDGET_CLASS(_elm_naviframe_parent_sc)->base.add(obj);
1271
1272    priv->dummy_edje = ELM_WIDGET_DATA(priv)->resize_obj;
1273    priv->auto_pushed = EINA_TRUE;
1274    priv->freeze_events = EINA_TRUE;
1275
1276    evas_object_event_callback_add(obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1277                                   _on_obj_size_hints_changed, obj);
1278    elm_widget_can_focus_set(obj, EINA_TRUE);
1279 }
1280
1281 static Eina_Bool
1282 _pop_transition_cb(void *data)
1283 {
1284    Elm_Naviframe_Item *prev_it, *it;
1285    it = (Elm_Naviframe_Item *)data;
1286
1287    it->animator = NULL;
1288
1289    prev_it = (Elm_Naviframe_Item *) elm_naviframe_top_item_get(WIDGET(it));
1290    if (prev_it)
1291      {
1292         elm_object_signal_emit(VIEW(prev_it), "elm,state,prev,popped,deferred",
1293                                "elm");
1294         //FIXME: Remove the below line once edje_object_message_signal_process is fixed.
1295         //This API crashes when in the midst of this API processing if edje object passed here is deleted.
1296         //edje_object_message_signal_process(elm_layout_edje_get(VIEW(prev_it)));
1297      }
1298    elm_object_signal_emit(VIEW(it), "elm,state,cur,popped,deferred", "elm");
1299
1300    //FIXME: Remove the below line once edje_object_message_signal_process is fixed.
1301    //This API crashes when in the midst of this API processing if edje object passed here is deleted.
1302    //edje_object_message_signal_process(elm_layout_edje_get(VIEW(it)));
1303
1304    return ECORE_CALLBACK_CANCEL;
1305 }
1306
1307 static void
1308 _elm_naviframe_smart_del(Evas_Object *obj)
1309 {
1310    Elm_Naviframe_Item *it;
1311
1312    ELM_NAVIFRAME_DATA_GET(obj, sd);
1313
1314    sd->on_deletion = EINA_TRUE;
1315
1316    while (sd->stack)
1317      {
1318         it = EINA_INLIST_CONTAINER_GET(sd->stack, Elm_Naviframe_Item);
1319         elm_widget_item_del(it);
1320      }
1321
1322    //All popping items which are not called yet by animator.
1323    EINA_LIST_FREE(sd->popping, it)
1324      {
1325         if (it->animator) ecore_animator_del(it->animator);
1326         elm_widget_item_del(it);
1327      }
1328    eina_list_free(sd->popping);
1329
1330    evas_object_del(sd->dummy_edje);
1331
1332    ELM_WIDGET_CLASS(_elm_naviframe_parent_sc)->base.del(obj);
1333 }
1334
1335 static void
1336 _elm_naviframe_smart_access(Evas_Object *obj, Eina_Bool is_access)
1337 {
1338    Elm_Naviframe_Item *it;
1339
1340    ELM_NAVIFRAME_CHECK(obj);
1341    ELM_NAVIFRAME_DATA_GET(obj, sd);
1342
1343    EINA_INLIST_FOREACH(sd->stack, it)
1344      _access_obj_process(it, is_access);
1345 }
1346
1347 static Eina_Bool
1348 _elm_naviframe_smart_event(Evas_Object *obj,
1349                            Evas_Object *src __UNUSED__,
1350                            Evas_Callback_Type type,
1351                            void *event_info)
1352 {
1353    Elm_Naviframe_Item *it;
1354    Evas_Event_Key_Down *ev = event_info;
1355
1356    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
1357    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
1358    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
1359
1360 //Tizen Only: Need to customize the "Escape" Key
1361    if (strcmp(ev->keyname, "Escape")) return EINA_FALSE;
1362
1363    it = elm_naviframe_top_item_get(obj);
1364    if (!it) return EINA_FALSE;
1365
1366    if (it->title_prev_btn)
1367      evas_object_smart_callback_call(it->title_prev_btn, SIG_CLICKED, NULL);
1368
1369    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1370
1371    return EINA_TRUE;
1372 }
1373
1374 static void
1375 _elm_naviframe_smart_set_user(Elm_Naviframe_Smart_Class *sc)
1376 {
1377    ELM_WIDGET_CLASS(sc)->base.add = _elm_naviframe_smart_add;
1378    ELM_WIDGET_CLASS(sc)->base.del = _elm_naviframe_smart_del;
1379
1380    ELM_WIDGET_CLASS(sc)->theme = _elm_naviframe_smart_theme;
1381    ELM_WIDGET_CLASS(sc)->focus_next = _elm_naviframe_smart_focus_next;
1382    ELM_WIDGET_CLASS(sc)->focus_direction = _elm_naviframe_smart_focus_direction;
1383    ELM_WIDGET_CLASS(sc)->access = _elm_naviframe_smart_access;
1384    ELM_WIDGET_CLASS(sc)->event = _elm_naviframe_smart_event;
1385
1386    ELM_CONTAINER_CLASS(sc)->content_set = _elm_naviframe_smart_content_set;
1387    ELM_CONTAINER_CLASS(sc)->content_get = _elm_naviframe_smart_content_get;
1388    ELM_CONTAINER_CLASS(sc)->content_unset = _elm_naviframe_smart_content_unset;
1389
1390    ELM_LAYOUT_CLASS(sc)->signal = _elm_naviframe_smart_signal;
1391    ELM_LAYOUT_CLASS(sc)->callback_add = _elm_naviframe_smart_signal_callback_add;
1392    ELM_LAYOUT_CLASS(sc)->text_set = _elm_naviframe_smart_text_set;
1393    ELM_LAYOUT_CLASS(sc)->text_get = _elm_naviframe_smart_text_get;
1394    ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_naviframe_smart_sizing_eval;
1395 }
1396
1397 static Eina_Bool
1398 _push_transition_cb(void *data)
1399 {
1400    Elm_Naviframe_Item *prev_it, *it = data;
1401
1402    ELM_NAVIFRAME_DATA_GET(WIDGET(it), sd);
1403
1404    it->animator = NULL;
1405
1406    if (sd->stack->last->prev)
1407      {
1408         prev_it = EINA_INLIST_CONTAINER_GET(sd->stack->last->prev,
1409                                             Elm_Naviframe_Item);
1410         elm_object_signal_emit(VIEW(prev_it), "elm,state,cur,pushed,deferred",
1411                                 "elm");
1412         edje_object_message_signal_process(elm_layout_edje_get(VIEW(prev_it)));
1413      }
1414    elm_object_signal_emit(VIEW(it), "elm,state,new,pushed,deferred", "elm");
1415    edje_object_message_signal_process(elm_layout_edje_get(VIEW(it)));
1416
1417    return ECORE_CALLBACK_CANCEL;
1418 }
1419
1420 EAPI const Elm_Naviframe_Smart_Class *
1421 elm_naviframe_smart_class_get(void)
1422 {
1423    static Elm_Naviframe_Smart_Class _sc =
1424      ELM_NAVIFRAME_SMART_CLASS_INIT_NAME_VERSION
1425        (ELM_NAVIFRAME_SMART_NAME);
1426    static const Elm_Naviframe_Smart_Class *class = NULL;
1427    Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
1428
1429    if (class)
1430      return class;
1431
1432    _elm_naviframe_smart_set(&_sc);
1433    esc->callbacks = _smart_callbacks;
1434    class = &_sc;
1435
1436    return class;
1437 }
1438
1439 EAPI Evas_Object *
1440 elm_naviframe_add(Evas_Object *parent)
1441 {
1442    Evas_Object *obj;
1443
1444    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1445
1446    obj = elm_widget_add(_elm_naviframe_smart_class_new(), parent);
1447    if (!obj) return NULL;
1448
1449    if (!elm_widget_sub_object_add(parent, obj))
1450      ERR("could not add %p as sub object of %p", obj, parent);
1451
1452    _elm_widget_orient_signal_emit(obj);
1453
1454    return obj;
1455 }
1456
1457 EAPI Elm_Object_Item *
1458 elm_naviframe_item_push(Evas_Object *obj,
1459                         const char *title_label,
1460                         Evas_Object *prev_btn,
1461                         Evas_Object *next_btn,
1462                         Evas_Object *content,
1463                         const char *item_style)
1464 {
1465    Elm_Naviframe_Item *prev_it, *it;
1466
1467    ELM_NAVIFRAME_CHECK(obj) NULL;
1468
1469    ELM_NAVIFRAME_DATA_GET(obj, sd);
1470
1471    prev_it = (Elm_Naviframe_Item *)elm_naviframe_top_item_get(obj);
1472    it = _item_new(obj, prev_it,
1473                   title_label, prev_btn, next_btn, content, item_style);
1474    if (!it) return NULL;
1475
1476    evas_object_show(VIEW(it));
1477    elm_widget_resize_object_set(obj, VIEW(it));
1478    if (prev_it)
1479      elm_widget_sub_object_add(obj, VIEW(prev_it));
1480    evas_object_smart_member_add(sd->dummy_edje, obj);
1481
1482    if (prev_it)
1483      {
1484         /* re-add as smart member */
1485         evas_object_smart_member_add(VIEW(prev_it), obj);
1486
1487         if (sd->freeze_events)
1488           {
1489              evas_object_freeze_events_set(VIEW(it), EINA_TRUE);
1490              evas_object_freeze_events_set(VIEW(prev_it), EINA_TRUE);
1491           }
1492
1493         elm_object_signal_emit(VIEW(prev_it), "elm,state,cur,pushed", "elm");
1494         elm_object_signal_emit(VIEW(it), "elm,state,new,pushed", "elm");
1495         edje_object_message_signal_process(elm_layout_edje_get(VIEW(prev_it)));
1496         edje_object_message_signal_process(elm_layout_edje_get(VIEW(it)));
1497
1498         prev_it->unfocusable = elm_widget_tree_unfocusable_get(VIEW(prev_it));
1499         elm_widget_tree_unfocusable_set(VIEW(prev_it), EINA_TRUE);
1500
1501         it->animator = ecore_animator_add(_push_transition_cb, it);
1502      }
1503    else
1504      elm_object_focus_set(VIEW(it), EINA_TRUE);
1505
1506    sd->stack = eina_inlist_append(sd->stack, EINA_INLIST_GET(it));
1507    evas_object_raise(VIEW(it));
1508
1509    /* access */
1510    if (_elm_config->access_mode) _access_focus_set(it);
1511
1512    elm_layout_sizing_eval(obj);
1513
1514    return (Elm_Object_Item *)it;
1515 }
1516
1517 EAPI Elm_Object_Item *
1518 elm_naviframe_item_insert_before(Evas_Object *obj,
1519                                  Elm_Object_Item *before,
1520                                  const char *title_label,
1521                                  Evas_Object *prev_btn,
1522                                  Evas_Object *next_btn,
1523                                  Evas_Object *content,
1524                                  const char *item_style)
1525 {
1526    Elm_Naviframe_Item *it, *prev_it = NULL;
1527
1528    ELM_NAVIFRAME_CHECK(obj) NULL;
1529    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(before, NULL);
1530    ELM_NAVIFRAME_DATA_GET(obj, sd);
1531
1532    it = (Elm_Naviframe_Item *)before;
1533    if (EINA_INLIST_GET(it)->prev)
1534      prev_it = EINA_INLIST_CONTAINER_GET(EINA_INLIST_GET(it)->prev,
1535                                          Elm_Naviframe_Item);
1536    it = _item_new(obj, prev_it,
1537                   title_label, prev_btn, next_btn, content, item_style);
1538    if (!it) return NULL;
1539
1540    sd->stack = eina_inlist_prepend_relative
1541        (sd->stack, EINA_INLIST_GET(it),
1542        EINA_INLIST_GET(((Elm_Naviframe_Item *)before)));
1543
1544    elm_layout_sizing_eval(obj);
1545
1546    return (Elm_Object_Item *)it;
1547 }
1548
1549 EAPI Elm_Object_Item *
1550 elm_naviframe_item_insert_after(Evas_Object *obj,
1551                                 Elm_Object_Item *after,
1552                                 const char *title_label,
1553                                 Evas_Object *prev_btn,
1554                                 Evas_Object *next_btn,
1555                                 Evas_Object *content,
1556                                 const char *item_style)
1557 {
1558    Elm_Naviframe_Item *it;
1559    Eina_Bool top_inserted = EINA_FALSE;
1560
1561    ELM_NAVIFRAME_CHECK(obj) NULL;
1562    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(after, NULL);
1563    ELM_NAVIFRAME_DATA_GET(obj, sd);
1564
1565    it = _item_new(obj, (Elm_Naviframe_Item *)after,
1566                   title_label, prev_btn, next_btn, content, item_style);
1567    if (!it) return NULL;
1568
1569    if (elm_naviframe_top_item_get(obj) == after) top_inserted = EINA_TRUE;
1570
1571    sd->stack = eina_inlist_append_relative
1572        (sd->stack, EINA_INLIST_GET(it),
1573        EINA_INLIST_GET(((Elm_Naviframe_Item *)after)));
1574
1575    if (top_inserted)
1576      {
1577         elm_widget_resize_object_set(obj, VIEW(it));
1578         elm_widget_sub_object_add(obj, VIEW(after));
1579         evas_object_smart_member_add(sd->dummy_edje, obj);
1580         evas_object_show(VIEW(it));
1581         evas_object_hide(VIEW(after));
1582         elm_object_focus_set(VIEW(it), EINA_TRUE);
1583      }
1584
1585    /* access */
1586    if (_elm_config->access_mode) _access_focus_set(it);
1587
1588    elm_layout_sizing_eval(obj);
1589
1590    return (Elm_Object_Item *)it;
1591 }
1592
1593 EAPI Evas_Object *
1594 elm_naviframe_item_pop(Evas_Object *obj)
1595 {
1596    Elm_Naviframe_Item *it, *prev_it = NULL;
1597    Evas_Object *content = NULL;
1598
1599    ELM_NAVIFRAME_CHECK(obj) NULL;
1600    ELM_NAVIFRAME_DATA_GET(obj, sd);
1601
1602    it = (Elm_Naviframe_Item *)elm_naviframe_top_item_get(obj);
1603    if (!it) return NULL;
1604
1605    if (it->pop_cb) it->pop_cb(it->pop_data, (Elm_Object_Item *)it);
1606
1607    if (sd->preserve)
1608      content = it->content;
1609
1610    evas_object_data_set(VIEW(it), "out_of_list", (void *)1);
1611
1612    it->unfocusable = elm_widget_tree_unfocusable_get(VIEW(it));
1613    elm_widget_tree_unfocusable_set(VIEW(it), EINA_TRUE);
1614
1615    if (sd->stack->last->prev)
1616      prev_it = EINA_INLIST_CONTAINER_GET
1617          (sd->stack->last->prev, Elm_Naviframe_Item);
1618
1619    sd->stack = eina_inlist_remove(sd->stack, EINA_INLIST_GET(it));
1620    if (!sd->stack) elm_widget_resize_object_set(obj, sd->dummy_edje);
1621
1622    if (prev_it)
1623      {
1624         if (sd->freeze_events)
1625           {
1626              evas_object_freeze_events_set(VIEW(it), EINA_TRUE);
1627              evas_object_freeze_events_set(VIEW(prev_it), EINA_TRUE);
1628           }
1629
1630         elm_widget_resize_object_set(obj, VIEW(prev_it));
1631         evas_object_smart_member_add(sd->dummy_edje, obj);
1632         evas_object_raise(VIEW(prev_it));
1633
1634         /* access */
1635         if (_elm_config->access_mode) _access_focus_set(prev_it);
1636
1637         /* these 2 signals MUST take place simultaneously */
1638         elm_object_signal_emit(VIEW(it), "elm,state,cur,popped", "elm");
1639         evas_object_show(VIEW(prev_it));
1640         elm_object_signal_emit(VIEW(prev_it), "elm,state,prev,popped", "elm");
1641
1642         edje_object_message_signal_process(elm_layout_edje_get(VIEW(it)));
1643         edje_object_message_signal_process(elm_layout_edje_get(VIEW(prev_it)));
1644
1645         if (it->animator) ecore_animator_del(it->animator);
1646         it->animator = ecore_animator_add(_pop_transition_cb, it);
1647         sd->popping = eina_list_append(sd->popping, it);
1648      }
1649    else
1650      elm_widget_item_del(it);
1651
1652    return content;
1653 }
1654
1655 EAPI void
1656 elm_naviframe_item_pop_to(Elm_Object_Item *it)
1657 {
1658    Elm_Naviframe_Item *nit;
1659    Eina_Inlist *l, *prev_l;
1660
1661    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it);
1662
1663    nit = (Elm_Naviframe_Item *)it;
1664    ELM_NAVIFRAME_DATA_GET(WIDGET(nit), sd);
1665
1666    if (it == elm_naviframe_top_item_get(WIDGET(nit))) return;
1667
1668    l = sd->stack->last->prev;
1669
1670    sd->on_deletion = EINA_TRUE;
1671
1672    while (l)
1673      {
1674         Elm_Naviframe_Item *iit = EINA_INLIST_CONTAINER_GET
1675             (l, Elm_Naviframe_Item);
1676
1677         if (iit == nit) break;
1678
1679         prev_l = l->prev;
1680         sd->stack = eina_inlist_remove(sd->stack, l);
1681
1682         elm_widget_item_del(iit);
1683
1684         l = prev_l;
1685      }
1686
1687    sd->on_deletion = EINA_FALSE;
1688
1689    elm_naviframe_item_pop(WIDGET(nit));
1690 }
1691
1692 EAPI void
1693 elm_naviframe_item_promote(Elm_Object_Item *it)
1694 {
1695    Elm_Object_Item *prev_top;
1696    Elm_Naviframe_Item *nit;
1697    Elm_Naviframe_Item *prev_it;
1698
1699    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it);
1700
1701    nit = (Elm_Naviframe_Item *)it;
1702    ELM_NAVIFRAME_DATA_GET(WIDGET(nit), sd);
1703
1704    prev_top = elm_naviframe_top_item_get(WIDGET(nit));
1705    if (it == prev_top) return;
1706
1707    /* remember, last is 1st on the naviframe, push it to last pos. */
1708    sd->stack = eina_inlist_demote(sd->stack, EINA_INLIST_GET(nit));
1709
1710    elm_widget_resize_object_set(WIDGET(it), VIEW(nit));
1711    elm_widget_sub_object_add(WIDGET(it), VIEW(prev_top));
1712    evas_object_smart_member_add(sd->dummy_edje, WIDGET(it));
1713
1714    /* this was the previous top one */
1715    prev_it = EINA_INLIST_CONTAINER_GET
1716        (sd->stack->last->prev, Elm_Naviframe_Item);
1717
1718    /* re-add as smart member */
1719    evas_object_smart_member_add(VIEW(prev_it), WIDGET(it));
1720
1721    prev_it->unfocusable = elm_widget_tree_unfocusable_get(VIEW(prev_it));
1722    elm_widget_tree_unfocusable_set(prev_it->content, EINA_TRUE);
1723
1724    if (sd->freeze_events)
1725      {
1726         evas_object_freeze_events_set(VIEW(it), EINA_TRUE);
1727         evas_object_freeze_events_set(VIEW(prev_it), EINA_TRUE);
1728      }
1729
1730    elm_object_signal_emit(VIEW(prev_it), "elm,state,cur,pushed", "elm");
1731
1732    evas_object_show(VIEW(nit));
1733    evas_object_raise(VIEW(nit));
1734
1735    elm_object_signal_emit(VIEW(nit), "elm,state,new,pushed", "elm");
1736
1737    edje_object_message_signal_process(elm_layout_edje_get(VIEW(prev_it)));
1738    edje_object_message_signal_process(elm_layout_edje_get(VIEW(nit)));
1739    if (nit->animator) ecore_animator_del(nit->animator);
1740    nit->animator = ecore_animator_add(_push_transition_cb, nit);
1741
1742    /* access */
1743    if (_elm_config->access_mode) _access_focus_set(nit);
1744 }
1745
1746 EAPI void
1747 elm_naviframe_item_simple_promote(Evas_Object *obj,
1748                                   Evas_Object *content)
1749 {
1750    Elm_Naviframe_Item *itr;
1751
1752    ELM_NAVIFRAME_CHECK(obj);
1753    ELM_NAVIFRAME_DATA_GET(obj, sd);
1754
1755    EINA_INLIST_FOREACH(sd->stack, itr)
1756      {
1757         if (elm_object_item_content_get((Elm_Object_Item *)itr) == content)
1758           {
1759              elm_naviframe_item_promote((Elm_Object_Item *)itr);
1760              break;
1761           }
1762      }
1763 }
1764
1765 EAPI void
1766 elm_naviframe_content_preserve_on_pop_set(Evas_Object *obj,
1767                                           Eina_Bool preserve)
1768 {
1769    ELM_NAVIFRAME_CHECK(obj);
1770    ELM_NAVIFRAME_DATA_GET(obj, sd);
1771
1772    sd->preserve = !!preserve;
1773 }
1774
1775 EAPI Eina_Bool
1776 elm_naviframe_content_preserve_on_pop_get(const Evas_Object *obj)
1777 {
1778    ELM_NAVIFRAME_CHECK(obj) EINA_FALSE;
1779    ELM_NAVIFRAME_DATA_GET(obj, sd);
1780
1781    return sd->preserve;
1782 }
1783
1784 EAPI Elm_Object_Item *
1785 elm_naviframe_top_item_get(const Evas_Object *obj)
1786 {
1787    ELM_NAVIFRAME_CHECK(obj) NULL;
1788    ELM_NAVIFRAME_DATA_GET(obj, sd);
1789
1790    if (!sd->stack) return NULL;
1791    return (Elm_Object_Item *)(EINA_INLIST_CONTAINER_GET
1792                                 (sd->stack->last, Elm_Naviframe_Item));
1793 }
1794
1795 EAPI Elm_Object_Item *
1796 elm_naviframe_bottom_item_get(const Evas_Object *obj)
1797 {
1798    ELM_NAVIFRAME_CHECK(obj) NULL;
1799    ELM_NAVIFRAME_DATA_GET(obj, sd);
1800
1801    if (!sd->stack) return NULL;
1802    return (Elm_Object_Item *)(EINA_INLIST_CONTAINER_GET
1803                                 (sd->stack, Elm_Naviframe_Item));
1804 }
1805
1806 EAPI void
1807 elm_naviframe_item_style_set(Elm_Object_Item *it,
1808                              const char *item_style)
1809 {
1810    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
1811
1812    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it);
1813
1814    if (item_style && !strcmp(item_style, nit->style)) return;
1815
1816    if (!item_style)
1817      if (!strcmp("basic", nit->style)) return;
1818
1819    _item_style_set(nit, item_style);
1820    _item_signals_emit(nit);
1821    _item_title_visible_update(nit);
1822 }
1823
1824 EAPI const char *
1825 elm_naviframe_item_style_get(const Elm_Object_Item *it)
1826 {
1827    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
1828
1829    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it, NULL);
1830
1831    return nit->style;
1832 }
1833
1834 EAPI void
1835 elm_naviframe_item_title_visible_set(Elm_Object_Item *it,
1836                                      Eina_Bool visible)
1837 {
1838    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
1839
1840    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it);
1841
1842    visible = !!visible;
1843    if (nit->title_visible == visible) return;
1844
1845    nit->title_visible = visible;
1846    _item_title_visible_update(nit);
1847 }
1848
1849 EAPI Eina_Bool
1850 elm_naviframe_item_title_visible_get(const Elm_Object_Item *it)
1851 {
1852    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
1853
1854    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it, EINA_FALSE);
1855
1856    return nit->title_visible;
1857 }
1858
1859 EAPI void
1860 elm_naviframe_item_pop_cb_set(Elm_Object_Item *it, Elm_Naviframe_Item_Pop_Cb func, void *data)
1861 {
1862    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
1863
1864    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it);
1865
1866    nit->pop_cb = func;
1867    nit->pop_data = data;
1868 }
1869
1870 EAPI void
1871 elm_naviframe_prev_btn_auto_pushed_set(Evas_Object *obj,
1872                                        Eina_Bool auto_pushed)
1873 {
1874    ELM_NAVIFRAME_CHECK(obj);
1875    ELM_NAVIFRAME_DATA_GET(obj, sd);
1876
1877    sd->auto_pushed = !!auto_pushed;
1878 }
1879
1880 EAPI Eina_Bool
1881 elm_naviframe_prev_btn_auto_pushed_get(const Evas_Object *obj)
1882 {
1883    ELM_NAVIFRAME_CHECK(obj) EINA_FALSE;
1884    ELM_NAVIFRAME_DATA_GET(obj, sd);
1885
1886    return sd->auto_pushed;
1887 }
1888
1889 EAPI Eina_List *
1890 elm_naviframe_items_get(const Evas_Object *obj)
1891 {
1892    Eina_List *ret = NULL;
1893    Elm_Naviframe_Item *itr;
1894
1895    ELM_NAVIFRAME_CHECK(obj) NULL;
1896    ELM_NAVIFRAME_DATA_GET(obj, sd);
1897
1898    EINA_INLIST_FOREACH(sd->stack, itr)
1899      ret = eina_list_append(ret, itr);
1900
1901    return ret;
1902 }
1903
1904 EAPI void
1905 elm_naviframe_event_enabled_set(Evas_Object *obj,
1906                                 Eina_Bool enabled)
1907 {
1908    ELM_NAVIFRAME_CHECK(obj);
1909    ELM_NAVIFRAME_DATA_GET(obj, sd);
1910
1911    enabled = !!enabled;
1912    if (sd->freeze_events == !enabled) return;
1913    sd->freeze_events = !enabled;
1914 }
1915
1916 EAPI Eina_Bool
1917 elm_naviframe_event_enabled_get(const Evas_Object *obj)
1918 {
1919    ELM_NAVIFRAME_CHECK(obj) EINA_FALSE;
1920    ELM_NAVIFRAME_DATA_GET(obj, sd);
1921
1922    return !sd->freeze_events;
1923 }