merge with master
[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 (nit->content && !sd->on_deletion)
463      {
464         nit->content_unfocusable =
465           elm_widget_tree_unfocusable_get(nit->content);
466         elm_widget_tree_unfocusable_set(nit->content, EINA_TRUE);
467      }
468
469    if (sd->stack->last->prev)
470      prev_it = EINA_INLIST_CONTAINER_GET
471          (sd->stack->last->prev, Elm_Naviframe_Item);
472
473    sd->stack = eina_inlist_remove(sd->stack, EINA_INLIST_GET(nit));
474    if (!sd->stack) elm_widget_resize_object_set(WIDGET(it), sd->dummy_edje);
475
476    if (top && !sd->on_deletion) /* must raise another one */
477      {
478         if (!prev_it) goto end;
479
480         if (sd->freeze_events)
481           {
482              evas_object_freeze_events_set(VIEW(prev_it), EINA_FALSE);
483           }
484         elm_widget_resize_object_set(WIDGET(prev_it), VIEW(prev_it));
485         evas_object_show(VIEW(prev_it));
486         evas_object_raise(VIEW(prev_it));
487
488         elm_object_signal_emit(VIEW(prev_it), "elm,state,visible", "elm");
489      }
490
491 end:
492
493    _item_free(nit);
494
495    return EINA_TRUE;
496 }
497
498 static void
499 _item_content_set(Elm_Naviframe_Item *it,
500                   Evas_Object *content)
501 {
502    if (it->content == content) return;
503
504    if (it->content) evas_object_del(it->content);
505    it->content = content;
506
507    if (!content) return;
508
509    elm_object_part_content_set(VIEW(it), CONTENT_PART, content);
510    elm_object_signal_emit(VIEW(it), "elm,state,content,show", "elm");
511
512    evas_object_event_callback_add
513      (content, EVAS_CALLBACK_DEL, _item_content_del_cb, it);
514 }
515
516 static void
517 _item_title_prev_btn_set(Elm_Naviframe_Item *it,
518                          Evas_Object *btn)
519 {
520    if (it->title_prev_btn == btn) return;
521    if (it->title_prev_btn) evas_object_del(it->title_prev_btn);
522    it->title_prev_btn = btn;
523    if (!btn) return;
524
525    elm_object_part_content_set(VIEW(it), PREV_BTN_PART, btn);
526    elm_object_signal_emit(VIEW(it), "elm,state,prev_btn,show", "elm");
527    evas_object_event_callback_add
528      (btn, EVAS_CALLBACK_DEL, _item_title_prev_btn_del_cb, it);
529 }
530
531 static void
532 _item_title_next_btn_set(Elm_Naviframe_Item *it,
533                          Evas_Object *btn)
534 {
535    if (it->title_next_btn == btn) return;
536    if (it->title_next_btn) evas_object_del(it->title_next_btn);
537    it->title_next_btn = btn;
538    if (!btn) return;
539
540    elm_object_part_content_set(VIEW(it), NEXT_BTN_PART, btn);
541    elm_object_signal_emit(VIEW(it), "elm,state,next_btn,show", "elm");
542
543    evas_object_event_callback_add
544      (btn, EVAS_CALLBACK_DEL, _item_title_next_btn_del_cb, it);
545 }
546
547 static void
548 _item_title_icon_set(Elm_Naviframe_Item *it,
549                      Evas_Object *icon)
550 {
551    if (it->title_icon == icon) return;
552    if (it->title_icon) evas_object_del(it->title_icon);
553    it->title_icon = icon;
554    if (!icon) return;
555
556    elm_object_part_content_set(VIEW(it), ICON_PART, icon);
557    elm_object_signal_emit(VIEW(it), "elm,state,icon,show", "elm");
558
559    evas_object_event_callback_add
560      (icon, EVAS_CALLBACK_DEL, _item_title_icon_del_cb, it);
561 }
562
563 static Evas_Object *
564 _item_content_unset(Elm_Naviframe_Item *it)
565 {
566    Evas_Object *content = it->content;
567
568    if (!content) return NULL;
569
570    elm_object_part_content_unset(VIEW(it), CONTENT_PART);
571    elm_object_signal_emit(VIEW(it), "elm,state,content,hide", "elm");
572
573    evas_object_event_callback_del
574      (content, EVAS_CALLBACK_DEL, _item_content_del_cb);
575
576    it->content = NULL;
577    return content;
578 }
579
580 static Evas_Object *
581 _item_title_prev_btn_unset(Elm_Naviframe_Item *it)
582 {
583    Evas_Object *content = it->title_prev_btn;
584
585    if (!content) return NULL;
586
587    elm_object_part_content_unset(VIEW(it), PREV_BTN_PART);
588    elm_object_signal_emit(VIEW(it), "elm,state,prev_btn,hide", "elm");
589
590    evas_object_event_callback_del
591      (content, EVAS_CALLBACK_DEL, _item_title_prev_btn_del_cb);
592
593    it->title_prev_btn = NULL;
594    return content;
595 }
596
597 static Evas_Object *
598 _item_title_next_btn_unset(Elm_Naviframe_Item *it)
599 {
600    Evas_Object *content = it->title_next_btn;
601
602    if (!content) return NULL;
603
604    elm_object_part_content_unset(VIEW(it), NEXT_BTN_PART);
605    elm_object_signal_emit(VIEW(it), "elm,state,next_btn,hide", "elm");
606
607    evas_object_event_callback_del
608      (content, EVAS_CALLBACK_DEL, _item_title_next_btn_del_cb);
609
610    it->title_next_btn = NULL;
611    return content;
612 }
613
614 static Evas_Object *
615 _item_title_icon_unset(Elm_Naviframe_Item *it)
616 {
617    Evas_Object *content = it->title_icon;
618
619    if (!content) return NULL;
620
621    elm_object_part_content_unset(VIEW(it), ICON_PART);
622    elm_object_signal_emit(VIEW(it), "elm,state,icon,hide", "elm");
623
624    evas_object_event_callback_del
625      (content, EVAS_CALLBACK_DEL, _item_title_icon_del_cb);
626
627    it->title_icon = NULL;
628    return content;
629 }
630
631 /* since we have each item as layout, we can't reusing the layout's
632  * aliasing, so let's do it ourselves */
633 static void
634 _part_aliasing_eval(const char **part)
635 {
636    if (!*part || !strcmp("default", *part))
637      *part = CONTENT_PART;
638    else if (!strcmp(*part, "prev_btn"))
639      *part = PREV_BTN_PART;
640    else if (!strcmp(*part, "next_btn"))
641      *part = NEXT_BTN_PART;
642    else if (!strcmp(*part, "icon"))
643      *part = ICON_PART;
644 }
645
646 static void
647 _title_content_set(Elm_Naviframe_Item *it,
648                    const char *part,
649                    Evas_Object *content)
650 {
651    Elm_Naviframe_Content_Item_Pair *pair = NULL;
652    char buf[1024];
653
654    EINA_INLIST_FOREACH(it->content_list, pair)
655      if (!strcmp(part, pair->part)) break;
656    if (pair)
657      {
658         if (pair->content == content) return;
659         if (pair->content)
660           evas_object_event_callback_del(pair->content,
661                                          EVAS_CALLBACK_DEL,
662                                          _title_content_del);
663        if (content) elm_object_part_content_set(VIEW(it), part, content);
664      }
665    else
666      {
667         if (!content) return;
668
669         //Remove the pair if new content was swallowed into other part.
670         EINA_INLIST_FOREACH(it->content_list, pair)
671           {
672              if (pair->content == content)
673                {
674                   eina_stringshare_del(pair->part);
675                   it->content_list = eina_inlist_remove(it->content_list,
676                                                         EINA_INLIST_GET(pair));
677                   evas_object_event_callback_del(pair->content,
678                                                  EVAS_CALLBACK_DEL,
679                                                  _title_content_del);
680                   free(pair);
681                   break;
682                }
683           }
684
685         //New pair
686         pair = ELM_NEW(Elm_Naviframe_Content_Item_Pair);
687         if (!pair)
688           {
689              ERR("Failed to allocate new content part of the item! : naviframe=%p",
690              WIDGET(it));
691              return;
692           }
693         pair->it = it;
694         eina_stringshare_replace(&pair->part, part);
695         it->content_list = eina_inlist_append(it->content_list,
696                                               EINA_INLIST_GET(pair));
697         elm_object_part_content_set(VIEW(it), part, content);
698         snprintf(buf, sizeof(buf), "elm,state,%s,show", part);
699         elm_object_signal_emit(VIEW(it), buf, "elm");
700      }
701    pair->content = content;
702    evas_object_event_callback_add(content,
703                                   EVAS_CALLBACK_DEL,
704                                   _title_content_del,
705                                   pair);
706
707    /* access */
708    if (_elm_config->access_mode)
709      _access_obj_process(it, EINA_TRUE);
710 }
711
712 static void
713 _item_content_set_hook(Elm_Object_Item *it,
714                        const char *part,
715                        Evas_Object *content)
716 {
717    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
718
719    _part_aliasing_eval(&part);
720
721    //specified parts
722    if (!part || !strcmp(CONTENT_PART, part))
723      _item_content_set(nit, content);
724    else if (!strcmp(part, PREV_BTN_PART))
725      _item_title_prev_btn_set(nit, content);
726    else if (!strcmp(part, NEXT_BTN_PART))
727      _item_title_next_btn_set(nit, content);
728    else if (!strcmp(part, ICON_PART))
729      _item_title_icon_set(nit, content);
730    else
731      _title_content_set(nit, part, content);
732
733    elm_layout_sizing_eval(WIDGET(it));
734 }
735
736 static Evas_Object *
737 _item_content_get_hook(const Elm_Object_Item *it,
738                        const char *part)
739 {
740    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
741
742    _part_aliasing_eval(&part);
743
744    //specified parts
745    if (!part || !strcmp(CONTENT_PART, part))
746      return nit->content;
747    else if (!strcmp(part, PREV_BTN_PART))
748      return nit->title_prev_btn;
749    else if (!strcmp(part, NEXT_BTN_PART))
750      return nit->title_next_btn;
751    else if (!strcmp(part, ICON_PART))
752      return nit->title_icon;
753
754    //common parts
755    return elm_object_part_content_get(VIEW(nit), part);
756 }
757
758 static Evas_Object *
759 _title_content_unset(Elm_Naviframe_Item *it, const char *part)
760 {
761    Elm_Naviframe_Content_Item_Pair *pair = NULL;
762    char buf[1028];
763    Evas_Object *content = NULL;
764
765    EINA_INLIST_FOREACH(it->content_list, pair)
766      {
767         if (!strcmp(part, pair->part))
768           {
769              content = pair->content;
770              eina_stringshare_del(pair->part);
771              it->content_list = eina_inlist_remove(it->content_list,
772                                                    EINA_INLIST_GET(pair));
773              free(pair);
774              break;
775           }
776      }
777
778    if (!content) return NULL;
779
780    elm_object_part_content_unset(VIEW(it), part);
781    snprintf(buf, sizeof(buf), "elm,state,%s,hide", part);
782    elm_object_signal_emit(VIEW(it), buf, "elm");
783    evas_object_event_callback_del(content,
784                                   EVAS_CALLBACK_DEL,
785                                   _title_content_del);
786    return content;
787 }
788
789 static Evas_Object *
790 _item_content_unset_hook(Elm_Object_Item *it,
791                          const char *part)
792 {
793    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
794    Evas_Object *o = NULL;
795
796    _part_aliasing_eval(&part);
797
798    //specified parts
799    if (!part || !strcmp(CONTENT_PART, part))
800      o = _item_content_unset(nit);
801    else if (!strcmp(part, PREV_BTN_PART))
802      o = _item_title_prev_btn_unset(nit);
803    else if (!strcmp(part, NEXT_BTN_PART))
804      o = _item_title_next_btn_unset(nit);
805    else if (!strcmp(part, ICON_PART))
806      o = _item_title_icon_unset(nit);
807    else
808      o = _title_content_unset(nit, part);
809
810    elm_layout_sizing_eval(WIDGET(it));
811
812    return o;
813 }
814
815 static void
816 _item_signal_emit_hook(Elm_Object_Item *it,
817                        const char *emission,
818                        const char *source)
819 {
820    elm_object_signal_emit(VIEW(it), emission, source);
821 }
822
823 static void
824 _elm_naviframe_smart_sizing_eval(Evas_Object *obj)
825 {
826    Evas_Coord minw = -1, minh = -1;
827    Elm_Naviframe_Item *it;
828    Evas_Coord x, y, w, h;
829
830    ELM_NAVIFRAME_DATA_GET(obj, sd);
831
832    if (sd->on_deletion) return;
833
834    evas_object_geometry_get(obj, &x, &y, &w, &h);
835    EINA_INLIST_FOREACH(sd->stack, it)
836      {
837         evas_object_move(VIEW(it), x, y);
838         evas_object_resize(VIEW(it), w, h);
839         edje_object_size_min_calc(elm_layout_edje_get(VIEW(it)),
840                                   &it->minw, &it->minh);
841         if (it->minw > minw) minw = it->minw;
842         if (it->minh > minh) minh = it->minh;
843      }
844
845    evas_object_size_hint_min_set(obj, minw, minh);
846    evas_object_size_hint_max_set(obj, -1, -1);
847 }
848
849 static void
850 _on_item_back_btn_clicked(void *data,
851                           Evas_Object *obj,
852                           void *event_info __UNUSED__)
853 {
854    /* Since edje has the event queue, clicked event could be happend
855       multiple times on some heavy environment. This callback del will
856       prevent those scenario and guarantee only one clicked for it's own
857       page. */
858    evas_object_smart_callback_del(obj, SIG_CLICKED, _on_item_back_btn_clicked);
859    elm_naviframe_item_pop(data);
860 }
861
862 static Evas_Object *
863 _back_btn_new(Evas_Object *obj, const char *title_label)
864 {
865    Evas_Object *btn, *ed;
866    char buf[1024];
867
868    btn = elm_button_add(obj);
869
870    if (!btn) return NULL;
871    evas_object_smart_callback_add
872      (btn, SIG_CLICKED, _on_item_back_btn_clicked, obj);
873    snprintf
874      (buf, sizeof(buf), "naviframe/back_btn/%s", elm_widget_style_get(obj));
875    elm_object_style_set(btn, buf);
876    if (title_label)
877      elm_layout_text_set(btn, NULL, title_label);
878    else
879      elm_object_domain_translatable_text_set(btn, PACKAGE, N_("Back"));
880
881    /* HACK NOTE: this explicit check only exists to avoid an ERR()
882     * message from elm_layout_content_set().
883     *
884     * The button was ALWAYS supposed to support an elm.swallow.content, but
885     * default naviframe/back_btn/default theme did not provide such, then
886     * old themes would emit such error message.
887     *
888     * Once we can break the theme API, remove this check and always
889     * set an icon.
890     */
891    ed = elm_layout_edje_get(btn);
892    if (edje_object_part_exists(ed, CONTENT_PART))
893      {
894         Evas_Object *ico = elm_icon_add(btn);
895         elm_icon_standard_set(ico, "arrow_left");
896         elm_layout_content_set(btn, CONTENT_PART, ico);
897      }
898
899    return btn;
900 }
901
902 static void
903 _elm_naviframe_smart_signal_callback_add(Evas_Object *obj,
904                                   const char *emission,
905                                   const char *source,
906                                   Edje_Signal_Cb func_cb,
907                                   void *data)
908 {
909    ELM_NAVIFRAME_DATA_GET(obj, sd);
910    Elm_Object_Item *it;
911
912    if (!sd->stack) return;
913
914    _elm_naviframe_parent_sc->callback_add(obj, emission, source, func_cb, data);
915
916    it = elm_naviframe_top_item_get(obj);
917    if (!it) return EINA_FALSE;
918
919    elm_object_signal_callback_add(VIEW(it), emission, source, func_cb, data);
920 }
921
922 static void
923 _elm_naviframe_smart_signal(Evas_Object *obj,
924                             const char *emission,
925                             const char *source)
926 {
927    ELM_NAVIFRAME_DATA_GET(obj, sd);
928
929    if (!sd->stack) return;
930
931    _elm_naviframe_parent_sc->signal(obj, emission, source);
932 }
933
934 /* content/text smart functions proxying things to the top item, which
935  * is the resize object of the layout */
936 static Eina_Bool
937 _elm_naviframe_smart_text_set(Evas_Object *obj,
938                               const char *part,
939                               const char *label)
940 {
941    Elm_Object_Item *it;
942
943    it = elm_naviframe_top_item_get(obj);
944    if (!it) return EINA_FALSE;
945
946    elm_object_item_part_text_set(it, part, label);
947
948    return !strcmp(elm_object_item_part_text_get(it, part), label);
949 }
950
951 static const char *
952 _elm_naviframe_smart_text_get(const Evas_Object *obj,
953                               const char *part)
954 {
955    Elm_Object_Item *it = elm_naviframe_top_item_get(obj);
956
957    if (!it) return NULL;
958
959    return elm_object_item_part_text_get(it, part);
960 }
961
962 /* we have to keep a "manual" set here because of the callbacks on the
963  * children */
964 static Eina_Bool
965 _elm_naviframe_smart_content_set(Evas_Object *obj,
966                                  const char *part,
967                                  Evas_Object *content)
968 {
969    Elm_Object_Item *it;
970
971    it = elm_naviframe_top_item_get(obj);
972    if (!it) return EINA_FALSE;
973
974    elm_object_item_part_content_set(it, part, content);
975
976    return content == elm_object_item_part_content_get(it, part);
977 }
978
979 static Evas_Object *
980 _elm_naviframe_smart_content_get(const Evas_Object *obj,
981                                  const char *part)
982 {
983    Elm_Object_Item *it = elm_naviframe_top_item_get(obj);
984
985    if (!it) return NULL;
986
987    return elm_object_item_part_content_get(it, part);
988 }
989
990 static Evas_Object *
991 _elm_naviframe_smart_content_unset(Evas_Object *obj,
992                                    const char *part)
993 {
994    Elm_Object_Item *it = elm_naviframe_top_item_get(obj);
995
996    if (!it) return NULL;
997
998    return elm_object_item_part_content_unset(it, part);
999 }
1000
1001 static void
1002 _on_item_title_clicked(void *data,
1003                        Evas_Object *obj __UNUSED__,
1004                        const char *emission __UNUSED__,
1005                        const char *source __UNUSED__)
1006 {
1007    Elm_Naviframe_Item *it = data;
1008
1009    evas_object_smart_callback_call(WIDGET(it), SIG_TITLE_CLICKED, it);
1010 }
1011
1012 /* "elm,state,cur,pushed"
1013  */
1014 static void
1015 _on_item_push_finished(void *data,
1016                        Evas_Object *obj __UNUSED__,
1017                        const char *emission __UNUSED__,
1018                        const char *source __UNUSED__)
1019 {
1020    Elm_Naviframe_Item *it = data;
1021
1022    if (!it) return;
1023
1024    ELM_NAVIFRAME_DATA_GET(WIDGET(it), sd);
1025
1026    evas_object_hide(VIEW(it));
1027
1028    if (it->content)
1029      elm_widget_tree_unfocusable_set(it->content, it->content_unfocusable);
1030
1031    if (sd->freeze_events)
1032      evas_object_freeze_events_set(VIEW(it), EINA_FALSE);
1033 }
1034
1035 /* "elm,state,cur,popped"
1036  */
1037 static void
1038 _on_item_pop_finished(void *data,
1039                       Evas_Object *obj __UNUSED__,
1040                       const char *emission __UNUSED__,
1041                       const char *source __UNUSED__)
1042 {
1043    Elm_Naviframe_Item *it = data;
1044
1045    ELM_NAVIFRAME_DATA_GET(WIDGET(it), sd);
1046
1047    if (sd->preserve && it->content)
1048      elm_widget_tree_unfocusable_set(it->content, it->content_unfocusable);
1049    sd->popping = eina_list_remove(sd->popping, it);
1050
1051    elm_widget_item_del(data);
1052 }
1053
1054 /* "elm,state,new,pushed",
1055  * "elm,state,prev,popped
1056  */
1057 static void
1058 _on_item_show_finished(void *data,
1059                        Evas_Object *obj __UNUSED__,
1060                        const char *emission __UNUSED__,
1061                        const char *source __UNUSED__)
1062 {
1063    Elm_Naviframe_Item *it = data;
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(it->content, it->content_unfocusable);
1070
1071    if (sd->freeze_events)
1072      evas_object_freeze_events_set(VIEW(it), EINA_FALSE);
1073
1074    evas_object_smart_callback_call(WIDGET(it), SIG_TRANSITION_FINISHED, data);
1075 }
1076
1077 static void
1078 _on_item_size_hints_changed(void *data,
1079                             Evas *e __UNUSED__,
1080                             Evas_Object *obj __UNUSED__,
1081                             void *event_info __UNUSED__)
1082 {
1083    elm_layout_sizing_eval(data);
1084 }
1085
1086 static void
1087 _item_dispmode_set(Elm_Naviframe_Item *it, Evas_Display_Mode dispmode)
1088 {
1089    if (it->dispmode == dispmode) return;
1090    switch (dispmode)
1091      {
1092       case EVAS_DISPLAY_MODE_COMPRESS:
1093          elm_object_signal_emit(VIEW(it), "display,mode,compress", "");
1094          break;
1095       default:
1096          elm_object_signal_emit(VIEW(it), "display,mode,default", "");
1097          break;
1098      }
1099    it->dispmode = dispmode;
1100 }
1101
1102 static Elm_Naviframe_Item *
1103 _item_new(Evas_Object *obj,
1104           const Elm_Naviframe_Item *prev_it,
1105           const char *title_label,
1106           Evas_Object *prev_btn,
1107           Evas_Object *next_btn,
1108           Evas_Object *content,
1109           const char *item_style)
1110 {
1111    Elm_Naviframe_Item *it;
1112
1113    ELM_NAVIFRAME_DATA_GET(obj, sd);
1114
1115    it = elm_widget_item_new(obj, Elm_Naviframe_Item);
1116    if (!it)
1117      {
1118         ERR("Failed to allocate new item! : naviframe=%p", obj);
1119         return NULL;
1120      }
1121
1122    elm_widget_item_del_pre_hook_set(it, _item_del_pre_hook);
1123    elm_widget_item_text_set_hook_set(it, _item_text_set_hook);
1124    elm_widget_item_text_get_hook_set(it, _item_text_get_hook);
1125    elm_widget_item_content_set_hook_set(it, _item_content_set_hook);
1126    elm_widget_item_content_get_hook_set(it, _item_content_get_hook);
1127    elm_widget_item_content_unset_hook_set(it, _item_content_unset_hook);
1128    elm_widget_item_signal_emit_hook_set(it, _item_signal_emit_hook);
1129
1130    //item base layout
1131    VIEW(it) = elm_layout_add(obj);
1132    evas_object_smart_member_add(VIEW(it), obj);
1133
1134    evas_object_event_callback_add
1135      (VIEW(it), EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1136      _on_item_size_hints_changed, obj);
1137
1138    elm_object_signal_callback_add
1139      (VIEW(it), "elm,action,show,finished", "", _on_item_show_finished, it);
1140    elm_object_signal_callback_add
1141      (VIEW(it), "elm,action,pushed,finished", "", _on_item_push_finished, it);
1142    elm_object_signal_callback_add
1143      (VIEW(it), "elm,action,popped,finished", "", _on_item_pop_finished, it);
1144    elm_object_signal_callback_add
1145      (VIEW(it), "elm,action,title,clicked", "", _on_item_title_clicked, it);
1146
1147    _item_style_set(it, item_style);
1148
1149    if (title_label)
1150      _item_text_set_hook((Elm_Object_Item *)it, TITLE_PART, title_label);
1151
1152    //title buttons
1153    if ((!prev_btn) && sd->auto_pushed && prev_it)
1154      {
1155         const char *prev_title = prev_it->title_label;
1156         prev_btn = _back_btn_new(obj, prev_title);
1157      }
1158
1159    if (prev_btn)
1160      {
1161         _item_content_set_hook((Elm_Object_Item *)it, PREV_BTN_PART, prev_btn);
1162
1163         if (!elm_layout_text_get(prev_btn, NULL))
1164           _elm_access_text_set
1165             (_elm_access_object_get(prev_btn), ELM_ACCESS_INFO, E_("Back"));
1166      }
1167
1168    if (next_btn)
1169      {
1170         _item_content_set_hook((Elm_Object_Item *)it, NEXT_BTN_PART, next_btn);
1171
1172         if (!elm_layout_text_get(next_btn, NULL))
1173           _elm_access_text_set
1174             (_elm_access_object_get(next_btn), ELM_ACCESS_INFO, E_("Next"));
1175      }
1176
1177    _item_content_set(it, content);
1178    _item_dispmode_set(it, sd->dispmode);
1179
1180    it->title_visible = EINA_TRUE;
1181
1182    return it;
1183 }
1184
1185 static void
1186 _on_obj_size_hints_changed(void *data __UNUSED__, Evas *e __UNUSED__,
1187                            Evas_Object *obj, void *event_info __UNUSED__)
1188 {
1189    Elm_Naviframe_Item *it;
1190    Evas_Display_Mode dispmode;
1191
1192    ELM_NAVIFRAME_DATA_GET(obj, sd);
1193
1194    dispmode = evas_object_size_hint_display_mode_get(obj);
1195    if (sd->dispmode == dispmode) return;
1196
1197    sd->dispmode = dispmode;
1198
1199    EINA_INLIST_FOREACH(sd->stack, it)
1200      _item_dispmode_set(it, dispmode);
1201 }
1202
1203 static Eina_Bool
1204 _elm_naviframe_smart_focus_next(const Evas_Object *obj,
1205                                 Elm_Focus_Direction dir,
1206                                 Evas_Object **next)
1207 {
1208    Evas_Object *ao;
1209    Eina_Bool ret;
1210    Eina_List *l = NULL;
1211    Elm_Naviframe_Item *top_it;
1212    Elm_Naviframe_Content_Item_Pair *content_pair = NULL;
1213    void *(*list_data_get)(const Eina_List *list);
1214
1215    top_it = (Elm_Naviframe_Item *)elm_naviframe_top_item_get(obj);
1216    if (!top_it) return EINA_FALSE;
1217
1218    if (!top_it->title_visible)
1219      {
1220         return elm_widget_focus_next_get(top_it->content, dir, next);
1221      }
1222
1223    list_data_get = eina_list_data_get;
1224
1225    /* access */
1226    if (_elm_config->access_mode)
1227      {
1228         ao = _access_object_get(top_it, TITLE_ACCESS_PART);
1229         if (ao) l = eina_list_append(l, ao);
1230      }
1231
1232    /* icon would be able to have an widget. ex: segment control */
1233    if ((top_it->title_icon) &&
1234        (elm_widget_can_focus_get(top_it->title_icon) ||
1235         elm_widget_child_can_focus_get(top_it->title_icon)))
1236      l = eina_list_append(l, top_it->title_icon);
1237
1238    if (top_it->title_prev_btn)
1239      l = eina_list_append(l, top_it->title_prev_btn);
1240    if (top_it->title_next_btn)
1241      l = eina_list_append(l, top_it->title_next_btn);
1242    if (top_it->content)
1243      l = eina_list_append(l, top_it->content);
1244    EINA_INLIST_FOREACH(top_it->content_list, content_pair)
1245      {
1246         if (elm_object_part_content_get(VIEW(top_it), content_pair->part))
1247           l = eina_list_append(l, elm_object_part_content_get(VIEW(top_it),
1248                                                               content_pair->part));
1249      }
1250    l = eina_list_append(l, VIEW(top_it));
1251
1252    ret = elm_widget_focus_list_next_get(obj, l, list_data_get, dir, next);
1253    eina_list_free(l);
1254
1255    return ret;
1256 }
1257
1258 static void
1259 _elm_naviframe_smart_add(Evas_Object *obj)
1260 {
1261    EVAS_SMART_DATA_ALLOC(obj, Elm_Naviframe_Smart_Data);
1262
1263    ELM_WIDGET_CLASS(_elm_naviframe_parent_sc)->base.add(obj);
1264
1265    priv->dummy_edje = ELM_WIDGET_DATA(priv)->resize_obj;
1266    priv->auto_pushed = EINA_TRUE;
1267    priv->freeze_events = EINA_TRUE;
1268
1269    evas_object_event_callback_add(obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1270                                   _on_obj_size_hints_changed, obj);
1271    elm_widget_can_focus_set(obj, EINA_TRUE);
1272 }
1273
1274 static Eina_Bool
1275 _pop_transition_cb(void *data)
1276 {
1277    Elm_Naviframe_Item *prev_it, *it;
1278    it = (Elm_Naviframe_Item *)data;
1279
1280    it->animator = NULL;
1281
1282    prev_it = (Elm_Naviframe_Item *) elm_naviframe_top_item_get(WIDGET(it));
1283    if (prev_it)
1284      {
1285         elm_object_signal_emit(VIEW(prev_it), "elm,state,prev,popped,deferred",
1286                                "elm");
1287         //FIXME: Remove the below line once edje_object_message_signal_process is fixed.
1288         //This API crashes when in the midst of this API processing if edje object passed here is deleted.
1289         //edje_object_message_signal_process(elm_layout_edje_get(VIEW(prev_it)));
1290      }
1291    elm_object_signal_emit(VIEW(it), "elm,state,cur,popped,deferred", "elm");
1292
1293    //FIXME: Remove the below line once edje_object_message_signal_process is fixed.
1294    //This API crashes when in the midst of this API processing if edje object passed here is deleted.
1295    //edje_object_message_signal_process(elm_layout_edje_get(VIEW(it)));
1296
1297    return ECORE_CALLBACK_CANCEL;
1298 }
1299
1300 static void
1301 _elm_naviframe_smart_del(Evas_Object *obj)
1302 {
1303    Elm_Naviframe_Item *it;
1304
1305    ELM_NAVIFRAME_DATA_GET(obj, sd);
1306
1307    sd->on_deletion = EINA_TRUE;
1308
1309    while (sd->stack)
1310      {
1311         it = EINA_INLIST_CONTAINER_GET(sd->stack, Elm_Naviframe_Item);
1312         elm_widget_item_del(it);
1313      }
1314
1315    //All popping items which are not called yet by animator.
1316    EINA_LIST_FREE(sd->popping, it)
1317      {
1318         if (it->animator) ecore_animator_del(it->animator);
1319         elm_widget_item_del(it);
1320      }
1321    eina_list_free(sd->popping);
1322
1323    evas_object_del(sd->dummy_edje);
1324
1325    ELM_WIDGET_CLASS(_elm_naviframe_parent_sc)->base.del(obj);
1326 }
1327
1328 static void
1329 _elm_naviframe_smart_access(Evas_Object *obj, Eina_Bool is_access)
1330 {
1331    Elm_Naviframe_Item *it;
1332
1333    ELM_NAVIFRAME_CHECK(obj);
1334    ELM_NAVIFRAME_DATA_GET(obj, sd);
1335
1336    EINA_INLIST_FOREACH(sd->stack, it)
1337      _access_obj_process(it, is_access);
1338 }
1339
1340 static Eina_Bool
1341 _elm_naviframe_smart_event(Evas_Object *obj,
1342                            Evas_Object *src __UNUSED__,
1343                            Evas_Callback_Type type,
1344                            void *event_info)
1345 {
1346    Elm_Naviframe_Item *it;
1347    Evas_Event_Key_Down *ev = event_info;
1348
1349    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
1350    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
1351    if (strcmp(ev->keyname, "BackSpace")) return EINA_FALSE;
1352
1353    it = elm_naviframe_top_item_get(obj);
1354    if (!it) return EINA_FALSE;
1355
1356    if (it->title_prev_btn)
1357      evas_object_smart_callback_call(it->title_prev_btn, SIG_CLICKED, NULL);
1358
1359    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1360
1361    return EINA_TRUE;
1362 }
1363
1364 static void
1365 _elm_naviframe_smart_set_user(Elm_Naviframe_Smart_Class *sc)
1366 {
1367    ELM_WIDGET_CLASS(sc)->base.add = _elm_naviframe_smart_add;
1368    ELM_WIDGET_CLASS(sc)->base.del = _elm_naviframe_smart_del;
1369
1370    ELM_WIDGET_CLASS(sc)->theme = _elm_naviframe_smart_theme;
1371    ELM_WIDGET_CLASS(sc)->focus_next = _elm_naviframe_smart_focus_next;
1372    ELM_WIDGET_CLASS(sc)->access = _elm_naviframe_smart_access;
1373    ELM_WIDGET_CLASS(sc)->event = _elm_naviframe_smart_event;
1374
1375    ELM_CONTAINER_CLASS(sc)->content_set = _elm_naviframe_smart_content_set;
1376    ELM_CONTAINER_CLASS(sc)->content_get = _elm_naviframe_smart_content_get;
1377    ELM_CONTAINER_CLASS(sc)->content_unset = _elm_naviframe_smart_content_unset;
1378
1379    ELM_LAYOUT_CLASS(sc)->signal = _elm_naviframe_smart_signal;
1380    ELM_LAYOUT_CLASS(sc)->callback_add = _elm_naviframe_smart_signal_callback_add;
1381    ELM_LAYOUT_CLASS(sc)->text_set = _elm_naviframe_smart_text_set;
1382    ELM_LAYOUT_CLASS(sc)->text_get = _elm_naviframe_smart_text_get;
1383    ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_naviframe_smart_sizing_eval;
1384 }
1385
1386 static Eina_Bool
1387 _push_transition_cb(void *data)
1388 {
1389    Elm_Naviframe_Item *prev_it, *it = data;
1390
1391    ELM_NAVIFRAME_DATA_GET(WIDGET(it), sd);
1392
1393    it->animator = NULL;
1394
1395    if (sd->stack->last->prev)
1396      {
1397         prev_it = EINA_INLIST_CONTAINER_GET(sd->stack->last->prev,
1398                                             Elm_Naviframe_Item);
1399         elm_object_signal_emit(VIEW(prev_it), "elm,state,cur,pushed,deferred",
1400                                 "elm");
1401         edje_object_message_signal_process(elm_layout_edje_get(VIEW(prev_it)));
1402      }
1403    elm_object_signal_emit(VIEW(it), "elm,state,new,pushed,deferred", "elm");
1404    edje_object_message_signal_process(elm_layout_edje_get(VIEW(it)));
1405
1406    return ECORE_CALLBACK_CANCEL;
1407 }
1408
1409 EAPI const Elm_Naviframe_Smart_Class *
1410 elm_naviframe_smart_class_get(void)
1411 {
1412    static Elm_Naviframe_Smart_Class _sc =
1413      ELM_NAVIFRAME_SMART_CLASS_INIT_NAME_VERSION
1414        (ELM_NAVIFRAME_SMART_NAME);
1415    static const Elm_Naviframe_Smart_Class *class = NULL;
1416    Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
1417
1418    if (class)
1419      return class;
1420
1421    _elm_naviframe_smart_set(&_sc);
1422    esc->callbacks = _smart_callbacks;
1423    class = &_sc;
1424
1425    return class;
1426 }
1427
1428 EAPI Evas_Object *
1429 elm_naviframe_add(Evas_Object *parent)
1430 {
1431    Evas_Object *obj;
1432
1433    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1434
1435    obj = elm_widget_add(_elm_naviframe_smart_class_new(), parent);
1436    if (!obj) return NULL;
1437
1438    if (!elm_widget_sub_object_add(parent, obj))
1439      ERR("could not add %p as sub object of %p", obj, parent);
1440
1441    return obj;
1442 }
1443
1444 EAPI Elm_Object_Item *
1445 elm_naviframe_item_push(Evas_Object *obj,
1446                         const char *title_label,
1447                         Evas_Object *prev_btn,
1448                         Evas_Object *next_btn,
1449                         Evas_Object *content,
1450                         const char *item_style)
1451 {
1452    Elm_Naviframe_Item *prev_it, *it;
1453
1454    ELM_NAVIFRAME_CHECK(obj) NULL;
1455
1456    ELM_NAVIFRAME_DATA_GET(obj, sd);
1457
1458    prev_it = (Elm_Naviframe_Item *)elm_naviframe_top_item_get(obj);
1459    it = _item_new(obj, prev_it,
1460                   title_label, prev_btn, next_btn, content, item_style);
1461    if (!it) return NULL;
1462
1463    evas_object_show(VIEW(it));
1464    elm_widget_resize_object_set(obj, VIEW(it));
1465    evas_object_smart_member_add(sd->dummy_edje, obj);
1466
1467    if (prev_it)
1468      {
1469         /* re-add as smart member */
1470         evas_object_smart_member_add(VIEW(prev_it), obj);
1471
1472         if (sd->freeze_events)
1473           {
1474              evas_object_freeze_events_set(VIEW(it), EINA_TRUE);
1475              evas_object_freeze_events_set(VIEW(prev_it), EINA_TRUE);
1476           }
1477
1478         elm_object_signal_emit(VIEW(prev_it), "elm,state,cur,pushed", "elm");
1479         elm_object_signal_emit(VIEW(it), "elm,state,new,pushed", "elm");
1480         edje_object_message_signal_process(elm_layout_edje_get(VIEW(prev_it)));
1481         edje_object_message_signal_process(elm_layout_edje_get(VIEW(it)));
1482
1483         if (prev_it->content)
1484           {
1485              prev_it->content_unfocusable =
1486                elm_widget_tree_unfocusable_get(prev_it->content);
1487              elm_widget_tree_unfocusable_set(prev_it->content, EINA_TRUE);
1488           }
1489
1490         it->animator = ecore_animator_add(_push_transition_cb, it);
1491      }
1492
1493    sd->stack = eina_inlist_append(sd->stack, EINA_INLIST_GET(it));
1494    evas_object_raise(VIEW(it));
1495
1496    /* access */
1497    if (_elm_config->access_mode) _access_focus_set(it);
1498
1499    elm_layout_sizing_eval(obj);
1500
1501    return (Elm_Object_Item *)it;
1502 }
1503
1504 EAPI Elm_Object_Item *
1505 elm_naviframe_item_insert_before(Evas_Object *obj,
1506                                  Elm_Object_Item *before,
1507                                  const char *title_label,
1508                                  Evas_Object *prev_btn,
1509                                  Evas_Object *next_btn,
1510                                  Evas_Object *content,
1511                                  const char *item_style)
1512 {
1513    Elm_Naviframe_Item *it, *prev_it = NULL;
1514
1515    ELM_NAVIFRAME_CHECK(obj) NULL;
1516    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(before, NULL);
1517    ELM_NAVIFRAME_DATA_GET(obj, sd);
1518
1519    it = (Elm_Naviframe_Item *)before;
1520    if (EINA_INLIST_GET(it)->prev)
1521      prev_it = EINA_INLIST_CONTAINER_GET(EINA_INLIST_GET(it)->prev,
1522                                          Elm_Naviframe_Item);
1523    it = _item_new(obj, prev_it,
1524                   title_label, prev_btn, next_btn, content, item_style);
1525    if (!it) return NULL;
1526
1527    sd->stack = eina_inlist_prepend_relative
1528        (sd->stack, EINA_INLIST_GET(it),
1529        EINA_INLIST_GET(((Elm_Naviframe_Item *)before)));
1530
1531    elm_layout_sizing_eval(obj);
1532
1533    return (Elm_Object_Item *)it;
1534 }
1535
1536 EAPI Elm_Object_Item *
1537 elm_naviframe_item_insert_after(Evas_Object *obj,
1538                                 Elm_Object_Item *after,
1539                                 const char *title_label,
1540                                 Evas_Object *prev_btn,
1541                                 Evas_Object *next_btn,
1542                                 Evas_Object *content,
1543                                 const char *item_style)
1544 {
1545    Elm_Naviframe_Item *it;
1546    Eina_Bool top_inserted = EINA_FALSE;
1547
1548    ELM_NAVIFRAME_CHECK(obj) NULL;
1549    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(after, NULL);
1550    ELM_NAVIFRAME_DATA_GET(obj, sd);
1551
1552    it = _item_new(obj, (Elm_Naviframe_Item *)after,
1553                   title_label, prev_btn, next_btn, content, item_style);
1554    if (!it) return NULL;
1555
1556    if (elm_naviframe_top_item_get(obj) == after) top_inserted = EINA_TRUE;
1557
1558    sd->stack = eina_inlist_append_relative
1559        (sd->stack, EINA_INLIST_GET(it),
1560        EINA_INLIST_GET(((Elm_Naviframe_Item *)after)));
1561
1562    if (top_inserted)
1563      {
1564         elm_widget_resize_object_set(obj, VIEW(it));
1565         evas_object_smart_member_add(sd->dummy_edje, obj);
1566         evas_object_show(VIEW(it));
1567         evas_object_hide(VIEW(after));
1568      }
1569
1570    /* access */
1571    if (_elm_config->access_mode) _access_focus_set(it);
1572
1573    elm_layout_sizing_eval(obj);
1574
1575    return (Elm_Object_Item *)it;
1576 }
1577
1578 EAPI Evas_Object *
1579 elm_naviframe_item_pop(Evas_Object *obj)
1580 {
1581    Elm_Naviframe_Item *it, *prev_it = NULL;
1582    Evas_Object *content = NULL;
1583
1584    ELM_NAVIFRAME_CHECK(obj) NULL;
1585    ELM_NAVIFRAME_DATA_GET(obj, sd);
1586
1587    it = (Elm_Naviframe_Item *)elm_naviframe_top_item_get(obj);
1588    if (!it) return NULL;
1589
1590    if (it->pop_cb) it->pop_cb(it->pop_data, (Elm_Object_Item *)it);
1591
1592    if (sd->preserve)
1593      content = it->content;
1594
1595    evas_object_data_set(VIEW(it), "out_of_list", (void *)1);
1596
1597    if (it->content)
1598      {
1599         it->content_unfocusable = elm_widget_tree_unfocusable_get(it->content);
1600         elm_widget_tree_unfocusable_set(it->content, EINA_TRUE);
1601      }
1602
1603    if (sd->stack->last->prev)
1604      prev_it = EINA_INLIST_CONTAINER_GET
1605          (sd->stack->last->prev, Elm_Naviframe_Item);
1606
1607    sd->stack = eina_inlist_remove(sd->stack, EINA_INLIST_GET(it));
1608    if (!sd->stack) elm_widget_resize_object_set(obj, sd->dummy_edje);
1609
1610    if (prev_it)
1611      {
1612         if (sd->freeze_events)
1613           {
1614              evas_object_freeze_events_set(VIEW(it), EINA_TRUE);
1615              evas_object_freeze_events_set(VIEW(prev_it), EINA_TRUE);
1616           }
1617
1618         elm_widget_resize_object_set(obj, VIEW(prev_it));
1619         evas_object_smart_member_add(sd->dummy_edje, obj);
1620         evas_object_raise(VIEW(prev_it));
1621
1622         /* access */
1623         if (_elm_config->access_mode) _access_focus_set(prev_it);
1624
1625         /* these 2 signals MUST take place simultaneously */
1626         elm_object_signal_emit(VIEW(it), "elm,state,cur,popped", "elm");
1627         evas_object_show(VIEW(prev_it));
1628         elm_object_signal_emit(VIEW(prev_it), "elm,state,prev,popped", "elm");
1629
1630         edje_object_message_signal_process(elm_layout_edje_get(VIEW(it)));
1631         edje_object_message_signal_process(elm_layout_edje_get(VIEW(prev_it)));
1632
1633         if (it->animator) ecore_animator_del(it->animator);
1634         it->animator = ecore_animator_add(_pop_transition_cb, it);
1635         sd->popping = eina_list_append(sd->popping, it);
1636      }
1637    else
1638      elm_widget_item_del(it);
1639
1640    return content;
1641 }
1642
1643 EAPI void
1644 elm_naviframe_item_pop_to(Elm_Object_Item *it)
1645 {
1646    Elm_Naviframe_Item *nit;
1647    Eina_Inlist *l, *prev_l;
1648
1649    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it);
1650
1651    nit = (Elm_Naviframe_Item *)it;
1652    ELM_NAVIFRAME_DATA_GET(WIDGET(nit), sd);
1653
1654    if (it == elm_naviframe_top_item_get(WIDGET(nit))) return;
1655
1656    l = sd->stack->last->prev;
1657
1658    sd->on_deletion = EINA_TRUE;
1659
1660    while (l)
1661      {
1662         Elm_Naviframe_Item *iit = EINA_INLIST_CONTAINER_GET
1663             (l, Elm_Naviframe_Item);
1664
1665         if (iit == nit) break;
1666
1667         prev_l = l->prev;
1668         sd->stack = eina_inlist_remove(sd->stack, l);
1669
1670         elm_widget_item_del(iit);
1671
1672         l = prev_l;
1673      }
1674
1675    sd->on_deletion = EINA_FALSE;
1676
1677    elm_naviframe_item_pop(WIDGET(nit));
1678 }
1679
1680 EAPI void
1681 elm_naviframe_item_promote(Elm_Object_Item *it)
1682 {
1683    Elm_Naviframe_Item *nit;
1684    Elm_Naviframe_Item *prev_it;
1685
1686    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it);
1687
1688    nit = (Elm_Naviframe_Item *)it;
1689    ELM_NAVIFRAME_DATA_GET(WIDGET(nit), sd);
1690
1691    if (it == elm_naviframe_top_item_get(WIDGET(nit))) return;
1692
1693    /* remember, last is 1st on the naviframe, push it to last pos. */
1694    sd->stack = eina_inlist_demote(sd->stack, EINA_INLIST_GET(nit));
1695
1696    elm_widget_resize_object_set(WIDGET(it), VIEW(nit));
1697    evas_object_smart_member_add(sd->dummy_edje, WIDGET(it));
1698
1699    /* this was the previous top one */
1700    prev_it = EINA_INLIST_CONTAINER_GET
1701        (sd->stack->last->prev, Elm_Naviframe_Item);
1702
1703    /* re-add as smart member */
1704    evas_object_smart_member_add(VIEW(prev_it), WIDGET(it));
1705
1706    if (prev_it->content)
1707      {
1708         prev_it->content_unfocusable =
1709           elm_widget_tree_unfocusable_get(prev_it->content);
1710         elm_widget_tree_unfocusable_set(prev_it->content, EINA_TRUE);
1711      }
1712
1713    if (sd->freeze_events)
1714      {
1715         evas_object_freeze_events_set(VIEW(it), EINA_TRUE);
1716         evas_object_freeze_events_set(VIEW(prev_it), EINA_TRUE);
1717      }
1718
1719    elm_object_signal_emit(VIEW(prev_it), "elm,state,cur,pushed", "elm");
1720
1721    evas_object_show(VIEW(nit));
1722    evas_object_raise(VIEW(nit));
1723
1724    elm_object_signal_emit(VIEW(nit), "elm,state,new,pushed", "elm");
1725
1726    edje_object_message_signal_process(elm_layout_edje_get(VIEW(prev_it)));
1727    edje_object_message_signal_process(elm_layout_edje_get(VIEW(nit)));
1728    if (nit->animator) ecore_animator_del(nit->animator);
1729    nit->animator = ecore_animator_add(_push_transition_cb, nit);
1730
1731    /* access */
1732    if (_elm_config->access_mode) _access_focus_set(nit);
1733 }
1734
1735 EAPI void
1736 elm_naviframe_item_simple_promote(Evas_Object *obj,
1737                                   Evas_Object *content)
1738 {
1739    Elm_Naviframe_Item *itr;
1740
1741    ELM_NAVIFRAME_CHECK(obj);
1742    ELM_NAVIFRAME_DATA_GET(obj, sd);
1743
1744    EINA_INLIST_FOREACH(sd->stack, itr)
1745      {
1746         if (elm_object_item_content_get((Elm_Object_Item *)itr) == content)
1747           {
1748              elm_naviframe_item_promote((Elm_Object_Item *)itr);
1749              break;
1750           }
1751      }
1752 }
1753
1754 EAPI void
1755 elm_naviframe_content_preserve_on_pop_set(Evas_Object *obj,
1756                                           Eina_Bool preserve)
1757 {
1758    ELM_NAVIFRAME_CHECK(obj);
1759    ELM_NAVIFRAME_DATA_GET(obj, sd);
1760
1761    sd->preserve = !!preserve;
1762 }
1763
1764 EAPI Eina_Bool
1765 elm_naviframe_content_preserve_on_pop_get(const Evas_Object *obj)
1766 {
1767    ELM_NAVIFRAME_CHECK(obj) EINA_FALSE;
1768    ELM_NAVIFRAME_DATA_GET(obj, sd);
1769
1770    return sd->preserve;
1771 }
1772
1773 EAPI Elm_Object_Item *
1774 elm_naviframe_top_item_get(const Evas_Object *obj)
1775 {
1776    ELM_NAVIFRAME_CHECK(obj) NULL;
1777    ELM_NAVIFRAME_DATA_GET(obj, sd);
1778
1779    if (!sd->stack) return NULL;
1780    return (Elm_Object_Item *)(EINA_INLIST_CONTAINER_GET
1781                                 (sd->stack->last, Elm_Naviframe_Item));
1782 }
1783
1784 EAPI Elm_Object_Item *
1785 elm_naviframe_bottom_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, Elm_Naviframe_Item));
1793 }
1794
1795 EAPI void
1796 elm_naviframe_item_style_set(Elm_Object_Item *it,
1797                              const char *item_style)
1798 {
1799    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
1800
1801    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it);
1802
1803    if (item_style && !strcmp(item_style, nit->style)) return;
1804
1805    if (!item_style)
1806      if (!strcmp("basic", nit->style)) return;
1807
1808    _item_style_set(nit, item_style);
1809    _item_signals_emit(nit);
1810    _item_title_visible_update(nit);
1811 }
1812
1813 EAPI const char *
1814 elm_naviframe_item_style_get(const Elm_Object_Item *it)
1815 {
1816    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
1817
1818    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it, NULL);
1819
1820    return nit->style;
1821 }
1822
1823 EAPI void
1824 elm_naviframe_item_title_visible_set(Elm_Object_Item *it,
1825                                      Eina_Bool visible)
1826 {
1827    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
1828
1829    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it);
1830
1831    visible = !!visible;
1832    if (nit->title_visible == visible) return;
1833
1834    nit->title_visible = visible;
1835    _item_title_visible_update(nit);
1836 }
1837
1838 EAPI Eina_Bool
1839 elm_naviframe_item_title_visible_get(const Elm_Object_Item *it)
1840 {
1841    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
1842
1843    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it, EINA_FALSE);
1844
1845    return nit->title_visible;
1846 }
1847
1848 EAPI void
1849 elm_naviframe_item_pop_cb_set(Elm_Object_Item *it, Elm_Naviframe_Item_Pop_Cb func, void *data)
1850 {
1851    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
1852
1853    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it);
1854
1855    nit->pop_cb = func;
1856    nit->pop_data = data;
1857 }
1858
1859 EAPI void
1860 elm_naviframe_prev_btn_auto_pushed_set(Evas_Object *obj,
1861                                        Eina_Bool auto_pushed)
1862 {
1863    ELM_NAVIFRAME_CHECK(obj);
1864    ELM_NAVIFRAME_DATA_GET(obj, sd);
1865
1866    sd->auto_pushed = !!auto_pushed;
1867 }
1868
1869 EAPI Eina_Bool
1870 elm_naviframe_prev_btn_auto_pushed_get(const Evas_Object *obj)
1871 {
1872    ELM_NAVIFRAME_CHECK(obj) EINA_FALSE;
1873    ELM_NAVIFRAME_DATA_GET(obj, sd);
1874
1875    return sd->auto_pushed;
1876 }
1877
1878 EAPI Eina_List *
1879 elm_naviframe_items_get(const Evas_Object *obj)
1880 {
1881    Eina_List *ret = NULL;
1882    Elm_Naviframe_Item *itr;
1883
1884    ELM_NAVIFRAME_CHECK(obj) NULL;
1885    ELM_NAVIFRAME_DATA_GET(obj, sd);
1886
1887    EINA_INLIST_FOREACH(sd->stack, itr)
1888      ret = eina_list_append(ret, itr);
1889
1890    return ret;
1891 }
1892
1893 EAPI void
1894 elm_naviframe_event_enabled_set(Evas_Object *obj,
1895                                 Eina_Bool enabled)
1896 {
1897    ELM_NAVIFRAME_CHECK(obj);
1898    ELM_NAVIFRAME_DATA_GET(obj, sd);
1899
1900    enabled = !!enabled;
1901    if (sd->freeze_events == !enabled) return;
1902    sd->freeze_events = !enabled;
1903 }
1904
1905 EAPI Eina_Bool
1906 elm_naviframe_event_enabled_get(const Evas_Object *obj)
1907 {
1908    ELM_NAVIFRAME_CHECK(obj) EINA_FALSE;
1909    ELM_NAVIFRAME_DATA_GET(obj, sd);
1910
1911    return !sd->freeze_events;
1912 }