elementary/naviframe - fixed internal memory leaks
[framework/uifw/elementary.git] / src / lib / elc_naviframe.c
index 11e0e42..32eb26b 100644 (file)
@@ -10,6 +10,7 @@ struct _Widget_Data
 {
    Eina_List    *stack;
    Evas_Object  *base;
+   Evas_Object  *rect;
    Eina_Bool     preserve: 1;
    Eina_Bool     pass_events: 1;
 };
@@ -79,6 +80,7 @@ static void _resize(void *data,
                     Evas *e,
                     Evas_Object *obj,
                     void *event_info);
+static void _hide(void *data, Evas *e, Evas_Object *obj, void *event_info);
 static void _title_clicked(void *data, Evas_Object *obj,
                            const char *emission,
                            const char *source);
@@ -136,7 +138,7 @@ _del_hook(Evas_Object *obj)
    wd = elm_widget_data_get(obj);
    if (!wd) return;
 
-   EINA_LIST_FOREACH(wd->stack, list, it)
+   EINA_LIST_REVERSE_FOREACH(wd->stack, list, it)
      _item_del(it);
    eina_list_free(wd->stack);
    free(wd);
@@ -184,24 +186,15 @@ _item_text_set_hook(Elm_Object_Item *it,
      snprintf(buf, sizeof(buf), "%s", part);
 
    EINA_LIST_FOREACH(navi_it->text_list, l, pair)
-     {
-        if (!strcmp(buf, pair->part))
-          {
-             if (pair->text)
-               {
-                  if (!strcmp(pair->text, label))
-                    return;
-               }
-             break;
-          }
-     }
+     if (!strcmp(buf, pair->part)) break;
 
    if (!pair)
      {
         pair = ELM_NEW(Elm_Naviframe_Text_Item_Pair);
         if (!pair)
           {
-             ERR("Failed to allocate new text part of the item! : naviframe=%p", navi_it->base.widget);
+             ERR("Failed to allocate new text part of the item! : naviframe=%p",
+             navi_it->base.widget);
              return;
           }
         eina_stringshare_replace(&pair->part, buf);
@@ -211,12 +204,16 @@ _item_text_set_hook(Elm_Object_Item *it,
    eina_stringshare_replace(&pair->text, label);
    edje_object_part_text_set(navi_it->base.view, buf, label);
 
-   snprintf(buf, sizeof(buf), "elm,state,%s,show", buf);
-
    if (label)
-     edje_object_signal_emit(navi_it->base.view, buf, "elm");
+     {
+        snprintf(buf, sizeof(buf), "elm,state,%s,show", buf);
+        edje_object_signal_emit(navi_it->base.view, buf, "elm");
+     }
    else
-     edje_object_signal_emit(navi_it->base.view, buf, "elm");
+     {
+        snprintf(buf, sizeof(buf), "elm,state,%s,hide", buf);
+        edje_object_signal_emit(navi_it->base.view, buf, "elm");
+     }
 
    _item_sizing_eval(navi_it);
 }
@@ -256,26 +253,24 @@ _item_content_set_hook(Elm_Object_Item *it,
    //specified parts
    if ((!part) || (!strcmp(part, "elm.swallow.content")))
      {
-       _item_content_set(navi_it, content);
-       return;
+        _item_content_set(navi_it, content);
+        return;
      }
    else if (!strcmp(part, "elm.swallow.prev_btn"))
      {
-       _title_prev_btn_set(navi_it, content, EINA_FALSE);
-       return;
+        _title_prev_btn_set(navi_it, content, EINA_FALSE);
+        return;
      }
    else if(!strcmp(part, "elm.swallow.next_btn"))
      {
-       _title_next_btn_set(navi_it, content);
-       return;
+        _title_next_btn_set(navi_it, content);
+        return;
      }
 
    //common part
    _title_content_set(navi_it, pair, part, content);
 }
 
-/*
-   */
 static Evas_Object *
 _item_content_get_hook(const Elm_Object_Item *it, const char *part)
 {
@@ -398,6 +393,13 @@ _move(void *data __UNUSED__,
       Evas_Object *obj,
       void *event_info __UNUSED__)
 {
+   Evas_Coord x, y;
+   Widget_Data *wd = elm_widget_data_get(obj);
+   if (!wd) return;
+
+   evas_object_geometry_get(obj, &x, &y, NULL, NULL);
+   evas_object_move(wd->rect, x, y);
+
    _sizing_eval(obj);
 }
 
@@ -407,10 +409,29 @@ _resize(void *data __UNUSED__,
         Evas_Object *obj,
         void *event_info __UNUSED__)
 {
+   Evas_Coord w, h;
+   Widget_Data *wd = elm_widget_data_get(obj);
+   if (!wd) return;
+
+   evas_object_geometry_get(obj, NULL, NULL, &w, &h);
+   evas_object_resize(wd->rect, w, h);
+
    _sizing_eval(obj);
 }
 
 static void
+_hide(void *data __UNUSED__,
+      Evas *e __UNUSED__,
+      Evas_Object *obj,
+      void *event_info __UNUSED__)
+{
+   Widget_Data *wd = elm_widget_data_get(obj);
+   if (!wd) return;
+   if (wd->pass_events)
+     evas_object_hide(wd->rect);
+}
+
+static void
 _title_clicked(void *data,
                Evas_Object *obj __UNUSED__,
                const char *emission __UNUSED__,
@@ -499,13 +520,7 @@ _title_content_set(Elm_Naviframe_Item *it,
    char buf[1024];
 
    EINA_LIST_FOREACH(it->content_list, l, pair)
-     {
-        if (!strcmp(part, pair->part))
-          {
-             if (pair->content == content) return;
-             break;
-          }
-     }
+     if (!strcmp(part, pair->part)) break;
 
    if (!pair)
      {
@@ -520,29 +535,38 @@ _title_content_set(Elm_Naviframe_Item *it,
         it->content_list = eina_list_append(it->content_list, pair);
      }
 
-   if (pair->content) evas_object_del(pair->content);
-   pair->content = content;
+   if ((pair->content) && (pair->content != content))
+     evas_object_del(pair->content);
 
    if (!content)
      {
         snprintf(buf, sizeof(buf), "elm,state,%s,hide", part);
         edje_object_signal_emit(it->base.view, buf, "elm");
+        pair->content = NULL;
         return;
      }
 
-   elm_widget_sub_object_add(it->base.widget, content);
+   if (pair->content != content)
+     {
+        elm_widget_sub_object_add(it->base.widget, content);
+        evas_object_event_callback_add(content,
+                                       EVAS_CALLBACK_DEL,
+                                       _title_content_del,
+                                       pair);
+     }
+
+   pair->content = content;
+
    edje_object_part_swallow(it->base.view, part, content);
    snprintf(buf, sizeof(buf), "elm,state,%s,show", part);
    edje_object_signal_emit(it->base.view, buf, "elm");
-   evas_object_event_callback_add(content,
-                                  EVAS_CALLBACK_DEL,
-                                  _title_content_del,
-                                  pair);
    _item_sizing_eval(it);
 }
 
 static void
-_title_prev_btn_set(Elm_Naviframe_Item *it, Evas_Object *btn, Eina_Bool back_btn)
+_title_prev_btn_set(Elm_Naviframe_Item *it,
+                    Evas_Object *btn,
+                    Eina_Bool back_btn)
 {
    if (it->title_prev_btn == btn) return;
 
@@ -603,26 +627,30 @@ _item_del(Elm_Naviframe_Item *it)
      evas_object_del(it->title_prev_btn);
    if (it->title_next_btn)
      evas_object_del(it->title_next_btn);
-      if ((it->content) && (!wd->preserve))
+   if ((it->content) && (!wd->preserve))
      evas_object_del(it->content);
 
    EINA_LIST_FOREACH(it->content_list, l, content_pair)
-     evas_object_del(content_pair->content);
+     {
+        evas_object_event_callback_del(content_pair->content, EVAS_CALLBACK_DEL, _title_content_del);
+        evas_object_del(content_pair->content);
+        eina_stringshare_del(content_pair->part);
+        free(content_pair);
+     }
 
    EINA_LIST_FOREACH(it->text_list, l, text_pair)
      {
         eina_stringshare_del(text_pair->part);
         eina_stringshare_del(text_pair->text);
+        free(text_pair);
      }
 
    eina_list_free(it->content_list);
    eina_list_free(it->text_list);
 
-   evas_object_del(it->base.view);
-
    wd->stack = eina_list_remove(wd->stack, it);
 
-   free(it);
+   elm_widget_item_del(it);
 }
 
 static void
@@ -663,7 +691,11 @@ _show_finished(void *data,
                                    SIG_TRANSITION_FINISHED,
                                    (void *) EINA_TRUE);
    if (wd->pass_events)
-     evas_object_pass_events_set(wd->base, EINA_FALSE);
+     {
+        evas_object_hide(wd->rect);
+        //FIXME:
+        evas_object_pass_events_set(wd->base, EINA_FALSE);
+     }
 }
 
 static void
@@ -672,7 +704,9 @@ _item_content_set(Elm_Naviframe_Item *navi_it, Evas_Object *content)
    if (navi_it->content == content) return;
    if (navi_it->content) evas_object_del(navi_it->content);
    elm_widget_sub_object_add(navi_it->base.widget, content);
-   edje_object_part_swallow(navi_it->base.view, "elm.swallow.content", content);
+   edje_object_part_swallow(navi_it->base.view,
+                            "elm.swallow.content",
+                            content);
    if (content)
      edje_object_signal_emit(navi_it->base.view,
                              "elm,state,content,show",
@@ -711,8 +745,14 @@ elm_naviframe_add(Evas_Object *parent)
    elm_widget_resize_object_set(obj, wd->base);
    _elm_theme_object_set(obj, wd->base, "naviframe", "base", "default");
 
+   //rect:
+   wd->rect = evas_object_rectangle_add(e);
+   evas_object_color_set(wd->rect, 0, 0, 0, 0);
+   elm_widget_sub_object_add(obj, wd->rect);
+
    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _move, obj);
    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize, obj);
+   evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _hide, obj);
    evas_object_smart_callbacks_descriptions_set(obj, _signals);
 
    wd->pass_events = EINA_TRUE;
@@ -721,7 +761,12 @@ elm_naviframe_add(Evas_Object *parent)
 }
 
 EAPI Elm_Object_Item *
-elm_naviframe_item_push(Evas_Object *obj, const char *title_label, Evas_Object *prev_btn, Evas_Object *next_btn, Evas_Object *content, const char *item_style)
+elm_naviframe_item_push(Evas_Object *obj,
+                        const char *title_label,
+                        Evas_Object *prev_btn,
+                        Evas_Object *next_btn,
+                        Evas_Object *content,
+                        const char *item_style)
 {
    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
    Widget_Data *wd;
@@ -790,7 +835,11 @@ elm_naviframe_item_push(Evas_Object *obj, const char *title_label, Evas_Object *
    if (prev_it)
      {
         if (wd->pass_events)
-          evas_object_pass_events_set(wd->base, EINA_TRUE);
+          {
+             evas_object_show(wd->rect);
+             //FIXME:
+             evas_object_pass_events_set(wd->base, EINA_TRUE);
+          }
         edje_object_signal_emit(prev_it->base.view,
                                 "elm,state,pushed",
                                 "elm");
@@ -827,13 +876,17 @@ elm_naviframe_item_pop(Evas_Object *obj)
    if (prev_it)
      {
         if (wd->pass_events)
-          evas_object_pass_events_set(wd->base, EINA_TRUE);
+          {
+             evas_object_show(wd->rect);
+             //FIXME:
+             evas_object_pass_events_set(wd->base, EINA_TRUE);
+          }
+        edje_object_signal_emit(it->base.view, "elm,state,popped", "elm");
         evas_object_show(prev_it->base.view);
         evas_object_raise(prev_it->base.view);
         edje_object_signal_emit(prev_it->base.view,
                                 "elm,state,show",
                                 "elm");
-        edje_object_signal_emit(it->base.view, "elm,state,popped", "elm");
      }
    else
      _item_del(it);
@@ -842,6 +895,29 @@ elm_naviframe_item_pop(Evas_Object *obj)
 }
 
 EAPI void
+elm_naviframe_item_pop_to(Elm_Object_Item *it)
+{
+   ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
+   Elm_Naviframe_Item *navi_it = ELM_CAST(it);
+   Widget_Data *wd = elm_widget_data_get(navi_it->base.widget);
+   Eina_List *l, *prev_l;
+
+   if (it == elm_naviframe_top_item_get(navi_it->base.widget)) return;
+
+   l = eina_list_last(wd->stack)->prev;
+
+   while(l)
+     {
+        if (l->data == it) break;
+        prev_l = l->prev;
+        _item_del(l->data);
+        wd->stack = eina_list_remove(wd->stack, l);
+        l = prev_l;
+     }
+   elm_naviframe_item_pop(navi_it->base.widget);
+}
+
+EAPI void
 elm_naviframe_content_preserve_on_pop_set(Evas_Object *obj, Eina_Bool preserve)
 {
    ELM_CHECK_WIDTYPE(obj, widtype);
@@ -882,6 +958,9 @@ elm_naviframe_item_style_set(Elm_Object_Item *it, const char *item_style)
 {
    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
    Elm_Naviframe_Item *navi_it = ELM_CAST(it);
+   Eina_List *l;
+   Elm_Naviframe_Content_Item_Pair *content_pair;
+   Elm_Naviframe_Text_Item_Pair *text_pair;
 
    char buf[256];
 
@@ -889,7 +968,8 @@ elm_naviframe_item_style_set(Elm_Object_Item *it, const char *item_style)
    else
      {
         if (strlen(item_style) > sizeof(buf))
-          WRN("too much long style name! : naviframe=%p", navi_it->base.widget);
+          WRN("too much long style name! : naviframe=%p",
+              navi_it->base.widget);
         else
           sprintf(buf, "item/%s", item_style);
      }
@@ -898,6 +978,38 @@ elm_naviframe_item_style_set(Elm_Object_Item *it, const char *item_style)
                          "naviframe",
                          buf,
                          elm_widget_style_get(navi_it->base.widget));
+   //recover item
+   EINA_LIST_FOREACH(navi_it->text_list, l, text_pair)
+     _item_text_set_hook(it, text_pair->part, text_pair->text);
+
+   EINA_LIST_FOREACH(navi_it->content_list, l, content_pair)
+     _item_content_set_hook(it, content_pair->part, content_pair->content);
+
+   //content
+   if (navi_it->content)
+     {
+        edje_object_part_swallow(navi_it->base.view,
+                                 "elm.swallow.content",
+                                 navi_it->content);
+        edje_object_signal_emit(navi_it->base.view,
+                                "elm,state,content,show",
+                                "elm");
+     }
+
+   //prev button
+   if (navi_it->title_prev_btn)
+     edje_object_part_swallow(navi_it->base.view,
+                              "elm.swallow.prev_btn",
+                              navi_it->title_prev_btn);
+
+   //next button
+   if (navi_it->title_next_btn)
+     edje_object_part_swallow(navi_it->base.view,
+                              "elm.swallow.next_btn",
+                              navi_it->title_next_btn);
+
+   navi_it->title_visible = EINA_TRUE;
+   _item_sizing_eval(navi_it);
 }
 
 EAPI const char *