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