forked from enlightenment/efl
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:
parent
3ca0135de1
commit
4607109531
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue