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 <cedric@osg.samsung.com>
This commit is contained in:
SangHyeon Lee 2016-02-12 20:14:13 +01:00 committed by Cedric BAIL
parent 3ca0135de1
commit 4607109531
6 changed files with 140 additions and 43 deletions

View File

@ -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");

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -25,6 +25,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.
*

View File

@ -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