gengrid: add item cache in gengrid for efficient realize/unrealize operation.
authorSangHyeon Lee <dltkdgus1764@gmail.com>
Thu, 25 Jun 2015 14:28:07 +0000 (16:28 +0200)
committerCedric BAIL <cedric@osg.samsung.com>
Thu, 25 Jun 2015 15:24:08 +0000 (17:24 +0200)
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>
src/bin/test.c
src/bin/test_gengrid.c
src/lib/elm_gengrid.c
src/lib/elm_gengrid_common.h
src/lib/elm_gengrid_item.eo
src/lib/elm_widget_gengrid.h

index 443d69c..04fb02d 100644 (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);
index 99ef7fe..ffd4857 100644 (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);
+}
index 0c12c9b..e8a7fde 100644 (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)
 {
@@ -614,11 +780,196 @@ _item_mouse_down_cb(void *data,
 }
 
 static void
-_elm_gengrid_item_unrealize(Elm_Gen_Item *it,
-                            Eina_Bool calc)
+_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)
+{
    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);
-   ELM_SAFE_FREE(it->states, elm_widget_stringlist_free);
 
-   EINA_LIST_FREE(it->content_objs, content)
-     evas_object_del(content);
+   _view_clear(VIEW(it), &(it->texts), &(it->contents));
 
+   ELM_SAFE_FREE(it->states, elm_widget_stringlist_free);
    eo_do(EO_OBJ(it), elm_wdg_item_track_cancel());
 
    it->unrealize_cb(it);
@@ -766,6 +1114,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)
 {
    if (it->position_update)
@@ -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));
 }
 
index b5aa1f9..a38717f 100644 (file)
@@ -4,7 +4,7 @@
 /**
  * Defines where to position the item in the genlist.
  *
- * @ingroup Genlist
+ * @ingroup Gengrid
  */
 typedef enum
 {
@@ -16,6 +16,21 @@ typedef enum
 
 
 /**
+ * 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
  */
 typedef Elm_Gen_Item_Class Elm_Gengrid_Item_Class;
index 18b9868..913199c 100644 (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.
index 5ffca37..586400f 100644 (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;