cedric pushed a commit to branch master.

http://git.enlightenment.org/core/elementary.git/commit/?id=4c86a66f28876b68e92a90c8f741eed1130dd034

commit 4c86a66f28876b68e92a90c8f741eed1130dd034
Author: SangHyeon Lee <sh10233....@samsung.com>
Date:   Fri Feb 12 20:14:13 2016 +0100

    genlist: add reusable_content_get item class function for support 
automatical content reusing in genlist.
    
    Summary:
       Add new Item Class function reusable_content_get for improve genlist
       performance.
       If user want to reuse specific part contents, return old content
       which was passed by parameter of rreusable_content_get function.
       genlist will automatically caching those contents when item unrealized,
       and reusing it on item realizing.
    
       reusable_content_get will be performed content_get with old object 
caching.
       But if user return NULL in reusable_content_get, content_get is called to
       get new object.
    
       This feature is refered in Task T2813
    
       @feature
    
    Test Plan: add test in genlist 1 case.
    
    Reviewers: raster, singh.amitesh, cedric
    
    Reviewed By: cedric
    
    Subscribers: smohanty, seoz, woohyun, Hermet, eagleeye
    
    Differential Revision: https://phab.enlightenment.org/D3252
    
    Signed-off-by: Cedric BAIL <ced...@osg.samsung.com>
---
 src/bin/test_genlist.c       |  34 +++++++++++-
 src/lib/elm_gen.h            |  12 ++++
 src/lib/elm_general.eot      |   3 +
 src/lib/elm_genlist.c        | 128 +++++++++++++++++++++++++++++--------------
 src/lib/elm_genlist_common.h |   5 ++
 src/lib/elm_widget_genlist.h |   1 +
 6 files changed, 140 insertions(+), 43 deletions(-)

diff --git a/src/bin/test_genlist.c b/src/bin/test_genlist.c
index ff64002..483199d 100644
--- a/src/bin/test_genlist.c
+++ b/src/bin/test_genlist.c
@@ -212,6 +212,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)
 {
@@ -392,9 +421,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");
diff --git a/src/lib/elm_gen.h b/src/lib/elm_gen.h
index 8c1ce84..08d6eb4 100644
--- a/src/lib/elm_gen.h
+++ b/src/lib/elm_gen.h
@@ -43,5 +43,17 @@ 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. */
+
 #define ELM_GEN_ITEM_CLASS_VERSION 2
 #define ELM_GEN_ITEM_CLASS_HEADER ELM_GEN_ITEM_CLASS_VERSION, 0, 0
diff --git a/src/lib/elm_general.eot b/src/lib/elm_general.eot
index 68e7e16..955ca6c 100644
--- a/src/lib/elm_general.eot
+++ b/src/lib/elm_general.eot
@@ -18,6 +18,9 @@ struct Elm.Gen.Item.Class.Functions
                                 item classes. ]]
    filter_get: Elm_Gen_Item_Filter_Get_Cb;  [[ Filter seeking class function 
for
                                                genlist/gengrid item classes. ]]
+   reusable_content_get: Elm_Gen_Item_Reusable_Content_Get_Cb; [[ Reusable 
content get class
+                                                                  function for 
gen item classes. ]]
+
 }
 
 struct Elm.Gen.Item.Class
diff --git a/src/lib/elm_genlist.c b/src/lib/elm_genlist.c
index 4848ebb..742c385 100644
--- a/src/lib/elm_genlist.c
+++ b/src/lib/elm_genlist.c
@@ -365,7 +365,7 @@ _item_content_realize(Elm_Gen_Item *it,
         EINA_LIST_FREE(*contents, content)
           evas_object_del(content);
      }
-   if (it->itc->func.content_get)
+   if (it->itc->func.content_get || it->itc->func.reusable_content_get)
      {
         Eina_List *source;
         const char *key;
@@ -377,46 +377,61 @@ _item_content_realize(Elm_Gen_Item *it,
              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);
-               }
+             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.content_get)
-               content = it->itc->func.content_get
-                  ((void *)WIDGET_ITEM_DATA_GET(EO_OBJ(it)), WIDGET(it), key);
-             if (!content) continue;
-
-             // 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)
+             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)
                {
-                  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 (old_w > minw) minw = old_w;
-                  if (old_h > minh) minw = old_h;
-                  evas_object_size_hint_min_set(content, minw, minh);
+                  // 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;
                }
 
