forked from enlightenment/efl
improve genlist item realize/nrealize by almost 2x. (4.7->2.7 sec for
processing of a genlist queue of 20,000 items). added genlist item cache to do this. yay!. also wil improve runtime scrolling - realiz/unrealize will be also equivalently faster, so less add/del overhead for the edje objects in gnelist itself. the icons that apps swallow in still get deleted and created. this is another matter for anothr day. ant be solved inside of genlist itself. probably need an unrealize callback per item and a way to steal your icons back from the item. SVN revision: 54214
This commit is contained in:
parent
8e67572fad
commit
a43c1d9ed1
|
@ -153,7 +153,7 @@ test_genlist(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_inf
|
|||
evas_object_show(bt_1500);
|
||||
elm_box_pack_end(bx, bt_1500);
|
||||
|
||||
for (i = 0; i < 2000; i++)
|
||||
for (i = 0; i < 20000; i++)
|
||||
{
|
||||
gli = elm_genlist_item_append(gl, &itc1,
|
||||
(void *)(long)i/* item data */,
|
||||
|
|
|
@ -244,6 +244,7 @@
|
|||
typedef struct _Widget_Data Widget_Data;
|
||||
typedef struct _Item_Block Item_Block;
|
||||
typedef struct _Pan Pan;
|
||||
typedef struct _Item_Cache Item_Cache;
|
||||
|
||||
struct _Widget_Data
|
||||
{
|
||||
|
@ -256,6 +257,7 @@ struct _Widget_Data
|
|||
Eina_List *queue, *selected;
|
||||
Elm_Genlist_Item *show_item;
|
||||
Elm_Genlist_Item *last_selected_item;
|
||||
Eina_Inlist *item_cache;
|
||||
Elm_List_Mode mode;
|
||||
Eina_Bool on_hold : 1;
|
||||
Eina_Bool multi : 1;
|
||||
|
@ -272,6 +274,8 @@ struct _Widget_Data
|
|||
struct {
|
||||
Evas_Coord x, y;
|
||||
} history[SWIPE_MOVES];
|
||||
int item_cache_count;
|
||||
int item_cache_max;
|
||||
int movements;
|
||||
int walking;
|
||||
int item_width;
|
||||
|
@ -306,11 +310,10 @@ struct _Elm_Genlist_Item
|
|||
const Elm_Genlist_Item_Class *itc;
|
||||
Elm_Genlist_Item *parent;
|
||||
Elm_Genlist_Item_Flags flags;
|
||||
struct
|
||||
{
|
||||
Evas_Smart_Cb func;
|
||||
const void *data;
|
||||
} func;
|
||||
struct {
|
||||
Evas_Smart_Cb func;
|
||||
const void *data;
|
||||
} func;
|
||||
|
||||
Evas_Object *spacer;
|
||||
Eina_List *labels, *icons, *states, *icon_objs;
|
||||
|
@ -320,19 +323,19 @@ struct _Elm_Genlist_Item
|
|||
|
||||
Elm_Genlist_Item *rel;
|
||||
|
||||
struct
|
||||
{
|
||||
const void *data;
|
||||
Elm_Tooltip_Item_Content_Cb content_cb;
|
||||
Evas_Smart_Cb del_cb;
|
||||
const char *style;
|
||||
} tooltip;
|
||||
struct {
|
||||
const void *data;
|
||||
Elm_Tooltip_Item_Content_Cb content_cb;
|
||||
Evas_Smart_Cb del_cb;
|
||||
const char *style;
|
||||
} tooltip;
|
||||
|
||||
const char *mouse_cursor;
|
||||
|
||||
int relcount;
|
||||
int walking;
|
||||
int expanded_depth;
|
||||
int order_num_in;
|
||||
|
||||
Eina_Bool before : 1;
|
||||
|
||||
|
@ -352,6 +355,22 @@ struct _Elm_Genlist_Item
|
|||
Eina_Bool updateme : 1;
|
||||
};
|
||||
|
||||
struct _Item_Cache
|
||||
{
|
||||
EINA_INLIST;
|
||||
|
||||
Evas_Object *base_view, *spacer;
|
||||
|
||||
const char *item_style; // it->itc->item_style
|
||||
Eina_Bool tree : 1; // it->flags & ELM_GENLIST_ITEM_SUBITEMS
|
||||
Eina_Bool compress : 1; // it->wd->compress
|
||||
Eina_Bool odd : 1; // in & 0x1
|
||||
|
||||
Eina_Bool selected : 1; // it->selected
|
||||
Eina_Bool disabled : 1; // it->disabled
|
||||
Eina_Bool expanded : 1; // it->expanded
|
||||
};
|
||||
|
||||
#define ELM_GENLIST_ITEM_FROM_INLIST(item) \
|
||||
((item) ? EINA_INLIST_CONTAINER_GET(item, Elm_Genlist_Item) : NULL)
|
||||
|
||||
|
@ -362,6 +381,7 @@ struct _Pan
|
|||
};
|
||||
|
||||
static const char *widtype = NULL;
|
||||
static void _item_cache_zero(Widget_Data *wd);
|
||||
static void _del_hook(Evas_Object *obj);
|
||||
static void _theme_hook(Evas_Object *obj);
|
||||
//static void _show_region_hook(void *data, Evas_Object *obj);
|
||||
|
@ -610,6 +630,7 @@ _del_hook(Evas_Object *obj)
|
|||
{
|
||||
Widget_Data *wd = elm_widget_data_get(obj);
|
||||
if (!wd) return;
|
||||
_item_cache_zero(wd);
|
||||
if (wd->calc_job) ecore_job_del(wd->calc_job);
|
||||
if (wd->update_job) ecore_job_del(wd->update_job);
|
||||
free(wd);
|
||||
|
@ -631,6 +652,7 @@ _theme_hook(Evas_Object *obj)
|
|||
Widget_Data *wd = elm_widget_data_get(obj);
|
||||
Item_Block *itb;
|
||||
if (!wd) return;
|
||||
_item_cache_zero(wd);
|
||||
elm_smart_scroller_object_theme_set(obj, wd->scr, "genlist", "base", elm_widget_style_get(obj));
|
||||
// edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale);
|
||||
wd->item_width = wd->item_height = 0;
|
||||
|
@ -1143,6 +1165,112 @@ _signal_contract(void *data, Evas_Object *obj __UNUSED__, const char *emission _
|
|||
evas_object_smart_callback_call(it->base.widget, "contract,request", it);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_item_cache_clean(Widget_Data *wd)
|
||||
{
|
||||
while ((wd->item_cache) && (wd->item_cache_count > wd->item_cache_max))
|
||||
{
|
||||
Item_Cache *itc;
|
||||
|
||||
itc = EINA_INLIST_CONTAINER_GET(wd->item_cache->last, Item_Cache);
|
||||
wd->item_cache = eina_inlist_remove(wd->item_cache,
|
||||
wd->item_cache->last);
|
||||
wd->item_cache_count--;
|
||||
if (itc->spacer) evas_object_del(itc->spacer);
|
||||
if (itc->base_view) evas_object_del(itc->base_view);
|
||||
if (itc->item_style) eina_stringshare_del(itc->item_style);
|
||||
free(itc);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_item_cache_zero(Widget_Data *wd)
|
||||
{
|
||||
int pmax = wd->item_cache_max;
|
||||
wd->item_cache_max = 0;
|
||||
_item_cache_clean(wd);
|
||||
wd->item_cache_max = pmax;
|
||||
}
|
||||
|
||||
static void
|
||||
_item_cache_add(Elm_Genlist_Item *it)
|
||||
{
|
||||
Item_Cache *itc;
|
||||
|
||||
if (it->wd->item_cache_max <= 0)
|
||||
{
|
||||
evas_object_del(it->base.view);
|
||||
it->base.view = NULL;
|
||||
evas_object_del(it->spacer);
|
||||
it->spacer = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
it->wd->item_cache_count++;
|
||||
itc = calloc(1, sizeof(Item_Cache));
|
||||
it->wd->item_cache = eina_inlist_prepend(it->wd->item_cache, EINA_INLIST_GET(itc));
|
||||
itc->spacer = it->spacer;
|
||||
it->spacer = NULL;
|
||||
itc->base_view = it->base.view;
|
||||
it->base.view = NULL;
|
||||
evas_object_hide(itc->base_view);
|
||||
evas_object_move(itc->base_view, -9999, -9999);
|
||||
itc->item_style = eina_stringshare_add(it->itc->item_style);
|
||||
if (it->flags & ELM_GENLIST_ITEM_SUBITEMS) itc->tree = 1;
|
||||
itc->compress = (it->wd->compress);
|
||||
itc->odd = (it->order_num_in & 0x1);
|
||||
itc->selected = it->selected;
|
||||
itc->disabled = it->disabled;
|
||||
itc->expanded = it->expanded;
|
||||
edje_object_signal_callback_del(it->base.view, "elm,action,expand,toggle",
|
||||
"elm", _signal_expand_toggle);
|
||||
edje_object_signal_callback_del(it->base.view, "elm,action,expand", "elm",
|
||||
_signal_expand);
|
||||
edje_object_signal_callback_del(it->base.view, "elm,action,contract",
|
||||
"elm", _signal_contract);
|
||||
evas_object_event_callback_del(it->base.view, EVAS_CALLBACK_MOUSE_DOWN,
|
||||
_mouse_down);
|
||||
evas_object_event_callback_del(it->base.view, EVAS_CALLBACK_MOUSE_UP,
|
||||
_mouse_up);
|
||||
evas_object_event_callback_del(it->base.view, EVAS_CALLBACK_MOUSE_MOVE,
|
||||
_mouse_move);
|
||||
_item_cache_clean(it->wd);
|
||||
}
|
||||
|
||||
static Item_Cache *
|
||||
_item_cache_find(Elm_Genlist_Item *it)
|
||||
{
|
||||
Item_Cache *itc;
|
||||
Eina_Bool tree = 0, odd;
|
||||
|
||||
if (it->flags & ELM_GENLIST_ITEM_SUBITEMS) tree = 1;
|
||||
odd = (it->order_num_in & 0x1);
|
||||
EINA_INLIST_FOREACH(it->wd->item_cache, itc)
|
||||
{
|
||||
if ((itc->tree == tree) &&
|
||||
(itc->odd == odd) &&
|
||||
(itc->compress == it->wd->compress) &&
|
||||
(!strcmp(it->itc->item_style, itc->item_style)))
|
||||
{
|
||||
it->wd->item_cache = eina_inlist_remove(it->wd->item_cache,
|
||||
EINA_INLIST_GET(itc));
|
||||
it->wd->item_cache_count--;
|
||||
return itc;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_item_cache_free(Item_Cache *itc)
|
||||
{
|
||||
if (itc->spacer) evas_object_del(itc->spacer);
|
||||
if (itc->base_view) evas_object_del(itc->base_view);
|
||||
if (itc->item_style) eina_stringshare_del(itc->item_style);
|
||||
free(itc);
|
||||
}
|
||||
|
||||
static void
|
||||
_item_realize(Elm_Genlist_Item *it, int in, int calc)
|
||||
{
|
||||
|
@ -1151,26 +1279,40 @@ _item_realize(Elm_Genlist_Item *it, int in, int calc)
|
|||
const char *treesize;
|
||||
char buf[1024];
|
||||
int depth, tsize = 20;
|
||||
|
||||
Item_Cache *itc;
|
||||
|
||||
if ((it->realized) || (it->delete_me)) return;
|
||||
it->base.view = edje_object_add(evas_object_evas_get(it->base.widget));
|
||||
edje_object_scale_set(it->base.view, elm_widget_scale_get(it->base.widget) *
|
||||
_elm_config->scale);
|
||||
evas_object_smart_member_add(it->base.view, it->wd->pan_smart);
|
||||
elm_widget_sub_object_add(it->base.widget, it->base.view);
|
||||
it->order_num_in = in;
|
||||
|
||||
if (it->flags & ELM_GENLIST_ITEM_SUBITEMS) strncpy(buf, "tree", sizeof(buf));
|
||||
else strncpy(buf, "item", sizeof(buf));
|
||||
if (it->wd->compress) strncat(buf, "_compress", sizeof(buf) - strlen(buf));
|
||||
|
||||
if (in & 0x1) strncat(buf, "_odd", sizeof(buf) - strlen(buf));
|
||||
strncat(buf, "/", sizeof(buf) - strlen(buf));
|
||||
strncat(buf, it->itc->item_style, sizeof(buf) - strlen(buf));
|
||||
|
||||
_elm_theme_object_set(it->base.widget, it->base.view, "genlist", buf, elm_widget_style_get(it->base.widget));
|
||||
it->spacer = evas_object_rectangle_add(evas_object_evas_get(it->base.widget));
|
||||
evas_object_color_set(it->spacer, 0, 0, 0, 0);
|
||||
elm_widget_sub_object_add(it->base.widget, it->spacer);
|
||||
itc = _item_cache_find(it);
|
||||
if (itc)
|
||||
{
|
||||
it->base.view = itc->base_view;
|
||||
itc->base_view = NULL;
|
||||
it->spacer = itc->spacer;
|
||||
itc->spacer = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
it->base.view = edje_object_add(evas_object_evas_get(it->base.widget));
|
||||
edje_object_scale_set(it->base.view, elm_widget_scale_get(it->base.widget) *
|
||||
_elm_config->scale);
|
||||
evas_object_smart_member_add(it->base.view, it->wd->pan_smart);
|
||||
elm_widget_sub_object_add(it->base.widget, it->base.view);
|
||||
|
||||
if (it->flags & ELM_GENLIST_ITEM_SUBITEMS) strncpy(buf, "tree", sizeof(buf));
|
||||
else strncpy(buf, "item", sizeof(buf));
|
||||
if (it->wd->compress) strncat(buf, "_compress", sizeof(buf) - strlen(buf));
|
||||
|
||||
if (in & 0x1) strncat(buf, "_odd", sizeof(buf) - strlen(buf));
|
||||
strncat(buf, "/", sizeof(buf) - strlen(buf));
|
||||
strncat(buf, it->itc->item_style, sizeof(buf) - strlen(buf));
|
||||
|
||||
_elm_theme_object_set(it->base.widget, it->base.view, "genlist", buf, elm_widget_style_get(it->base.widget));
|
||||
it->spacer = evas_object_rectangle_add(evas_object_evas_get(it->base.widget));
|
||||
evas_object_color_set(it->spacer, 0, 0, 0, 0);
|
||||
elm_widget_sub_object_add(it->base.widget, it->spacer);
|
||||
}
|
||||
for (it2 = it, depth = 0; it2->parent; it2 = it2->parent) depth += 1;
|
||||
it->expanded_depth = depth;
|
||||
treesize = edje_object_data_get(it->base.view, "treesize");
|
||||
|
@ -1198,12 +1340,39 @@ _item_realize(Elm_Genlist_Item *it, int in, int calc)
|
|||
_mouse_up, it);
|
||||
evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MOUSE_MOVE,
|
||||
_mouse_move, it);
|
||||
if (it->selected)
|
||||
edje_object_signal_emit(it->base.view, "elm,state,selected", "elm");
|
||||
if (it->disabled)
|
||||
edje_object_signal_emit(it->base.view, "elm,state,disabled", "elm");
|
||||
if (it->expanded)
|
||||
edje_object_signal_emit(it->base.view, "elm,state,expanded", "elm");
|
||||
if (itc)
|
||||
{
|
||||
if (it->selected != itc->selected)
|
||||
{
|
||||
if (it->selected)
|
||||
edje_object_signal_emit(it->base.view, "elm,state,selected", "elm");
|
||||
else
|
||||
edje_object_signal_emit(it->base.view, "elm,state,unselected", "elm");
|
||||
}
|
||||
if (it->disabled != itc->disabled)
|
||||
{
|
||||
if (it->disabled)
|
||||
edje_object_signal_emit(it->base.view, "elm,state,disabled", "elm");
|
||||
else
|
||||
edje_object_signal_emit(it->base.view, "elm,state,enabled", "elm");
|
||||
}
|
||||
if (it->expanded != itc->expanded)
|
||||
{
|
||||
if (it->expanded)
|
||||
edje_object_signal_emit(it->base.view, "elm,state,expanded", "elm");
|
||||
else
|
||||
edje_object_signal_emit(it->base.view, "elm,state,contracted", "elm");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (it->selected)
|
||||
edje_object_signal_emit(it->base.view, "elm,state,selected", "elm");
|
||||
if (it->disabled)
|
||||
edje_object_signal_emit(it->base.view, "elm,state,disabled", "elm");
|
||||
if (it->expanded)
|
||||
edje_object_signal_emit(it->base.view, "elm,state,expanded", "elm");
|
||||
}
|
||||
}
|
||||
|
||||
if ((calc) && (it->wd->homogeneous) && (it->wd->item_width))
|
||||
|
@ -1234,6 +1403,8 @@ _item_realize(Elm_Genlist_Item *it, int in, int calc)
|
|||
edje_object_part_text_set(it->base.view, l->data, s);
|
||||
free(s);
|
||||
}
|
||||
else if (itc)
|
||||
edje_object_part_text_set(it->base.view, l->data, "");
|
||||
}
|
||||
}
|
||||
if (it->itc->func.icon_get)
|
||||
|
@ -1272,6 +1443,11 @@ _item_realize(Elm_Genlist_Item *it, int in, int calc)
|
|||
snprintf(buf, sizeof(buf), "elm,state,%s,active", key);
|
||||
edje_object_signal_emit(it->base.view, buf, "elm");
|
||||
}
|
||||
else if (itc)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "elm,state,%s,passive", key);
|
||||
edje_object_signal_emit(it->base.view, buf, "elm");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!it->mincalcd)
|
||||
|
@ -1311,6 +1487,8 @@ _item_realize(Elm_Genlist_Item *it, int in, int calc)
|
|||
|
||||
it->realized = EINA_TRUE;
|
||||
it->want_unrealize = EINA_FALSE;
|
||||
|
||||
if (itc) _item_cache_free(itc);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1324,10 +1502,7 @@ _item_unrealize(Elm_Genlist_Item *it)
|
|||
ecore_timer_del(it->long_timer);
|
||||
it->long_timer = NULL;
|
||||
}
|
||||
evas_object_del(it->base.view);
|
||||
it->base.view = NULL;
|
||||
evas_object_del(it->spacer);
|
||||
it->spacer = NULL;
|
||||
_item_cache_add(it);
|
||||
elm_widget_stringlist_free(it->labels);
|
||||
it->labels = NULL;
|
||||
elm_widget_stringlist_free(it->icons);
|
||||
|
@ -1901,6 +2076,7 @@ elm_genlist_add(Evas_Object *parent)
|
|||
wd->obj = obj;
|
||||
wd->mode = ELM_LIST_SCROLL;
|
||||
wd->max_items_per_block = 32;
|
||||
wd->item_cache_max = wd->max_items_per_block * 2;
|
||||
wd->longpress_timeout = 1.0;
|
||||
|
||||
evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
|
||||
|
@ -2128,6 +2304,11 @@ _item_idler(void *data)
|
|||
{
|
||||
Widget_Data *wd = data;
|
||||
|
||||
//xxx
|
||||
//static double q_start = 0.0;
|
||||
//if (q_start == 0.0) q_start = ecore_time_get();
|
||||
//xxx
|
||||
|
||||
if (_queue_proecess(wd, 1) > 0)
|
||||
{
|
||||
if (wd->calc_job) ecore_job_del(wd->calc_job);
|
||||
|
@ -2135,6 +2316,9 @@ _item_idler(void *data)
|
|||
}
|
||||
if (!wd->queue)
|
||||
{
|
||||
//xxx
|
||||
//printf("PROCESS TIME: %3.3f\n", ecore_time_get() - q_start);
|
||||
//xxx
|
||||
wd->queue_idler = NULL;
|
||||
return ECORE_CALLBACK_CANCEL;
|
||||
}
|
||||
|
@ -3890,6 +4074,8 @@ elm_genlist_block_count_set(Evas_Object *obj, int n)
|
|||
Widget_Data *wd = elm_widget_data_get(obj);
|
||||
if (!wd) return;
|
||||
wd->max_items_per_block = n;
|
||||
wd->item_cache_max = wd->max_items_per_block * 2;
|
||||
_item_cache_clean(wd);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue