genlist: apply reusable content feature 68/94068/3 submit/tizen/20161101.043805 submit/tizen/20161101.045014
authorSangHyeon Lee <sh10233.lee@samsung.com>
Thu, 27 Oct 2016 05:31:51 +0000 (14:31 +0900)
committerGerrit Code Review <gerrit@review.vlan103.tizen.org>
Tue, 1 Nov 2016 03:58:33 +0000 (20:58 -0700)
Apply genlist item reusable content feature into tizen.
This patch is merged commit from upstream patches.

Change-Id: I88e411db28bb91833036afc2bed85adf8a2faa2f
Signed-off-by: SangHyeon Lee <sh10233.lee@samsung.com>
src/bin/test_genlist.c
src/lib/elm_gen.h
src/lib/elm_genlist.c
src/lib/elm_genlist_common.h
src/lib/elm_widget_genlist.h
src/mobile_lib/elm_genlist.c
src/mobile_lib/elm_genlist_common.h
src/mobile_lib/elm_widget_genlist.h

index d7e33de..62751ff 100644 (file)
@@ -213,6 +213,35 @@ Eina_Bool gl_state_get(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, con
    return EINA_FALSE;
 }
 
+Evas_Object *gl_reusable_content_get(void *data EINA_UNUSED, Evas_Object *obj, const char *part, Evas_Object *old)
+{
+   if (old && !strcmp(part, "elm.swallow.end"))
+     {
+        // Reuse old content
+        // Here need to add initializing and state changing
+        // for cached content.
+        // printf("content reuse for cached content %p, %s\n", old, part);
+        return old;
+     }
+   else
+     {
+        // Create new content object for non-reused part.
+        //printf("content create in reuse %p, %s\n", old, part);
+        char buf[PATH_MAX];
+        Evas_Object *ic = elm_icon_add(obj);
+        if (!strcmp(part, "elm.swallow.end"))
+          snprintf(buf, sizeof(buf), "%s/images/bubble.png", elm_app_data_dir_get());
+        else
+          snprintf(buf, sizeof(buf), "%s/images/logo_small.png", elm_app_data_dir_get());
+        elm_image_file_set(ic, buf, NULL);
+        evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
+        return ic;
+     }
+
+   // If return NULL value, content_get will be called to get new content.
+   // return NULL;
+}
+
 static void
 gl_sel(void *data, Evas_Object *obj, void *event_info)
 {
@@ -400,9 +429,12 @@ test_genlist(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_i
    api->itc1 = elm_genlist_item_class_new();
    api->itc1->item_style = "default";
    api->itc1->func.text_get = gl_text_get1;
-   api->itc1->func.content_get = gl_content_get;
+   api->itc1->func.content_get = NULL; // gl_content_get;
    api->itc1->func.state_get = gl_state_get;
    api->itc1->func.del = NULL;
+   // use content_reuse function for reusing
+   // repeated content objects instead of content_get
+   api->itc1->func.reusable_content_get = gl_reusable_content_get;
 
    bt_50 = elm_button_add(win);
    elm_object_text_set(bt_50, "Go to 50");
index a69c992..6d43429 100644 (file)
@@ -63,6 +63,19 @@ typedef void                          (*Elm_Gen_Item_Del_Cb)(void *data, Evas_Ob
  */
 typedef Eina_Bool                     (*Elm_Gen_Item_Filter_Get_Cb)(void *data, Evas_Object *obj, void *key); /**< Filter seeking class function for gen item classes. */
 
+/**
+ * Reusable content get class function for Elm_Gen_Item_Class.
+ * @param data The data passed in the item creation function
+ * @param obj The base widget object
+ * @param part The part name of the swallow
+ * @param old The old content object for reusing
+ * @return The content object to swallow
+ *
+ * @since 1.18
+ */
+typedef Evas_Object                  *(*Elm_Gen_Item_Reusable_Content_Get_Cb)(void *data, Evas_Object *obj, const char *part, Evas_Object *old); /**< Cache Pop class function for gen item classes. */
+
+
 struct _Elm_Gen_Item_Class
 {
    int           version;  /**< Set by elementary if you alloc an item class using elm_genlist/gengrid_item_class_new(), or if you set your own class (must be const) then set it to ELM_GENLIST/GENGRID_ITEM_CLASS_VERSION */
@@ -81,10 +94,11 @@ struct _Elm_Gen_Item_Class
         Elm_Gen_Item_State_Get_Cb   state_get; /**< State fetching class function for genlist/gengrid item classes. */
         Elm_Gen_Item_Del_Cb         del; /**< Deletion class function for genlist/gengrid item classes. */
         Elm_Gen_Item_Filter_Get_Cb  filter_get;  /**< Filter seeking class function for genlist/gengrid item classes. */
+        Elm_Gen_Item_Reusable_Content_Get_Cb  reusable_content_get;  /**< Reusable content get class function for gen item classes. */
      } func;
 }; /**< #Elm_Gen_Item_Class member definitions */
 
-#define ELM_GEN_ITEM_CLASS_VERSION 2
+#define ELM_GEN_ITEM_CLASS_VERSION 3
 #define ELM_GEN_ITEM_CLASS_HEADER ELM_GEN_ITEM_CLASS_VERSION, 0, 0
 
 typedef enum
index 9cad7f5..f3ac96c 100644 (file)
@@ -362,36 +362,42 @@ _item_content_realize(Elm_Gen_Item *it,
    Eina_Bool tmp;
    Evas_Object *content;
    char buf[256];
+   Eina_List *source;
+   const char *key;
 
    if (!parts)
      {
         EINA_LIST_FREE(*contents, content)
           evas_object_del(content);
      }
-   if (it->itc->func.content_get)
+   if ((!it->itc->func.content_get) &&
+      ((it->itc->version < 3) || (!it->itc->func.reusable_content_get))) return;
+
+   source = elm_widget_stringlist_get(edje_object_data_get(target, src));
+
+   EINA_LIST_FREE(source, key)
      {
-        Eina_List *source;
-        const char *key;
+        if (parts && fnmatch(parts, key, FNM_PERIOD))
+          continue;
 
-        source = elm_widget_stringlist_get(edje_object_data_get(target, src));
+        Evas_Object *old = NULL;
+        old = edje_object_part_swallow_get(target, key);
 
-        EINA_LIST_FREE(source, key)
+        // Reuse content by popping from the cache
+        content = NULL;
+        if (it->itc->func.reusable_content_get)
+          content = it->itc->func.reusable_content_get(
+             (void *)WIDGET_ITEM_DATA_GET(EO_OBJ(it)), WIDGET(it), key, old);
+        if (!content)
           {
-             if (parts && fnmatch(parts, key, FNM_PERIOD))
-               continue;
-
-             Evas_Object *old = edje_object_part_swallow_get(target, key);
-             if (old)
-               {
-                  *contents = eina_list_remove(*contents, old);
-                  evas_object_del(old);
-               }
-             content = NULL;
+             // Call the content get
              if (it->itc->func.content_get)
                content = it->itc->func.content_get
                   ((void *)WIDGET_ITEM_DATA_GET(EO_OBJ(it)), WIDGET(it), key);
-             if (!content) continue;
-
+             if (!content) goto out;
+          }
+        if (content != old)
+          {
              // FIXME: cause elm_layout sizing eval is delayed by smart calc,
              // genlist cannot get actual min size of edje.
              // This is workaround code to set min size directly.
@@ -406,27 +412,33 @@ _item_content_realize(Elm_Gen_Item *it,
                   evas_object_size_hint_min_set(content, minw, minh);
                }
 
-             *contents = eina_list_append(*contents, content);
-
              if (!edje_object_part_swallow(target, key, content))
                {
                   ERR("%s (%p) can not be swallowed into %s",
                       evas_object_type_get(content), content, key);
-                  evas_object_hide(content);
-                  continue;
+                  evas_object_del(content);
+                  goto out;
                }
              elm_widget_sub_object_add(WIDGET(it), content);
-             if (eo_do_ret(EO_OBJ(it), tmp, elm_wdg_item_disabled_get()))
-               elm_widget_disabled_set(content, EINA_TRUE);
+          }
+        *contents = eina_list_append(*contents, content);
 
-             snprintf(buf, sizeof(buf), "elm,state,%s,visible", key);
-             edje_object_signal_emit(target, buf, "elm");
+        if (eo_do_ret(EO_OBJ(it), tmp, elm_wdg_item_disabled_get()))
+          elm_widget_disabled_set(content, EINA_TRUE);
 
-             if (_elm_config->atspi_mode && eo_isa(content, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
-               {
-                  eo_do(content, elm_interface_atspi_accessible_parent_set(EO_OBJ(it)));
-                  elm_interface_atspi_accessible_children_changed_added_signal_emit(EO_OBJ(it), content);
-               }
+        snprintf(buf, sizeof(buf), "elm,state,%s,visible", key);
+        edje_object_signal_emit(target, buf, "elm");
+out:
+        if (old && content != old)
+          {
+             *contents = eina_list_remove(*contents, old);
+             evas_object_del(old);
+          }
+
+        if (_elm_config->atspi_mode && eo_isa(content, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
+          {
+             eo_do(content, elm_interface_atspi_accessible_parent_set(EO_OBJ(it)));
+             elm_interface_atspi_accessible_children_changed_added_signal_emit(EO_OBJ(it), content);
           }
      }
 }
@@ -577,8 +589,11 @@ _view_clear(Evas_Object *view, Eina_List **texts, Eina_List **contents)
      edje_object_part_text_set(view, part, NULL);
    ELM_SAFE_FREE(*texts, elm_widget_stringlist_free);
 
-   EINA_LIST_FREE(*contents, c)
-     evas_object_del(c);
+   if (contents)
+     {
+        EINA_LIST_FREE(*contents, c)
+           evas_object_del(c);
+     }
 }
 
 static void
@@ -662,7 +677,7 @@ _elm_genlist_item_unrealize(Elm_Gen_Item *it,
      eo_do(WIDGET(it), eo_event_callback_call(ELM_GENLIST_EVENT_UNREALIZED, EO_OBJ(it)));
    ELM_SAFE_FREE(it->long_timer, ecore_timer_del);
 
-   _view_clear(VIEW(it), &(it->texts), &(it->contents));
+   _view_clear(VIEW(it), &(it->texts), NULL);
    ELM_SAFE_FREE(it->item_focus_chain, eina_list_free);
 
    eo_do(EO_OBJ(it), elm_wdg_item_track_cancel());
@@ -1550,11 +1565,18 @@ _item_cache_pop(Elm_Genlist_Data *sd, Item_Cache *itc)
 static void
 _item_cache_free(Item_Cache *itc)
 {
+   Evas_Object *c;
+   const char *part;
+
    if (!itc) return;
 
    evas_object_del(itc->spacer);
    evas_object_del(itc->base_view);
-   eina_stringshare_del(itc->item_style);
+   itc->item_class = NULL;
+   EINA_LIST_FREE(itc->contents, c)
+     {
+        evas_object_del(c);
+     }
    ELM_SAFE_FREE(itc, free);
 }
 
@@ -1587,7 +1609,7 @@ _item_cache_zero(Elm_Genlist_Data *sd)
 
 // add an item to item cache
 static Eina_Bool
-_item_cache_add(Elm_Gen_Item *it)
+_item_cache_add(Elm_Gen_Item *it, Eina_List *contents)
 {
    if (it->item->nocache_once || it->item->nocache) return EINA_FALSE;
 
@@ -1611,7 +1633,8 @@ _item_cache_add(Elm_Gen_Item *it)
      }
    itc->spacer = it->spacer;
    itc->base_view = VIEW(it);
-   itc->item_style = eina_stringshare_add(it->itc->item_style);
+   itc->item_class = it->itc;
+   itc->contents = contents;
    if (it->item->type & ELM_GENLIST_ITEM_TREE)
      {
         itc->tree = 1;
@@ -1677,9 +1700,9 @@ _item_cache_find(Elm_Gen_Item *it)
    EINA_INLIST_FOREACH_SAFE(sd->item_cache, l, itc)
      {
         if ((itc->tree == tree) &&
-            (((!it->itc->item_style) && (!itc->item_style)) ||
-             (it->itc->item_style && itc->item_style &&
-              (!strcmp(it->itc->item_style, itc->item_style)))))
+            (((!it->itc) && (!itc->item_class)) ||
+             (it->itc && itc->item_class &&
+              (it->itc == itc->item_class))))
           {
              itc = _item_cache_pop(sd, itc);
              if (!itc) continue;
@@ -1689,6 +1712,8 @@ _item_cache_find(Elm_Gen_Item *it)
              itc->spacer = NULL;
              itc->base_view = NULL;
 
+             eina_list_free(itc->contents);
+             itc->contents = NULL;
              _item_cache_free(itc);
              return EINA_TRUE;
           }
@@ -1696,6 +1721,18 @@ _item_cache_find(Elm_Gen_Item *it)
    return EINA_FALSE;
 }
 
+static Eina_List *
+_content_cache_add(Elm_Gen_Item *it, Eina_List **cache)
+{
+   Evas_Object *content = NULL;
+   EINA_LIST_FREE(it->contents, content)
+     {
+        *cache = eina_list_append(*cache, content);
+     }
+
+   return *cache;
+}
+
 static char *
 _access_info_cb(void *data, Evas_Object *obj EINA_UNUSED)
 {
@@ -5171,10 +5208,12 @@ _decorate_item_finished_signal_cb(void *data,
 static void
 _item_unrealize(Elm_Gen_Item *it)
 {
-   Evas_Object *content;
+   Evas_Object *c;
+   Eina_List *cache = NULL;
    ELM_GENLIST_DATA_GET_FROM_ITEM(it, sd);
-   EINA_LIST_FREE(it->item->flip_contents, content)
-     evas_object_del(content);
+
+   EINA_LIST_FREE(it->item->flip_contents, c)
+     evas_object_del(c);
 
    /* access */
    if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
@@ -5192,10 +5231,14 @@ _item_unrealize(Elm_Gen_Item *it)
    _decorate_item_unrealize(it);
    if (GL_IT(it)->wsd->decorate_all_mode) _decorate_all_item_unrealize(it);
 
-   if (!_item_cache_add(it))
+   if (!_item_cache_add(it, _content_cache_add(it, &cache)))
      {
         ELM_SAFE_FREE(VIEW(it), evas_object_del);
         ELM_SAFE_FREE(it->spacer, evas_object_del);
+        EINA_LIST_FREE(cache, c)
+          {
+             evas_object_del(c);
+          }
      }
 
    it->states = NULL;
index 567ec89..dd2cdbf 100644 (file)
@@ -27,6 +27,11 @@ typedef Elm_Gen_Item_State_Get_Cb Elm_Genlist_Item_State_Get_Cb;
 typedef Elm_Gen_Item_Del_Cb Elm_Genlist_Item_Del_Cb;
 
 /**
+ * @see Elm_Gen_Item_Reusable_Content_Get_Cb
+ */
+typedef Elm_Gen_Item_Reusable_Content_Get_Cb Elm_Genlist_Reusable_Content_Get_Cb;
+
+/**
  * Create a new genlist item class in a given genlist widget.
  *
  * @return New allocated genlist item class.
index f9c4c83..d1cb5f8 100644 (file)
@@ -281,8 +281,9 @@ struct _Item_Cache
    EINA_INLIST;
 
    Evas_Object *base_view, *spacer;
-   const char  *item_style; // it->itc->item_style
+   const Elm_Genlist_Item_Class  *item_class; // it->itc
    Eina_Bool    tree : 1; // it->group
+   Eina_List   *contents; // content objects for reusing
 };
 
 struct _Item_Size
index 8e647cb..243db0c 100644 (file)
@@ -322,6 +322,39 @@ _banded_item_bg_index_color_set(Elm_Gen_Item *it_top, Evas_Coord ox, Evas_Coord
 #endif
 
 static void
+_item_content_free(Evas_Object *content)
+{
+   // FIXME: For animation, befor del, processing edc.
+   if (evas_object_smart_type_check(content, "elm_layout"))
+     edje_object_message_signal_process(elm_layout_edje_get(content));
+   // FIXME: If parent-child relationship was broken before 'ic'
+   // is deleted, freeze_pop will not be called. ex) elm_slider
+   // If layout is used instead of edje, this problme can be
+   // solved.
+   if (elm_widget_is(content) && (0 != elm_widget_scroll_freeze_get(content)))
+     elm_widget_scroll_freeze_pop(content);
+   evas_object_del(content);
+}
+
+static void
+_item_cache_free(Elm_Genlist_Data *sd, Item_Cache *ic)
+{
+   Evas_Object *c;
+   if (!ic) return;
+
+   if (ic->base_view) evas_object_del(ic->base_view);
+   ic->item_class = NULL;
+   EINA_LIST_FREE(ic->contents, c)
+     {
+        _item_content_free(c);
+     }
+   sd->item_cache = eina_inlist_remove(sd->item_cache, EINA_INLIST_GET(ic));
+   sd->item_cache_count--;
+   // Free should be performed after inlist is poped
+   free(ic);
+}
+
+static void
 _item_cache_all_free(Elm_Genlist_Data *sd)
 {
    // It would be better not to use
@@ -329,39 +362,34 @@ _item_cache_all_free(Elm_Genlist_Data *sd)
    while (sd->item_cache)
      {
         Item_Cache *ic = EINA_INLIST_CONTAINER_GET(sd->item_cache->last, Item_Cache);
-        if (ic->base_view) evas_object_del(ic->base_view);
-        if (ic->item_style) eina_stringshare_del(ic->item_style);
-        sd->item_cache = eina_inlist_remove(sd->item_cache, EINA_INLIST_GET(ic));
-        // Free should be performed after inlist is poped
-        free(ic);
+        _item_cache_free(sd, ic);
      }
    sd->item_cache = NULL;
    sd->item_cache_count = 0;
 }
 
 static void
-_item_cache_push(Elm_Gen_Item *it)
+_item_cache_push(Elm_Gen_Item *it, Eina_List *contents)
 {
    Elm_Genlist_Data *sd = GL_IT(it)->wsd;
    Item_Cache *ic = NULL;
+   Evas_Object *content;
 
    if (sd->no_cache)
      {
         if (VIEW(it)) evas_object_del(VIEW(it));
         VIEW(it) = NULL;
+        EINA_LIST_FREE(contents, content)
+          {
+             _item_content_free(content);
+          }
         return;
      }
 
    if (sd->item_cache_count >= sd->item_cache_max)
-    {
+     {
         ic = EINA_INLIST_CONTAINER_GET(sd->item_cache->last, Item_Cache);
-        if (ic->base_view) evas_object_del(ic->base_view);
-        eina_stringshare_del(ic->item_style);
-        sd->item_cache = eina_inlist_remove(sd->item_cache,
-                                            sd->item_cache->last);
-        sd->item_cache_count--;
-        // Free should be performed after inlist is poped
-        free(ic);
+        _item_cache_free(sd, ic);
      }
 
    ic = ELM_NEW(Item_Cache);
@@ -369,6 +397,10 @@ _item_cache_push(Elm_Gen_Item *it)
      {
         if (VIEW(it)) evas_object_del(VIEW(it));
         VIEW(it) = NULL;
+        EINA_LIST_FREE(contents, content)
+          {
+             _item_content_free(content);
+          }
         return;
      }
    // set item's state as default before pushing item into cache.
@@ -382,7 +414,8 @@ _item_cache_push(Elm_Gen_Item *it)
 
    ic->base_view = VIEW(it);
    ic->multiline = GL_IT(it)->multiline;
-   ic->item_style = eina_stringshare_add(it->itc->item_style);
+   ic->item_class = it->itc;
+   ic->contents = contents;
    evas_object_hide(ic->base_view);
 
    sd->item_cache = eina_inlist_prepend(sd->item_cache, EINA_INLIST_GET(ic));
@@ -398,12 +431,12 @@ _item_cache_pop(Elm_Gen_Item *it)
    Eina_Inlist *l;
    Elm_Genlist_Data *sd = GL_IT(it)->wsd;
 
-   if (!it->itc->item_style) return EINA_FALSE;
+   if (!it->itc) return EINA_FALSE;
 
    EINA_INLIST_FOREACH_SAFE(sd->item_cache, l, ic)
      {
-        if (ic->item_style &&
-            (!strcmp(it->itc->item_style, ic->item_style)))
+        if (it->itc && ic->item_class &&
+            (it->itc == ic->item_class))
           {
              sd->item_cache =
                 eina_inlist_remove(sd->item_cache, EINA_INLIST_GET(ic));
@@ -411,8 +444,9 @@ _item_cache_pop(Elm_Gen_Item *it)
 
              VIEW(it) = ic->base_view;
              GL_IT(it)->multiline = ic->multiline;
-             eina_stringshare_del(ic->item_style);
 
+             eina_list_free(ic->contents);
+             ic->contents = NULL;
              free(ic);
              return EINA_TRUE;
           }
@@ -420,6 +454,18 @@ _item_cache_pop(Elm_Gen_Item *it)
    return EINA_FALSE;
 }
 
+static Eina_List *
+_content_cache_add(Elm_Gen_Item *it, Eina_List **cache)
+{
+   Evas_Object *content = NULL;
+   EINA_LIST_FREE(it->content_objs, content)
+     {
+        *cache = eina_list_append(*cache, content);
+     }
+
+   return *cache;
+}
+
 // TIZEN_ONLY(20150828) : to prevent unnecessary genlist rendering
 // _changed is called instead of evas_object_smart_changed API.
 static void
@@ -667,107 +713,111 @@ _changed_size_hints(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSE
    _changed(GL_IT(it)->wsd->pan_obj);
 }
 
-static Eina_List *
+// FIXME: There are applications which do not use elm_win as top widget.
+// This is workaround! Those could not use focus!
+static Eina_Bool _focus_enabled(Evas_Object *obj)
+{
+   if (!elm_widget_focus_get(obj)) return EINA_FALSE;
+
+   const Evas_Object *win = elm_widget_top_get(obj);
+   const char *type = evas_object_type_get(win);
+
+   if (type && !strcmp(type, "elm_win"))
+     {
+        return elm_win_focus_highlight_enabled_get(win);
+     }
+   return EINA_FALSE;
+}
+
+static void
 _item_content_realize(Elm_Gen_Item *it,
                       Evas_Object *target,
-                      Eina_List *contents,
+                      Eina_List **contents,
                       const char *src,
                       const char *parts)
 {
+   Eina_Bool tmp;
+   Evas_Object *content;
    char buf[256];
+   Eina_List *source;
+   const char *key;
 
    if (!parts)
      {
-        Evas_Object *c;
-        EINA_LIST_FREE(contents, c)
-          {
-             // FIXME: For animation, befor del, processing edc.
-             if (evas_object_smart_type_check(c, "elm_layout"))
-               edje_object_message_signal_process(elm_layout_edje_get(c));
-             // FIXME: If parent-child relationship was broken before 'ic'
-             // is deleted, freeze_pop will not be called. ex) elm_slider
-             // If layout is used instead of edje, this problme can be
-             // solved.
-             if (elm_widget_is(c) && (0 != elm_widget_scroll_freeze_get(c)))
-               elm_widget_scroll_freeze_pop(c);
-             evas_object_del(c);
-          }
+        EINA_LIST_FREE(*contents, content)
+           _item_content_free(content);
      }
-   if (it->itc->func.content_get)
+   if ((!it->itc->func.content_get) &&
+      ((it->itc->version < 3) || (!it->itc->func.reusable_content_get))) return;
+
+   source = elm_widget_stringlist_get(edje_object_data_get(target, src));
+
+   EINA_LIST_FREE(source, key)
      {
-        const char *key;
         Evas_Object *ic = NULL;
-        Eina_List *source;
         Eina_Bool ret;
 
-        source = elm_widget_stringlist_get
-           (edje_object_data_get(target, src));
-
-        EINA_LIST_FREE(source, key)
-          {
-             if (parts && fnmatch(parts, key, FNM_PERIOD))
-               continue;
+        if (parts && fnmatch(parts, key, FNM_PERIOD))
+          continue;
 
-             Evas_Object *old = edje_object_part_swallow_get(target, key);
-             if (old)
-               {
-                  contents = eina_list_remove(contents, old);
-                  // FIXME: For animation, befor del, processing edc.
-                  if (evas_object_smart_type_check(old, "elm_layout"))
-                    edje_object_message_signal_process(elm_layout_edje_get(old));
-                  // FIXME: If parent-child relationship was broken before 'ic'
-                  // is deleted, freeze_pop will not be called. ex) elm_slider
-                  // If layout is used instead of edje, this problme can be
-                  // solved.
-                  if (elm_widget_is(old) && (0 != elm_widget_scroll_freeze_get(old)))
-                    elm_widget_scroll_freeze_pop(old);
-                  evas_object_del(old);
-               }
+        Evas_Object *old = NULL;
+        old = edje_object_part_swallow_get(target, key);
 
+        // Reuse content by popping from the cache
+        content = NULL;
+        if (it->itc->func.reusable_content_get)
+          content = it->itc->func.reusable_content_get(
+             (void *)WIDGET_ITEM_DATA_GET(EO_OBJ(it)), WIDGET(it), key, old);
+        if (!content)
+          {
+             // Call the content get
              if (it->itc->func.content_get)
-               ic = it->itc->func.content_get
+               content = it->itc->func.content_get
                    ((void *)WIDGET_ITEM_DATA_GET(EO_OBJ(it)), WIDGET(it), key);
-             if (ic)
+             if (!content) goto out;
+          }
+        if (content != old)
+          {
+             // FIXME: cause elm_layout sizing eval is delayed by smart calc,
+             // genlist cannot get actual min size of edje.
+             // This is workaround code to set min size directly.
+             if (eo_class_get(content) == ELM_LAYOUT_CLASS)
                {
-                  // TIZEN_ONLY(20150630): Add contents min height calculation for "full" style
-                  if (eo_class_get(ic) == ELM_LAYOUT_CLASS)
-                    {
-                       Evas_Coord minw, minh;
-
-                       edje_object_size_min_calc(elm_layout_edje_get(ic), &minw, &minh);
-                       evas_object_size_hint_min_set(ic, minw, minh);
-                    }
-                  // TIZEN_ONLY
+                  Evas_Coord old_w, old_h, minw = 0, minh = 0;
+                  evas_object_size_hint_min_get(content, &old_w, &old_h);
+                  edje_object_size_min_calc(elm_layout_edje_get(content), &minw, &minh);
 
-                  if (!edje_object_part_swallow(target, key, ic))
-                    {
-                      WRN("%s (%p) can not be swallowed into %s",
-                           evas_object_type_get(ic), ic, key);
-                       continue;
-                    }
-                  if (eo_do_ret(EO_OBJ(it), ret,  elm_wdg_item_disabled_get()))
-                    elm_widget_disabled_set(ic, EINA_TRUE);
-                  evas_object_show(ic);
-                  contents = eina_list_append(contents, ic);
+                  if (old_w > minw) minw = old_w;
+                  if (old_h > minh) minw = old_h;
+                  evas_object_size_hint_min_set(content, minw, minh);
+               }
+             if (!edje_object_part_swallow(target, key, content))
+               {
+                  ERR("%s (%p) can not be swallowed into %s",
+                      evas_object_type_get(content), content, key);
+                  evas_object_del(content);
+                  goto out;
+               }
+             elm_widget_sub_object_add(WIDGET(it), content);
+          }
+        *contents = eina_list_append(*contents, content);
 
-                  if (GL_IT(it)->wsd->realization_mode)
-                    {
-                       evas_object_event_callback_add
-                          (ic, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
-                           _changed_size_hints, it);
-                    }
+        if (eo_do_ret(EO_OBJ(it), tmp, elm_wdg_item_disabled_get()))
+          elm_widget_disabled_set(content, EINA_TRUE);
 
-                  snprintf(buf, sizeof(buf), "elm,state,%s,visible", key);
-                  edje_object_signal_emit(target, buf, "elm");
-               }
+        snprintf(buf, sizeof(buf), "elm,state,%s,visible", key);
+        edje_object_signal_emit(target, buf, "elm");
+out:
+        if (old && content != old)
+          {
+             *contents = eina_list_remove(*contents, old);
+             _item_content_free(old);
           }
      }
 
 #ifndef TIZEN_PROFILE_WEARABLE
    _banded_item_bg_add(it, target);
 #endif
-
-   return contents;
 }
 
 static void
@@ -880,18 +930,11 @@ _view_clear(Evas_Object *view, Eina_List **contents)
      (edje_object_data_get(view, "texts"));
    EINA_LIST_FREE(texts, part)
      edje_object_part_text_set(view, part, NULL);
-   EINA_LIST_FREE(*contents, c)
+
+   if (contents)
      {
-        // FIXME: For animation, befor del, processing edc.
-        if (evas_object_smart_type_check(c, "elm_layout"))
-          edje_object_message_signal_process(elm_layout_edje_get(c));
-        // FIXME: If parent-child relationship was broken before 'ic'
-        // is deleted, freeze_pop will not be called. ex) elm_slider
-        // If layout is used instead of edje, this problme can be
-        // solved.
-        if (elm_widget_is(c) && (0 != elm_widget_scroll_freeze_get(c)))
-          elm_widget_scroll_freeze_pop(c);
-        evas_object_del(c);
+        EINA_LIST_FREE(*contents, c)
+           _item_content_free(c);
      }
 }
 
@@ -900,8 +943,7 @@ _view_inflate(Evas_Object *view, Elm_Gen_Item *it, Eina_List **contents)
 {
    if (!view) return;
    _item_text_realize(it, view, NULL);
-   *contents = _item_content_realize(it, view, *contents,
-                                     "contents", NULL);
+   if (contents) _item_content_realize(it, view, contents, "contents", NULL);
    _item_state_realize(it, view, NULL);
 }
 
@@ -1070,6 +1112,7 @@ _item_unrealize(Elm_Gen_Item *it,
                 Eina_Bool calc)
 {
    Evas_Object *content;
+   Eina_List *cache = NULL;
 
    if (!it->realized) return;
 
@@ -1110,7 +1153,7 @@ _item_unrealize(Elm_Gen_Item *it,
    EINA_LIST_FREE(GL_IT(it)->flip_content_objs, content)
     evas_object_del(content);
    if (it->spacer) evas_object_del(it->spacer);
-   _view_clear(VIEW(it), &(it->content_objs));
+   _view_clear(VIEW(it), NULL);
 
 // TIZEN ONLY : for banded ux
 #ifndef TIZEN_PROFILE_WEARABLE
@@ -1139,7 +1182,9 @@ _item_unrealize(Elm_Gen_Item *it,
    if (it->base->color_classes)
      edje_object_color_class_clear(VIEW(it));
 //
-   _item_cache_push(it);
+   _item_cache_push(it, _content_cache_add(it, &cache));
+
+
    it->realized = EINA_FALSE;
 }
 
@@ -1568,9 +1613,8 @@ _item_realize(Elm_Gen_Item *it,
      edje_object_signal_emit(VIEW(it), SIGNAL_BG_CHANGE, "elm");
    if (it->flipped)
      {
-        GL_IT(it)->flip_content_objs =
-           _item_content_realize(it, VIEW(it), GL_IT(it)->flip_content_objs,
-                                 "flips", NULL);
+        _item_content_realize(it, VIEW(it), &GL_IT(it)->flip_contents,
+                              "flips", NULL);
         edje_object_signal_emit(VIEW(it), SIGNAL_FLIP_ENABLED, "elm");
      }
 
@@ -4988,9 +5032,8 @@ _item_update(Elm_Gen_Item *it)
    _view_inflate(VIEW(it), it, &(it->content_objs));
    if (it->flipped)
      {
-        GL_IT(it)->flip_content_objs =
-           _item_content_realize(it, VIEW(it), GL_IT(it)->flip_content_objs,
-                                 "flips", NULL);
+        _item_content_realize(it, VIEW(it), &(GL_IT(it)->flip_content_objs),
+                               "flips", NULL);
         edje_object_signal_emit(VIEW(it), SIGNAL_FLIP_ENABLED, "elm");
      }
    if (GL_IT(it)->wsd->decorate_all_mode)
@@ -5653,7 +5696,7 @@ _elm_genlist_elm_widget_atspi(Eo *obj EINA_UNUSED, Elm_Genlist_Data *sd, Eina_Bo
                     {
                        elm_interface_atspi_accessible_added(EO_OBJ(it));
                        elm_interface_atspi_accessible_children_changed_added_signal_emit(sd->obj, EO_OBJ(it));
-                       EINA_LIST_FOREACH(it->contents, l, content)
+                       EINA_LIST_FOREACH(it->content_objs, l, content)
                          {
                             if (eo_isa(content, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
                               {
@@ -6918,27 +6961,23 @@ _elm_genlist_item_fields_update(Eo *eo_item EINA_UNUSED, Elm_Gen_Item *it,
      }
    if ((!itf) || (itf & ELM_GENLIST_ITEM_FIELD_CONTENT))
      {
-        it->content_objs = _item_content_realize
-           (it, VIEW(it), it->content_objs, "contents", parts);
+        _item_content_realize(it, VIEW(it), &it->content_objs, "contents", parts);
         if (it->flipped)
           {
-             GL_IT(it)->flip_content_objs =
-               _item_content_realize(it, VIEW(it), GL_IT(it)->flip_content_objs,
+              _item_content_realize(it, VIEW(it), &GL_IT(it)->flip_content_objs,
                                      "flips", parts);
           }
         if (GL_IT(it)->deco_it_view)
           {
-             GL_IT(it)->deco_it_contents =
-               _item_content_realize(it, GL_IT(it)->deco_it_view,
-                                     GL_IT(it)->deco_it_contents,
-                                     "contents", parts);
+             _item_content_realize(it, GL_IT(it)->deco_it_view,
+                                   &GL_IT(it)->deco_it_contents,
+                                   "contents", parts);
           }
         if (GL_IT(it)->wsd->decorate_all_mode)
           {
-             GL_IT(it)->deco_all_contents =
-               _item_content_realize(it, it->deco_all_view,
-                                     GL_IT(it)->deco_all_contents,
-                                     "contents", parts);
+             _item_content_realize(it, it->deco_all_view,
+                                   &GL_IT(it)->deco_all_contents,
+                                   "contents", parts);
           }
      }
 
@@ -7878,8 +7917,7 @@ _elm_genlist_item_flip_set(Eo *eo_it EINA_UNUSED, Elm_Gen_Item *it, Eina_Bool fl
 
    if (it->flipped)
      {
-        GL_IT(it)->flip_content_objs =
-           _item_content_realize(it, VIEW(it), GL_IT(it)->flip_content_objs,
+        _item_content_realize(it, VIEW(it), &GL_IT(it)->flip_content_objs,
                                  "flips", NULL);
 
         edje_object_signal_emit(VIEW(it), SIGNAL_FLIP_ENABLED, "elm");
index e1f2cf1..76f6ee8 100644 (file)
@@ -69,6 +69,12 @@ typedef Elm_Gen_Item_State_Get_Cb Elm_Genlist_Item_State_Get_Cb;
 typedef Elm_Gen_Item_Del_Cb Elm_Genlist_Item_Del_Cb;
 
 /**
+ * @see Elm_Gen_Item_Reusable_Content_Get_Cb
+ */
+typedef Elm_Gen_Item_Reusable_Content_Get_Cb Elm_Genlist_Reusable_Content_Get_Cb;
+
+
+/**
  * @brief Create a new genlist item class in a given genlist widget.
  *
  * @details This adds genlist item class for the genlist widget.
index 53e2270..43ab80a 100644 (file)
@@ -312,12 +312,13 @@ struct _Item_Cache
 
    Evas_Object *base_view, *spacer;
 
-   const char  *item_style; // it->itc->item_style
+   const Elm_Genlist_Item_Class  *item_class; // it->itc
    Eina_Bool    multiline;
    Eina_Bool    selected : 1; // it->selected
    Eina_Bool    disabled : 1; // it->disabled
    Eina_Bool    expanded : 1; // it->item->expanded
    Eina_Bool    tree : 1; // it->group
+   Eina_List   *contents; // content objects for reusing
 };
 
 typedef struct _Elm_Genlist_Pan_Data Elm_Genlist_Pan_Data;