gengrid: add item cache in gengrid for efficient realize/unrealize operation.

Summary:
gengrid realize/unrealize items each smart calculation if their posiiton is updated.
This concept will be occurred useless view object creation and deletion.
So instead of delete items in unrealize function, push item cache into cache list,
and pop item cache from cache list in realize function to reuse item view object
more efficiently.
the cache concept is already implemented in genlist widget and this patch is improved
item cache of genlist cache.
@feature

```
NOTICE: This patch is written under the D2561 Patch which add elm_gengrid_item_fields_update.
        So it must submitted after D2561.
```

Test Plan:
I've tested below three cases,
   1. tested ith this patch in elementary_test and checked all gengrid features are working properly.
   2. tested with changing CACHE_MAX to another value which is set 40 in default
       and checked all gengrid features are working properly.
   3. tested with set it->item->nocache true, and checked cache is never generated
       and checked all gengrid features are working properly.

Reviewers: raster, Hermet, seoz, jaehwan, singh.amitesh

Subscribers: eagleeye, singh.amitesh, Jaehyun

Differential Revision: https://phab.enlightenment.org/D2641

Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
This commit is contained in:
SangHyeon Lee 2015-06-25 16:28:07 +02:00 committed by Cedric BAIL
parent 7ee4a5b8b1
commit d700a9b86f
6 changed files with 745 additions and 97 deletions

View File

@ -140,6 +140,7 @@ void test_gengrid5(void *data, Evas_Object *obj, void *event_info);
void test_gengrid_item_styles(void *data, Evas_Object *obj, void *event_info);
void test_gengrid_speed(void *data, Evas_Object *obj, void *event_info);
void test_gengrid_focus(void *data, Evas_Object *obj, void *event_info);
void test_gengrid_update(void *data, Evas_Object *obj, void *event_info);
void test_win_state(void *data, Evas_Object *obj, void *event_info);
void test_win_state2(void *data, Evas_Object *obj, void *event_info);
void test_progressbar(void *data, Evas_Object *obj, void *event_info);
@ -695,6 +696,7 @@ add_tests:
ADD_TEST(NULL, "Lists - Gengrid", "GenGrid Item Styles", test_gengrid_item_styles);
ADD_TEST(NULL, "Lists - Gengrid", "Gengrid Update Speed", test_gengrid_speed);
ADD_TEST(NULL, "Lists - Gengrid", "GenGrid Focus", test_gengrid_focus);
ADD_TEST(NULL, "Lists - Gengrid", "GenGrid Update", test_gengrid_update);
//------------------------------//
ADD_TEST(NULL, "General", "Scaling", test_scaling);

View File

