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