-             *contents = eina_list_append(*contents, content);
-             if (!edje_object_part_swallow(target, key, content))
+             if (content != old)
                {
-                  ERR("%s (%p) can not be swallowed into %s",
-                      evas_object_type_get(content), content, key);
-                  evas_object_hide(content);
-                  continue;
+                  // 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)
+                    {
+                       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 (old_w > minw) minw = old_w;
+                       if (old_h > minh) minw = old_h;
+                       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;
+                    }
+                  elm_widget_sub_object_add(WIDGET(it), content);
                }
-             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);
 
              snprintf(buf, sizeof(buf), "elm,state,%s,visible", key);
              edje_object_signal_emit(target, buf, "elm");
+
+             if (old && content != old)
+               {
+                  *contents = eina_list_remove(*contents, old);
+                  evas_object_del(old);
+               }
           }
      }
 }
@@ -544,8 +559,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
@@ -626,7 +644,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());
@@ -1306,8 +1324,7 @@ _elm_genlist_item_state_update(Elm_Gen_Item *it)
 }
 
 static void
-_view_inflate(Evas_Object *view, Elm_Gen_Item *it, Eina_List **sources,
-              Eina_List **contents)
+_view_inflate(Evas_Object *view, Elm_Gen_Item *it, Eina_List **sources, 
Eina_List **contents)
 {
    if (!view) return;
    if (sources) _item_text_realize(it, view, sources, NULL);
@@ -1487,11 +1504,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);
+   EINA_LIST_FREE(itc->contents, c)
+     {
+        evas_object_del(c);
+     }
    ELM_SAFE_FREE(itc, free);
 }
 
@@ -1524,7 +1548,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;
 
@@ -1549,6 +1573,7 @@ _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->contents = contents;
    if (it->item->type & ELM_GENLIST_ITEM_TREE)
      {
         itc->tree = 1;
@@ -1622,7 +1647,8 @@ _item_cache_find(Elm_Gen_Item *it)
              VIEW(it) = itc->base_view;
              itc->spacer = NULL;
              itc->base_view = NULL;
-
+             eina_list_free(itc->contents);
+             itc->contents = NULL;
              _item_cache_free(itc);
              return EINA_TRUE;
           }
@@ -1630,6 +1656,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)
 {
@@ -4212,7 +4250,7 @@ _item_mouse_down_cb(void *data,
    else sd->on_hold = EINA_FALSE;
    if (sd->on_hold) return;
    sd->wasselected = it->selected;
-   
+
    ecore_timer_del(it->item->swipe_timer);
    it->item->swipe_timer = ecore_timer_add(SWIPE_TIME, _swipe_cancel, it);
    ELM_SAFE_FREE(it->long_timer, ecore_timer_del);
@@ -5074,9 +5112,11 @@ _decorate_item_finished_signal_cb(void *data,
 static void
 _item_unrealize(Elm_Gen_Item *it)
 {
-   Evas_Object *content;
-   EINA_LIST_FREE(it->item->flip_contents, content)
-     evas_object_del(content);
+   Evas_Object *c;
+   Eina_List *cache = NULL;
+
+   EINA_LIST_FREE(it->item->flip_contents, c)
+     evas_object_del(c);
 
    /* access */
    if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
@@ -5086,10 +5126,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;
diff --git a/src/lib/elm_genlist_common.h b/src/lib/elm_genlist_common.h
index 094e1eb..c2a2ee1 100644
--- a/src/lib/elm_genlist_common.h
+++ b/src/lib/elm_genlist_common.h
@@ -26,6 +26,11 @@ typedef Elm_Gen_Item_Del_Cb Elm_Genlist_Item_Del_Cb;
 typedef Elm_Gen_Item_Filter_Get_Cb Elm_Genlist_Item_Filter_Get_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.
diff --git a/src/lib/elm_widget_genlist.h b/src/lib/elm_widget_genlist.h
index 8107e20..bf06755 100644
--- a/src/lib/elm_widget_genlist.h
+++ b/src/lib/elm_widget_genlist.h
@@ -278,6 +278,7 @@ struct _Item_Cache
    Evas_Object *base_view, *spacer;
    const char  *item_style; // it->itc->item_style
    Eina_Bool    tree : 1; // it->group
+   Eina_List   *contents; // content objects for reusing
 };
 
 struct _Item_Size

-- 


Reply via email to