@ -29,6 +29,7 @@ struct _api_data
unsigned int state; /* What state we are testing */
Evas_Object *box; /* Use this to get box content */
Evas_Object *grid;
Elm_Gengrid_Item_Field_Type field_type;
};
typedef struct _api_data api_data;
@ -1848,3 +1849,263 @@ test_gengrid_focus(void *data EINA_UNUSED,
evas_object_resize(win, 600, 600);
evas_object_show(win);
}
char *
_gg_update_text_get(void *data EINA_UNUSED,
Evas_Object *obj EINA_UNUSED,
const char *part EINA_UNUSED)
{
char *txt[] = {"Sky", "Stone", "Water", "Flower", "Sand", "Sun", "Moon", "Star", "Cloud", NULL};
int n = rand() % 9;
return strdup(txt[n]);
}
Evas_Object *
_gg_update_content_get(void *data, Evas_Object *obj, const char *part)
{
const Item_Data *id = data;
char buf[256];
int n = 0;
if (!strcmp(part, "elm.swallow.icon"))
{
n = rand() % 9;
Evas_Object *image = elm_image_add(obj);
snprintf(buf, sizeof(buf), "%s/images/%s", elm_app_data_dir_get(), img[n]);
elm_image_file_set(image, buf, NULL);
elm_image_aspect_fixed_set(image, EINA_FALSE);
evas_object_show(image);
return image;
}
else if (!strcmp(part, "elm.swallow.end"))
{
Evas_Object *ck = elm_check_add(obj);
evas_object_propagate_events_set(ck, EINA_FALSE);
elm_check_state_set(ck, id->onoff);
evas_object_smart_callback_add(ck, "changed", grid_item_check_changed, data);
evas_object_show(ck);
return ck;
}
return NULL;
}
Eina_Bool
_gg_update_state_get(void *data EINA_UNUSED,
Evas_Object *obj EINA_UNUSED,
const char *part EINA_UNUSED)
{
return EINA_FALSE;
}
static void
_gg_item_update_clicked_cb(void *data,
Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
api_data *api = (api_data *)data;
Evas_Object *gengrid = api->grid;
Eina_List *l = elm_gengrid_realized_items_get(gengrid);
Elm_Object_Item *item = NULL;
Item_Data *id = NULL;
EINA_LIST_FREE(l, item)
{
id = elm_object_item_data_get(item);
if (id && id->onoff) elm_gengrid_item_update(item);
}
}
static void
_gg_item_fields_update_clicked_cb(void *data,
Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
api_data *api = (api_data *)data;
Evas_Object *gengrid = api->grid;
Eina_List *l = elm_gengrid_realized_items_get(gengrid);
Elm_Object_Item *item = NULL;
Item_Data *id = NULL;
EINA_LIST_FREE(l, item)
{
id = elm_object_item_data_get(item);
if (id && id->onoff)
{
elm_gengrid_item_fields_update(item, "*", api->field_type);
}
}
}
static void
_gg_text_update_changed_cb(void *data,
Evas_Object *obj,
void *event_info EINA_UNUSED)
{
api_data *api = (api_data *)data;
if (elm_check_state_get(obj))
api->field_type |= ELM_GENGRID_ITEM_FIELD_TEXT;
else
api->field_type ^= ELM_GENGRID_ITEM_FIELD_TEXT;
}
static void
_gg_content_update_changed_cb(void *data,
Evas_Object *obj,
void *event_info EINA_UNUSED)
{
api_data *api = (api_data *)data;
if (elm_check_state_get(obj))
api->field_type |= ELM_GENGRID_ITEM_FIELD_CONTENT;
else
api->field_type ^= ELM_GENGRID_ITEM_FIELD_CONTENT;
}
static void
_gg_state_update_changed_cb(void *data,
Evas_Object *obj,
void *event_info EINA_UNUSED)
{
api_data *api = (api_data *)data;
if (elm_check_state_get(obj))
api->field_type |= ELM_GENGRID_ITEM_FIELD_STATE;
else
api->field_type ^= ELM_GENGRID_ITEM_FIELD_STATE;
}
void
test_gengrid_update(void *data EINA_UNUSED,
Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
Evas_Object *win, *bx, *gengrid, *btn, *fr, *bx_opt, *ck;
Elm_Gengrid_Item_Class *ic;
api_data *api = calloc(1, sizeof(api_data));
Item_Data *id;
int i;
win = elm_win_util_standard_add("gengrid-update", "Gengrid Update");
elm_win_autodel_set(win, EINA_TRUE);
api->box = bx = elm_box_add(win);
evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_win_resize_object_add(win, bx);
evas_object_show(bx);
api->grid = gengrid = elm_gengrid_add(bx);
elm_gengrid_item_size_set(gengrid,
ELM_SCALE_SIZE(150),
ELM_SCALE_SIZE(150));
evas_object_size_hint_weight_set(gengrid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(gengrid, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_box_pack_end(bx, gengrid);
evas_object_show(gengrid);
evas_object_smart_callback_add(gengrid, "item,focused", _gengrid_focus_item_cb, "item,focused");
evas_object_smart_callback_add(gengrid, "item,unfocused", _gengrid_focus_item_cb, "item,unfocused");
evas_object_smart_callback_add(gengrid, "selected", _gengrid_focus_item_cb, "selected");
evas_object_smart_callback_add(gengrid, "unselected", _gengrid_focus_item_cb, "unselected");
evas_object_smart_callback_add(gengrid, "activated", _gengrid_focus_item_cb, "activated");
evas_object_smart_callback_add(gengrid, "highlighted", _gengrid_focus_item_cb, "highlighted");
evas_object_smart_callback_add(gengrid, "unhighlighted", _gengrid_focus_item_cb, "unhighlighted");
evas_object_event_callback_add(gengrid, EVAS_CALLBACK_KEY_DOWN, _gengrid_focus_key_down_cb, NULL);
//initialize field type
api->field_type = ELM_GENGRID_ITEM_FIELD_ALL;
//Field Options
fr = elm_frame_add(bx);
elm_object_text_set(fr, "Field Options");
evas_object_size_hint_weight_set(fr, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(fr, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_box_pack_end(bx, fr);
evas_object_show(fr);
bx_opt = elm_box_add(fr);
elm_box_horizontal_set(bx_opt, EINA_TRUE);
elm_object_content_set(fr, bx_opt);
evas_object_show(bx_opt);
ck = elm_check_add(bx_opt);
elm_object_text_set(ck, "TEXT");
elm_check_state_set(ck, EINA_FALSE);
evas_object_size_hint_weight_set(ck, EVAS_HINT_EXPAND, 0.0);
evas_object_smart_callback_add(ck, "changed",
_gg_text_update_changed_cb,
api);
elm_box_pack_end(bx_opt, ck);
evas_object_show(ck);
ck = elm_check_add(bx_opt);
elm_object_text_set(ck, "CONTENT");
elm_check_state_set(ck, EINA_FALSE);
evas_object_size_hint_weight_set(ck, EVAS_HINT_EXPAND, 0.0);
evas_object_smart_callback_add(ck, "changed",
_gg_content_update_changed_cb,
api);
elm_box_pack_end(bx_opt, ck);
evas_object_show(ck);
ck = elm_check_add(bx_opt);
elm_object_text_set(ck, "STATE");
elm_check_state_set(ck, EINA_FALSE);
evas_object_size_hint_weight_set(ck, EVAS_HINT_EXPAND, 0.0);
evas_object_smart_callback_add(ck, "changed",
_gg_state_update_changed_cb,
api);
elm_box_pack_end(bx_opt, ck);
evas_object_show(ck);
//Update Buttons
fr = elm_frame_add(bx);
elm_object_text_set(fr, "Update Options");
evas_object_size_hint_weight_set(fr, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(fr, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_box_pack_end(bx, fr);
evas_object_show(fr);
bx_opt = elm_box_add(fr);
elm_box_horizontal_set(bx_opt, EINA_TRUE);
elm_object_content_set(fr, bx_opt);
evas_object_show(bx_opt);
btn = elm_button_add(bx_opt);
elm_object_text_set(btn, "Update");
evas_object_smart_callback_add(btn, "clicked", _gg_item_update_clicked_cb, api);
elm_box_pack_end(bx_opt, btn);
evas_object_show(btn);
btn = elm_button_add(bx_opt);
elm_object_text_set(btn, "Fields Update");
evas_object_smart_callback_add(btn, "clicked", _gg_item_fields_update_clicked_cb, api);
elm_box_pack_end(bx_opt, btn);
evas_object_show(btn);
//Gengrid Item Append
ic = elm_gengrid_item_class_new();
ic->item_style = "default";
ic->func.text_get = _gg_update_text_get;
ic->func.content_get = _gg_update_content_get;
ic->func.state_get = _gg_update_state_get;
ic->func.del = grid_del;
for (i = 0; i < 24; i++)
{
id = calloc(1, sizeof(Item_Data));
id->mode = i;
id->item = elm_gengrid_item_append(gengrid, ic, id, NULL, NULL);
if (i == 4)
elm_object_item_disabled_set(id->item, EINA_TRUE);
}
elm_gengrid_item_class_free(ic);
evas_object_resize(win, 600, 600);
evas_object_show(win);
}

View File

@ -34,6 +34,8 @@
#define PRELOAD 1
#define REORDER_EFFECT_TIME 0.5
#define CACHE_MAX 40
EAPI const char ELM_GENGRID_SMART_NAME[] = "elm_gengrid";
EAPI const char ELM_GENGRID_PAN_SMART_NAME[] = "elm_gengrid_pan";
@ -93,6 +95,8 @@ static Eina_Bool _key_action_move(Evas_Object *obj, const char *params);
static Eina_Bool _key_action_select(Evas_Object *obj, const char *params);
static Eina_Bool _key_action_escape(Evas_Object *obj, const char *params);
static void _item_position_update(Eina_Inlist *list, int idx);
static void _item_mouse_callbacks_add(Elm_Gen_Item *it, Evas_Object *view);
static void _item_mouse_callbacks_del(Elm_Gen_Item *it, Evas_Object *view);
static const Elm_Action key_actions[] = {
@ -102,6 +106,168 @@ static const Elm_Action key_actions[] = {
{NULL, NULL}
};
//-- item cache handle routine --//
// push item cache into caches
static Eina_Bool
_item_cache_push(Elm_Gengrid_Data *sd, Item_Cache *itc)
{
if (!itc || (sd->item_cache_max <= 0))
return EINA_FALSE;
sd->item_cache_count++;
sd->item_cache =
eina_inlist_prepend(sd->item_cache, EINA_INLIST_GET(itc));
return EINA_TRUE;
}
// pop item cache from caches
static Item_Cache *
_item_cache_pop(Elm_Gengrid_Data *sd, Item_Cache *itc)
{
if ((!itc) || (!sd->item_cache) ||
(sd->item_cache_count <= 0))
return NULL;
sd->item_cache =
eina_inlist_remove (sd->item_cache, EINA_INLIST_GET(itc));
sd->item_cache_count--;
return itc;
}
// free one item cache from caches
static void
_item_cache_free(Item_Cache *itc)
{
if (!itc) return;
evas_object_del(itc->spacer);
evas_object_del(itc->base_view);
eina_stringshare_del(itc->item_style);
ELM_SAFE_FREE(itc ,free);
}
// clean up item cache by removing overflowed caches
static void
_item_cache_clean(Elm_Gengrid_Data *sd)
{
evas_event_freeze(evas_object_evas_get(sd->obj));
while ((sd->item_cache) && (sd->item_cache_count > sd->item_cache_max))
{
Item_Cache *itc =
EINA_INLIST_CONTAINER_GET(sd->item_cache->last, Item_Cache);
_item_cache_free(_item_cache_pop(sd, itc));
}
evas_event_thaw(evas_object_evas_get(sd->obj));
evas_event_thaw_eval(evas_object_evas_get(sd->obj));
}
// empty all item caches
static void
_item_cache_zero(Elm_Gengrid_Data *sd)
{
int pmax = sd->item_cache_max;
sd->item_cache_max = 0;
_item_cache_clean(sd);
sd->item_cache_max = pmax;
}
// add an item to item cache
static Eina_Bool
_item_cache_add(Elm_Gen_Item *it)
{
if (it->item->nocache_once || it->item->nocache) return EINA_FALSE;
Item_Cache *itc = NULL;
ELM_GENGRID_DATA_GET_FROM_ITEM(it, sd);
Evas_Object *obj = sd->obj;
evas_event_freeze(evas_object_evas_get(obj));
if (sd->item_cache_max > 0)
itc = ELM_NEW(Item_Cache);
if (!_item_cache_push(sd, itc))
{
if (itc) ELM_SAFE_FREE(itc, free);
evas_event_thaw(evas_object_evas_get(obj));
evas_event_thaw_eval(evas_object_evas_get(obj));
return EINA_FALSE;
}
itc->spacer = it->spacer;
itc->base_view = VIEW(it);
itc->item_style = eina_stringshare_add(it->itc->item_style);
if (!it->group)
{
Eina_Bool tmp;
if (it->selected)
edje_object_signal_emit(itc->base_view, "elm,state,unselected", "elm");
if (eo_do_ret(EO_OBJ(it), tmp, elm_wdg_item_disabled_get()))
edje_object_signal_emit(itc->base_view, "elm,state,enabled", "elm");
if (it == (Elm_Gen_Item *)sd->focused_item &&
elm_widget_focus_highlight_enabled_get(obj))
edje_object_signal_emit(itc->base_view, "elm,state,unfocused", "elm");
ELM_SAFE_FREE(it->long_timer, ecore_timer_del);
// FIXME: other callbacks?
_item_mouse_callbacks_del(it, itc->base_view);
}
edje_object_mirrored_set(VIEW(it),
elm_widget_mirrored_get(WIDGET(it)));
edje_object_scale_set(VIEW(it),
elm_widget_scale_get(WIDGET(it))
* elm_config_scale_get());
evas_object_hide(itc->base_view);
evas_object_move(itc->base_view, -9999, -9999);
it->spacer = NULL;
VIEW(it) = NULL;
_item_cache_clean(sd);
evas_event_thaw(evas_object_evas_get(obj));
evas_event_thaw_eval(evas_object_evas_get(obj));
return EINA_TRUE;
}
// find an item from item cache and remove it from the cache
static Eina_Bool
_item_cache_find(Elm_Gen_Item *it)
{
if (it->item->nocache_once || it->item->nocache) return EINA_FALSE;
Item_Cache *itc = NULL;
Eina_Inlist *l;
ELM_GENGRID_DATA_GET_FROM_ITEM(it, sd);
EINA_INLIST_FOREACH_SAFE(sd->item_cache, l, itc)
{
if (((!it->itc->item_style) && (!itc->item_style)) ||
(it->itc->item_style && itc->item_style &&
(!strcmp(it->itc->item_style, itc->item_style))))
{
itc = _item_cache_pop(sd, itc);
if (!itc) continue;
it->spacer = itc->spacer;
VIEW(it) = itc->base_view;
itc->spacer = NULL;
itc->base_view = NULL;
_item_cache_free(itc);
return EINA_TRUE;
}
}
return EINA_FALSE;
}
static Eina_Bool
_is_no_select(Elm_Gen_Item *it)
{
@ -613,12 +779,197 @@ _item_mouse_down_cb(void *data,
it->long_timer = NULL;
}
static void
_item_text_realize(Elm_Gen_Item *it,
Evas_Object *target,
Eina_List **source,
const char *parts)
{
const Eina_List *l;
const char *key;
char *s;
if (!it->itc->func.text_get) return;
if (!(*source))
*source = elm_widget_stringlist_get
(edje_object_data_get(target, "texts"));
EINA_LIST_FOREACH(*source, l, key)
{
if (parts && fnmatch(parts, key, FNM_PERIOD)) continue;
s = it->itc->func.text_get
((void *)WIDGET_ITEM_DATA_GET(EO_OBJ(it)), WIDGET(it), key);
if (s)
{
edje_object_part_text_escaped_set(target, key, s);
free(s);
}
else
{
edje_object_part_text_set(target, key, "");
}
if (_elm_config->atspi_mode)
elm_interface_atspi_accessible_name_changed_signal_emit(EO_OBJ(it));
}
}
static void
_item_content_realize(Elm_Gen_Item *it,
Evas_Object *target,
Eina_List **contents,
const char *src,
const char *parts)
{
Eina_Bool tmp;
Evas_Object *content;
if (!parts)
{
EINA_LIST_FREE(*contents, content)
evas_object_del(content);
}
if (it->itc->func.content_get)
{
Eina_List *source;
const char *key;
source = elm_widget_stringlist_get(edje_object_data_get(target, src));
EINA_LIST_FREE(source, key)
{
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;
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))
{
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);
if (eo_do_ret(EO_OBJ(it), tmp, elm_wdg_item_disabled_get()))
elm_widget_disabled_set(content, EINA_TRUE);
}
}
}
static void
_item_state_realize(Elm_Gen_Item *it, Evas_Object *target, const char *parts)
{
Eina_List *src;
const char *key;
char buf[4096];
if (!it->itc->func.state_get) return;
src = elm_widget_stringlist_get(edje_object_data_get(target, "states"));
EINA_LIST_FREE(src, key)
{
if (parts && fnmatch(parts, key, FNM_PERIOD)) continue;
Eina_Bool on = it->itc->func.state_get
((void *)WIDGET_ITEM_DATA_GET(EO_OBJ(it)), WIDGET(it), key);
if (on)
{
snprintf(buf, sizeof(buf), "elm,state,%s,active", key);
edje_object_signal_emit(target, buf, "elm");
}
else
{
snprintf(buf, sizeof(buf), "elm,state,%s,passive", key);
edje_object_signal_emit(target, buf, "elm");
}
}
edje_object_message_signal_process(target);
}
static void
_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);
if (contents) _item_content_realize(it, view, contents, "contents", NULL);
_item_state_realize(it, view, NULL);
}
/**
* Apply the right style for the created item view.
*/
static void
_view_style_update(Elm_Gen_Item *it, Evas_Object *view, const char *style)
{
char buf[1024];
ELM_GENGRID_DATA_GET_FROM_ITEM(it, sd);
snprintf(buf, sizeof(buf), "item/%s", style ? style : "default");
if (!elm_widget_theme_object_set(WIDGET(it), view,
"gengrid", buf,
elm_widget_style_get(WIDGET(it))))
{
ERR("%s is not a valid gengrid item style. "
"Automatically falls back into default style.",
style);
elm_widget_theme_object_set
(WIDGET(it), view, "gengrid", "item/default", "default");
}
edje_object_mirrored_set(view, elm_widget_mirrored_get(WIDGET(it)));
edje_object_scale_set(view, elm_widget_scale_get(WIDGET(it)) *
elm_config_scale_get());
evas_object_stack_below(view, sd->stack);
}
/**
* Create a VIEW(it) during _item_realize()
*/
static Evas_Object *
_view_create(Elm_Gen_Item *it, const char *style)
{
Evas_Object *view = edje_object_add(evas_object_evas_get(WIDGET(it)));
evas_object_smart_member_add(view, GG_IT(it)->wsd->pan_obj);
elm_widget_sub_object_add(WIDGET(it), view);
edje_object_scale_set(view, elm_widget_scale_get(WIDGET(it)) *
elm_config_scale_get());
_view_style_update(it, view, style);
return view;
}
static void
_view_clear(Evas_Object *view, Eina_List **texts, Eina_List **contents)
{
const char *part;
Evas_Object *c;
const Eina_List *l;
EINA_LIST_FOREACH(*texts, l, part)
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);
}
static void
_elm_gengrid_item_unrealize(Elm_Gen_Item *it,
Eina_Bool calc)
{
Evas_Object *content;
if (!it->realized) return;
if (GG_IT(it)->wsd->reorder_it == it) return;
@ -626,13 +977,10 @@ _elm_gengrid_item_unrealize(Elm_Gen_Item *it,
if (!calc)
evas_object_smart_callback_call(WIDGET(it), SIG_UNREALIZED, EO_OBJ(it));
ELM_SAFE_FREE(it->long_timer, ecore_timer_del);
ELM_SAFE_FREE(it->texts, elm_widget_stringlist_free);
ELM_SAFE_FREE(it->contents, elm_widget_stringlist_free);
_view_clear(VIEW(it), &(it->texts), &(it->contents));
ELM_SAFE_FREE(it->states, elm_widget_stringlist_free);
EINA_LIST_FREE(it->content_objs, content)
evas_object_del(content);
eo_do(EO_OBJ(it), elm_wdg_item_track_cancel());
it->unrealize_cb(it);
@ -765,6 +1113,36 @@ _item_mouse_up_cb(void *data,
}
}
static void
_item_mouse_callbacks_add(Elm_Gen_Item *it,
Evas_Object *view)
{
evas_object_event_callback_add
(view, EVAS_CALLBACK_MOUSE_IN, _item_mouse_in_cb, it);
evas_object_event_callback_add
(view, EVAS_CALLBACK_MOUSE_MOVE, _item_mouse_move_cb, it);
evas_object_event_callback_add
(view, EVAS_CALLBACK_MOUSE_DOWN, _item_mouse_down_cb, it);
evas_object_event_callback_add
(view, EVAS_CALLBACK_MOUSE_UP, _item_mouse_up_cb, it);
}
static void
_item_mouse_callbacks_del(Elm_Gen_Item *it,
Evas_Object *view)
{
evas_object_event_callback_del_full
(view, EVAS_CALLBACK_MOUSE_IN, _item_mouse_in_cb, it);
evas_object_event_callback_del_full
(view, EVAS_CALLBACK_MOUSE_MOVE, _item_mouse_move_cb, it);
evas_object_event_callback_del_full
(view, EVAS_CALLBACK_MOUSE_DOWN, _item_mouse_down_cb, it);
evas_object_event_callback_del_full
(view, EVAS_CALLBACK_MOUSE_UP, _item_mouse_up_cb, it);
}
static void
_elm_gengrid_item_index_update(Elm_Gen_Item *it)
{
@ -778,8 +1156,11 @@ _elm_gengrid_item_index_update(Elm_Gen_Item *it)
static void
_item_unrealize_cb(Elm_Gen_Item *it)
{
ELM_SAFE_FREE(VIEW(it), evas_object_del);
ELM_SAFE_FREE(it->spacer, evas_object_del);
if (!_item_cache_add(it))
{
ELM_SAFE_FREE(VIEW(it), evas_object_del);
ELM_SAFE_FREE(it->spacer, evas_object_del);
}
}
static char *
@ -854,8 +1235,6 @@ static void
_item_realize(Elm_Gen_Item *it)
{
Eina_Bool tmp;
char buf[1024];
char style[1024];
ELM_GENGRID_DATA_GET_FROM_ITEM(it, sd);
Elm_Object_Item *eo_it = EO_OBJ(it);
@ -863,26 +1242,14 @@ _item_realize(Elm_Gen_Item *it)
(it->generation < sd->generation))
return;
VIEW(it) = edje_object_add(evas_object_evas_get(WIDGET(it)));
edje_object_scale_set
(VIEW(it), elm_widget_scale_get(WIDGET(it)) * elm_config_scale_get());
edje_object_mirrored_set(VIEW(it), elm_widget_mirrored_get(WIDGET(it)));
evas_object_smart_member_add(VIEW(it), sd->pan_obj);
elm_widget_sub_object_add(WIDGET(it), VIEW(it));
snprintf(style, sizeof(style), "item/%s",
it->itc->item_style ? it->itc->item_style : "default");
if (!elm_widget_theme_object_set(WIDGET(it), VIEW(it), "gengrid", style,
elm_widget_style_get(WIDGET(it))))
if (!_item_cache_find(it))
{
ERR("%s is not a valid gengrid item style. "
"Automatically falls back into default style.",
it->itc->item_style);
elm_widget_theme_object_set
(WIDGET(it), VIEW(it), "gengrid", "item/default", "default");
VIEW(it) = _view_create(it, it->itc->item_style);
if (it->item->nocache_once)
it->item->nocache_once = EINA_FALSE;
}
evas_object_stack_below(VIEW(it), sd->stack);
if (edje_object_part_exists(VIEW(it), "elm.swallow.pad"))
if (it->spacer && edje_object_part_exists(VIEW(it), "elm.swallow.pad"))
{
it->spacer =
evas_object_rectangle_add(evas_object_evas_get(WIDGET(it)));
@ -895,64 +1262,8 @@ _item_realize(Elm_Gen_Item *it)
/* access */
if (_elm_config->access_mode) _access_widget_item_register(it);
if (it->itc->func.text_get)
{
const Eina_List *l;
const char *key;
it->texts =
elm_widget_stringlist_get(edje_object_data_get(VIEW(it), "texts"));
EINA_LIST_FOREACH(it->texts, l, key)
{
char *s = it->itc->func.text_get
((void *)WIDGET_ITEM_DATA_GET(eo_it), WIDGET(it), key);
if (s)
{
edje_object_part_text_escaped_set(VIEW(it), key, s);
free(s);
}
}
}
if (it->itc->func.content_get)
{
const Eina_List *l;
const char *key;
Evas_Object *ic = NULL;
it->contents = elm_widget_stringlist_get
(edje_object_data_get(VIEW(it), "contents"));
EINA_LIST_FOREACH(it->contents, l, key)
{
ic = it->itc->func.content_get((void *)WIDGET_ITEM_DATA_GET(eo_it), WIDGET(it), key);
if (ic)
{
it->content_objs = eina_list_append(it->content_objs, ic);
edje_object_part_swallow(VIEW(it), key, ic);
evas_object_show(ic);
elm_widget_sub_object_add(WIDGET(it), ic);
}
}
}
if (it->itc->func.state_get)
{
const Eina_List *l;
const char *key;
it->states =
elm_widget_stringlist_get(edje_object_data_get(VIEW(it), "states"));
EINA_LIST_FOREACH(it->states, l, key)
{
Eina_Bool on = it->itc->func.state_get
((void *)WIDGET_ITEM_DATA_GET(eo_it), WIDGET(it), l->data);
if (on)
{
snprintf(buf, sizeof(buf), "elm,state,%s,active", key);
edje_object_signal_emit(VIEW(it), buf, "elm");
}
}
}
/* infate texts, contents and states of view object */
_view_inflate(VIEW(it), it, &it->texts, &it->contents);
if (it->group)
{
@ -981,15 +1292,7 @@ _item_realize(Elm_Gen_Item *it)
&sd->item_height);
}
evas_object_event_callback_add
(VIEW(it), EVAS_CALLBACK_MOUSE_DOWN, _item_mouse_down_cb, it);
evas_object_event_callback_add
(VIEW(it), EVAS_CALLBACK_MOUSE_UP, _item_mouse_up_cb, it);
evas_object_event_callback_add
(VIEW(it), EVAS_CALLBACK_MOUSE_MOVE, _item_mouse_move_cb, it);
evas_object_event_callback_add
(VIEW(it), EVAS_CALLBACK_MOUSE_IN, _item_mouse_in_cb, it);
_item_mouse_callbacks_add(it, VIEW(it));
_elm_gengrid_item_index_update(it);
if (it->selected)
@ -3236,6 +3539,7 @@ _mirrored_set(Evas_Object *obj,
ELM_GENGRID_DATA_GET(obj, sd);
_item_cache_zero(sd);
eo_do_super(obj, MY_CLASS, elm_interface_scrollable_mirrored_set(rtl));
if (!sd->items) return;
@ -3747,6 +4051,7 @@ _elm_gengrid_evas_object_smart_add(Eo *obj, Elm_Gengrid_Data *priv)
priv->align_x = 0.5;
priv->align_y = 0.5;
priv->highlight = EINA_TRUE;
priv->item_cache_max = CACHE_MAX;
priv->pan_obj = eo_add(MY_PAN_CLASS, evas_object_evas_get(obj));
pan_data = eo_data_scope_get(priv->pan_obj, MY_PAN_CLASS);
@ -3768,6 +4073,7 @@ _elm_gengrid_evas_object_smart_del(Eo *obj, Elm_Gengrid_Data *sd)
ELM_SAFE_FREE(sd->pan_obj, evas_object_del);
ELM_SAFE_FREE(sd->stack, evas_object_del);
_item_cache_zero(sd);
ecore_job_del(sd->calc_job);
eo_do_super(obj, MY_CLASS, evas_obj_smart_del());
@ -4075,6 +4381,28 @@ _elm_gengrid_item_update(Eo *eo_item EINA_UNUSED, Elm_Gen_Item *it)
_item_place(it, it->x, it->y);
}
EOLIAN static void
_elm_gengrid_item_fields_update(Eo *eo_item EINA_UNUSED, Elm_Gen_Item *it,
const char *parts,
Elm_Gengrid_Item_Field_Type itf)
{
ELM_GENGRID_ITEM_CHECK_OR_RETURN(it);
if (!it->realized) return;
if (it->want_unrealize) return;
if ((!itf) || (itf & ELM_GENGRID_ITEM_FIELD_TEXT))
_item_text_realize(it, VIEW(it), &it->texts, parts);
if ((!itf) || (itf & ELM_GENGRID_ITEM_FIELD_CONTENT))
_item_content_realize(it, VIEW(it), &it->contents, "contents", parts);
if ((!itf) || (itf & ELM_GENGRID_ITEM_FIELD_STATE))
_item_state_realize(it, VIEW(it), parts);
_item_place(it, it->x, it->y);
}
EOLIAN static const Elm_Gengrid_Item_Class *
_elm_gengrid_item_item_class_get(Eo *eo_item EINA_UNUSED, Elm_Gen_Item *item)
{
@ -4090,6 +4418,8 @@ _elm_gengrid_item_item_class_update(Eo *eo_it EINA_UNUSED, Elm_Gen_Item *it,
if (it->generation < GG_IT(it)->wsd->generation) return;
it->itc = itc;
it->item->nocache_once = EINA_TRUE;
elm_gengrid_item_update(EO_OBJ(it));
}

View File

@ -4,7 +4,7 @@
/**
* Defines where to position the item in the genlist.
*
* @ingroup Genlist
* @ingroup Gengrid
*/
typedef enum
{
@ -15,6 +15,21 @@ typedef enum
} Elm_Gengrid_Item_Scrollto_Type;
/**
* Defines the type of the item part
* Used while updating item's parts
* It can be used at updating multi fields.
*
* @ingroup Gengrid
*/
typedef enum
{
ELM_GENGRID_ITEM_FIELD_ALL = 0,
ELM_GENGRID_ITEM_FIELD_TEXT = (1 << 0),
ELM_GENGRID_ITEM_FIELD_CONTENT = (1 << 1),
ELM_GENGRID_ITEM_FIELD_STATE = (1 << 2)
} Elm_Gengrid_Item_Field_Type;
/**
* @see Elm_Gen_Item_Class
*/

View File

@ -209,6 +209,29 @@ class Elm.Gengrid_Item(Elm.Widget_Item)
@ingroup Gengrid
*/
}
fields_update {
/*@
Update the part of an item
This updates an item's part by calling item's fetching functions again
to get the contents, texts and states. Use this when the original
item data has changed and the changes are desired to be reflected.
Second parts argument is used for globbing to match '*', '?', and '.'
It can be used at updating multi fields.
Use elm_gengrid_realized_items_update() to update an item's all
property.
@see elm_gengrid_iitem_update()
@ingroup Gengrid
@since 1.15
*/
params {
@in parts: const (char) *; /*@ The name of item's part */
@in itf: Elm_Gengrid_Item_Field_Type; /*@ The type of item's part type */
}
}
item_class_update {
/*@
Update the item class of a gengrid item.

View File

@ -129,6 +129,12 @@ struct _Elm_Gengrid_Data
Eina_Bool wheel_disabled : 1; /**< a flag that shows mouse wheel is disabled or not. */
/**< value whether item loop feature is enabled or not. */
Eina_Bool item_loop_enable : 1;
Eina_Inlist *item_cache; /* an inlist of
* edje object it
* cache. */
int item_cache_count;
int item_cache_max;
};
struct Elm_Gen_Item_Type
@ -144,6 +150,17 @@ struct Elm_Gen_Item_Type
Eina_Bool group_realized : 1;
Eina_Bool moving : 1;
Eina_Bool nocache_once : 1; /* do not use cache for
* this item only once */
Eina_Bool nocache : 1; /* do not use cache for this item */
};
typedef struct _Item_Cache Item_Cache;
struct _Item_Cache
{
EINA_INLIST;
Evas_Object *base_view, *spacer;
const char *item_style; // it->itc->item_style
};
typedef struct _Elm_Gengrid_Pan_Data Elm_Gengrid_Pan_Data;