From 63c665cc9fbd5ae7f13dea1f2cf9fbd0be2897e5 Mon Sep 17 00:00:00 2001 From: Larry Jr Date: Fri, 7 Jul 2017 17:42:55 -0300 Subject: elementary, efl_ui_list added lazy load WIP --- src/examples/elementary/efl_ui_list_example_1.c | 7 +- src/lib/elementary/efl_ui_list.c | 716 ++++++++++++++---------- src/lib/elementary/efl_ui_list_private.h | 49 +- 3 files changed, 456 insertions(+), 316 deletions(-) diff --git a/src/examples/elementary/efl_ui_list_example_1.c b/src/examples/elementary/efl_ui_list_example_1.c index ff9b2d75df..cdbebee2ad 100644 --- a/src/examples/elementary/efl_ui_list_example_1.c +++ b/src/examples/elementary/efl_ui_list_example_1.c @@ -42,8 +42,7 @@ _realized_cb(void *data, const Efl_Event *event) Efl_Ui_List_Item_Event *ie = event->info; Private_Data *pd = data; - ie->layout = efl_add(ELM_LAYOUT_CLASS, pd->li); - efl_ui_view_model_set(ie->layout, ie->child); + //efl_ui_view_model_set(ie->layout, ie->child); elm_layout_theme_set(ie->layout, "list", "item", "default"); evas_object_size_hint_weight_set(ie->layout, EVAS_HINT_EXPAND, 0); @@ -59,8 +58,8 @@ _unrealized_cb(void *data EINA_UNUSED, const Efl_Event *event) { Efl_Ui_List_Item_Event *ie = event->info; - efl_ui_view_model_set(ie->layout, NULL); - efl_del(ie->layout); + //efl_ui_view_model_set(ie->layout, NULL); + //efl_del(ie->layout); } static Efl_Model* diff --git a/src/lib/elementary/efl_ui_list.c b/src/lib/elementary/efl_ui_list.c index 09598aab4f..53397c96fd 100644 --- a/src/lib/elementary/efl_ui_list.c +++ b/src/lib/elementary/efl_ui_list.c @@ -10,7 +10,7 @@ #define SIG_CHILD_ADDED "child,added" #define SIG_CHILD_REMOVED "child,removed" #define SELECTED_PROP "selected" -#define MAX_ITEMS_PER_BLOCK 32 +#define AVERAGE_SIZE_INIT 10 static const Evas_Smart_Cb_Description _smart_callbacks[] = { {SIG_CHILD_ADDED, ""}, @@ -18,12 +18,15 @@ static const Evas_Smart_Cb_Description _smart_callbacks[] = { {NULL, NULL} }; -void _efl_ui_list_custom_layout(Efl_Ui_List *list); -void _efl_ui_list_item_select_set(Efl_Ui_List_Item *item, Eina_Bool select); -Eina_Bool _efl_ui_list_item_select_clear(Eo *obj); -Efl_Ui_List_Item *_child_new(Efl_Ui_List_Data *pd, Efl_Model *model); -void _child_remove(Efl_Ui_List_Data *pd, Efl_Ui_List_Item *item); -void _realize_items(Eo *obj, Efl_Ui_List_Data *pd); +void _efl_ui_list_custom_layout(Efl_Ui_List *); +void _efl_ui_list_item_select_set(Efl_Ui_List_Item *, Eina_Bool); +Eina_Bool _efl_ui_list_item_select_clear(Eo *); +static Efl_Ui_List_Item *_child_new(Efl_Ui_List_Data *, Efl_Model *); +static void _child_remove(Efl_Ui_List_Data *, Efl_Ui_List_Item *); +static void _item_calc(Efl_Ui_List_Data *, Efl_Ui_List_Item *); +static void _layout_realize(Efl_Ui_List_Data *, Efl_Ui_List_Item *); +static void _layout_unrealize(Efl_Ui_List_Data *, Efl_Ui_List_Item *); +static Eina_Bool _load_items(Eo *, Efl_Ui_List_Data *, Eina_Bool); static Eina_Bool _key_action_move(Evas_Object *obj, const char *params); static Eina_Bool _key_action_select(Evas_Object *obj, const char *params); @@ -45,29 +48,47 @@ _horiz(Efl_Orient dir) EOLIAN static void _efl_ui_list_pan_elm_pan_pos_set(Eo *obj EINA_UNUSED, Efl_Ui_List_Pan_Data *psd, Evas_Coord x, Evas_Coord y) { - Evas_Coord ox, oy, ow, oh; + Evas_Coord ox, oy, ow, oh, cw; Efl_Ui_List_Data *pd = psd->wpd; Efl_Ui_List_Item *litem; - Eina_List *li; + Eina_Array_Iterator iterator; + unsigned int i; - if ((x == pd->pan_x) && (y == pd->pan_y)) return; - pd->pan_x = x; - pd->pan_y = y; + EINA_SAFETY_ON_NULL_RETURN(pd); + if (((x == pd->pan.x) && (y == pd->pan.y))) return; - evas_object_geometry_get(psd->wobj, &ox, &oy, &ow, &oh); + evas_object_geometry_get(pd->obj, &ox, &oy, &ow, &oh); + if (_horiz(pd->orient)) + { + pd->pan.diff += x - pd->pan.x; + cw = ow / 4; + } + else + { + pd->pan.diff += y - pd->pan.y; + cw = oh / 4; + } + + pd->pan.x = x; + pd->pan.y = y; - EINA_LIST_FOREACH(pd->realizes, li, litem) + if (abs(pd->pan.diff) > cw) { - if (litem->layout) - evas_object_move(litem->layout, (litem->x + 0 - pd->pan_x), (litem->y + 0 - pd->pan_y)); + pd->pan.diff = 0; + _load_items(obj, pd, EINA_FALSE); +// _efl_ui_list_custom_layout(pd->obj); + return; } + + EINA_ARRAY_ITER_NEXT(pd->items, i, litem, iterator) + evas_object_move(litem->layout, (litem->x + 0 - pd->pan.x), (litem->y + 0 - pd->pan.y)); } EOLIAN static void _efl_ui_list_pan_elm_pan_pos_get(Eo *obj EINA_UNUSED, Efl_Ui_List_Pan_Data *psd, Evas_Coord *x, Evas_Coord *y) { - if (x) *x = psd->wpd->pan_x; - if (y) *y = psd->wpd->pan_y; + if (x) *x = psd->wpd->pan.x; + if (y) *y = psd->wpd->pan.y; } EOLIAN static void @@ -144,8 +165,10 @@ _child_added_cb(void *data, const Efl_Event *event) Efl_Model_Children_Event* evt = event->info; Efl_Ui_List *obj = data; EFL_UI_LIST_DATA_GET_OR_RETURN(obj, pd); + pd->item_count++; - _child_new(pd, evt->child); +//FIXME: the new data is visible? is yes reload sliced children and test if have changes +// _child_new(pd, evt->child); evas_object_smart_changed(pd->obj); } @@ -154,21 +177,23 @@ _child_removed_cb(void *data, const Efl_Event *event) { Efl_Model_Children_Event* evt = event->info; Efl_Ui_List *obj = data; - Efl_Ui_List_Item *item = NULL; - Eina_List *li; + Efl_Ui_List_Item *item; + Eina_Array_Iterator iterator; + unsigned int i; EFL_UI_LIST_DATA_GET_OR_RETURN(obj, pd); + pd->item_count--; - EINA_LIST_FOREACH(pd->items, li, item) + EINA_ARRAY_ITER_NEXT(pd->items, i, item, iterator) { if (item->model == evt->child) { _child_remove(pd, item); - pd->items = eina_list_remove_list(pd->items, li); + //FIXME pd->items = eina_list_remove_list(pd->items, li); + evas_object_smart_changed(pd->obj); break; } } - evas_object_smart_changed(pd->obj); } static void @@ -281,6 +306,25 @@ _item_selected_then(void * data, Efl_Event const* event) } } +static void +_count_then(void * data, Efl_Event const* event) +{ + Efl_Ui_List_Data *pd = data; + EINA_SAFETY_ON_NULL_RETURN(pd); + int *count = ((Efl_Future_Event_Success*)event->info)->value; + + pd->future = NULL; + pd->item_count = *count; +} + +static void +_count_error(void * data, Efl_Event const* event EINA_UNUSED) +{ + Efl_Ui_List_Data *pd = data; + EINA_SAFETY_ON_NULL_RETURN(pd); + pd->future = NULL; +} + static void _item_property_then(void * data, Efl_Event const* event) { @@ -294,8 +338,7 @@ _item_property_then(void * data, Efl_Event const* event) if (vtype == EINA_VALUE_TYPE_STRING || vtype == EINA_VALUE_TYPE_STRINGSHARE) eina_value_get(value, &style); - if (item->layout) - elm_object_style_set(item->layout, style); + elm_object_style_set(item->layout, style); } static void @@ -330,53 +373,31 @@ _efl_model_properties_changed_cb(void *data, const Efl_Event *event) } } -void +static void _child_remove(Efl_Ui_List_Data *pd, Efl_Ui_List_Item *item) { EINA_SAFETY_ON_NULL_RETURN(item); EINA_SAFETY_ON_NULL_RETURN(item->model); - if (item->future) - { - efl_future_cancel(item->future); - item->future = NULL; - } - - if (pd->focused == item) - { - pd->focused = NULL; - } - - if (item->selected) - { - item->selected = EINA_FALSE; - pd->selected = eina_list_remove(pd->selected, item); - } - - efl_event_callback_del(item->model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _efl_model_properties_changed_cb, item); + _layout_unrealize(pd, item); - efl_unref(item->model); + elm_widget_sub_object_del(pd->obj, item->layout); free(item); } -static Eina_Bool +static void _layout_realize(Efl_Ui_List_Data *pd, Efl_Ui_List_Item *item) { Efl_Ui_List_Item_Event evt; + efl_ui_view_model_set(item->layout, item->model); //XXX: move to realize?? + evt.child = item->model; - evt.layout = NULL; + evt.layout = item->layout; evt.index = item->index; - efl_event_callback_call(item->obj, EFL_UI_LIST_EVENT_ITEM_REALIZED, &evt); - - pd->realizes = eina_list_append(pd->realizes, item); - if (evt.layout == NULL) - return EINA_FALSE; - - item->layout = efl_ref(evt.layout); - elm_widget_sub_object_add(pd->obj, item->layout); - evas_object_smart_member_add(item->layout, pd->pan_obj); + efl_event_callback_add(item->model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _efl_model_properties_changed_cb, item); //XXX move to elm_layout obj?? + efl_event_callback_call(item->obj, EFL_UI_LIST_EVENT_ITEM_REALIZED, &evt); evas_object_show(item->layout); @@ -388,7 +409,7 @@ _layout_realize(Efl_Ui_List_Data *pd, Efl_Ui_List_Item *item) if (pd->select_mode != ELM_OBJECT_SELECT_MODE_NONE) efl_ui_model_connect(item->layout, "signal/elm,state,%v", "selected"); - return EINA_TRUE; + _item_calc(pd, item); } static void @@ -397,23 +418,37 @@ _layout_unrealize(Efl_Ui_List_Data *pd, Efl_Ui_List_Item *item) Efl_Ui_List_Item_Event evt; EINA_SAFETY_ON_NULL_RETURN(item); - if (item->layout) + if (item->future) + { + efl_future_cancel(item->future); + item->future = NULL; + } + + if (pd->focused == item) + pd->focused = NULL; + + if (item->selected) { - efl_event_callback_del(item->layout, ELM_WIDGET_EVENT_FOCUSED, _on_item_focused, item); - efl_event_callback_del(item->layout, ELM_WIDGET_EVENT_UNFOCUSED, _on_item_unfocused, item); - evas_object_event_callback_del_full(item->layout, EVAS_CALLBACK_MOUSE_DOWN, _on_item_mouse_down, item); - evas_object_event_callback_del_full(item->layout, EVAS_CALLBACK_MOUSE_UP, _on_item_mouse_up, item); - efl_ui_model_connect(item->layout, "signal/elm,state,%v", NULL); - elm_widget_sub_object_del(pd->obj, item->layout); - efl_unref(item->layout); + item->selected = EINA_FALSE; + pd->selected = eina_list_remove(pd->selected, item); } + efl_event_callback_del(item->model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _efl_model_properties_changed_cb, item); + efl_event_callback_del(item->layout, ELM_WIDGET_EVENT_FOCUSED, _on_item_focused, item); + efl_event_callback_del(item->layout, ELM_WIDGET_EVENT_UNFOCUSED, _on_item_unfocused, item); + evas_object_event_callback_del_full(item->layout, EVAS_CALLBACK_MOUSE_DOWN, _on_item_mouse_down, item); + evas_object_event_callback_del_full(item->layout, EVAS_CALLBACK_MOUSE_UP, _on_item_mouse_up, item); + efl_ui_model_connect(item->layout, "signal/elm,state,%v", NULL); + evt.child = item->model; evt.layout = item->layout; evt.index = item->index; efl_event_callback_call(item->obj, EFL_UI_LIST_EVENT_ITEM_UNREALIZED, &evt); + efl_ui_view_model_set(item->layout, NULL); + + efl_unref(item->model); - pd->realizes = eina_list_remove(pd->realizes, item); + evas_object_hide(item->layout); } Efl_Ui_List_Item * @@ -421,73 +456,168 @@ _child_new(Efl_Ui_List_Data *pd, Efl_Model *model) { EINA_SAFETY_ON_NULL_RETURN_VAL(pd, NULL); - Eina_Stringshare *style_prop = eina_stringshare_add("style"); Efl_Ui_List_Item *item = calloc(1, sizeof(Efl_Ui_List_Item)); item->obj = pd->obj; item->model = efl_ref(model); - item->layout = NULL; + item->layout = efl_add(ELM_LAYOUT_CLASS, pd->obj); item->future = NULL; - item->index = eina_list_count(pd->items); + item->index = eina_array_count(pd->items) + pd->realized.start; - pd->items = eina_list_append(pd->items, item); + elm_widget_sub_object_add(pd->obj, item->layout); + evas_object_smart_member_add(item->layout, pd->pan.obj); - efl_event_callback_add(item->model, EFL_MODEL_EVENT_PROPERTIES_CHANGED, _efl_model_properties_changed_cb, item); +// FIXME: really need get it in model? + Eina_Stringshare *style_prop = eina_stringshare_add("style"); if (_efl_model_properties_has(item->model, style_prop)) { item->future = efl_model_property_get(item->model, style_prop); efl_future_then(item->future, &_item_property_then, &_item_property_error, NULL, item); } eina_stringshare_del(style_prop); - +// + _layout_realize(pd, item); return item; } static void _children_then(void * data, Efl_Event const* event) { - Efl_Ui_List_Data *pd = data; + Efl_Ui_List_Slice *sd = data; + Efl_Ui_List_Data *pd = sd->pd; Eina_Accessor *acc = (Eina_Accessor*)((Efl_Future_Event_Success*)event->info)->value; Eo *child_model; - unsigned i = 0; + Efl_Ui_List_Item *item; + unsigned i, idx, count, diff; + Eina_Bool horz = _horiz(pd->orient); + Eina_Array *array = pd->items; EINA_SAFETY_ON_NULL_RETURN(pd); + + pd->future = NULL; EINA_SAFETY_ON_NULL_RETURN(acc); ELM_WIDGET_DATA_GET_OR_RETURN(pd->obj, wd); + count = eina_array_count(pd->items); - EINA_ACCESSOR_FOREACH(acc, i, child_model) + if (sd->slicestart < pd->realized.start) { - _child_new(pd, child_model); + diff = pd->realized.start - sd->newstart; + diff = diff > count ? count : diff; + idx = count - diff; + if (diff) + { + Efl_Ui_List_Item **cacheit; + size_t s = sizeof(Efl_Ui_List_Item *); + + cacheit = calloc(diff, s); + memcpy(cacheit, array->data+idx, diff * s); + + for (i = idx; i < count; ++i) + { + item = eina_array_data_get(array, i); + _layout_unrealize(pd, item); + } + memmove(array->data+diff, array->data, idx * s); + memcpy(array->data, cacheit, diff * s); + } + idx = 0; + } + else + { + diff = sd->newstart - pd->realized.start; + diff = diff > count ? count : diff; + idx = count - diff; + if (diff) + { + Efl_Ui_List_Item **cacheit; + size_t s = sizeof(Efl_Ui_List_Item *); + + cacheit = calloc(diff, s); + memcpy(cacheit, array->data, diff * s); + + for (i = 0; i < diff; ++i) + { + item = eina_array_data_get(array, i); + _layout_unrealize(pd, item); + } + memmove(array->data, array->data+diff, idx * s); + memcpy(array->data+idx, cacheit, diff * s); + } } + EINA_ACCESSOR_FOREACH(acc, i, child_model) + { + if (idx < eina_array_count(array)) + { + item = eina_array_data_get(array, idx); + item->model = efl_ref(child_model); + item->index = sd->newstart + idx; + + if (horz) + pd->realized.w -= item->minw; + else + pd->realized.h -= item->minh; + + _layout_realize(pd, item); + } + else + { + item = _child_new(pd, child_model); + eina_array_push(pd->items, item); + } + if (horz) + { + pd->realized.w += item->minw; + if (item->minh > pd->realized.h) + pd->realized.h = item->minh; + } + else + { + pd->realized.h += item->minh; + if (item->minw > pd->realized.w) + pd->realized.w = item->minw; + } + ++idx; + } + + pd->avsom = horz ? pd->realized.w : pd->realized.h; + pd->realized.start = sd->newstart; + free(sd); + pd->avit = pd->avsom / eina_array_count(pd->items); evas_object_smart_changed(pd->obj); } static void _efl_ui_list_children_free(Eo *obj EINA_UNUSED, Efl_Ui_List_Data *pd) { + Eina_Array_Iterator iterator; Efl_Ui_List_Item *item; - Eina_List *li; + unsigned int i; EINA_SAFETY_ON_NULL_RETURN(pd); if(!pd->items) return; + EINA_ARRAY_ITER_NEXT(pd->items, i, item, iterator) + { + _layout_unrealize(pd, item); + free(item); + item = NULL; + } - EINA_LIST_FOREACH(pd->realizes, li, item) - _layout_unrealize(pd, item); - - EINA_LIST_FREE(pd->items, item) - _child_remove(pd, item); - - pd->items = NULL; + eina_array_clean(pd->items); } static void _children_error(void * data EINA_UNUSED, Efl_Event const* event EINA_UNUSED) -{} +{ + Efl_Ui_List_Slice *sd = data; + Efl_Ui_List_Data *pd = sd->pd; + pd->future = NULL; + free(data); +} static void _show_region_hook(void *data EINA_UNUSED, Evas_Object *obj) @@ -499,29 +629,20 @@ _show_region_hook(void *data EINA_UNUSED, Evas_Object *obj) elm_interface_scrollable_content_region_show(obj, x, y, w, h); } -static void -_update_viewmodel(Eo *obj, Efl_Ui_List_Data *pd) -{ - _efl_ui_list_children_free(obj, pd); - efl_future_then(efl_model_children_slice_get(pd->model, 0, 0), - &_children_then, &_children_error, NULL, pd); -} - EOLIAN static void _efl_ui_list_select_mode_set(Eo *obj EINA_UNUSED, Efl_Ui_List_Data *pd, Elm_Object_Select_Mode mode) { + Eina_Array_Iterator iterator; Efl_Ui_List_Item *item; - Eina_List *li; + unsigned int i; if (pd->select_mode == mode) return; if (pd->select_mode == ELM_OBJECT_SELECT_MODE_NONE) { - EINA_LIST_FOREACH(pd->realizes, li, item) + EINA_ARRAY_ITER_NEXT(pd->items, i, item, iterator) { - if (!item->layout) continue; - if (item->selected) elm_layout_signal_emit(item->layout, "elm,state,selected", "elm"); @@ -530,10 +651,8 @@ _efl_ui_list_select_mode_set(Eo *obj EINA_UNUSED, Efl_Ui_List_Data *pd, Elm_Obje } else if (mode == ELM_OBJECT_SELECT_MODE_NONE) { - EINA_LIST_FOREACH(pd->realizes, li, item) + EINA_ARRAY_ITER_NEXT(pd->items, i, item, iterator) { - if (!item->layout) continue; - if (item->selected) elm_layout_signal_emit(item->layout, "elm,state,unselected", "elm"); @@ -613,8 +732,8 @@ _efl_ui_list_elm_widget_focus_next(Eo *obj, Efl_Ui_List_Data *pd, Elm_Focus_Dire list_data_get = eina_list_data_get; else { - items = pd->items; - list_data_get = _efl_ui_list_eina_list_layout_get; + // items = pd->items; + //FIXME list_data_get = _efl_ui_list_eina_list_layout_get; if (!items) return EINA_FALSE; } @@ -638,8 +757,8 @@ _efl_ui_list_elm_widget_focus_direction(Eo *obj, Efl_Ui_List_Data *pd, const Eva list_data_get = eina_list_data_get; else { - items = pd->items; - list_data_get = _efl_ui_list_eina_list_layout_get; +//FIXME items = pd->items; +// list_data_get = _efl_ui_list_eina_list_layout_get; if (!items) return EINA_FALSE; } @@ -665,7 +784,7 @@ _efl_ui_list_efl_gfx_position_set(Eo *obj, Efl_Ui_List_Data *pd, Evas_Coord x, E efl_gfx_position_set(efl_super(obj, MY_CLASS), x, y); evas_object_move(pd->hit_rect, x, y); - evas_object_move(pd->pan_obj, x - pd->pan_x, y - pd->pan_y); + evas_object_move(pd->pan.obj, x - pd->pan.x, y - pd->pan.y); _efl_ui_list_custom_layout(obj); } @@ -676,9 +795,11 @@ _efl_ui_list_efl_gfx_size_set(Eo *obj, Efl_Ui_List_Data *pd, Evas_Coord w, Evas_ return; efl_gfx_size_set(efl_super(obj, MY_CLASS), w, h); - evas_object_resize(pd->hit_rect, w, h); - printf("resize %d %d \n", w, h); + + if (_load_items(obj, pd, EINA_TRUE)) + return; + _efl_ui_list_custom_layout(obj); } @@ -746,16 +867,17 @@ _efl_ui_list_efl_canvas_group_group_add(Eo *obj, Efl_Ui_List_Data *pd EINA_UNUSE (obj, EINA_FALSE, _elm_config->thumbscroll_bounce_enable); pd->mode = ELM_LIST_COMPRESS; + pd->avit = AVERAGE_SIZE_INIT; elm_interface_atspi_accessible_type_set(obj, ELM_ATSPI_TYPE_DISABLED); - pd->pan_obj = efl_add(MY_PAN_CLASS, evas_object_evas_get(obj)); - pan_data = efl_data_scope_get(pd->pan_obj, MY_PAN_CLASS); + pd->pan.obj = efl_add(MY_PAN_CLASS, evas_object_evas_get(obj)); + pan_data = efl_data_scope_get(pd->pan.obj, MY_PAN_CLASS); efl_data_ref(obj, MY_CLASS); pan_data->wobj = obj; pan_data->wpd = pd; - elm_interface_scrollable_extern_pan_set(obj, pd->pan_obj); - evas_object_show(pd->pan_obj); + elm_interface_scrollable_extern_pan_set(obj, pd->pan.obj); + evas_object_show(pd->pan.obj); edje_object_size_min_calc(wd->resize_obj, &minw, &minh); evas_object_size_hint_min_set(obj, minw, minh); @@ -767,11 +889,11 @@ _efl_ui_list_efl_canvas_group_group_add(Eo *obj, Efl_Ui_List_Data *pd EINA_UNUSE EOLIAN static void _efl_ui_list_efl_canvas_group_group_del(Eo *obj, Efl_Ui_List_Data *pd) { - pd->delete_me = EINA_TRUE; - _efl_ui_list_children_free(obj, pd); - ELM_SAFE_FREE(pd->pan_obj, evas_object_del); + eina_array_free(pd->items); + + ELM_SAFE_FREE(pd->pan.obj, evas_object_del); efl_canvas_group_del(efl_super(obj, MY_CLASS)); } @@ -807,23 +929,30 @@ _efl_ui_list_efl_ui_view_model_set(Eo *obj, Efl_Ui_List_Data *pd, Efl_Model *mod if (pd->model == model) return; + if (pd->future) efl_future_cancel(pd->future); + if (pd->model) { - efl_event_callback_del(pd->model, EFL_MODEL_EVENT_CHILD_ADDED, _child_added_cb, obj); - efl_event_callback_del(pd->model, EFL_MODEL_EVENT_CHILD_REMOVED, _child_removed_cb, obj); - efl_unref(pd->model); - pd->model = NULL; + efl_event_callback_del(pd->model, EFL_MODEL_EVENT_CHILD_ADDED, _child_added_cb, obj); + efl_event_callback_del(pd->model, EFL_MODEL_EVENT_CHILD_REMOVED, _child_removed_cb, obj); + efl_unref(pd->model); + pd->model = NULL; } + _efl_ui_list_children_free(obj, pd); + if (model) { - pd->model = model; - efl_ref(pd->model); - efl_event_callback_add(pd->model, EFL_MODEL_EVENT_CHILD_ADDED, _child_added_cb, obj); - efl_event_callback_add(pd->model, EFL_MODEL_EVENT_CHILD_REMOVED, _child_removed_cb, obj); + pd->model = model; + efl_ref(pd->model); + efl_event_callback_add(pd->model, EFL_MODEL_EVENT_CHILD_ADDED, _child_added_cb, obj); + efl_event_callback_add(pd->model, EFL_MODEL_EVENT_CHILD_REMOVED, _child_removed_cb, obj); + efl_future_then(efl_model_children_count_get(pd->model), &_count_then, &_count_error, NULL, pd); + if (_load_items(obj, pd, EINA_TRUE)) + return; } - _update_viewmodel(obj, pd); + _efl_ui_list_custom_layout(obj); } EOLIAN static Efl_Model * @@ -831,6 +960,7 @@ _efl_ui_list_efl_ui_view_model_get(Eo *obj EINA_UNUSED, Efl_Ui_List_Data *pd) { return pd->model; } + EOLIAN const Elm_Atspi_Action * _efl_ui_list_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUSED, Efl_Ui_List_Data *pd EINA_UNUSED) { @@ -854,11 +984,12 @@ _efl_ui_list_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUS EOLIAN Eina_List* _efl_ui_list_elm_interface_atspi_accessible_children_get(Eo *obj, Efl_Ui_List_Data *pd) { - Eina_List *ret = NULL, *ret2 = NULL; Efl_Ui_List_Item *litem; - Eina_List *li; + Eina_Array_Iterator iterator; + unsigned int i; + Eina_List *ret = NULL, *ret2 = NULL; - EINA_LIST_FOREACH(pd->realizes, li, litem) + EINA_ARRAY_ITER_NEXT(pd->items, i, litem, iterator) ret = eina_list_append(ret, litem->layout); ret2 = elm_interface_atspi_accessible_children_get(efl_super(obj, MY_CLASS)); @@ -887,7 +1018,7 @@ _efl_ui_list_elm_interface_atspi_selection_child_select(Eo *obj EINA_UNUSED, Efl { if (pd->select_mode != ELM_OBJECT_SELECT_MODE_NONE) { - Efl_Ui_List_Item *item = eina_list_nth(pd->items, child_index); + Efl_Ui_List_Item *item = eina_array_data_get(pd->items, child_index); if (item) _efl_ui_list_item_select_set(item, EINA_TRUE); return EINA_TRUE; @@ -910,7 +1041,7 @@ _efl_ui_list_elm_interface_atspi_selection_selected_child_deselect(Eo *obj EINA_ EOLIAN Eina_Bool _efl_ui_list_elm_interface_atspi_selection_is_child_selected(Eo *obj EINA_UNUSED, Efl_Ui_List_Data *pd, int child_index) { - Efl_Ui_List_Item *item = eina_list_nth(pd->items, child_index); + Efl_Ui_List_Item *item = eina_array_data_get(pd->items, child_index); EINA_SAFETY_ON_NULL_RETURN_VAL(item, EINA_FALSE); return item->selected; } @@ -919,12 +1050,13 @@ EOLIAN Eina_Bool _efl_ui_list_elm_interface_atspi_selection_all_children_select(Eo *obj EINA_UNUSED, Efl_Ui_List_Data *pd) { Efl_Ui_List_Item *item; - Eina_List *l; + Eina_Array_Iterator iterator; + unsigned int i; if (pd->select_mode == ELM_OBJECT_SELECT_MODE_NONE) return EINA_FALSE; - EINA_LIST_FOREACH(pd->items, l, item) + EINA_ARRAY_ITER_NEXT(pd->items, i, item, iterator) _efl_ui_list_item_select_set(item, EINA_TRUE); return EINA_TRUE; @@ -948,7 +1080,7 @@ _efl_ui_list_elm_interface_atspi_selection_clear(Eo *obj EINA_UNUSED, Efl_Ui_Lis EOLIAN Eina_Bool _efl_ui_list_elm_interface_atspi_selection_child_deselect(Eo *obj EINA_UNUSED, Efl_Ui_List_Data *pd, int child_index) { - Efl_Ui_List_Item *item = eina_list_nth(pd->items, child_index); + Efl_Ui_List_Item *item = eina_array_data_get(pd->items, child_index); if (item) { _efl_ui_list_item_select_set(item, EINA_FALSE); @@ -995,7 +1127,7 @@ static Eina_Bool _key_action_move(Evas_Object *obj, const char *params) else if (!strcmp(dir, "last")) { item = eina_list_data_get(eina_list_last(pd->items)); - elm_obj_pan_pos_max_get(pd->pan_obj, &x, &y); + elm_obj_pan_pos_max_get(pd->pan.obj, &x, &y); } else */ if (!strcmp(dir, "prior")) @@ -1127,72 +1259,97 @@ _efl_ui_list_item_select_set(Efl_Ui_List_Item *item, Eina_Bool selected) efl_event_callback_legacy_call(item->layout, EFL_UI_EVENT_UNSELECTED, item); } -typedef struct _Item_Calc Item_Calc; - -struct _Item_Calc +static void +_item_calc(Efl_Ui_List_Data *pd, Efl_Ui_List_Item *item) { - Evas_Object *obj; - double weight[2]; - double align[2]; - int max[2]; + Evas_Coord old_w, old_h; int pad[4]; - int want[2]; - int id; - Efl_Ui_List_Item *litem; -}; - -Evas_Coord -_item_weight_calc(Efl_Ui_List_Item *item, Eina_Bool horizon) -{ - Evas_Coord old_w, old_h, minw = 0, minh = 0; efl_gfx_size_hint_combined_min_get(item->layout, &old_w, &old_h); - edje_object_size_min_calc(elm_layout_edje_get(item->layout), &minw, &minh); + edje_object_size_min_calc(elm_layout_edje_get(item->layout), &item->minw, &item->minh); + efl_gfx_size_hint_margin_get(item->layout, &pad[0], &pad[1], &pad[2], &pad[3]); + efl_gfx_size_hint_weight_get(item->layout, &item->wx, &item->wy); + + if (old_w > item->minw) item->minw = old_w; + if (old_h > item->minh) item->minh = old_h; - if (old_w > minw) minw = old_w; - if (old_h > minh) minh = old_h; - evas_object_size_hint_min_set(item->layout, minw, minh); + if (item->wx < 0) item->wx = 0; + if (item->wy < 0) item->wy = 0; + evas_object_size_hint_min_set(item->layout, item->minw, item->minh); - if (horizon) - return minw; + item->minw += pad[0] + pad[1]; + item->minh += pad[2] + pad[3]; - return minh; + pd->weight.x += item->wx; + pd->weight.y += item->wy; } -void -_realize_items(Eo *obj, Efl_Ui_List_Data *pd) +static Eina_Bool +_load_items(Eo *obj, Efl_Ui_List_Data *pd, Eina_Bool recalc) { - Efl_Ui_List_Item *litem; - Eina_List *li, *subitems; - int rlzw, objw, i; - Eina_Bool horiz = _horiz(pd->orient); + Efl_Ui_List_Slice *sd; + int slice, slicestart, newstart, count = 0; + Evas_Coord w = 0, h = 0; - if (horiz) + if (pd->future) + efl_future_cancel(pd->future); + + if (pd->items) + count = eina_array_count(pd->items); + + if ((!recalc && count == pd->item_count) || pd->avit < 1) + return EINA_FALSE; + + evas_object_geometry_get(obj, NULL, NULL, &w, &h); + if (_horiz(pd->orient)) { - rlzw = pd->rlzw; - evas_object_geometry_get(obj, NULL, NULL, &objw, NULL); + slice = (w / pd->avit) * 2; + newstart = (pd->pan.x / pd->avit) - (slice / 4); } else { - rlzw = pd->rlzh; - evas_object_geometry_get(obj, NULL, NULL, NULL, &objw); + slice = (h / pd->avit) * 2; + newstart = (pd->pan.y / pd->avit) - (slice / 4); } - i = eina_list_count(pd->realizes); //TODO add unrealized upper items - subitems = eina_list_nth_list(pd->items, i); + slice = slice > 8 ? slice : 8; + slicestart = newstart = newstart > 1 ? newstart : 1; + + printf("avit=%d slice=%d\n", pd->avit, slice); + if (!recalc && newstart == pd->realized.start && slice == pd->realized.slice) + return EINA_FALSE; + + pd->realized.slice = slice; + if (!pd->items) + pd->items = eina_array_new(8); - EINA_LIST_FOREACH(subitems, li, litem) + if (count) { - if (rlzw > objw) - break; + if (newstart < pd->realized.start) + { + if(pd->realized.start - newstart < slice) + slice = pd->realized.start - newstart; + } + else if (newstart < pd->realized.start + count) + { + slicestart = pd->realized.start + count; + slice -= slicestart - newstart; + } + } - if (!_layout_realize(pd, litem)) - continue; + printf("start=%d slicestart=%d slice=%d\n", newstart, slicestart, slice); + if (slice > 0) + { + sd = malloc(sizeof(Efl_Ui_List_Slice)); + sd->pd = pd; + sd->slicestart = slicestart; + sd->newstart = newstart; - rlzw += _item_weight_calc(litem, horiz); + pd->future = efl_model_children_slice_get(pd->model, slicestart, slice); + efl_future_then(pd->future, &_children_then, &_children_error, NULL, sd); } - return; + return EINA_TRUE; } void @@ -1201,19 +1358,17 @@ _efl_ui_list_custom_layout(Efl_Ui_List *ui_list) EFL_UI_LIST_DATA_GET_OR_RETURN(ui_list, pd); Efl_Ui_List_Item *litem; Evas_Object *o; - Eina_List *li; - int wantw = 0, wanth = 0; // requested size - int boxx, boxy, boxw, boxh; - Item_Calc *items, *item; Eina_Bool horiz = _horiz(pd->orient), zeroweight = EINA_FALSE; - int id = 0, count, boxl = 0, boxr = 0, boxt = 0, boxb = 0; - int length, want, pad, extra = 0, rounding = 0; - double cur_pos = 0, weight[2] = { 0, 0 }, scale; - double box_align[2]; + Evas_Coord ow, oh, want; + int boxx, boxy, boxw, boxh, length, pad, extra = 0, rounding = 0; + int boxl = 0, boxr = 0, boxt = 0, boxb = 0; + double cur_pos = 0, scale, box_align[2], weight[2] = { 0, 0 }; Eina_Bool box_fill[2] = { EINA_FALSE, EINA_FALSE }; - ELM_WIDGET_DATA_GET_OR_RETURN(ui_list, wd); + Eina_Array_Iterator iterator; + unsigned int i; + int id, count = 0; - _realize_items(ui_list, pd); + ELM_WIDGET_DATA_GET_OR_RETURN(ui_list, wd); evas_object_geometry_get(ui_list, &boxx, &boxy, &boxw, &boxh); efl_gfx_size_hint_margin_get(ui_list, &boxl, &boxr, &boxt, &boxb); @@ -1234,71 +1389,17 @@ _efl_ui_list_custom_layout(Efl_Ui_List *ui_list) box_align[1] = 0.5; } - count = eina_list_count(pd->realizes); + if (pd->items) + count = eina_array_count(pd->items); + if (!count) { evas_object_size_hint_min_set(wd->resize_obj, 0, 0); return; } - items = alloca(count * sizeof(*items)); -#ifdef DEBUG - memset(items, 0, count * sizeof(*items)); -#endif - - Evas_Coord ow, oh; elm_interface_scrollable_content_viewport_geometry_get (ui_list, NULL, NULL, &ow, &oh); - // scan all items, get their properties, calculate total weight & min size - EINA_LIST_FOREACH(pd->realizes, li, litem) - { - item = &items[id]; - o = item->obj = litem->layout; - item->litem = litem; - - efl_gfx_size_hint_weight_get(o, &item->weight[0], &item->weight[1]); - efl_gfx_size_hint_align_get(o, &item->align[0], &item->align[1]); - efl_gfx_size_hint_margin_get(o, &item->pad[0], &item->pad[1], &item->pad[2], &item->pad[3]); - efl_gfx_size_hint_max_get(o, &item->max[0], &item->max[1]); - efl_gfx_size_hint_combined_min_get(o, &item->want[0], &item->want[1]); - - if (item->weight[0] < 0) item->weight[0] = 0; - if (item->weight[1] < 0) item->weight[1] = 0; - - if (item->align[0] < 0) item->align[0] = -1; - if (item->align[1] < 0) item->align[1] = -1; - if (item->align[0] > 1) item->align[0] = 1; - if (item->align[1] > 1) item->align[1] = 1; - - if (item->want[0] < 0) item->want[0] = 0; - if (item->want[1] < 0) item->want[1] = 0; - - if (item->max[0] <= 0) item->max[0] = INT_MAX; - if (item->max[1] <= 0) item->max[1] = INT_MAX; - if (item->max[0] < item->want[0]) item->max[0] = item->want[0]; - if (item->max[1] < item->want[1]) item->max[1] = item->want[1]; - - item->want[0] += item->pad[0] + item->pad[1]; - item->want[1] += item->pad[2] + item->pad[3]; - - weight[0] += item->weight[0]; - weight[1] += item->weight[1]; - if (horiz) - { - wantw += item->want[0]; - if (item->want[1] > wanth) - wanth = item->want[1]; - } - else - { - wanth += item->want[1]; - if (item->want[0] > wantw) - wantw = item->want[0]; - } - - item->id = id++; - } - // box outer margin boxw -= boxl + boxr; boxh -= boxt + boxb; @@ -1309,47 +1410,43 @@ _efl_ui_list_custom_layout(Efl_Ui_List *ui_list) if (horiz) { length = boxw; - want = wantw; + want = pd->realized.w; pad = pd->pad.scalable ? (pd->pad.h * scale) : pd->pad.h; + + // padding can not be squeezed (note: could make it an option) + length -= pad * (count - 1); + // available space. if <0 we overflow + extra = length - want; + + pd->minw = pd->realized.w + boxl + boxr + pad * (count - 1); + pd->minh = pd->realized.h + boxt + boxb; + if (pd->item_count > count) + pd->minw *= pd->item_count / count; } else { length = boxh; - want = wanth; + want = pd->realized.h; pad = pd->pad.scalable ? (pd->pad.v * scale) : pd->pad.v; - } - // padding can not be squeezed (note: could make it an option) - length -= pad * (count - 1); + // padding can not be squeezed (note: could make it an option) + length -= pad * (count - 1); + // available space. if <0 we overflow + extra = length - want; - // available space. if <0 we overflow - extra = length - want; - - int ilen; - ilen = eina_list_count(pd->items); - if (horiz) - { - pd->minw = wantw + boxl + boxr + pad * (count - 1); - pd->minh = wanth + boxt + boxb; - pd->rlzw = pd->minw; - pd->rlzh = pd->minh; - if (ilen > count) - pd->minw *= ilen / count; - } - else - { - pd->minw = wantw + boxl + boxr; - pd->minh = wanth + pad * (count - 1) + boxt + boxb; - pd->rlzw = pd->minw; - pd->rlzh = pd->minh; - if (ilen > count) - pd->minh *= ilen / count; + pd->minw = pd->realized.w + boxl + boxr; + pd->minh = pd->realized.h + pad * (count - 1) + boxt + boxb; + printf("minh=%d, total=%d, count=%d\n", pd->minh, pd->item_count, count); + if (pd->item_count > count) + pd->minh *= pd->item_count / count; } evas_object_size_hint_min_set(wd->resize_obj, pd->minw, pd->minh); if (extra < 0) extra = 0; + weight[0] = pd->weight.x; + weight[1] = pd->weight.y; if (EINA_DBL_EQ(weight[!horiz], 0)) { if (box_fill[!horiz]) @@ -1365,20 +1462,42 @@ _efl_ui_list_custom_layout(Efl_Ui_List *ui_list) weight[!horiz] = count; } - for (id = 0; id < count; id++) + cur_pos += pd->avit * (pd->realized.start -1); + + id = 0; + // scan all items, get their properties, calculate total weight & min size + EINA_ARRAY_ITER_NEXT(pd->items, i, litem, iterator) { + o = litem->layout; double cx, cy, cw, ch, x, y, w, h; - item = &items[id]; + double align[2]; + int item_pad[4], max[2]; + + efl_gfx_size_hint_align_get(o, &align[0], &align[1]); + efl_gfx_size_hint_max_get(o, &max[0], &max[1]); + efl_gfx_size_hint_margin_get(o, &item_pad[0], &item_pad[1], &item_pad[2], &item_pad[3]); + + if (align[0] < 0) align[0] = -1; + if (align[1] < 0) align[1] = -1; + if (align[0] > 1) align[0] = 1; + if (align[1] > 1) align[1] = 1; + + if (max[0] <= 0) max[0] = INT_MAX; + if (max[1] <= 0) max[1] = INT_MAX; + if (max[0] < litem->minw) max[0] = litem->minw; + if (max[1] < litem->minh) max[1] = litem->minh; + + id++; // extra rounding up (compensate cumulative error) - if ((item->id == (count - 1)) && (cur_pos - floor(cur_pos) >= 0.5)) + if ((id == (count - 1)) && (cur_pos - floor(cur_pos) >= 0.5)) rounding = 1; if (horiz) { cx = boxx + cur_pos; cy = boxy; - cw = item->want[0] + rounding + (zeroweight ? 1.0 : item->weight[0]) * extra / weight[0]; + cw = litem->minw + rounding + (zeroweight ? 1.0 : litem->wx) * extra / weight[0]; ch = boxh; cur_pos += cw + pad; } @@ -1387,56 +1506,56 @@ _efl_ui_list_custom_layout(Efl_Ui_List *ui_list) cx = boxx; cy = boxy + cur_pos; cw = boxw; - ch = item->want[1] + rounding + (zeroweight ? 1.0 : item->weight[1]) * extra / weight[1]; + ch = litem->minh + rounding + (zeroweight ? 1.0 : litem->wy) * extra / weight[1]; cur_pos += ch + pad; } // horizontally - if (item->max[0] < INT_MAX) + if (max[0] < INT_MAX) { - w = MIN(MAX(item->want[0] - item->pad[0] - item->pad[1], item->max[0]), cw); - if (item->align[0] < 0) + w = MIN(MAX(litem->minw - item_pad[0] - item_pad[1], max[0]), cw); + if (align[0] < 0) { // bad case: fill+max are not good together - x = cx + ((cw - w) * box_align[0]) + item->pad[0]; + x = cx + ((cw - w) * box_align[0]) + item_pad[0]; } else - x = cx + ((cw - w) * item->align[0]) + item->pad[0]; + x = cx + ((cw - w) * align[0]) + item_pad[0]; } - else if (item->align[0] < 0) + else if (align[0] < 0) { // fill x - w = cw - item->pad[0] - item->pad[1]; - x = cx + item->pad[0]; + w = cw - item_pad[0] - item_pad[1]; + x = cx + item_pad[0]; } else { - w = item->want[0] - item->pad[0] - item->pad[1]; - x = cx + ((cw - w) * item->align[0]) + item->pad[0]; + w = litem->minw - item_pad[0] - item_pad[1]; + x = cx + ((cw - w) * align[0]) + item_pad[0]; } // vertically - if (item->max[1] < INT_MAX) + if (max[1] < INT_MAX) { - h = MIN(MAX(item->want[1] - item->pad[2] - item->pad[3], item->max[1]), ch); - if (item->align[1] < 0) + h = MIN(MAX(litem->minh - item_pad[2] - item_pad[3], max[1]), ch); + if (align[1] < 0) { // bad case: fill+max are not good together - y = cy + ((ch - h) * box_align[1]) + item->pad[2]; + y = cy + ((ch - h) * box_align[1]) + item_pad[2]; } else - y = cy + ((ch - h) * item->align[1]) + item->pad[2]; + y = cy + ((ch - h) * align[1]) + item_pad[2]; } - else if (item->align[1] < 0) + else if (align[1] < 0) { // fill y - h = ch - item->pad[2] - item->pad[3]; - y = cy + item->pad[2]; + h = ch - item_pad[2] - item_pad[3]; + y = cy + item_pad[2]; } else { - h = item->want[1] - item->pad[2] - item->pad[3]; - y = cy + ((ch - h) * item->align[1]) + item->pad[2]; + h = litem->minh - item_pad[2] - item_pad[3]; + y = cy + ((ch - h) * align[1]) + item_pad[2]; } if (horiz) @@ -1450,9 +1569,10 @@ _efl_ui_list_custom_layout(Efl_Ui_List *ui_list) if (w > ow) w = ow; } - item->litem->x = x; - item->litem->y = y; - evas_object_geometry_set(item->obj, (x + 0 - pd->pan_x), (y + 0 - pd->pan_y), w, h); + litem->x = x; + litem->y = y; + evas_object_geometry_set(o, (x + 0 - pd->pan.x), (y + 0 - pd->pan.y), w, h); +// printf("obj=%d currpos=%.2f moved to X=%.2f, Y=%.2f\n", litem->index, cur_pos, x, y); } } diff --git a/src/lib/elementary/efl_ui_list_private.h b/src/lib/elementary/efl_ui_list_private.h index 3b02e0a5e9..1385c364a6 100644 --- a/src/lib/elementary/efl_ui_list_private.h +++ b/src/lib/elementary/efl_ui_list_private.h @@ -21,14 +21,14 @@ struct _Efl_Ui_List_Item Elm_Layout *layout; Efl_Future *future; unsigned int index; - Evas_Coord x, y, w, h; + Evas_Coord x, y, minw, minh; + double h, v, wx, wy; Eina_Bool down: 1; Eina_Bool selected: 1; Eina_Bool longpressed : 1; Ecore_Timer *long_timer; }; - typedef struct _Efl_Ui_List_Data Efl_Ui_List_Data; struct _Efl_Ui_List_Data @@ -37,33 +37,45 @@ struct _Efl_Ui_List_Data Evas_Object *hit_rect; Efl_Model *model; - Efl_Orient orient; + Efl_Orient orient; Eina_Bool homogeneous : 1; - Eina_Bool delete_me : 1; Eina_Bool recalc : 1; Eina_Bool on_hold : 1; - Eina_Bool was_selected : 1; struct { - double h, v; - Eina_Bool scalable: 1; + double h, v; + Eina_Bool scalable: 1; } pad; struct { - double h, v; + double h, v; } align; - Eina_List *items, *selected; - Eina_List *realizes; + struct { + double x, y; + } weight; + + struct { + Evas_Coord x, y, w, h; + int start; + int slice; + } realized; + + struct { + Evas_Coord x, y, diff; + Evas_Object *obj; + } pan; + + Eina_List *selected; + Eina_Array *items; Eina_Stringshare *style; Elm_Object_Select_Mode select_mode; Elm_List_Mode mode; - unsigned int re_idx; - Evas_Object *pan_obj; - Eina_Bool pan_changed : 1; - Evas_Coord pan_x, pan_y, minw, minh, dx, dy, rlzw, rlzh; + Evas_Coord minw, minh; Efl_Ui_List_Item *focused; + int avit, avsom, item_count; + Efl_Future *future; }; typedef struct _Efl_Ui_List_Pan_Data Efl_Ui_List_Pan_Data; @@ -75,6 +87,15 @@ struct _Efl_Ui_List_Pan_Data Ecore_Job *resize_job; }; +typedef struct _Efl_Ui_List_Slice Efl_Ui_List_Slice; + +struct _Efl_Ui_List_Slice +{ + Efl_Ui_List_Data *pd; + int newstart, slicestart, newsize; +}; + + #define EFL_UI_LIST_DATA_GET(o, ptr) \ Efl_Ui_List_Data * ptr = efl_data_scope_get(o, EFL_UI_LIST_CLASS) -- cgit v1.2.1