[access] support back gesture
[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 Eina_Bool
1375 _elm_naviframe_smart_activate(Evas_Object *obj, Elm_Activate act)
1376 {
1377    Elm_Naviframe_Item *it;
1378
1379    if (act != ELM_ACTIVATE_BACK) return EINA_FALSE;
1380    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
1381
1382    it = (Elm_Naviframe_Item *)elm_naviframe_top_item_get(obj);
1383    if (!it) return EINA_FALSE;
1384
1385    if (it->title_prev_btn)
1386      evas_object_smart_callback_call(it->title_prev_btn, SIG_CLICKED, NULL);
1387
1388    return EINA_TRUE;
1389 }
1390
1391 static void
1392 _elm_naviframe_smart_set_user(Elm_Naviframe_Smart_Class *sc)
1393 {
1394    ELM_WIDGET_CLASS(sc)->base.add = _elm_naviframe_smart_add;
1395    ELM_WIDGET_CLASS(sc)->base.del = _elm_naviframe_smart_del;
1396
1397    ELM_WIDGET_CLASS(sc)->theme = _elm_naviframe_smart_theme;
1398    ELM_WIDGET_CLASS(sc)->focus_next = _elm_naviframe_smart_focus_next;
1399    ELM_WIDGET_CLASS(sc)->focus_direction = _elm_naviframe_smart_focus_direction;
1400    ELM_WIDGET_CLASS(sc)->access = _elm_naviframe_smart_access;
1401    ELM_WIDGET_CLASS(sc)->event = _elm_naviframe_smart_event;
1402    ELM_WIDGET_CLASS(sc)->activate = _elm_naviframe_smart_activate;
1403
1404    ELM_CONTAINER_CLASS(sc)->content_set = _elm_naviframe_smart_content_set;
1405    ELM_CONTAINER_CLASS(sc)->content_get = _elm_naviframe_smart_content_get;
1406    ELM_CONTAINER_CLASS(sc)->content_unset = _elm_naviframe_smart_content_unset;
1407
1408    ELM_LAYOUT_CLASS(sc)->signal = _elm_naviframe_smart_signal;
1409    ELM_LAYOUT_CLASS(sc)->callback_add = _elm_naviframe_smart_signal_callback_add;
1410    ELM_LAYOUT_CLASS(sc)->text_set = _elm_naviframe_smart_text_set;
1411    ELM_LAYOUT_CLASS(sc)->text_get = _elm_naviframe_smart_text_get;
1412    ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_naviframe_smart_sizing_eval;
1413 }
1414
1415 static Eina_Bool
1416 _push_transition_cb(void *data)
1417 {
1418    Elm_Naviframe_Item *prev_it, *it = data;
1419
1420    ELM_NAVIFRAME_DATA_GET(WIDGET(it), sd);
1421
1422    it->animator = NULL;
1423
1424    if (sd->stack->last->prev)
1425      {
1426         prev_it = EINA_INLIST_CONTAINER_GET(sd->stack->last->prev,
1427                                             Elm_Naviframe_Item);
1428         elm_object_signal_emit(VIEW(prev_it), "elm,state,cur,pushed,deferred",
1429                                 "elm");
1430         edje_object_message_signal_process(elm_layout_edje_get(VIEW(prev_it)));
1431      }
1432    elm_object_signal_emit(VIEW(it), "elm,state,new,pushed,deferred", "elm");
1433    edje_object_message_signal_process(elm_layout_edje_get(VIEW(it)));
1434
1435    return ECORE_CALLBACK_CANCEL;
1436 }
1437
1438 EAPI const Elm_Naviframe_Smart_Class *
1439 elm_naviframe_smart_class_get(void)
1440 {
1441    static Elm_Naviframe_Smart_Class _sc =
1442      ELM_NAVIFRAME_SMART_CLASS_INIT_NAME_VERSION
1443        (ELM_NAVIFRAME_SMART_NAME);
1444    static const Elm_Naviframe_Smart_Class *class = NULL;
1445    Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
1446
1447    if (class)
1448      return class;
1449
1450    _elm_naviframe_smart_set(&_sc);
1451    esc->callbacks = _smart_callbacks;
1452    class = &_sc;
1453
1454    return class;
1455 }
1456
1457 EAPI Evas_Object *
1458 elm_naviframe_add(Evas_Object *parent)
1459 {
1460    Evas_Object *obj;
1461
1462    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1463
1464    obj = elm_widget_add(_elm_naviframe_smart_class_new(), parent);
1465    if (!obj) return NULL;
1466
1467    if (!elm_widget_sub_object_add(parent, obj))
1468      ERR("could not add %p as sub object of %p", obj, parent);
1469
1470    _elm_widget_orient_signal_emit(obj);
1471
1472    return obj;
1473 }
1474
1475 EAPI Elm_Object_Item *
1476 elm_naviframe_item_push(Evas_Object *obj,
1477                         const char *title_label,
1478                         Evas_Object *prev_btn,
1479                         Evas_Object *next_btn,
1480                         Evas_Object *content,
1481                         const char *item_style)
1482 {
1483    Elm_Naviframe_Item *prev_it, *it;
1484
1485    ELM_NAVIFRAME_CHECK(obj) NULL;
1486
1487    ELM_NAVIFRAME_DATA_GET(obj, sd);
1488
1489    prev_it = (Elm_Naviframe_Item *)elm_naviframe_top_item_get(obj);
1490    it = _item_new(obj, prev_it,
1491                   title_label, prev_btn, next_btn, content, item_style);
1492    if (!it) return NULL;
1493
1494    evas_object_show(VIEW(it));
1495    elm_widget_resize_object_set(obj, VIEW(it));
1496    if (prev_it)
1497      elm_widget_sub_object_add(obj, VIEW(prev_it));
1498    evas_object_smart_member_add(sd->dummy_edje, obj);
1499
1500    if (prev_it)
1501      {
1502         /* re-add as smart member */
1503         evas_object_smart_member_add(VIEW(prev_it), obj);
1504
1505         if (sd->freeze_events)
1506           {
1507              evas_object_freeze_events_set(VIEW(it), EINA_TRUE);
1508              evas_object_freeze_events_set(VIEW(prev_it), EINA_TRUE);
1509           }
1510
1511         elm_object_signal_emit(VIEW(prev_it), "elm,state,cur,pushed", "elm");
1512         elm_object_signal_emit(VIEW(it), "elm,state,new,pushed", "elm");
1513         edje_object_message_signal_process(elm_layout_edje_get(VIEW(prev_it)));
1514         edje_object_message_signal_process(elm_layout_edje_get(VIEW(it)));
1515
1516         prev_it->unfocusable = elm_widget_tree_unfocusable_get(VIEW(prev_it));
1517         elm_widget_tree_unfocusable_set(VIEW(prev_it), EINA_TRUE);
1518
1519         it->animator = ecore_animator_add(_push_transition_cb, it);
1520      }
1521    else
1522      elm_object_focus_set(VIEW(it), EINA_TRUE);
1523
1524    sd->stack = eina_inlist_append(sd->stack, EINA_INLIST_GET(it));
1525    evas_object_raise(VIEW(it));
1526
1527    /* access */
1528    if (_elm_config->access_mode) _access_focus_set(it);
1529
1530    elm_layout_sizing_eval(obj);
1531
1532    return (Elm_Object_Item *)it;
1533 }
1534
1535 EAPI Elm_Object_Item *
1536 elm_naviframe_item_insert_before(Evas_Object *obj,
1537                                  Elm_Object_Item *before,
1538                                  const char *title_label,
1539                                  Evas_Object *prev_btn,
1540                                  Evas_Object *next_btn,
1541                                  Evas_Object *content,
1542                                  const char *item_style)
1543 {
1544    Elm_Naviframe_Item *it, *prev_it = NULL;
1545
1546    ELM_NAVIFRAME_CHECK(obj) NULL;
1547    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(before, NULL);
1548    ELM_NAVIFRAME_DATA_GET(obj, sd);
1549
1550    it = (Elm_Naviframe_Item *)before;
1551    if (EINA_INLIST_GET(it)->prev)
1552      prev_it = EINA_INLIST_CONTAINER_GET(EINA_INLIST_GET(it)->prev,
1553                                          Elm_Naviframe_Item);
1554    it = _item_new(obj, prev_it,
1555                   title_label, prev_btn, next_btn, content, item_style);
1556    if (!it) return NULL;
1557
1558    sd->stack = eina_inlist_prepend_relative
1559        (sd->stack, EINA_INLIST_GET(it),
1560        EINA_INLIST_GET(((Elm_Naviframe_Item *)before)));
1561
1562    elm_layout_sizing_eval(obj);
1563
1564    return (Elm_Object_Item *)it;
1565 }
1566
1567 EAPI Elm_Object_Item *
1568 elm_naviframe_item_insert_after(Evas_Object *obj,
1569                                 Elm_Object_Item *after,
1570                                 const char *title_label,
1571                                 Evas_Object *prev_btn,
1572                                 Evas_Object *next_btn,
1573                                 Evas_Object *content,
1574                                 const char *item_style)
1575 {
1576    Elm_Naviframe_Item *it;
1577    Eina_Bool top_inserted = EINA_FALSE;
1578
1579    ELM_NAVIFRAME_CHECK(obj) NULL;
1580    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(after, NULL);
1581    ELM_NAVIFRAME_DATA_GET(obj, sd);
1582
1583    it = _item_new(obj, (Elm_Naviframe_Item *)after,
1584                   title_label, prev_btn, next_btn, content, item_style);
1585    if (!it) return NULL;
1586
1587    if (elm_naviframe_top_item_get(obj) == after) top_inserted = EINA_TRUE;
1588
1589    sd->stack = eina_inlist_append_relative
1590        (sd->stack, EINA_INLIST_GET(it),
1591        EINA_INLIST_GET(((Elm_Naviframe_Item *)after)));
1592
1593    if (top_inserted)
1594      {
1595         elm_widget_resize_object_set(obj, VIEW(it));
1596         elm_widget_sub_object_add(obj, VIEW(after));
1597         evas_object_smart_member_add(sd->dummy_edje, obj);
1598         evas_object_show(VIEW(it));
1599         evas_object_hide(VIEW(after));
1600         elm_object_focus_set(VIEW(it), EINA_TRUE);
1601      }
1602
1603    /* access */
1604    if (_elm_config->access_mode) _access_focus_set(it);
1605
1606    elm_layout_sizing_eval(obj);
1607
1608    return (Elm_Object_Item *)it;
1609 }
1610
1611 EAPI Evas_Object *
1612 elm_naviframe_item_pop(Evas_Object *obj)
1613 {
1614    Elm_Naviframe_Item *it, *prev_it = NULL;
1615    Evas_Object *content = NULL;
1616
1617    ELM_NAVIFRAME_CHECK(obj) NULL;
1618    ELM_NAVIFRAME_DATA_GET(obj, sd);
1619
1620    it = (Elm_Naviframe_Item *)elm_naviframe_top_item_get(obj);
1621    if (!it) return NULL;
1622
1623    if (it->pop_cb) it->pop_cb(it->pop_data, (Elm_Object_Item *)it);
1624
1625    if (sd->preserve)
1626      content = it->content;
1627
1628    evas_object_data_set(VIEW(it), "out_of_list", (void *)1);
1629
1630    it->unfocusable = elm_widget_tree_unfocusable_get(VIEW(it));
1631    elm_widget_tree_unfocusable_set(VIEW(it), EINA_TRUE);
1632
1633    if (sd->stack->last->prev)
1634      prev_it = EINA_INLIST_CONTAINER_GET
1635          (sd->stack->last->prev, Elm_Naviframe_Item);
1636
1637    sd->stack = eina_inlist_remove(sd->stack, EINA_INLIST_GET(it));
1638    if (!sd->stack) elm_widget_resize_object_set(obj, sd->dummy_edje);
1639
1640    if (prev_it)
1641      {
1642         if (sd->freeze_events)
1643           {
1644              evas_object_freeze_events_set(VIEW(it), EINA_TRUE);
1645              evas_object_freeze_events_set(VIEW(prev_it), EINA_TRUE);
1646           }
1647
1648         elm_widget_resize_object_set(obj, VIEW(prev_it));
1649         evas_object_smart_member_add(sd->dummy_edje, obj);
1650         evas_object_raise(VIEW(prev_it));
1651
1652         /* access */
1653         if (_elm_config->access_mode) _access_focus_set(prev_it);
1654
1655         /* these 2 signals MUST take place simultaneously */
1656         elm_object_signal_emit(VIEW(it), "elm,state,cur,popped", "elm");
1657         evas_object_show(VIEW(prev_it));
1658         elm_object_signal_emit(VIEW(prev_it), "elm,state,prev,popped", "elm");
1659
1660         edje_object_message_signal_process(elm_layout_edje_get(VIEW(it)));
1661         edje_object_message_signal_process(elm_layout_edje_get(VIEW(prev_it)));
1662
1663         if (it->animator) ecore_animator_del(it->animator);
1664         it->animator = ecore_animator_add(_pop_transition_cb, it);
1665         sd->popping = eina_list_append(sd->popping, it);
1666      }
1667    else
1668      elm_widget_item_del(it);
1669
1670    return content;
1671 }
1672
1673 EAPI void
1674 elm_naviframe_item_pop_to(Elm_Object_Item *it)
1675 {
1676    Elm_Naviframe_Item *nit;
1677    Eina_Inlist *l, *prev_l;
1678
1679    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it);
1680
1681    nit = (Elm_Naviframe_Item *)it;
1682    ELM_NAVIFRAME_DATA_GET(WIDGET(nit), sd);
1683
1684    if (it == elm_naviframe_top_item_get(WIDGET(nit))) return;
1685
1686    l = sd->stack->last->prev;
1687
1688    sd->on_deletion = EINA_TRUE;
1689
1690    while (l)
1691      {
1692         Elm_Naviframe_Item *iit = EINA_INLIST_CONTAINER_GET
1693             (l, Elm_Naviframe_Item);
1694
1695         if (iit == nit) break;
1696
1697         prev_l = l->prev;
1698         sd->stack = eina_inlist_remove(sd->stack, l);
1699
1700         elm_widget_item_del(iit);
1701
1702         l = prev_l;
1703      }
1704
1705    sd->on_deletion = EINA_FALSE;
1706
1707    elm_naviframe_item_pop(WIDGET(nit));
1708 }
1709
1710 EAPI void
1711 elm_naviframe_item_promote(Elm_Object_Item *it)
1712 {
1713    Elm_Object_Item *prev_top;
1714    Elm_Naviframe_Item *nit;
1715    Elm_Naviframe_Item *prev_it;
1716
1717    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it);
1718
1719    nit = (Elm_Naviframe_Item *)it;
1720    ELM_NAVIFRAME_DATA_GET(WIDGET(nit), sd);
1721
1722    prev_top = elm_naviframe_top_item_get(WIDGET(nit));
1723    if (it == prev_top) return;
1724
1725    /* remember, last is 1st on the naviframe, push it to last pos. */
1726    sd->stack = eina_inlist_demote(sd->stack, EINA_INLIST_GET(nit));
1727
1728    elm_widget_resize_object_set(WIDGET(it), VIEW(nit));
1729    elm_widget_sub_object_add(WIDGET(it), VIEW(prev_top));
1730    evas_object_smart_member_add(sd->dummy_edje, WIDGET(it));
1731
1732    /* this was the previous top one */
1733    prev_it = EINA_INLIST_CONTAINER_GET
1734        (sd->stack->last->prev, Elm_Naviframe_Item);
1735
1736    /* re-add as smart member */
1737    evas_object_smart_member_add(VIEW(prev_it), WIDGET(it));
1738
1739    prev_it->unfocusable = elm_widget_tree_unfocusable_get(VIEW(prev_it));
1740    elm_widget_tree_unfocusable_set(prev_it->content, EINA_TRUE);
1741
1742    if (sd->freeze_events)
1743      {
1744         evas_object_freeze_events_set(VIEW(it), EINA_TRUE);
1745         evas_object_freeze_events_set(VIEW(prev_it), EINA_TRUE);
1746      }
1747
1748    elm_object_signal_emit(VIEW(prev_it), "elm,state,cur,pushed", "elm");
1749
1750    evas_object_show(VIEW(nit));
1751    evas_object_raise(VIEW(nit));
1752
1753    elm_object_signal_emit(VIEW(nit), "elm,state,new,pushed", "elm");
1754
1755    edje_object_message_signal_process(elm_layout_edje_get(VIEW(prev_it)));
1756    edje_object_message_signal_process(elm_layout_edje_get(VIEW(nit)));
1757    if (nit->animator) ecore_animator_del(nit->animator);
1758    nit->animator = ecore_animator_add(_push_transition_cb, nit);
1759
1760    /* access */
1761    if (_elm_config->access_mode) _access_focus_set(nit);
1762 }
1763
1764 EAPI void
1765 elm_naviframe_item_simple_promote(Evas_Object *obj,
1766                                   Evas_Object *content)
1767 {
1768    Elm_Naviframe_Item *itr;
1769
1770    ELM_NAVIFRAME_CHECK(obj);
1771    ELM_NAVIFRAME_DATA_GET(obj, sd);
1772
1773    EINA_INLIST_FOREACH(sd->stack, itr)
1774      {
1775         if (elm_object_item_content_get((Elm_Object_Item *)itr) == content)
1776           {
1777              elm_naviframe_item_promote((Elm_Object_Item *)itr);
1778              break;
1779           }
1780      }
1781 }
1782
1783 EAPI void
1784 elm_naviframe_content_preserve_on_pop_set(Evas_Object *obj,
1785                                           Eina_Bool preserve)
1786 {
1787    ELM_NAVIFRAME_CHECK(obj);
1788    ELM_NAVIFRAME_DATA_GET(obj, sd);
1789
1790    sd->preserve = !!preserve;
1791 }
1792
1793 EAPI Eina_Bool
1794 elm_naviframe_content_preserve_on_pop_get(const Evas_Object *obj)
1795 {
1796    ELM_NAVIFRAME_CHECK(obj) EINA_FALSE;
1797    ELM_NAVIFRAME_DATA_GET(obj, sd);
1798
1799    return sd->preserve;
1800 }
1801
1802 EAPI Elm_Object_Item *
1803 elm_naviframe_top_item_get(const Evas_Object *obj)
1804 {
1805    ELM_NAVIFRAME_CHECK(obj) NULL;
1806    ELM_NAVIFRAME_DATA_GET(obj, sd);
1807
1808    if (!sd->stack) return NULL;
1809    return (Elm_Object_Item *)(EINA_INLIST_CONTAINER_GET
1810                                 (sd->stack->last, Elm_Naviframe_Item));
1811 }
1812
1813 EAPI Elm_Object_Item *
1814 elm_naviframe_bottom_item_get(const Evas_Object *obj)
1815 {
1816    ELM_NAVIFRAME_CHECK(obj) NULL;
1817    ELM_NAVIFRAME_DATA_GET(obj, sd);
1818
1819    if (!sd->stack) return NULL;
1820    return (Elm_Object_Item *)(EINA_INLIST_CONTAINER_GET
1821                                 (sd->stack, Elm_Naviframe_Item));
1822 }
1823
1824 EAPI void
1825 elm_naviframe_item_style_set(Elm_Object_Item *it,
1826                              const char *item_style)
1827 {
1828    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
1829
1830    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it);
1831
1832    if (item_style && !strcmp(item_style, nit->style)) return;
1833
1834    if (!item_style)
1835      if (!strcmp("basic", nit->style)) return;
1836
1837    _item_style_set(nit, item_style);
1838    _item_signals_emit(nit);
1839    _item_title_visible_update(nit);
1840 }
1841
1842 EAPI const char *
1843 elm_naviframe_item_style_get(const Elm_Object_Item *it)
1844 {
1845    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
1846
1847    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it, NULL);
1848
1849    return nit->style;
1850 }
1851
1852 EAPI void
1853 elm_naviframe_item_title_visible_set(Elm_Object_Item *it,
1854                                      Eina_Bool visible)
1855 {
1856    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
1857
1858    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it);
1859
1860    visible = !!visible;
1861    if (nit->title_visible == visible) return;
1862
1863    nit->title_visible = visible;
1864    _item_title_visible_update(nit);
1865 }
1866
1867 EAPI Eina_Bool
1868 elm_naviframe_item_title_visible_get(const Elm_Object_Item *it)
1869 {
1870    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
1871
1872    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it, EINA_FALSE);
1873
1874    return nit->title_visible;
1875 }
1876
1877 EAPI void
1878 elm_naviframe_item_pop_cb_set(Elm_Object_Item *it, Elm_Naviframe_Item_Pop_Cb func, void *data)
1879 {
1880    Elm_Naviframe_Item *nit = (Elm_Naviframe_Item *)it;
1881
1882    ELM_NAVIFRAME_ITEM_CHECK_OR_RETURN(it);
1883
1884    nit->pop_cb = func;
1885    nit->pop_data = data;
1886 }
1887
1888 EAPI void
1889 elm_naviframe_prev_btn_auto_pushed_set(Evas_Object *obj,
1890                                        Eina_Bool auto_pushed)
1891 {
1892    ELM_NAVIFRAME_CHECK(obj);
1893    ELM_NAVIFRAME_DATA_GET(obj, sd);
1894
1895    sd->auto_pushed = !!auto_pushed;
1896 }
1897
1898 EAPI Eina_Bool
1899 elm_naviframe_prev_btn_auto_pushed_get(const Evas_Object *obj)
1900 {
1901    ELM_NAVIFRAME_CHECK(obj) EINA_FALSE;
1902    ELM_NAVIFRAME_DATA_GET(obj, sd);
1903
1904    return sd->auto_pushed;
1905 }
1906
1907 EAPI Eina_List *
1908 elm_naviframe_items_get(const Evas_Object *obj)
1909 {
1910    Eina_List *ret = NULL;
1911    Elm_Naviframe_Item *itr;
1912
1913    ELM_NAVIFRAME_CHECK(obj) NULL;
1914    ELM_NAVIFRAME_DATA_GET(obj, sd);
1915
1916    EINA_INLIST_FOREACH(sd->stack, itr)
1917      ret = eina_list_append(ret, itr);
1918
1919    return ret;
1920 }
1921
1922 EAPI void
1923 elm_naviframe_event_enabled_set(Evas_Object *obj,
1924                                 Eina_Bool enabled)
1925 {
1926    ELM_NAVIFRAME_CHECK(obj);
1927    ELM_NAVIFRAME_DATA_GET(obj, sd);
1928
1929    enabled = !!enabled;
1930    if (sd->freeze_events == !enabled) return;
1931    sd->freeze_events = !enabled;
1932 }
1933
1934 EAPI Eina_Bool
1935 elm_naviframe_event_enabled_get(const Evas_Object *obj)
1936 {
1937    ELM_NAVIFRAME_CHECK(obj) EINA_FALSE;
1938    ELM_NAVIFRAME_DATA_GET(obj, sd);
1939
1940    return !sd->freeze_events;
1941 }