#include #include #include #include #include "elm_priv.h" #include "els_scroller.h" #include "elm_genlist.h" #define MAX_ITEMS_PER_BLOCK 32 #define REORDER_EFFECT_TIME 0.5 #define ELM_GEN_SETUP(wd) \ (wd)->calc_cb = (Ecore_Cb)_calc_job; \ (wd)->clear_cb = (Ecore_Cb)_clear_cb; \ (wd)->sizing_cb = (Ecore_Cb)_sizing_eval #define ELM_GEN_ITEM_SETUP(it) \ (it)->del_cb = (Ecore_Cb)_item_del; \ (it)->highlight_cb = (Ecore_Cb)_item_highlight; \ (it)->unsel_cb = (Ecore_Cb)_item_unselect; \ (it)->unhighlight_cb = (Ecore_Cb)_item_unhighlight; \ (it)->unrealize_cb = (Ecore_Cb)_item_unrealize_cb typedef struct _Item_Block Item_Block; typedef struct _Item_Cache Item_Cache; struct Elm_Gen_Item_Type { Elm_Gen_Item *it; Item_Block *block; Eina_List *items; Evas_Coord w, h, minw, minh; Elm_Gen_Item *group_item; Elm_Genlist_Item_Flags flags; Eina_List *mode_labels, *mode_contents, *mode_states, *mode_content_objs; Ecore_Timer *swipe_timer; Evas_Coord scrl_x, scrl_y, old_scrl_y; Elm_Gen_Item *rel; Evas_Object *mode_view; int expanded_depth; int order_num_in; Eina_Bool before : 1; Eina_Bool want_realize : 1; Eina_Bool expanded : 1; Eina_Bool mincalcd : 1; Eina_Bool queued : 1; Eina_Bool showme : 1; Eina_Bool updateme : 1; Eina_Bool nocache : 1; Eina_Bool stacking_even : 1; Eina_Bool nostacking : 1; Eina_Bool move_effect_enabled : 1; }; struct _Item_Block { EINA_INLIST; int count; int num; int reorder_offset; Widget_Data *wd; Eina_List *items; Evas_Coord x, y, w, h, minw, minh; Eina_Bool want_unrealize : 1; Eina_Bool realized : 1; Eina_Bool changed : 1; Eina_Bool updateme : 1; Eina_Bool showme : 1; Eina_Bool must_recalc : 1; }; struct _Item_Cache { EINA_INLIST; Evas_Object *base_view, *spacer; const char *item_style; // it->itc->item_style Eina_Bool tree : 1; // it->group Eina_Bool compress : 1; // it->wd->compress Eina_Bool selected : 1; // it->selected Eina_Bool disabled : 1; // it->disabled Eina_Bool expanded : 1; // it->item->expanded }; static const char *widtype = NULL; static void _item_cache_zero(Widget_Data *wd); static void _del_hook(Evas_Object *obj); static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl); static void _theme_hook(Evas_Object *obj); static void _show_region_hook(void *data, Evas_Object *obj); static void _sizing_eval(Evas_Object *obj); static void _item_realize(Elm_Gen_Item *it, int in, Eina_Bool calc); static void _item_unrealize_cb(Elm_Gen_Item *it); static void _item_block_unrealize(Item_Block *itb); static void _calc_job(void *data); static void _on_focus_hook(void *data, Evas_Object *obj); static Eina_Bool _item_multi_select_up(Widget_Data *wd); static Eina_Bool _item_multi_select_down(Widget_Data *wd); static Eina_Bool _item_single_select_up(Widget_Data *wd); static Eina_Bool _item_single_select_down(Widget_Data *wd); static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src, Evas_Callback_Type type, void *event_info); static void _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source); static Eina_Bool _deselect_all_items(Widget_Data *wd); static void _pan_calculate(Evas_Object *obj); static void _pan_max_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y); static void _item_position(Elm_Gen_Item *it, Evas_Object *obj, Evas_Coord it_x, Evas_Coord it_y); static void _mode_item_realize(Elm_Gen_Item *it); static void _mode_item_unrealize(Elm_Gen_Item *it); static void _item_mode_set(Elm_Gen_Item *it); static void _item_mode_unset(Widget_Data *wd); static void _group_items_recalc(void *data); static void _item_move_after(Elm_Gen_Item *it, Elm_Gen_Item *after); static void _item_move_before(Elm_Gen_Item *it, Elm_Gen_Item *before); static void _item_auto_scroll(Widget_Data *wd); static void _elm_genlist_clear(Evas_Object *obj, Eina_Bool standby); static Evas_Smart_Class _pan_sc = EVAS_SMART_CLASS_INIT_VERSION; static const char SIG_ACTIVATED[] = "activated"; static const char SIG_CLICKED_DOUBLE[] = "clicked,double"; static const char SIG_SELECTED[] = "selected"; static const char SIG_UNSELECTED[] = "unselected"; static const char SIG_EXPANDED[] = "expanded"; static const char SIG_CONTRACTED[] = "contracted"; static const char SIG_EXPAND_REQUEST[] = "expand,request"; static const char SIG_CONTRACT_REQUEST[] = "contract,request"; static const char SIG_REALIZED[] = "realized"; static const char SIG_UNREALIZED[] = "unrealized"; static const char SIG_DRAG_START_UP[] = "drag,start,up"; static const char SIG_DRAG_START_DOWN[] = "drag,start,down"; static const char SIG_DRAG_START_LEFT[] = "drag,start,left"; static const char SIG_DRAG_START_RIGHT[] = "drag,start,right"; static const char SIG_DRAG_STOP[] = "drag,stop"; static const char SIG_DRAG[] = "drag"; static const char SIG_LONGPRESSED[] = "longpressed"; static const char SIG_SCROLL_ANIM_START[] = "scroll,anim,start"; static const char SIG_SCROLL_ANIM_STOP[] = "scroll,anim,stop"; static const char SIG_SCROLL_DRAG_START[] = "scroll,drag,start"; static const char SIG_SCROLL_DRAG_STOP[] = "scroll,drag,stop"; static const char SIG_EDGE_TOP[] = "edge,top"; static const char SIG_EDGE_BOTTOM[] = "edge,bottom"; static const char SIG_EDGE_LEFT[] = "edge,left"; static const char SIG_EDGE_RIGHT[] = "edge,right"; static const char SIG_MULTI_SWIPE_LEFT[] = "multi,swipe,left"; static const char SIG_MULTI_SWIPE_RIGHT[] = "multi,swipe,right"; static const char SIG_MULTI_SWIPE_UP[] = "multi,swipe,up"; static const char SIG_MULTI_SWIPE_DOWN[] = "multi,swipe,down"; static const char SIG_MULTI_PINCH_OUT[] = "multi,pinch,out"; static const char SIG_MULTI_PINCH_IN[] = "multi,pinch,in"; static const char SIG_SWIPE[] = "swipe"; static const char SIG_MOVED[] = "moved"; static const Evas_Smart_Cb_Description _signals[] = { {SIG_CLICKED_DOUBLE, ""}, {SIG_ACTIVATED, ""}, {SIG_SELECTED, ""}, {SIG_UNSELECTED, ""}, {SIG_EXPANDED, ""}, {SIG_CONTRACTED, ""}, {SIG_EXPAND_REQUEST, ""}, {SIG_CONTRACT_REQUEST, ""}, {SIG_REALIZED, ""}, {SIG_UNREALIZED, ""}, {SIG_DRAG_START_UP, ""}, {SIG_DRAG_START_DOWN, ""}, {SIG_DRAG_START_LEFT, ""}, {SIG_DRAG_START_RIGHT, ""}, {SIG_DRAG_STOP, ""}, {SIG_DRAG, ""}, {SIG_LONGPRESSED, ""}, {SIG_SCROLL_ANIM_START, ""}, {SIG_SCROLL_ANIM_STOP, ""}, {SIG_SCROLL_DRAG_START, ""}, {SIG_SCROLL_DRAG_STOP, ""}, {SIG_EDGE_TOP, ""}, {SIG_EDGE_BOTTOM, ""}, {SIG_EDGE_LEFT, ""}, {SIG_EDGE_RIGHT, ""}, {SIG_MULTI_SWIPE_LEFT, ""}, {SIG_MULTI_SWIPE_RIGHT, ""}, {SIG_MULTI_SWIPE_UP, ""}, {SIG_MULTI_SWIPE_DOWN, ""}, {SIG_MULTI_PINCH_OUT, ""}, {SIG_MULTI_PINCH_IN, ""}, {SIG_SWIPE, ""}, {SIG_MOVED, ""}, {NULL, NULL} }; static Eina_Compare_Cb _elm_genlist_item_compare_cb; static Eina_Compare_Cb _elm_genlist_item_compare_data_cb; /* TEMPORARY */ #undef ELM_CHECK_WIDTYPE #define ELM_CHECK_WIDTYPE(obj, widtype) \ if ((!obj) || (!elm_genlist_type_check((obj), __func__))) return #undef ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN #define ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, ...) \ ELM_WIDGET_ITEM_CHECK_OR_RETURN((Elm_Widget_Item *)it, __VA_ARGS__); \ ELM_CHECK_WIDTYPE(WIDGET((it)), widtype) __VA_ARGS__; static const char *_gengrid = NULL; static const char *_genlist = NULL; /* THIS FUNCTION IS HACKY AND TEMPORARY!!! */ Eina_Bool elm_genlist_type_check(const Evas_Object *obj, const char *func) { const char *provided, *expected = "(unknown)"; static int abort_on_warn = -1; provided = elm_widget_type_get(obj); if (!_genlist) _genlist = eina_stringshare_add("genlist"); if (!_gengrid) _gengrid = eina_stringshare_add("gengrid"); if (EINA_LIKELY(provided == _genlist) || EINA_LIKELY(provided == _gengrid)) return EINA_TRUE; if ((!provided) || (!provided[0])) { provided = evas_object_type_get(obj); if ((!provided) || (!provided[0])) provided = "(unknown)"; } ERR("Passing Object: %p in function: %s, of type: '%s' when expecting type: '%s'", obj, func, provided, expected); if (abort_on_warn == -1) { if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1; else abort_on_warn = 0; } if (abort_on_warn == 1) abort(); return EINA_FALSE; } static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info) { if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE; Evas_Event_Key_Down *ev = event_info; Widget_Data *wd = elm_widget_data_get(obj); Evas_Coord pan_max_x = 0, pan_max_y = 0; if (!wd) return EINA_FALSE; if (!wd->items) return EINA_FALSE; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE; if (elm_widget_disabled_get(obj)) return EINA_FALSE; Elm_Gen_Item *it = NULL; Evas_Coord x = 0; Evas_Coord y = 0; Evas_Coord step_x = 0; Evas_Coord step_y = 0; Evas_Coord v_w = 0; Evas_Coord v_h = 0; Evas_Coord page_x = 0; Evas_Coord page_y = 0; elm_smart_scroller_child_pos_get(wd->scr, &x, &y); elm_smart_scroller_step_size_get(wd->scr, &step_x, &step_y); elm_smart_scroller_page_size_get(wd->scr, &page_x, &page_y); elm_smart_scroller_child_viewport_size_get(wd->scr, &v_w, &v_h); if ((!strcmp(ev->keyname, "Left")) || (!strcmp(ev->keyname, "KP_Left"))) { x -= step_x; } else if ((!strcmp(ev->keyname, "Right")) || (!strcmp(ev->keyname, "KP_Right"))) { x += step_x; } else if ((!strcmp(ev->keyname, "Up")) || (!strcmp(ev->keyname, "KP_Up"))) { if (((evas_key_modifier_is_set(ev->modifiers, "Shift")) && (_item_multi_select_up(wd))) || (_item_single_select_up(wd))) { ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; return EINA_TRUE; } else y -= step_y; } else if ((!strcmp(ev->keyname, "Down")) || (!strcmp(ev->keyname, "KP_Down"))) { if (((evas_key_modifier_is_set(ev->modifiers, "Shift")) && (_item_multi_select_down(wd))) || (_item_single_select_down(wd))) { ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; return EINA_TRUE; } else y += step_y; } else if ((!strcmp(ev->keyname, "Home")) || (!strcmp(ev->keyname, "KP_Home"))) { it = elm_genlist_first_item_get(obj); elm_genlist_item_bring_in(it); ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; return EINA_TRUE; } else if ((!strcmp(ev->keyname, "End")) || (!strcmp(ev->keyname, "KP_End"))) { it = elm_genlist_last_item_get(obj); elm_genlist_item_bring_in(it); ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; return EINA_TRUE; } else if ((!strcmp(ev->keyname, "Prior")) || (!strcmp(ev->keyname, "KP_Prior"))) { if (page_y < 0) y -= -(page_y * v_h) / 100; else y -= page_y; } else if ((!strcmp(ev->keyname, "Next")) || (!strcmp(ev->keyname, "KP_Next"))) { if (page_y < 0) y += -(page_y * v_h) / 100; else y += page_y; } else if (!strcmp(ev->keyname, "Escape")) { if (!_deselect_all_items(wd)) return EINA_FALSE; ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; return EINA_TRUE; } else if (((!strcmp(ev->keyname, "Return")) || (!strcmp(ev->keyname, "KP_Enter")) || (!strcmp(ev->keyname, "space"))) && (!wd->multi) && (wd->selected)) { it = elm_genlist_selected_item_get(obj); elm_genlist_item_expanded_set(it, !elm_genlist_item_expanded_get(it)); evas_object_smart_callback_call(WIDGET(it), SIG_ACTIVATED, it); } else return EINA_FALSE; ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; _pan_max_get(wd->pan_smart, &pan_max_x, &pan_max_y); if (x < 0) x = 0; if (x > pan_max_x) x = pan_max_x; if (y < 0) y = 0; if (y > pan_max_y) y = pan_max_y; elm_smart_scroller_child_pos_set(wd->scr, x, y); return EINA_TRUE; } static Eina_Bool _deselect_all_items(Widget_Data *wd) { if (!wd->selected) return EINA_FALSE; while (wd->selected) elm_genlist_item_selected_set(wd->selected->data, EINA_FALSE); return EINA_TRUE; } static Eina_Bool _item_multi_select_up(Widget_Data *wd) { if (!wd->selected) return EINA_FALSE; if (!wd->multi) return EINA_FALSE; Elm_Gen_Item *prev = elm_genlist_item_prev_get(wd->last_selected_item); if (!prev) return EINA_TRUE; if (elm_genlist_item_selected_get(prev)) { elm_genlist_item_selected_set(wd->last_selected_item, EINA_FALSE); wd->last_selected_item = prev; elm_genlist_item_show(wd->last_selected_item); } else { elm_genlist_item_selected_set(prev, EINA_TRUE); elm_genlist_item_show(prev); } return EINA_TRUE; } static Eina_Bool _item_multi_select_down(Widget_Data *wd) { if (!wd->selected) return EINA_FALSE; if (!wd->multi) return EINA_FALSE; Elm_Gen_Item *next = elm_genlist_item_next_get(wd->last_selected_item); if (!next) return EINA_TRUE; if (elm_genlist_item_selected_get(next)) { elm_genlist_item_selected_set(wd->last_selected_item, EINA_FALSE); wd->last_selected_item = next; elm_genlist_item_show(wd->last_selected_item); } else { elm_genlist_item_selected_set(next, EINA_TRUE); elm_genlist_item_show(next); } return EINA_TRUE; } static Eina_Bool _item_single_select_up(Widget_Data *wd) { Elm_Gen_Item *prev; if (!wd->selected) { prev = ELM_GEN_ITEM_FROM_INLIST(wd->items->last); while ((prev) && (prev->generation < wd->generation)) prev = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(prev)->prev); } else prev = elm_genlist_item_prev_get(wd->last_selected_item); if (!prev) return EINA_FALSE; _deselect_all_items(wd); elm_genlist_item_selected_set(prev, EINA_TRUE); elm_genlist_item_show(prev); return EINA_TRUE; } static Eina_Bool _item_single_select_down(Widget_Data *wd) { Elm_Gen_Item *next; if (!wd->selected) { next = ELM_GEN_ITEM_FROM_INLIST(wd->items); while ((next) && (next->generation < wd->generation)) next = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(next)->next); } else next = elm_genlist_item_next_get(wd->last_selected_item); if (!next) return EINA_FALSE; _deselect_all_items(wd); elm_genlist_item_selected_set(next, EINA_TRUE); elm_genlist_item_show(next); return EINA_TRUE; } static void _on_focus_hook(void *data __UNUSED__, Evas_Object *obj) { Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; if (elm_widget_focus_get(obj)) { elm_object_signal_emit(wd->obj, "elm,action,focus", "elm"); evas_object_focus_set(wd->obj, EINA_TRUE); if ((wd->selected) && (!wd->last_selected_item)) wd->last_selected_item = eina_list_data_get(wd->selected); } else { elm_object_signal_emit(wd->obj, "elm,action,unfocus", "elm"); evas_object_focus_set(wd->obj, EINA_FALSE); } } static void _del_hook(Evas_Object *obj) { Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; _item_cache_zero(wd); if (wd->calc_job) ecore_job_del(wd->calc_job); if (wd->update_job) ecore_job_del(wd->update_job); if (wd->queue_idle_enterer) ecore_idle_enterer_del(wd->queue_idle_enterer); if (wd->must_recalc_idler) ecore_idler_del(wd->must_recalc_idler); if (wd->multi_timer) ecore_timer_del(wd->multi_timer); if (wd->mode_type) eina_stringshare_del(wd->mode_type); if (wd->scr_hold_timer) ecore_timer_del(wd->scr_hold_timer); free(wd); } static void _del_pre_hook(Evas_Object *obj) { Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; elm_genlist_clear(obj); evas_object_del(wd->pan_smart); wd->pan_smart = NULL; } static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl) { Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; _item_cache_zero(wd); elm_smart_scroller_mirrored_set(wd->scr, rtl); } static void _theme_hook(Evas_Object *obj) { Widget_Data *wd = elm_widget_data_get(obj); Item_Block *itb; if (!wd) return; evas_event_freeze(evas_object_evas_get(wd->obj)); _item_cache_zero(wd); _elm_widget_mirrored_reload(obj); _mirrored_set(obj, elm_widget_mirrored_get(obj)); elm_smart_scroller_object_theme_set(obj, wd->scr, "genlist", "base", elm_widget_style_get(obj)); edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale); wd->item_width = wd->item_height = 0; wd->group_item_width = wd->group_item_height = 0; wd->minw = wd->minh = wd->realminw = 0; EINA_INLIST_FOREACH(wd->blocks, itb) { Eina_List *l; Elm_Gen_Item *it; if (itb->realized) _item_block_unrealize(itb); EINA_LIST_FOREACH(itb->items, l, it) it->item->mincalcd = EINA_FALSE; itb->changed = EINA_TRUE; } if (wd->calc_job) ecore_job_del(wd->calc_job); wd->calc_job = ecore_job_add(_calc_job, wd); _sizing_eval(obj); evas_event_thaw(evas_object_evas_get(wd->obj)); evas_event_thaw_eval(evas_object_evas_get(wd->obj)); } static void _show_region_hook(void *data, Evas_Object *obj) { Widget_Data *wd = elm_widget_data_get(data); Evas_Coord x, y, w, h; if (!wd) return; elm_widget_show_region_get(obj, &x, &y, &w, &h); //x & y are screen coordinates, Add with pan coordinates x += wd->pan_x; y += wd->pan_y; elm_smart_scroller_child_region_show(wd->scr, x, y, w, h); } static void _translate_hook(Evas_Object *obj) { evas_object_smart_callback_call(obj, "language,changed", NULL); } static void _sizing_eval(Evas_Object *obj) { Widget_Data *wd = elm_widget_data_get(obj); Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1; if (!wd) return; evas_object_size_hint_min_get(wd->scr, &minw, &minh); evas_object_size_hint_max_get(wd->scr, &maxw, &maxh); minh = -1; if (wd->height_for_width) { Evas_Coord vw, vh; elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh); if ((vw != 0) && (vw != wd->prev_viewport_w)) { Item_Block *itb; wd->prev_viewport_w = vw; EINA_INLIST_FOREACH(wd->blocks, itb) { itb->must_recalc = EINA_TRUE; } if (wd->calc_job) ecore_job_del(wd->calc_job); wd->calc_job = ecore_job_add(_calc_job, wd); } } if (wd->mode == ELM_LIST_LIMIT) { Evas_Coord vmw, vmh; minw = wd->realminw; maxw = -1; edje_object_size_min_calc (elm_smart_scroller_edje_object_get(wd->scr), &vmw, &vmh); minw = vmw + minw; } else { Evas_Coord vmw, vmh; edje_object_size_min_calc (elm_smart_scroller_edje_object_get(wd->scr), &vmw, &vmh); minw = vmw; minh = vmh; } evas_object_size_hint_min_set(obj, minw, minh); evas_object_size_hint_max_set(obj, maxw, maxh); } static void _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source) { Widget_Data *wd = elm_widget_data_get(obj); edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), emission, source); } static void _item_highlight(Elm_Gen_Item *it) { const char *selectraise; if ((it->wd->no_select) || (it->generation < it->wd->generation) || (it->highlighted) || (it->disabled) || (it->display_only) || (it->item->mode_view)) return; edje_object_signal_emit(VIEW(it), "elm,state,selected", "elm"); selectraise = edje_object_data_get(VIEW(it), "selectraise"); if ((selectraise) && (!strcmp(selectraise, "on"))) { evas_object_raise(VIEW(it)); if ((it->item->group_item) && (it->item->group_item->realized)) evas_object_raise(it->item->VIEW(group_item)); } it->highlighted = EINA_TRUE; } static void _item_unhighlight(Elm_Gen_Item *it) { if ((it->generation < it->wd->generation) || (!it->highlighted)) return; edje_object_signal_emit(VIEW(it), "elm,state,unselected", "elm"); if (!it->item->nostacking) { if ((it->item->order_num_in & 0x1) ^ it->item->stacking_even) evas_object_lower(VIEW(it)); else evas_object_raise(VIEW(it)); } it->highlighted = EINA_FALSE; } static void _item_block_del(Elm_Gen_Item *it) { Eina_Inlist *il; Item_Block *itb = it->item->block; itb->items = eina_list_remove(itb->items, it); itb->count--; itb->changed = EINA_TRUE; if (it->wd->calc_job) ecore_job_del(it->wd->calc_job); it->wd->calc_job = ecore_job_add(_calc_job, it->wd); if (itb->count < 1) { il = EINA_INLIST_GET(itb); Item_Block *itbn = (Item_Block *)(il->next); if (it->parent) it->parent->item->items = eina_list_remove(it->parent->item->items, it); else it->wd->blocks = eina_inlist_remove(it->wd->blocks, il); free(itb); if (itbn) itbn->changed = EINA_TRUE; } else { if (itb->count < itb->wd->max_items_per_block/2) { il = EINA_INLIST_GET(itb); Item_Block *itbp = (Item_Block *)(il->prev); Item_Block *itbn = (Item_Block *)(il->next); if ((itbp) && ((itbp->count + itb->count) < itb->wd->max_items_per_block + itb->wd->max_items_per_block/2)) { Elm_Gen_Item *it2; EINA_LIST_FREE(itb->items, it2) { it2->item->block = itbp; itbp->items = eina_list_append(itbp->items, it2); itbp->count++; itbp->changed = EINA_TRUE; } it->wd->blocks = eina_inlist_remove(it->wd->blocks, EINA_INLIST_GET(itb)); free(itb); } else if ((itbn) && ((itbn->count + itb->count) < itb->wd->max_items_per_block + itb->wd->max_items_per_block/2)) { while (itb->items) { Eina_List *last = eina_list_last(itb->items); Elm_Gen_Item *it2 = last->data; it2->item->block = itbn; itb->items = eina_list_remove_list(itb->items, last); itbn->items = eina_list_prepend(itbn->items, it2); itbn->count++; itbn->changed = EINA_TRUE; } it->wd->blocks = eina_inlist_remove(it->wd->blocks, EINA_INLIST_GET(itb)); free(itb); } } } } static void _item_del(Elm_Gen_Item *it) { Evas_Object *obj = WIDGET(it); evas_event_freeze(evas_object_evas_get(obj)); elm_genlist_item_subitems_clear(it); if (it->wd->show_item == it) it->wd->show_item = NULL; if (it->realized) _elm_genlist_item_unrealize(it, EINA_FALSE); if (it->item->block) _item_block_del(it); if (it->item->queued) it->wd->queue = eina_list_remove(it->wd->queue, it); if (it->wd->anchor_item == it) { it->wd->anchor_item = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next); if (!it->wd->anchor_item) it->wd->anchor_item = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev); } if (it->parent) it->parent->item->items = eina_list_remove(it->parent->item->items, it); if (it->item->swipe_timer) ecore_timer_del(it->item->swipe_timer); _elm_genlist_item_del_serious(it); evas_event_thaw(evas_object_evas_get(obj)); evas_event_thaw_eval(evas_object_evas_get(obj)); } static void _clear_cb(Widget_Data *wd) { wd->anchor_item = NULL; while (wd->blocks) { Item_Block *itb = (Item_Block *)(wd->blocks); wd->blocks = eina_inlist_remove(wd->blocks, wd->blocks); if (itb->items) eina_list_free(itb->items); free(itb); } if (wd->queue_idle_enterer) { ecore_idle_enterer_del(wd->queue_idle_enterer); wd->queue_idle_enterer = NULL; } if (wd->must_recalc_idler) { ecore_idler_del(wd->must_recalc_idler); wd->must_recalc_idler = NULL; } if (wd->queue) wd->queue = eina_list_free(wd->queue); if (wd->reorder_move_animator) { ecore_animator_del(wd->reorder_move_animator); wd->reorder_move_animator = NULL; } wd->show_item = NULL; wd->reorder_old_pan_y = 0; } static void _item_unselect(Elm_Gen_Item *it) { if ((it->generation < it->wd->generation) || (!it->selected)) return; it->selected = EINA_FALSE; it->wd->selected = eina_list_remove(it->wd->selected, it); evas_object_smart_callback_call(WIDGET(it), SIG_UNSELECTED, it); } static void _mouse_move(void *data, Evas *evas __UNUSED__, Evas_Object *obj, void *event_info) { Elm_Gen_Item *it = data; Evas_Event_Mouse_Move *ev = event_info; Evas_Coord minw = 0, minh = 0, x, y, dx, dy, adx, ady; Evas_Coord ox, oy, ow, oh, it_scrl_y, y_pos; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) { if (!it->wd->on_hold) { it->wd->on_hold = EINA_TRUE; if (!it->wd->wasselected) { _item_unhighlight(it); _item_unselect(it); } } } if (it->wd->multitouched) { it->wd->cur_x = ev->cur.canvas.x; it->wd->cur_y = ev->cur.canvas.y; return; } if ((it->dragging) && (it->down)) { if (it->wd->movements == SWIPE_MOVES) it->wd->swipe = EINA_TRUE; else { it->wd->history[it->wd->movements].x = ev->cur.canvas.x; it->wd->history[it->wd->movements].y = ev->cur.canvas.y; if (abs((it->wd->history[it->wd->movements].x - it->wd->history[0].x)) > 40) it->wd->swipe = EINA_TRUE; else it->wd->movements++; } if (it->long_timer) { ecore_timer_del(it->long_timer); it->long_timer = NULL; } evas_object_smart_callback_call(WIDGET(it), SIG_DRAG, it); return; } if ((!it->down) /* || (it->wd->on_hold)*/ || (it->wd->longpressed)) { if (it->long_timer) { ecore_timer_del(it->long_timer); it->long_timer = NULL; } if ((it->wd->reorder_mode) && (it->wd->reorder_it)) { evas_object_geometry_get(it->wd->pan_smart, &ox, &oy, &ow, &oh); it_scrl_y = ev->cur.canvas.y - it->wd->reorder_it->dy; if (!it->wd->reorder_start_y) it->wd->reorder_start_y = it->item->block->y + it->y; if (it_scrl_y < oy) y_pos = oy; else if (it_scrl_y + it->wd->reorder_it->item->h > oy + oh) y_pos = oy + oh - it->wd->reorder_it->item->h; else y_pos = it_scrl_y; _item_position(it, VIEW(it), it->item->scrl_x, y_pos); if (it->wd->calc_job) ecore_job_del(it->wd->calc_job); it->wd->calc_job = ecore_job_add(_calc_job, it->wd); } return; } if (!it->display_only) elm_coords_finger_size_adjust(1, &minw, 1, &minh); evas_object_geometry_get(obj, &x, &y, NULL, NULL); x = ev->cur.canvas.x - x; y = ev->cur.canvas.y - y; dx = x - it->dx; adx = dx; if (adx < 0) adx = -dx; dy = y - it->dy; ady = dy; if (ady < 0) ady = -dy; minw /= 2; minh /= 2; if ((adx > minw) || (ady > minh)) { it->dragging = EINA_TRUE; if (it->long_timer) { ecore_timer_del(it->long_timer); it->long_timer = NULL; } if (!it->wd->wasselected) { _item_unhighlight(it); _item_unselect(it); } if (dy < 0) { if (ady > adx) evas_object_smart_callback_call(WIDGET(it), SIG_DRAG_START_UP, it); else { if (dx < 0) evas_object_smart_callback_call(WIDGET(it), SIG_DRAG_START_LEFT, it); else evas_object_smart_callback_call(WIDGET(it), SIG_DRAG_START_RIGHT, it); } } else { if (ady > adx) evas_object_smart_callback_call(WIDGET(it), SIG_DRAG_START_DOWN, it); else { if (dx < 0) evas_object_smart_callback_call(WIDGET(it), SIG_DRAG_START_LEFT, it); else evas_object_smart_callback_call(WIDGET(it), SIG_DRAG_START_RIGHT, it); } } } } static Eina_Bool _long_press(void *data) { Elm_Gen_Item *it = data, *it_tmp; Eina_List *list, *l; it->long_timer = NULL; if ((it->disabled) || (it->dragging) || (it->display_only)) return ECORE_CALLBACK_CANCEL; it->wd->longpressed = EINA_TRUE; evas_object_smart_callback_call(WIDGET(it), SIG_LONGPRESSED, it); if ((it->wd->reorder_mode) && (!it->group)) { it->wd->reorder_it = it; it->wd->reorder_start_y = 0; evas_object_raise(VIEW(it)); elm_smart_scroller_hold_set(it->wd->scr, EINA_TRUE); elm_smart_scroller_bounce_allow_set(it->wd->scr, EINA_FALSE, EINA_FALSE); list = elm_genlist_realized_items_get(it->wd->obj); EINA_LIST_FOREACH(list, l, it_tmp) { if (it != it_tmp) _item_unselect(it_tmp); } if (elm_genlist_item_expanded_get(it)) { elm_genlist_item_expanded_set(it, EINA_FALSE); return ECORE_CALLBACK_RENEW; } edje_object_signal_emit(VIEW(it), "elm,state,reorder,enabled", "elm"); } return ECORE_CALLBACK_CANCEL; } static void _swipe(Elm_Gen_Item *it) { int i, sum = 0; if (!it) return; if ((it->display_only) || (it->disabled)) return; it->wd->swipe = EINA_FALSE; for (i = 0; i < it->wd->movements; i++) { sum += it->wd->history[i].x; if (abs(it->wd->history[0].y - it->wd->history[i].y) > 10) return; } sum /= it->wd->movements; if (abs(sum - it->wd->history[0].x) <= 10) return; evas_object_smart_callback_call(WIDGET(it), SIG_SWIPE, it); } static Eina_Bool _swipe_cancel(void *data) { Elm_Gen_Item *it = data; if (!it) return ECORE_CALLBACK_CANCEL; it->wd->swipe = EINA_FALSE; it->wd->movements = 0; return ECORE_CALLBACK_RENEW; } static Eina_Bool _multi_cancel(void *data) { Widget_Data *wd = data; if (!wd) return ECORE_CALLBACK_CANCEL; wd->multi_timeout = EINA_TRUE; return ECORE_CALLBACK_RENEW; } static void _multi_touch_gesture_eval(void *data) { Elm_Gen_Item *it = data; it->wd->multitouched = EINA_FALSE; if (it->wd->multi_timer) { ecore_timer_del(it->wd->multi_timer); it->wd->multi_timer = NULL; } if (it->wd->multi_timeout) { it->wd->multi_timeout = EINA_FALSE; return; } Evas_Coord minw = 0, minh = 0; Evas_Coord off_x, off_y, off_mx, off_my; elm_coords_finger_size_adjust(1, &minw, 1, &minh); off_x = abs(it->wd->cur_x - it->wd->prev_x); off_y = abs(it->wd->cur_y - it->wd->prev_y); off_mx = abs(it->wd->cur_mx - it->wd->prev_mx); off_my = abs(it->wd->cur_my - it->wd->prev_my); if (((off_x > minw) || (off_y > minh)) && ((off_mx > minw) || (off_my > minh))) { if ((off_x + off_mx) > (off_y + off_my)) { if ((it->wd->cur_x > it->wd->prev_x) && (it->wd->cur_mx > it->wd->prev_mx)) evas_object_smart_callback_call(WIDGET(it), SIG_MULTI_SWIPE_RIGHT, it); else if ((it->wd->cur_x < it->wd->prev_x) && (it->wd->cur_mx < it->wd->prev_mx)) evas_object_smart_callback_call(WIDGET(it), SIG_MULTI_SWIPE_LEFT, it); else if (abs(it->wd->cur_x - it->wd->cur_mx) > abs(it->wd->prev_x - it->wd->prev_mx)) evas_object_smart_callback_call(WIDGET(it), SIG_MULTI_PINCH_OUT, it); else evas_object_smart_callback_call(WIDGET(it), SIG_MULTI_PINCH_IN, it); } else { if ((it->wd->cur_y > it->wd->prev_y) && (it->wd->cur_my > it->wd->prev_my)) evas_object_smart_callback_call(WIDGET(it), SIG_MULTI_SWIPE_DOWN, it); else if ((it->wd->cur_y < it->wd->prev_y) && (it->wd->cur_my < it->wd->prev_my)) evas_object_smart_callback_call(WIDGET(it), SIG_MULTI_SWIPE_UP, it); else if (abs(it->wd->cur_y - it->wd->cur_my) > abs(it->wd->prev_y - it->wd->prev_my)) evas_object_smart_callback_call(WIDGET(it), SIG_MULTI_PINCH_OUT, it); else evas_object_smart_callback_call(WIDGET(it), SIG_MULTI_PINCH_IN, it); } } it->wd->multi_timeout = EINA_FALSE; } static void _multi_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) { Elm_Gen_Item *it = data; Evas_Event_Multi_Down *ev = event_info; if ((it->wd->multi_device != 0) || (it->wd->multitouched) || (it->wd->multi_timeout)) return; it->wd->multi_device = ev->device; it->wd->multi_down = EINA_TRUE; it->wd->multitouched = EINA_TRUE; it->wd->prev_mx = ev->canvas.x; it->wd->prev_my = ev->canvas.y; if (!it->wd->wasselected) { _item_unhighlight(it); _item_unselect(it); } it->wd->wasselected = EINA_FALSE; it->wd->longpressed = EINA_FALSE; if (it->long_timer) { ecore_timer_del(it->long_timer); it->long_timer = NULL; } if (it->dragging) { it->dragging = EINA_FALSE; evas_object_smart_callback_call(WIDGET(it), SIG_DRAG_STOP, it); } if (it->item->swipe_timer) { ecore_timer_del(it->item->swipe_timer); it->item->swipe_timer = NULL; } if (it->wd->on_hold) { it->wd->swipe = EINA_FALSE; it->wd->movements = 0; it->wd->on_hold = EINA_FALSE; } } static void _multi_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) { Elm_Gen_Item *it = data; Evas_Event_Multi_Up *ev = event_info; if (it->wd->multi_device != ev->device) return; it->wd->multi_device = 0; it->wd->multi_down = EINA_FALSE; if (it->wd->mouse_down) return; _multi_touch_gesture_eval(data); } static void _multi_move(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) { Elm_Gen_Item *it = data; Evas_Event_Multi_Move *ev = event_info; if (it->wd->multi_device != ev->device) return; it->wd->cur_mx = ev->cur.canvas.x; it->wd->cur_my = ev->cur.canvas.y; } static void _mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj, void *event_info) { Elm_Gen_Item *it = data; Evas_Event_Mouse_Down *ev = event_info; Evas_Coord x, y; if (ev->button != 1) return; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) { it->wd->on_hold = EINA_TRUE; } it->down = EINA_TRUE; it->dragging = EINA_FALSE; evas_object_geometry_get(obj, &x, &y, NULL, NULL); it->dx = ev->canvas.x - x; it->dy = ev->canvas.y - y; it->wd->mouse_down = EINA_TRUE; if (!it->wd->multitouched) { it->wd->prev_x = ev->canvas.x; it->wd->prev_y = ev->canvas.y; it->wd->multi_timeout = EINA_FALSE; if (it->wd->multi_timer) ecore_timer_del(it->wd->multi_timer); it->wd->multi_timer = ecore_timer_add(1, _multi_cancel, it->wd); } it->wd->longpressed = EINA_FALSE; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) it->wd->on_hold = EINA_TRUE; else it->wd->on_hold = EINA_FALSE; if (it->wd->on_hold) return; it->wd->wasselected = it->selected; _item_highlight(it); if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK) if ((!it->disabled) && (!it->display_only)) { evas_object_smart_callback_call(WIDGET(it), SIG_CLICKED_DOUBLE, it); evas_object_smart_callback_call(WIDGET(it), SIG_ACTIVATED, it); } if (it->long_timer) ecore_timer_del(it->long_timer); if (it->item->swipe_timer) ecore_timer_del(it->item->swipe_timer); it->item->swipe_timer = ecore_timer_add(0.4, _swipe_cancel, it); if (it->realized) it->long_timer = ecore_timer_add(it->wd->longpress_timeout, _long_press, it); else it->long_timer = NULL; it->wd->swipe = EINA_FALSE; it->wd->movements = 0; } static void _mouse_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) { Elm_Gen_Item *it = data; Evas_Event_Mouse_Up *ev = event_info; Eina_Bool dragged = EINA_FALSE; if (ev->button != 1) return; it->down = EINA_FALSE; it->wd->mouse_down = EINA_FALSE; if (it->wd->multitouched) { if ((!it->wd->multi) && (!it->selected) && (it->highlighted)) _item_unhighlight(it); if (it->wd->multi_down) return; _multi_touch_gesture_eval(data); return; } if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) it->wd->on_hold = EINA_TRUE; else it->wd->on_hold = EINA_FALSE; if (it->long_timer) { ecore_timer_del(it->long_timer); it->long_timer = NULL; } if (it->dragging) { it->dragging = EINA_FALSE; evas_object_smart_callback_call(WIDGET(it), SIG_DRAG_STOP, it); dragged = 1; } if (it->item->swipe_timer) { ecore_timer_del(it->item->swipe_timer); it->item->swipe_timer = NULL; } if (it->wd->multi_timer) { ecore_timer_del(it->wd->multi_timer); it->wd->multi_timer = NULL; it->wd->multi_timeout = EINA_FALSE; } if (it->wd->on_hold) { if (it->wd->swipe) _swipe(data); it->wd->longpressed = EINA_FALSE; it->wd->on_hold = EINA_FALSE; return; } if ((it->wd->reorder_mode) && (it->wd->reorder_it)) { Evas_Coord it_scrl_y = ev->canvas.y - it->wd->reorder_it->dy; if (it->wd->reorder_rel && (it->wd->reorder_it->parent == it->wd->reorder_rel->parent)) { if (it_scrl_y <= it->wd->reorder_rel->item->scrl_y) _item_move_before(it->wd->reorder_it, it->wd->reorder_rel); else _item_move_after(it->wd->reorder_it, it->wd->reorder_rel); } else { if (it->wd->calc_job) ecore_job_del(it->wd->calc_job); it->wd->calc_job = ecore_job_add(_calc_job, it->wd); } edje_object_signal_emit(VIEW(it), "elm,state,reorder,disabled", "elm"); it->wd->reorder_it = it->wd->reorder_rel = NULL; elm_smart_scroller_hold_set(it->wd->scr, EINA_FALSE); elm_smart_scroller_bounce_allow_set(it->wd->scr, it->wd->h_bounce, it->wd->v_bounce); } if (it->wd->longpressed) { it->wd->longpressed = EINA_FALSE; if (!it->wd->wasselected) { _item_unhighlight(it); _item_unselect(it); } it->wd->wasselected = EINA_FALSE; return; } if (dragged) { if (it->want_unrealize) { _elm_genlist_item_unrealize(it, EINA_FALSE); if (it->item->block->want_unrealize) _item_block_unrealize(it->item->block); } } if ((it->disabled) || (dragged) || (it->display_only)) return; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; if (it->wd->multi) { if (!it->selected) { _item_highlight(it); it->sel_cb(it); } else { _item_unhighlight(it); _item_unselect(it); } } else { if (!it->selected) { Widget_Data *wd = it->wd; if (wd) { while (wd->selected) { _item_unhighlight(wd->selected->data); _item_unselect(wd->selected->data); } } } else { const Eina_List *l, *l_next; Elm_Gen_Item *it2; EINA_LIST_FOREACH_SAFE(it->wd->selected, l, l_next, it2) if (it2 != it) { _item_unhighlight(it2); _item_unselect(it2); } //_item_highlight(it); //_item_select(it); } _item_highlight(it); it->sel_cb(it); } } static void _signal_expand_toggle(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) { Elm_Gen_Item *it = data; if (it->item->expanded) evas_object_smart_callback_call(WIDGET(it), SIG_CONTRACT_REQUEST, it); else evas_object_smart_callback_call(WIDGET(it), SIG_EXPAND_REQUEST, it); } static void _signal_expand(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) { Elm_Gen_Item *it = data; if (!it->item->expanded) evas_object_smart_callback_call(WIDGET(it), SIG_EXPAND_REQUEST, it); } static void _signal_contract(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) { Elm_Gen_Item *it = data; if (it->item->expanded) evas_object_smart_callback_call(WIDGET(it), SIG_CONTRACT_REQUEST, it); } static Eina_Bool _scr_hold_timer_cb(void *data) { if (!data) return ECORE_CALLBACK_CANCEL; Widget_Data *wd = data; elm_smart_scroller_hold_set(wd->scr, EINA_FALSE); wd->scr_hold_timer = NULL; return ECORE_CALLBACK_CANCEL; } static void _mode_finished_signal_cb(void *data, Evas_Object *obj, const char *emission __UNUSED__, const char *source __UNUSED__) { if (!data) return; if (!obj) return; Elm_Gen_Item *it = data; if ((it->generation < it->wd->generation) || (!it->realized) || (!it->item->mode_view)) return; char buf[1024]; Evas *te = evas_object_evas_get(obj); evas_event_freeze(te); it->item->nocache = EINA_FALSE; _mode_item_unrealize(it); if (it->item->group_item) evas_object_raise(it->item->VIEW(group_item)); snprintf(buf, sizeof(buf), "elm,state,%s,passive,finished", it->wd->mode_type); edje_object_signal_callback_del_full(obj, buf, "elm", _mode_finished_signal_cb, it); evas_event_thaw(te); evas_event_thaw_eval(te); } static void _item_cache_clean(Widget_Data *wd) { evas_event_freeze(evas_object_evas_get(wd->obj)); while ((wd->item_cache) && (wd->item_cache_count > wd->item_cache_max)) { Item_Cache *itc; itc = EINA_INLIST_CONTAINER_GET(wd->item_cache->last, Item_Cache); wd->item_cache = eina_inlist_remove(wd->item_cache, wd->item_cache->last); wd->item_cache_count--; if (itc->spacer) evas_object_del(itc->spacer); if (itc->base_view) evas_object_del(itc->base_view); if (itc->item_style) eina_stringshare_del(itc->item_style); free(itc); } evas_event_thaw(evas_object_evas_get(wd->obj)); evas_event_thaw_eval(evas_object_evas_get(wd->obj)); } static void _item_cache_zero(Widget_Data *wd) { int pmax = wd->item_cache_max; wd->item_cache_max = 0; _item_cache_clean(wd); wd->item_cache_max = pmax; } static void _item_cache_add(Elm_Gen_Item *it) { Item_Cache *itc; evas_event_freeze(evas_object_evas_get(it->wd->obj)); if (it->wd->item_cache_max <= 0) { evas_object_del(VIEW(it)); VIEW(it) = NULL; evas_object_del(it->spacer); it->spacer = NULL; evas_event_thaw(evas_object_evas_get(it->wd->obj)); evas_event_thaw_eval(evas_object_evas_get(it->wd->obj)); return; } it->wd->item_cache_count++; itc = calloc(1, sizeof(Item_Cache)); it->wd->item_cache = eina_inlist_prepend(it->wd->item_cache, EINA_INLIST_GET(itc)); itc->spacer = it->spacer; it->spacer = NULL; itc->base_view = VIEW(it); VIEW(it) = NULL; evas_object_hide(itc->base_view); evas_object_move(itc->base_view, -9999, -9999); itc->item_style = eina_stringshare_add(it->itc->item_style); if (it->item->flags & ELM_GENLIST_ITEM_SUBITEMS) itc->tree = 1; itc->compress = (it->wd->compress); itc->selected = it->selected; itc->disabled = it->disabled; itc->expanded = it->item->expanded; if (it->long_timer) { ecore_timer_del(it->long_timer); it->long_timer = NULL; } if (it->item->swipe_timer) { ecore_timer_del(it->item->swipe_timer); it->item->swipe_timer = NULL; } // FIXME: other callbacks? edje_object_signal_callback_del_full(itc->base_view, "elm,action,expand,toggle", "elm", _signal_expand_toggle, it); edje_object_signal_callback_del_full(itc->base_view, "elm,action,expand", "elm", _signal_expand, it); edje_object_signal_callback_del_full(itc->base_view, "elm,action,contract", "elm", _signal_contract, it); evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, it); evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MOUSE_UP, _mouse_up, it); evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move, it); evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MULTI_DOWN, _multi_down, it); evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MULTI_UP, _multi_up, it); evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MULTI_MOVE, _multi_move, it); _item_cache_clean(it->wd); evas_event_thaw(evas_object_evas_get(it->wd->obj)); evas_event_thaw_eval(evas_object_evas_get(it->wd->obj)); } static Item_Cache * _item_cache_find(Elm_Gen_Item *it) { Item_Cache *itc; Eina_Bool tree = 0; if (it->item->flags & ELM_GENLIST_ITEM_SUBITEMS) tree = 1; EINA_INLIST_FOREACH(it->wd->item_cache, itc) { if ((itc->selected) || (itc->disabled) || (itc->expanded)) continue; if ((itc->tree == tree) && (itc->compress == it->wd->compress) && (!strcmp(it->itc->item_style, itc->item_style))) { it->wd->item_cache = eina_inlist_remove(it->wd->item_cache, EINA_INLIST_GET(itc)); it->wd->item_cache_count--; return itc; } } return NULL; } static void _elm_genlist_item_odd_even_update(Elm_Gen_Item *it) { if (!it->item->nostacking) { if ((it->item->order_num_in & 0x1) ^ it->item->stacking_even) evas_object_lower(VIEW(it)); else evas_object_raise(VIEW(it)); } if (it->item->order_num_in & 0x1) edje_object_signal_emit(VIEW(it), "elm,state,odd", "elm"); else edje_object_signal_emit(VIEW(it), "elm,state,even", "elm"); } static void _elm_genlist_item_state_update(Elm_Gen_Item *it, Item_Cache *itc) { if (itc) { if (it->selected != itc->selected) { if (it->selected) edje_object_signal_emit(VIEW(it), "elm,state,selected", "elm"); } if (it->disabled != itc->disabled) { if (it->disabled) edje_object_signal_emit(VIEW(it), "elm,state,disabled", "elm"); } if (it->item->expanded != itc->expanded) { if (it->item->expanded) edje_object_signal_emit(VIEW(it), "elm,state,expanded", "elm"); } } else { if (it->selected) edje_object_signal_emit(VIEW(it), "elm,state,selected", "elm"); if (it->disabled) edje_object_signal_emit(VIEW(it), "elm,state,disabled", "elm"); if (it->item->expanded) edje_object_signal_emit(VIEW(it), "elm,state,expanded", "elm"); } } static void _item_cache_free(Item_Cache *itc) { if (itc->spacer) evas_object_del(itc->spacer); if (itc->base_view) evas_object_del(itc->base_view); if (itc->item_style) eina_stringshare_del(itc->item_style); free(itc); } static void _item_del_hook(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) { Elm_Gen_Item *it = event_info; if (!it) return; if (it->wd->last_selected_item == it) it->wd->last_selected_item = NULL; } static void _item_label_realize(Elm_Gen_Item *it, Evas_Object *target, Eina_List **source, const char *parts) { if (it->itc->func.text_get) { const Eina_List *l; const char *key; *source = elm_widget_stringlist_get(edje_object_data_get(target, "labels")); EINA_LIST_FOREACH(*source, l, key) { if (parts && fnmatch(parts, key, FNM_PERIOD)) continue; char *s = it->itc->func.text_get ((void *)it->base.data, WIDGET(it), key); if (s) { edje_object_part_text_set(target, key, s); free(s); } else { edje_object_part_text_set(target, key, ""); } } } } static Eina_List * _item_content_unrealize(Elm_Gen_Item *it, Evas_Object *target, Eina_List **source, const char *parts) { Eina_List *res = it->content_objs; if (it->itc->func.content_get) { const Eina_List *l; const char *key; Evas_Object *ic = NULL; EINA_LIST_FOREACH(*source, l, key) { if (parts && fnmatch(parts, key, FNM_PERIOD)) continue; ic = edje_object_part_swallow_get(target, key); if (ic) { res = eina_list_remove(res, ic); edje_object_part_unswallow(target, ic); evas_object_del(ic); } } } return res; } static Eina_List * _item_content_realize(Elm_Gen_Item *it, Evas_Object *target, Eina_List **source, const char *parts) { Eina_List *res = NULL; if (it->itc->func.content_get) { const Eina_List *l; const char *key; Evas_Object *ic = NULL; *source = elm_widget_stringlist_get(edje_object_data_get(target, "contents")); if (parts && (eina_list_count(*source) != eina_list_count(it->content_objs))) res = it->content_objs; EINA_LIST_FOREACH(*source, l, key) { if (parts && fnmatch(parts, key, FNM_PERIOD)) continue; if (it->itc->func.content_get) ic = it->itc->func.content_get ((void *)it->base.data, WIDGET(it), key); if (ic) { res = eina_list_append(res, ic); edje_object_part_swallow(target, key, ic); evas_object_show(ic); elm_widget_sub_object_add(WIDGET(it), ic); if (it->disabled) elm_widget_disabled_set(ic, EINA_TRUE); } } } return res; } static void _item_state_realize(Elm_Gen_Item *it, Evas_Object *target, Eina_List **source, const char *parts) { if (it->itc->func.state_get) { const Eina_List *l; const char *key; char buf[4096]; *source = elm_widget_stringlist_get(edje_object_data_get(target, "states")); EINA_LIST_FOREACH(*source, l, key) { if (parts && fnmatch(parts, key, FNM_PERIOD)) continue; Eina_Bool on = it->itc->func.state_get ((void *)it->base.data, 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"); } } } } static void _item_realize(Elm_Gen_Item *it, int in, Eina_Bool calc) { Elm_Gen_Item *it2; const char *treesize; char buf[1024]; int depth, tsize = 20; Item_Cache *itc = NULL; if (it->generation < it->wd->generation) return; //evas_event_freeze(evas_object_evas_get(it->wd->obj)); if (it->realized) { if (it->item->order_num_in != in) { it->item->order_num_in = in; _elm_genlist_item_odd_even_update(it); _elm_genlist_item_state_update(it, NULL); } //evas_event_thaw(evas_object_evas_get(it->wd->obj)); //evas_event_thaw_eval(evas_object_evas_get(it->wd->obj)); return; } it->item->order_num_in = in; if (it->item->nocache) it->item->nocache = EINA_FALSE; else itc = _item_cache_find(it); if (itc) { VIEW(it) = itc->base_view; itc->base_view = NULL; it->spacer = itc->spacer; itc->spacer = NULL; } else { const char *stacking_even; const char *stacking; 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); evas_object_smart_member_add(VIEW(it), it->wd->pan_smart); elm_widget_sub_object_add(WIDGET(it), VIEW(it)); if (it->item->flags & ELM_GENLIST_ITEM_SUBITEMS) strncpy(buf, "tree", sizeof(buf)); else strncpy(buf, "item", sizeof(buf)); if (it->wd->compress) strncat(buf, "_compress", sizeof(buf) - strlen(buf)); strncat(buf, "/", sizeof(buf) - strlen(buf)); strncat(buf, it->itc->item_style, sizeof(buf) - strlen(buf)); _elm_theme_object_set(WIDGET(it), VIEW(it), "genlist", buf, elm_widget_style_get(WIDGET(it))); stacking_even = edje_object_data_get(VIEW(it), "stacking_even"); if (!stacking_even) stacking_even = "above"; it->item->stacking_even = !!strcmp("above", stacking_even); stacking = edje_object_data_get(VIEW(it), "stacking"); if (!stacking) stacking = "yes"; it->item->nostacking = !!strcmp("yes", stacking); edje_object_mirrored_set(VIEW(it), elm_widget_mirrored_get(WIDGET(it))); it->spacer = evas_object_rectangle_add(evas_object_evas_get(WIDGET(it))); evas_object_color_set(it->spacer, 0, 0, 0, 0); elm_widget_sub_object_add(WIDGET(it), it->spacer); } _elm_genlist_item_odd_even_update(it); for (it2 = it, depth = 0; it2->parent; it2 = it2->parent) { if (!it2->parent->group) depth += 1; } it->item->expanded_depth = depth; treesize = edje_object_data_get(VIEW(it), "treesize"); if (treesize) tsize = atoi(treesize); evas_object_size_hint_min_set(it->spacer, (depth * tsize) * _elm_config->scale, 1); edje_object_part_swallow(VIEW(it), "elm.swallow.pad", it->spacer); if (!calc) { edje_object_signal_callback_add(VIEW(it), "elm,action,expand,toggle", "elm", _signal_expand_toggle, it); edje_object_signal_callback_add(VIEW(it), "elm,action,expand", "elm", _signal_expand, it); edje_object_signal_callback_add(VIEW(it), "elm,action,contract", "elm", _signal_contract, it); evas_object_event_callback_add(VIEW(it), EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, it); evas_object_event_callback_add(VIEW(it), EVAS_CALLBACK_MOUSE_UP, _mouse_up, it); evas_object_event_callback_add(VIEW(it), EVAS_CALLBACK_MOUSE_MOVE, _mouse_move, it); evas_object_event_callback_add(VIEW(it), EVAS_CALLBACK_MULTI_DOWN, _multi_down, it); evas_object_event_callback_add(VIEW(it), EVAS_CALLBACK_MULTI_UP, _multi_up, it); evas_object_event_callback_add(VIEW(it), EVAS_CALLBACK_MULTI_MOVE, _multi_move, it); _elm_genlist_item_state_update(it, itc); } if ((calc) && (it->wd->homogeneous) && ((it->wd->item_width) || ((it->wd->item_width) && (it->wd->group_item_width)))) { /* homogenous genlist shortcut */ if (!it->item->mincalcd) { if (it->group) { it->item->w = it->item->minw = it->wd->group_item_width; it->item->h = it->item->minh = it->wd->group_item_height; } else { it->item->w = it->item->minw = it->wd->item_width; it->item->h = it->item->minh = it->wd->item_height; } it->item->mincalcd = EINA_TRUE; } } else { /* FIXME: If you see that assert, please notify us and we will clean our mess */ assert(eina_list_count(it->content_objs) == 0); _item_label_realize(it, VIEW(it), &it->labels, NULL); it->content_objs = _item_content_realize(it, VIEW(it), &it->contents, NULL); _item_state_realize(it, VIEW(it), &it->states, NULL); if (!it->item->mincalcd) { Evas_Coord mw = -1, mh = -1; if (!it->display_only) elm_coords_finger_size_adjust(1, &mw, 1, &mh); if (it->wd->height_for_width) mw = it->wd->prev_viewport_w; edje_object_size_min_restricted_calc(VIEW(it), &mw, &mh, mw, mh); if (!it->display_only) elm_coords_finger_size_adjust(1, &mw, 1, &mh); it->item->w = it->item->minw = mw; it->item->h = it->item->minh = mh; it->item->mincalcd = EINA_TRUE; if ((!it->wd->group_item_width) && (it->group)) { it->wd->group_item_width = mw; it->wd->group_item_height = mh; } else if ((!it->wd->item_width) && (it->item->flags == ELM_GENLIST_ITEM_NONE)) { it->wd->item_width = mw; it->wd->item_height = mh; } } if (!calc) evas_object_show(VIEW(it)); } if (it->tooltip.content_cb) { elm_widget_item_tooltip_content_cb_set(it, it->tooltip.content_cb, it->tooltip.data, NULL); elm_widget_item_tooltip_style_set(it, it->tooltip.style); elm_widget_item_tooltip_window_mode_set(it, it->tooltip.free_size); } if (it->mouse_cursor) elm_widget_item_cursor_set(it, it->mouse_cursor); it->realized = EINA_TRUE; it->want_unrealize = EINA_FALSE; if (itc) _item_cache_free(itc); //evas_event_thaw(evas_object_evas_get(it->wd->obj)); //evas_event_thaw_eval(evas_object_evas_get(it->wd->obj)); if (!calc) evas_object_smart_callback_call(WIDGET(it), SIG_REALIZED, it); edje_object_message_signal_process(VIEW(it)); } static void _item_unrealize_cb(Elm_Gen_Item *it) { if (it->item->nocache) { evas_object_del(VIEW(it)); VIEW(it) = NULL; evas_object_del(it->spacer); it->spacer = NULL; } else { 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); _item_cache_add(it); } _mode_item_unrealize(it); it->states = NULL; it->realized = EINA_FALSE; it->want_unrealize = EINA_FALSE; } static Eina_Bool _item_block_recalc(Item_Block *itb, int in, Eina_Bool qadd) { const Eina_List *l; Elm_Gen_Item *it; Evas_Coord minw = 0, minh = 0; Eina_Bool showme = EINA_FALSE, changed = EINA_FALSE; Evas_Coord y = 0; //evas_event_freeze(evas_object_evas_get(itb->wd->obj)); itb->num = in; EINA_LIST_FOREACH(itb->items, l, it) { if (it->generation < it->wd->generation) continue; showme |= it->item->showme; if (!itb->realized) { if (qadd) { if (!it->item->mincalcd) changed = EINA_TRUE; if (changed) { _item_realize(it, in, EINA_TRUE); _elm_genlist_item_unrealize(it, EINA_TRUE); } } else { _item_realize(it, in, EINA_TRUE); _elm_genlist_item_unrealize(it, EINA_TRUE); } } else _item_realize(it, in, EINA_FALSE); minh += it->item->minh; if (minw < it->item->minw) minw = it->item->minw; in++; it->x = 0; it->y = y; y += it->item->h; } itb->minw = minw; itb->minh = minh; itb->changed = EINA_FALSE; //evas_event_thaw(evas_object_evas_get(itb->wd->obj)); //evas_event_thaw_eval(evas_object_evas_get(itb->wd->obj)); return showme; } static void _item_block_realize(Item_Block *itb) { if (itb->realized) return; itb->realized = EINA_TRUE; itb->want_unrealize = EINA_FALSE; } static void _item_block_unrealize(Item_Block *itb) { const Eina_List *l; Elm_Gen_Item *it; Eina_Bool dragging = EINA_FALSE; if (!itb->realized) return; evas_event_freeze(evas_object_evas_get(itb->wd->obj)); EINA_LIST_FOREACH(itb->items, l, it) { if (!it->group) { if (it->dragging) { dragging = EINA_TRUE; it->want_unrealize = EINA_TRUE; } else _elm_genlist_item_unrealize(it, EINA_FALSE); } } if (!dragging) { itb->realized = EINA_FALSE; itb->want_unrealize = EINA_TRUE; } else itb->want_unrealize = EINA_FALSE; evas_event_thaw(evas_object_evas_get(itb->wd->obj)); evas_event_thaw_eval(evas_object_evas_get(itb->wd->obj)); } static int _get_space_for_reorder_item(Elm_Gen_Item *it) { Evas_Coord rox, roy, row, roh, oy, oh; Eina_Bool top = EINA_FALSE; Elm_Gen_Item *reorder_it = it->wd->reorder_it; if (!reorder_it) return 0; evas_object_geometry_get(it->wd->pan_smart, NULL, &oy, NULL, &oh); evas_object_geometry_get(it->wd->VIEW(reorder_it), &rox, &roy, &row, &roh); if ((it->wd->reorder_start_y < it->item->block->y) && (roy - oy + (roh / 2) >= it->item->block->y - it->wd->pan_y)) { it->item->block->reorder_offset = it->wd->reorder_it->item->h * -1; if (it->item->block->count == 1) it->wd->reorder_rel = it; } else if ((it->wd->reorder_start_y >= it->item->block->y) && (roy - oy + (roh / 2) <= it->item->block->y - it->wd->pan_y)) { it->item->block->reorder_offset = it->wd->reorder_it->item->h; } else it->item->block->reorder_offset = 0; it->item->scrl_y += it->item->block->reorder_offset; top = (ELM_RECTS_INTERSECT(it->item->scrl_x, it->item->scrl_y, it->item->w, it->item->h, rox, roy + (roh / 2), row, 1)); if (top) { it->wd->reorder_rel = it; it->item->scrl_y += it->wd->reorder_it->item->h; return it->wd->reorder_it->item->h; } else return 0; } static Eina_Bool _reorder_move_animator_cb(void *data) { Elm_Gen_Item *it = data; Eina_Bool down = EINA_FALSE; double t; int y, dy = it->item->h / 10 * _elm_config->scale, diff; t = ((0.0 > (t = ecore_loop_time_get()-it->wd->start_time)) ? 0.0 : t); if (t <= REORDER_EFFECT_TIME) y = (1 * sin((t / REORDER_EFFECT_TIME) * (M_PI / 2)) * dy); else y = dy; diff = abs(it->item->old_scrl_y - it->item->scrl_y); if (diff > it->item->h) y = diff / 2; if (it->item->old_scrl_y < it->item->scrl_y) { it->item->old_scrl_y += y; down = EINA_TRUE; } else if (it->item->old_scrl_y > it->item->scrl_y) { it->item->old_scrl_y -= y; down = EINA_FALSE; } _item_position(it, VIEW(it), it->item->scrl_x, it->item->old_scrl_y); _group_items_recalc(it->wd); if ((it->wd->reorder_pan_move) || (down && it->item->old_scrl_y >= it->item->scrl_y) || (!down && it->item->old_scrl_y <= it->item->scrl_y)) { it->item->old_scrl_y = it->item->scrl_y; it->item->move_effect_enabled = EINA_FALSE; it->wd->reorder_move_animator = NULL; return ECORE_CALLBACK_CANCEL; } return ECORE_CALLBACK_RENEW; } static void _item_position(Elm_Gen_Item *it, Evas_Object *view, Evas_Coord it_x, Evas_Coord it_y) { if (!it) return; if (!view) return; evas_event_freeze(evas_object_evas_get(it->wd->obj)); evas_object_resize(view, it->item->w, it->item->h); evas_object_move(view, it_x, it_y); evas_object_show(view); evas_event_thaw(evas_object_evas_get(it->wd->obj)); evas_event_thaw_eval(evas_object_evas_get(it->wd->obj)); } static void _item_block_position(Item_Block *itb, int in) { const Eina_List *l; Elm_Gen_Item *it; Elm_Gen_Item *git; Evas_Coord y = 0, ox, oy, ow, oh, cvx, cvy, cvw, cvh; Eina_Bool vis = EINA_FALSE; evas_event_freeze(evas_object_evas_get(itb->wd->obj)); evas_object_geometry_get(itb->wd->pan_smart, &ox, &oy, &ow, &oh); evas_output_viewport_get(evas_object_evas_get(itb->wd->obj), &cvx, &cvy, &cvw, &cvh); EINA_LIST_FOREACH(itb->items, l, it) { if (it->generation < it->wd->generation) continue; else if (it->wd->reorder_it == it) continue; it->x = 0; it->y = y; it->item->w = itb->w; it->item->scrl_x = itb->x + it->x - it->wd->pan_x + ox; it->item->scrl_y = itb->y + it->y - it->wd->pan_y + oy; vis = (ELM_RECTS_INTERSECT(it->item->scrl_x, it->item->scrl_y, it->item->w, it->item->h, cvx, cvy, cvw, cvh)); if (!it->group) { if ((itb->realized) && (!it->realized)) { if (vis) _item_realize(it, in, EINA_FALSE); } if (it->realized) { if (vis) { if (it->wd->reorder_mode) y += _get_space_for_reorder_item(it); git = it->item->group_item; if (git) { if (git->item->scrl_y < oy) git->item->scrl_y = oy; if ((git->item->scrl_y + git->item->h) > (it->item->scrl_y + it->item->h)) git->item->scrl_y = (it->item->scrl_y + it->item->h) - git->item->h; git->item->want_realize = EINA_TRUE; } if ((it->wd->reorder_it) && (it->item->old_scrl_y != it->item->scrl_y)) { if (!it->item->move_effect_enabled) { it->item->move_effect_enabled = EINA_TRUE; it->wd->reorder_move_animator = ecore_animator_add( _reorder_move_animator_cb, it); } } if (!it->item->move_effect_enabled) { if (it->item->mode_view) _item_position(it, it->item->mode_view, it->item->scrl_x, it->item->scrl_y); else _item_position(it, VIEW(it), it->item->scrl_x, it->item->scrl_y); it->item->old_scrl_y = it->item->scrl_y; } } else { if (!it->dragging) _elm_genlist_item_unrealize(it, EINA_FALSE); } } in++; } else { if (vis) it->item->want_realize = EINA_TRUE; } y += it->item->h; } evas_event_thaw(evas_object_evas_get(itb->wd->obj)); evas_event_thaw_eval(evas_object_evas_get(itb->wd->obj)); } static void _group_items_recalc(void *data) { Widget_Data *wd = data; Eina_List *l; Elm_Gen_Item *git; evas_event_freeze(evas_object_evas_get(wd->obj)); EINA_LIST_FOREACH(wd->group_items, l, git) { if (git->item->want_realize) { if (!git->realized) _item_realize(git, 0, EINA_FALSE); evas_object_resize(VIEW(git), wd->minw, git->item->h); evas_object_move(VIEW(git), git->item->scrl_x, git->item->scrl_y); evas_object_show(VIEW(git)); evas_object_raise(VIEW(git)); } else if (!git->item->want_realize && git->realized) { if (!git->dragging) _elm_genlist_item_unrealize(git, EINA_FALSE); } } evas_event_thaw(evas_object_evas_get(wd->obj)); evas_event_thaw_eval(evas_object_evas_get(wd->obj)); } static Eina_Bool _must_recalc_idler(void *data) { Widget_Data *wd = data; if (wd->calc_job) ecore_job_del(wd->calc_job); wd->calc_job = ecore_job_add(_calc_job, wd); wd->must_recalc_idler = NULL; return ECORE_CALLBACK_CANCEL; } static void _calc_job(void *data) { Widget_Data *wd = data; Item_Block *itb, *chb = NULL; Evas_Coord minw = -1, minh = 0, y = 0, ow; int in = 0; Eina_Bool minw_change = EINA_FALSE; Eina_Bool did_must_recalc = EINA_FALSE; if (!wd) return; evas_object_geometry_get(wd->pan_smart, NULL, NULL, &ow, &wd->h); if (wd->w != ow) wd->w = ow; evas_event_freeze(evas_object_evas_get(wd->obj)); EINA_INLIST_FOREACH(wd->blocks, itb) { Eina_Bool showme = EINA_FALSE; itb->num = in; showme = itb->showme; itb->showme = EINA_FALSE; if (chb) { if (itb->realized) _item_block_unrealize(itb); } if ((itb->changed) || ((itb->must_recalc) && (!did_must_recalc))) { if (itb->must_recalc) { Eina_List *l; Elm_Gen_Item *it; EINA_LIST_FOREACH(itb->items, l, it) if (it->item->mincalcd) it->item->mincalcd = EINA_FALSE; itb->changed = EINA_TRUE; if (itb->must_recalc) did_must_recalc = EINA_TRUE; itb->must_recalc = EINA_FALSE; } if (itb->realized) _item_block_unrealize(itb); showme = _item_block_recalc(itb, in, EINA_FALSE); chb = itb; } itb->y = y; itb->x = 0; minh += itb->minh; if (minw == -1) minw = itb->minw; else if ((!itb->must_recalc) && (minw < itb->minw)) { minw = itb->minw; minw_change = EINA_TRUE; } itb->w = minw; itb->h = itb->minh; y += itb->h; in += itb->count; if ((showme) && (wd->show_item) && (!wd->show_item->item->queued)) { wd->show_item->item->showme = EINA_FALSE; if (wd->bring_in) elm_smart_scroller_region_bring_in(wd->scr, wd->show_item->x + wd->show_item->item->block->x, wd->show_item->y + wd->show_item->item->block->y, wd->show_item->item->block->w, wd->show_item->item->h); else elm_smart_scroller_child_region_show(wd->scr, wd->show_item->x + wd->show_item->item->block->x, wd->show_item->y + wd->show_item->item->block->y, wd->show_item->item->block->w, wd->show_item->item->h); wd->show_item = NULL; } } if (minw_change) { EINA_INLIST_FOREACH(wd->blocks, itb) { itb->minw = minw; itb->w = itb->minw; } } if ((chb) && (EINA_INLIST_GET(chb)->next)) { EINA_INLIST_FOREACH(EINA_INLIST_GET(chb)->next, itb) { if (itb->realized) _item_block_unrealize(itb); } } wd->realminw = minw; if (minw < wd->w) minw = wd->w; if ((minw != wd->minw) || (minh != wd->minh)) { wd->minw = minw; wd->minh = minh; evas_object_smart_callback_call(wd->pan_smart, "changed", NULL); _sizing_eval(wd->obj); if ((wd->anchor_item) && (wd->anchor_item->item->block) && (!wd->auto_scroll_enabled)) { Elm_Gen_Item *it; Evas_Coord it_y; it = wd->anchor_item; it_y = wd->anchor_y; elm_smart_scroller_child_pos_set(wd->scr, wd->pan_x, it->item->block->y + it->y + it_y); wd->anchor_item = it; wd->anchor_y = it_y; } } if (did_must_recalc) { if (!wd->must_recalc_idler) wd->must_recalc_idler = ecore_idler_add(_must_recalc_idler, wd); } wd->calc_job = NULL; evas_object_smart_changed(wd->pan_smart); evas_event_thaw(evas_object_evas_get(wd->obj)); evas_event_thaw_eval(evas_object_evas_get(wd->obj)); } static void _update_job(void *data) { Widget_Data *wd = data; Eina_List *l2; Item_Block *itb; int num, num0; Eina_Bool position = EINA_FALSE, recalc = EINA_FALSE; if (!wd) return; wd->update_job = NULL; num = 0; evas_event_freeze(evas_object_evas_get(wd->obj)); EINA_INLIST_FOREACH(wd->blocks, itb) { Evas_Coord itminw, itminh; Elm_Gen_Item *it; if (!itb->updateme) { num += itb->count; if (position) _item_block_position(itb, num); continue; } num0 = num; recalc = EINA_FALSE; EINA_LIST_FOREACH(itb->items, l2, it) { if (it->item->updateme) { itminw = it->item->minw; itminh = it->item->minh; it->item->updateme = EINA_FALSE; if (it->realized) { _elm_genlist_item_unrealize(it, EINA_FALSE); _item_realize(it, num, EINA_FALSE); position = EINA_TRUE; } else { _item_realize(it, num, EINA_TRUE); _elm_genlist_item_unrealize(it, EINA_TRUE); } if ((it->item->minw != itminw) || (it->item->minh != itminh)) recalc = EINA_TRUE; } num++; } itb->updateme = EINA_FALSE; if (recalc) { position = EINA_TRUE; itb->changed = EINA_TRUE; _item_block_recalc(itb, num0, EINA_FALSE); _item_block_position(itb, num0); } } if (position) { if (wd->calc_job) ecore_job_del(wd->calc_job); wd->calc_job = ecore_job_add(_calc_job, wd); } evas_event_thaw(evas_object_evas_get(wd->obj)); evas_event_thaw_eval(evas_object_evas_get(wd->obj)); } static void _pan_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y) { Pan *sd = evas_object_smart_data_get(obj); Item_Block *itb; if (!sd) return; // Evas_Coord ow, oh; // evas_object_geometry_get(obj, NULL, NULL, &ow, &oh); // ow = sd->wd->minw - ow; // if (ow < 0) ow = 0; // oh = sd->wd->minh - oh; // if (oh < 0) oh = 0; // if (x < 0) x = 0; // if (y < 0) y = 0; // if (x > ow) x = ow; // if (y > oh) y = oh; if ((x == sd->wd->pan_x) && (y == sd->wd->pan_y)) return; sd->wd->pan_x = x; sd->wd->pan_y = y; EINA_INLIST_FOREACH(sd->wd->blocks, itb) { if ((itb->y + itb->h) > y) { Elm_Gen_Item *it; Eina_List *l2; EINA_LIST_FOREACH(itb->items, l2, it) { if ((itb->y + it->y) >= y) { sd->wd->anchor_item = it; sd->wd->anchor_y = -(itb->y + it->y - y); goto done; } } } } done: if (!sd->wd->reorder_move_animator) evas_object_smart_changed(obj); } static void _pan_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y) { Pan *sd = evas_object_smart_data_get(obj); if (!sd) return; if (x) *x = sd->wd->pan_x; if (y) *y = sd->wd->pan_y; } static void _pan_max_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y) { Pan *sd = evas_object_smart_data_get(obj); Evas_Coord ow, oh; if (!sd) return; evas_object_geometry_get(obj, NULL, NULL, &ow, &oh); ow = sd->wd->minw - ow; if (ow < 0) ow = 0; oh = sd->wd->minh - oh; if (oh < 0) oh = 0; if (x) *x = ow; if (y) *y = oh; } static void _pan_min_get(Evas_Object *obj __UNUSED__, Evas_Coord *x, Evas_Coord *y) { if (x) *x = 0; if (y) *y = 0; } static void _pan_child_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h) { Pan *sd = evas_object_smart_data_get(obj); if (!sd) return; if (w) *w = sd->wd->minw; if (h) *h = sd->wd->minh; } static void _pan_add(Evas_Object *obj) { Pan *sd; Evas_Object_Smart_Clipped_Data *cd; _pan_sc.add(obj); cd = evas_object_smart_data_get(obj); sd = ELM_NEW(Pan); if (!sd) return; sd->__clipped_data = *cd; free(cd); evas_object_smart_data_set(obj, sd); } static void _pan_del(Evas_Object *obj) { Pan *sd = evas_object_smart_data_get(obj); if (!sd) return; if (sd->resize_job) { ecore_job_del(sd->resize_job); sd->resize_job = NULL; } _pan_sc.del(obj); } static void _pan_resize_job(void *data) { Pan *sd = data; if (!sd) return; _sizing_eval(sd->wd->obj); sd->resize_job = NULL; } static void _pan_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h) { Pan *sd = evas_object_smart_data_get(obj); Evas_Coord ow, oh; if (!sd) return; evas_object_geometry_get(obj, NULL, NULL, &ow, &oh); if ((ow == w) && (oh == h)) return; if ((sd->wd->height_for_width) && (ow != w)) { /* fix me later */ if (sd->resize_job) ecore_job_del(sd->resize_job); sd->resize_job = ecore_job_add(_pan_resize_job, sd); } sd->wd->pan_resized = EINA_TRUE; evas_object_smart_changed(obj); if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job); sd->wd->calc_job = NULL; /* OLD if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job); sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd); */ } static void _pan_calculate(Evas_Object *obj) { Pan *sd = evas_object_smart_data_get(obj); Item_Block *itb; Evas_Coord ox, oy, ow, oh, cvx, cvy, cvw, cvh; int in = 0; Elm_Gen_Item *git; Eina_List *l; if (!sd) return; evas_event_freeze(evas_object_evas_get(obj)); if (sd->wd->pan_resized) { _calc_job(sd->wd); sd->wd->pan_resized = EINA_FALSE; } evas_object_geometry_get(obj, &ox, &oy, &ow, &oh); evas_output_viewport_get(evas_object_evas_get(obj), &cvx, &cvy, &cvw, &cvh); EINA_LIST_FOREACH(sd->wd->group_items, l, git) { git->item->want_realize = EINA_FALSE; } EINA_INLIST_FOREACH(sd->wd->blocks, itb) { itb->w = sd->wd->minw; if (ELM_RECTS_INTERSECT(itb->x - sd->wd->pan_x + ox, itb->y - sd->wd->pan_y + oy, itb->w, itb->h, cvx, cvy, cvw, cvh)) { if ((!itb->realized) || (itb->changed)) _item_block_realize(itb); _item_block_position(itb, in); } else { if (itb->realized) _item_block_unrealize(itb); } in += itb->count; } if ((!sd->wd->reorder_it) || (sd->wd->reorder_pan_move)) _group_items_recalc(sd->wd); if ((sd->wd->reorder_mode) && (sd->wd->reorder_it)) { if (sd->wd->pan_y != sd->wd->reorder_old_pan_y) sd->wd->reorder_pan_move = EINA_TRUE; else sd->wd->reorder_pan_move = EINA_FALSE; evas_object_raise(sd->wd->VIEW(reorder_it)); sd->wd->reorder_old_pan_y = sd->wd->pan_y; sd->wd->start_time = ecore_loop_time_get(); } _item_auto_scroll(sd->wd); evas_event_thaw(evas_object_evas_get(obj)); evas_event_thaw_eval(evas_object_evas_get(obj)); } static void _pan_move(Evas_Object *obj, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__) { Pan *sd = evas_object_smart_data_get(obj); if (!sd) return; if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job); sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd); } static void _hold_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__) { Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; elm_smart_scroller_hold_set(wd->scr, 1); } static void _hold_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__) { Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; elm_smart_scroller_hold_set(wd->scr, 0); } static void _freeze_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__) { Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; elm_smart_scroller_freeze_set(wd->scr, 1); } static void _freeze_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__) { Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; elm_smart_scroller_freeze_set(wd->scr, 0); } static void _scr_anim_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) { evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_START, NULL); } static void _scr_anim_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) { evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_STOP, NULL); } static void _scr_drag_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) { evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_START, NULL); } static void _scr_drag_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) { evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_STOP, NULL); } static void _edge_left(void *data, Evas_Object *scr __UNUSED__, void *event_info __UNUSED__) { Evas_Object *obj = data; evas_object_smart_callback_call(obj, SIG_EDGE_LEFT, NULL); } static void _edge_right(void *data, Evas_Object *scr __UNUSED__, void *event_info __UNUSED__) { Evas_Object *obj = data; evas_object_smart_callback_call(obj, SIG_EDGE_RIGHT, NULL); } static void _edge_top(void *data, Evas_Object *scr __UNUSED__, void *event_info __UNUSED__) { Evas_Object *obj = data; evas_object_smart_callback_call(obj, SIG_EDGE_TOP, NULL); } static void _edge_bottom(void *data, Evas_Object *scr __UNUSED__, void *event_info __UNUSED__) { Evas_Object *obj = data; evas_object_smart_callback_call(obj, SIG_EDGE_BOTTOM, NULL); } static void _mode_item_realize(Elm_Gen_Item *it) { char buf[1024]; if ((it->item->mode_view) || (it->generation < it->wd->generation)) return; evas_event_freeze(evas_object_evas_get(it->wd->obj)); it->item->mode_view = edje_object_add(evas_object_evas_get(WIDGET(it))); edje_object_scale_set(it->item->mode_view, elm_widget_scale_get(WIDGET(it)) * _elm_config->scale); evas_object_smart_member_add(it->item->mode_view, it->wd->pan_smart); elm_widget_sub_object_add(WIDGET(it), it->item->mode_view); strncpy(buf, "item", sizeof(buf)); if (it->wd->compress) strncat(buf, "_compress", sizeof(buf) - strlen(buf)); if (it->item->order_num_in & 0x1) strncat(buf, "_odd", sizeof(buf) - strlen(buf)); strncat(buf, "/", sizeof(buf) - strlen(buf)); strncat(buf, it->wd->mode_item_style, sizeof(buf) - strlen(buf)); _elm_theme_object_set(WIDGET(it), it->item->mode_view, "genlist", buf, elm_widget_style_get(WIDGET(it))); edje_object_mirrored_set(it->item->mode_view, elm_widget_mirrored_get(WIDGET(it))); /* signal callback add */ evas_object_event_callback_add(it->item->mode_view, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, it); evas_object_event_callback_add(it->item->mode_view, EVAS_CALLBACK_MOUSE_UP, _mouse_up, it); evas_object_event_callback_add(it->item->mode_view, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move, it); /* text_get, content_get, state_get */ /* FIXME: If you see that assert, please notify us and we will clean our mess */ assert(eina_list_count(it->item->mode_content_objs) == 0); _item_label_realize(it, it->item->mode_view, &it->item->mode_labels, NULL); it->item->mode_content_objs = _item_content_realize(it, it->item->mode_view, &it->item->mode_contents, NULL); _item_state_realize(it, it->item->mode_view, &it->item->mode_states, NULL); edje_object_part_swallow(it->item->mode_view, edje_object_data_get(it->item->mode_view, "mode_part"), VIEW(it)); it->want_unrealize = EINA_FALSE; evas_event_thaw(evas_object_evas_get(it->wd->obj)); evas_event_thaw_eval(evas_object_evas_get(it->wd->obj)); } static void _mode_item_unrealize(Elm_Gen_Item *it) { Widget_Data *wd = it->wd; Evas_Object *content; if (!it->item->mode_view) return; evas_event_freeze(evas_object_evas_get(it->wd->obj)); elm_widget_stringlist_free(it->item->mode_labels); it->item->mode_labels = NULL; elm_widget_stringlist_free(it->item->mode_contents); it->item->mode_contents = NULL; elm_widget_stringlist_free(it->item->mode_states); EINA_LIST_FREE(it->item->mode_content_objs, content) evas_object_del(content); edje_object_part_unswallow(it->item->mode_view, VIEW(it)); evas_object_smart_member_add(VIEW(it), wd->pan_smart); evas_object_del(it->item->mode_view); it->item->mode_view = NULL; if (wd->mode_item == it) wd->mode_item = NULL; evas_event_thaw(evas_object_evas_get(it->wd->obj)); evas_event_thaw_eval(evas_object_evas_get(it->wd->obj)); } static void _item_mode_set(Elm_Gen_Item *it) { if (!it) return; Widget_Data *wd = it->wd; if (!wd) return; char buf[1024]; wd->mode_item = it; it->item->nocache = EINA_TRUE; if (wd->scr_hold_timer) { ecore_timer_del(wd->scr_hold_timer); wd->scr_hold_timer = NULL; } elm_smart_scroller_hold_set(wd->scr, EINA_TRUE); wd->scr_hold_timer = ecore_timer_add(0.1, _scr_hold_timer_cb, wd); evas_event_freeze(evas_object_evas_get(it->wd->obj)); _mode_item_realize(it); if (it->item->group_item) evas_object_raise(it->item->VIEW(group_item)); _item_position(it, it->item->mode_view, it->item->scrl_x, it->item->scrl_y); evas_event_thaw(evas_object_evas_get(it->wd->obj)); evas_event_thaw_eval(evas_object_evas_get(it->wd->obj)); snprintf(buf, sizeof(buf), "elm,state,%s,active", wd->mode_type); edje_object_signal_emit(it->item->mode_view, buf, "elm"); } static void _item_mode_unset(Widget_Data *wd) { if (!wd) return; if (!wd->mode_item) return; char buf[1024], buf2[1024]; Elm_Gen_Item *it; it = wd->mode_item; it->item->nocache = EINA_TRUE; snprintf(buf, sizeof(buf), "elm,state,%s,passive", wd->mode_type); snprintf(buf2, sizeof(buf2), "elm,state,%s,passive,finished", wd->mode_type); edje_object_signal_emit(it->item->mode_view, buf, "elm"); edje_object_signal_callback_add(it->item->mode_view, buf2, "elm", _mode_finished_signal_cb, it); wd->mode_item = NULL; } static void _item_auto_scroll(Widget_Data *wd) { if (!wd) return; Elm_Gen_Item *it; Eina_List *l; Evas_Coord ox, oy, ow, oh; if ((wd->expanded_item) && (wd->auto_scroll_enabled)) { evas_object_geometry_get(wd->obj, &ox, &oy, &ow, &oh); if (wd->expanded_item->item->scrl_y > (oh + oy) / 2) { EINA_LIST_FOREACH(wd->expanded_item->item->items, l, it) elm_genlist_item_bring_in(it); } wd->auto_scroll_enabled = EINA_FALSE; } } EAPI Evas_Object * elm_genlist_add(Evas_Object *parent) { Evas_Object *obj; Evas *e; Widget_Data *wd; Evas_Coord minw, minh; static Evas_Smart *smart = NULL; if (!smart) { static Evas_Smart_Class sc; evas_object_smart_clipped_smart_set(&_pan_sc); sc = _pan_sc; sc.name = "elm_genlist_pan"; sc.version = EVAS_SMART_CLASS_VERSION; sc.add = _pan_add; sc.del = _pan_del; sc.resize = _pan_resize; sc.move = _pan_move; sc.calculate = _pan_calculate; if (!(smart = evas_smart_class_new(&sc))) return NULL; } ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL); ELM_SET_WIDTYPE(widtype, "genlist"); ELM_GEN_SETUP(wd); elm_widget_type_set(obj, "genlist"); elm_widget_sub_object_add(parent, obj); elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL); elm_widget_signal_emit_hook_set(obj, _signal_emit_hook); elm_widget_data_set(obj, wd); elm_widget_del_hook_set(obj, _del_hook); elm_widget_del_pre_hook_set(obj, _del_pre_hook); elm_widget_theme_hook_set(obj, _theme_hook); elm_widget_can_focus_set(obj, EINA_TRUE); elm_widget_event_hook_set(obj, _event_hook); elm_widget_on_show_region_hook_set(obj, _show_region_hook, obj); elm_widget_translate_hook_set(obj, _translate_hook); wd->generation = 1; wd->scr = elm_smart_scroller_add(e); elm_smart_scroller_widget_set(wd->scr, obj); elm_smart_scroller_object_theme_set(obj, wd->scr, "genlist", "base", elm_widget_style_get(obj)); elm_smart_scroller_bounce_allow_set(wd->scr, EINA_FALSE, _elm_config->thumbscroll_bounce_enable); elm_widget_resize_object_set(obj, wd->scr); evas_object_smart_callback_add(wd->scr, "animate,start", _scr_anim_start, obj); evas_object_smart_callback_add(wd->scr, "animate,stop", _scr_anim_stop, obj); evas_object_smart_callback_add(wd->scr, "drag,start", _scr_drag_start, obj); evas_object_smart_callback_add(wd->scr, "drag,stop", _scr_drag_stop, obj); evas_object_smart_callback_add(wd->scr, "edge,left", _edge_left, obj); evas_object_smart_callback_add(wd->scr, "edge,right", _edge_right, obj); evas_object_smart_callback_add(wd->scr, "edge,top", _edge_top, obj); evas_object_smart_callback_add(wd->scr, "edge,bottom", _edge_bottom, obj); wd->obj = obj; wd->mode = ELM_LIST_SCROLL; wd->max_items_per_block = MAX_ITEMS_PER_BLOCK; wd->item_cache_max = wd->max_items_per_block * 2; wd->longpress_timeout = _elm_config->longpress_timeout; evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj); evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj); evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj); evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj); wd->pan_smart = evas_object_smart_add(e, smart); wd->pan = evas_object_smart_data_get(wd->pan_smart); wd->pan->wd = wd; elm_smart_scroller_extern_pan_set(wd->scr, wd->pan_smart, _pan_set, _pan_get, _pan_max_get, _pan_min_get, _pan_child_size_get); edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr), &minw, &minh); evas_object_size_hint_min_set(obj, minw, minh); evas_object_smart_callbacks_descriptions_set(obj, _signals); _mirrored_set(obj, elm_widget_mirrored_get(obj)); _sizing_eval(obj); return obj; } void _item_select(Elm_Gen_Item *it) { if ((it->wd->no_select) || (it->generation < it->wd->generation) || (it->mode_set)) return; if (!it->selected) { it->selected = EINA_TRUE; it->wd->selected = eina_list_append(it->wd->selected, it); } else if (!it->wd->always_select) return; evas_object_ref(WIDGET(it)); it->walking++; it->wd->walking++; if (it->func.func) it->func.func((void *)it->func.data, WIDGET(it), it); if (it->generation == it->wd->generation) evas_object_smart_callback_call(WIDGET(it), SIG_SELECTED, it); it->walking--; it->wd->walking--; evas_object_unref(WIDGET(it)); if ((it->wd->clear_me) && (!it->wd->walking)) _elm_genlist_clear(WIDGET(it), EINA_TRUE); else { if ((!it->walking) && (it->generation < it->wd->generation)) { if (!it->relcount) it->del_cb(it); } else it->wd->last_selected_item = it; } } static Evas_Object * _item_content_get_hook(Elm_Gen_Item *it, const char *part) { return edje_object_part_swallow_get(VIEW(it), part); } static void _item_content_set_hook(Elm_Gen_Item *it, const char *part, Evas_Object *content) { edje_object_part_swallow(VIEW(it), part, content); } static Evas_Object * _item_content_unset_hook(Elm_Gen_Item *it, const char *part) { Evas_Object *obj; obj = edje_object_part_swallow_get(VIEW(it), part); if (!obj) return NULL; edje_object_part_unswallow(VIEW(it), obj); return obj; } static const char * _item_label_hook(Elm_Gen_Item *it, const char *part) { if (!it->itc->func.text_get) return NULL; return edje_object_part_text_get(VIEW(it), part); } Elm_Gen_Item * _elm_genlist_item_new(Widget_Data *wd, const Elm_Gen_Item_Class *itc, const void *data, Elm_Gen_Item *parent, Evas_Smart_Cb func, const void *func_data) { Elm_Gen_Item *it; it = elm_widget_item_new(wd->obj, Elm_Gen_Item); if (!it) return NULL; it->wd = wd; it->generation = wd->generation; it->itc = itc; it->base.data = data; it->parent = parent; it->func.func = func; it->func.data = func_data; elm_widget_item_content_get_hook_set(it, _item_content_get_hook); elm_widget_item_content_set_hook_set(it, _item_content_set_hook); elm_widget_item_content_unset_hook_set(it, _item_content_unset_hook); /* TEMPORARY */ it->sel_cb = (Ecore_Cb)_item_select; elm_widget_item_text_get_hook_set(it, _item_label_hook); return it; } static Elm_Gen_Item * _item_new(Widget_Data *wd, const Elm_Genlist_Item_Class *itc, const void *data, Elm_Gen_Item *parent, Elm_Genlist_Item_Flags flags, Evas_Smart_Cb func, const void *func_data) { Elm_Gen_Item *it; it = _elm_genlist_item_new(wd, itc, data, parent, func, func_data); if (!it) return NULL; it->item = ELM_NEW(Elm_Gen_Item_Type); it->item->flags = flags; if (flags & ELM_GENLIST_ITEM_GROUP) it->group++; it->item->expanded_depth = 0; elm_widget_item_del_cb_set(it, _item_del_hook); ELM_GEN_ITEM_SETUP(it); if (it->parent) { if (it->parent->group) it->item->group_item = parent; else if (it->parent->item->group_item) it->item->group_item = it->parent->item->group_item; } return it; } static Item_Block * _item_block_new(Widget_Data *wd, Eina_Bool prepend) { Item_Block *itb; itb = calloc(1, sizeof(Item_Block)); if (!itb) return NULL; itb->wd = wd; if (prepend) wd->blocks = eina_inlist_prepend(wd->blocks, EINA_INLIST_GET(itb)); else wd->blocks = eina_inlist_append(wd->blocks, EINA_INLIST_GET(itb)); return itb; } static Eina_Bool _item_block_add(Widget_Data *wd, Elm_Gen_Item *it) { Item_Block *itb = NULL; if (!it->item->rel) { newblock: if (it->item->rel) { itb = calloc(1, sizeof(Item_Block)); if (!itb) return EINA_FALSE; itb->wd = wd; if (!it->item->rel->item->block) { wd->blocks = eina_inlist_append(wd->blocks, EINA_INLIST_GET(itb)); itb->items = eina_list_append(itb->items, it); } else { if (it->item->before) { wd->blocks = eina_inlist_prepend_relative (wd->blocks, EINA_INLIST_GET(itb), EINA_INLIST_GET(it->item->rel->item->block)); itb->items = eina_list_prepend_relative(itb->items, it, it->item->rel); } else { wd->blocks = eina_inlist_append_relative (wd->blocks, EINA_INLIST_GET(itb), EINA_INLIST_GET(it->item->rel->item->block)); itb->items = eina_list_append_relative(itb->items, it, it->item->rel); } } } else { if (it->item->before) { if (wd->blocks) { itb = (Item_Block *)(wd->blocks); if (itb->count >= wd->max_items_per_block) { itb = _item_block_new(wd, EINA_TRUE); if (!itb) return EINA_FALSE; } } else { itb = _item_block_new(wd, EINA_TRUE); if (!itb) return EINA_FALSE; } itb->items = eina_list_prepend(itb->items, it); } else { if (wd->blocks) { itb = (Item_Block *)(wd->blocks->last); if (itb->count >= wd->max_items_per_block) { itb = _item_block_new(wd, EINA_FALSE); if (!itb) return EINA_FALSE; } } else { itb = _item_block_new(wd, EINA_FALSE); if (!itb) return EINA_FALSE; } itb->items = eina_list_append(itb->items, it); } } } else { if (it->item->rel->item->queued) { /* NOTE: for a strange reason eina_list and eina_inlist don't have the same property on sorted insertion order, so the queue is not always ordered like the item list. This lead to issue where we depend on a item that is not yet created. As a quick work around, we reschedule the calc of the item and stop reordering the list to prevent any nasty issue to show up here. */ wd->queue = eina_list_append(wd->queue, it); wd->requeue = EINA_TRUE; it->item->queued = EINA_TRUE; return EINA_FALSE; } itb = it->item->rel->item->block; if (!itb) goto newblock; if (it->item->before) itb->items = eina_list_prepend_relative(itb->items, it, it->item->rel); else itb->items = eina_list_append_relative(itb->items, it, it->item->rel); } itb->count++; itb->changed = EINA_TRUE; it->item->block = itb; if (itb->wd->calc_job) ecore_job_del(itb->wd->calc_job); itb->wd->calc_job = ecore_job_add(_calc_job, itb->wd); if (it->item->rel) { it->item->rel->relcount--; if ((it->item->rel->generation < it->wd->generation) && (!it->item->rel->relcount)) _item_del(it->item->rel); it->item->rel = NULL; } if (itb->count > itb->wd->max_items_per_block) { Item_Block *itb2; Elm_Gen_Item *it2; int newc; Eina_Bool done = EINA_FALSE; newc = itb->count / 2; if (EINA_INLIST_GET(itb)->prev) { Item_Block *itbp = (Item_Block *)(EINA_INLIST_GET(itb)->prev); if (itbp->count + newc < wd->max_items_per_block / 2) { /* moving items to previous block */ while ((itb->count > newc) && (itb->items)) { it2 = eina_list_data_get(itb->items); itb->items = eina_list_remove_list(itb->items, itb->items); itb->count--; itbp->items = eina_list_append(itbp->items, it2); it2->item->block = itbp; itbp->count++; } done = EINA_TRUE; } } if (!done && EINA_INLIST_GET(itb)->next) { Item_Block *itbn = (Item_Block *)(EINA_INLIST_GET(itb)->next); if (itbn->count + newc < wd->max_items_per_block / 2) { /* moving items to next block */ while ((itb->count > newc) && (itb->items)) { Eina_List *l; l = eina_list_last(itb->items); it2 = eina_list_data_get(l); itb->items = eina_list_remove_list(itb->items, l); itb->count--; itbn->items = eina_list_prepend(itbn->items, it2); it2->item->block = itbn; itbn->count++; } done = EINA_TRUE; } } if (!done) { /* moving items to new block */ itb2 = calloc(1, sizeof(Item_Block)); if (!itb2) return EINA_FALSE; itb2->wd = wd; wd->blocks = eina_inlist_append_relative(wd->blocks, EINA_INLIST_GET(itb2), EINA_INLIST_GET(itb)); itb2->changed = EINA_TRUE; while ((itb->count > newc) && (itb->items)) { Eina_List *l; l = eina_list_last(itb->items); it2 = l->data; itb->items = eina_list_remove_list(itb->items, l); itb->count--; itb2->items = eina_list_prepend(itb2->items, it2); it2->item->block = itb2; itb2->count++; } } } return EINA_TRUE; } static int _queue_process(Widget_Data *wd) { int n; Eina_Bool showme = EINA_FALSE; double t0, t; t0 = ecore_loop_time_get(); //evas_event_freeze(evas_object_evas_get(wd->obj)); for (n = 0; (wd->queue) && (n < 128); n++) { Elm_Gen_Item *it; it = eina_list_data_get(wd->queue); wd->queue = eina_list_remove_list(wd->queue, wd->queue); it->item->queued = EINA_FALSE; if (!_item_block_add(wd, it)) continue; if (!wd->blocks) _item_block_realize(it->item->block); t = ecore_time_get(); if (it->item->block->changed) { showme = _item_block_recalc(it->item->block, it->item->block->num, EINA_TRUE); it->item->block->changed = 0; } if (showme) it->item->block->showme = EINA_TRUE; if (eina_inlist_count(wd->blocks) > 1) { if ((t - t0) > (ecore_animator_frametime_get())) break; } } //evas_event_thaw(evas_object_evas_get(wd->obj)); //evas_event_thaw_eval(evas_object_evas_get(wd->obj)); return n; } static Eina_Bool _idle_process(void *data, Eina_Bool *wakeup) { Widget_Data *wd = data; //xxx //static double q_start = 0.0; //if (q_start == 0.0) q_start = ecore_time_get(); //xxx if (_queue_process(wd) > 0) *wakeup = EINA_TRUE; if (!wd->queue) { //xxx //printf("PROCESS TIME: %3.3f\n", ecore_time_get() - q_start); //xxx return ECORE_CALLBACK_CANCEL; } return ECORE_CALLBACK_RENEW; } static Eina_Bool _item_idle_enterer(void *data) { Widget_Data *wd = data; Eina_Bool wakeup = EINA_FALSE; Eina_Bool ok = _idle_process(data, &wakeup); if (wakeup) { // wake up mainloop if (wd->calc_job) ecore_job_del(wd->calc_job); wd->calc_job = ecore_job_add(_calc_job, wd); } if (ok == ECORE_CALLBACK_CANCEL) wd->queue_idle_enterer = NULL; return ok; } static void _item_queue(Widget_Data *wd, Elm_Gen_Item *it, Eina_Compare_Cb cb) { if (it->item->queued) return; it->item->queued = EINA_TRUE; if (cb && !wd->requeue) wd->queue = eina_list_sorted_insert(wd->queue, cb, it); else wd->queue = eina_list_append(wd->queue, it); // FIXME: why does a freeze then thaw here cause some genlist // elm_genlist_item_append() to be much much slower? // evas_event_freeze(evas_object_evas_get(wd->obj)); while ((wd->queue) && ((!wd->blocks) || (!wd->blocks->next))) { if (wd->queue_idle_enterer) { ecore_idle_enterer_del(wd->queue_idle_enterer); wd->queue_idle_enterer = NULL; } _queue_process(wd); } // evas_event_thaw(evas_object_evas_get(wd->obj)); // evas_event_thaw_eval(evas_object_evas_get(wd->obj)); if (!wd->queue_idle_enterer) wd->queue_idle_enterer = ecore_idle_enterer_add(_item_idle_enterer, wd); } static int _elm_genlist_item_compare_data(const void *data, const void *data1) { const Elm_Gen_Item *it = data; const Elm_Gen_Item *item1 = data1; return _elm_genlist_item_compare_data_cb(it->base.data, item1->base.data); } static int _elm_genlist_item_compare(const void *data, const void *data1) { const Elm_Gen_Item *it, *item1; it = ELM_GEN_ITEM_FROM_INLIST(data); item1 = ELM_GEN_ITEM_FROM_INLIST(data1); return _elm_genlist_item_compare_cb(it, item1); } static int _elm_genlist_item_list_compare(const void *data, const void *data1) { const Elm_Gen_Item *it = data; const Elm_Gen_Item *item1 = data1; return _elm_genlist_item_compare_cb(it, item1); } static void _item_move_after(Elm_Gen_Item *it, Elm_Gen_Item *after) { if (!it) return; if (!after) return; it->wd->items = eina_inlist_remove(it->wd->items, EINA_INLIST_GET(it)); _item_block_del(it); it->wd->items = eina_inlist_append_relative(it->wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(after)); it->item->rel = after; it->item->rel->relcount++; it->item->before = EINA_FALSE; if (after->item->group_item) it->item->group_item = after->item->group_item; _item_queue(it->wd, it, NULL); evas_object_smart_callback_call(WIDGET(it), SIG_MOVED, it); } static void _item_move_before(Elm_Gen_Item *it, Elm_Gen_Item *before) { if (!it) return; if (!before) return; it->wd->items = eina_inlist_remove(it->wd->items, EINA_INLIST_GET(it)); _item_block_del(it); it->wd->items = eina_inlist_prepend_relative(it->wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(before)); it->item->rel = before; it->item->rel->relcount++; it->item->before = EINA_TRUE; if (before->item->group_item) it->item->group_item = before->item->group_item; _item_queue(it->wd, it, NULL); evas_object_smart_callback_call(WIDGET(it), SIG_MOVED, it); } EAPI Elm_Gen_Item * elm_genlist_item_append(Evas_Object *obj, const Elm_Genlist_Item_Class *itc, const void *data, Elm_Gen_Item *parent, Elm_Genlist_Item_Flags flags, Evas_Smart_Cb func, const void *func_data) { ELM_CHECK_WIDTYPE(obj, widtype) NULL; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return NULL; Elm_Gen_Item *it = _item_new(wd, itc, data, parent, flags, func, func_data); if (!it) return NULL; if (!it->parent) { if (it->group) wd->group_items = eina_list_append(wd->group_items, it); wd->items = eina_inlist_append(wd->items, EINA_INLIST_GET(it)); it->item->rel = NULL; } else { Elm_Gen_Item *it2 = NULL; Eina_List *ll = eina_list_last(it->parent->item->items); if (ll) it2 = ll->data; it->parent->item->items = eina_list_append(it->parent->item->items, it); if (!it2) it2 = it->parent; wd->items = eina_inlist_append_relative(wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(it2)); it->item->rel = it2; it->item->rel->relcount++; } it->item->before = EINA_FALSE; _item_queue(wd, it, NULL); return it; } EAPI Elm_Gen_Item * elm_genlist_item_prepend(Evas_Object *obj, const Elm_Genlist_Item_Class *itc, const void *data, Elm_Gen_Item *parent, Elm_Genlist_Item_Flags flags, Evas_Smart_Cb func, const void *func_data) { ELM_CHECK_WIDTYPE(obj, widtype) NULL; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return NULL; Elm_Gen_Item *it = _item_new(wd, itc, data, parent, flags, func, func_data); if (!it) return NULL; if (!it->parent) { if (it->group) wd->group_items = eina_list_prepend(wd->group_items, it); wd->items = eina_inlist_prepend(wd->items, EINA_INLIST_GET(it)); it->item->rel = NULL; } else { Elm_Gen_Item *it2 = NULL; Eina_List *ll = it->parent->item->items; if (ll) it2 = ll->data; it->parent->item->items = eina_list_prepend(it->parent->item->items, it); if (!it2) it2 = it->parent; wd->items = eina_inlist_prepend_relative(wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(it2)); it->item->rel = it2; it->item->rel->relcount++; } it->item->before = EINA_TRUE; _item_queue(wd, it, NULL); return it; } EAPI Elm_Gen_Item * elm_genlist_item_insert_after(Evas_Object *obj, const Elm_Genlist_Item_Class *itc, const void *data, Elm_Gen_Item *parent, Elm_Gen_Item *after, Elm_Genlist_Item_Flags flags, Evas_Smart_Cb func, const void *func_data) { ELM_CHECK_WIDTYPE(obj, widtype) NULL; EINA_SAFETY_ON_NULL_RETURN_VAL(after, NULL); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return NULL; /* It makes no sense to insert after in an empty list with after != NULL, something really bad is happening in your app. */ EINA_SAFETY_ON_NULL_RETURN_VAL(wd->items, NULL); Elm_Gen_Item *it = _item_new(wd, itc, data, parent, flags, func, func_data); if (!it) return NULL; if (!it->parent) { if ((it->group) && (after->group)) wd->group_items = eina_list_append_relative(wd->group_items, it, after); } else { it->parent->item->items = eina_list_append_relative(it->parent->item->items, it, after); } wd->items = eina_inlist_append_relative(wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(after)); it->item->rel = after; it->item->rel->relcount++; it->item->before = EINA_FALSE; _item_queue(wd, it, NULL); return it; } EAPI Elm_Gen_Item * elm_genlist_item_insert_before(Evas_Object *obj, const Elm_Genlist_Item_Class *itc, const void *data, Elm_Gen_Item *parent, Elm_Gen_Item *before, Elm_Genlist_Item_Flags flags, Evas_Smart_Cb func, const void *func_data) { ELM_CHECK_WIDTYPE(obj, widtype) NULL; EINA_SAFETY_ON_NULL_RETURN_VAL(before, NULL); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return NULL; /* It makes no sense to insert before in an empty list with before != NULL, something really bad is happening in your app. */ EINA_SAFETY_ON_NULL_RETURN_VAL(wd->items, NULL); Elm_Gen_Item *it = _item_new(wd, itc, data, parent, flags, func, func_data); if (!it) return NULL; if (!it->parent) { if (it->group && before->group) wd->group_items = eina_list_prepend_relative(wd->group_items, it, before); } else { it->parent->item->items = eina_list_prepend_relative(it->parent->item->items, it, before); } wd->items = eina_inlist_prepend_relative(wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(before)); it->item->rel = before; it->item->rel->relcount++; it->item->before = EINA_TRUE; _item_queue(wd, it, NULL); return it; } EAPI Elm_Gen_Item * elm_genlist_item_direct_sorted_insert(Evas_Object *obj, const Elm_Genlist_Item_Class *itc, const void *data, Elm_Gen_Item *parent, Elm_Genlist_Item_Flags flags, Eina_Compare_Cb comp, Evas_Smart_Cb func, const void *func_data) { ELM_CHECK_WIDTYPE(obj, widtype) NULL; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return NULL; Elm_Gen_Item *rel = NULL; Elm_Gen_Item *it = _item_new(wd, itc, data, parent, flags, func, func_data); if (!it) return NULL; _elm_genlist_item_compare_cb = comp; if (it->parent) { Eina_List *l; int cmp_result; l = eina_list_search_sorted_near_list(it->parent->item->items, _elm_genlist_item_list_compare, it, &cmp_result); if (l) rel = eina_list_data_get(l); else rel = it->parent; if (cmp_result >= 0) { it->parent->item->items = eina_list_prepend_relative_list(it->parent->item->items, it, l); wd->items = eina_inlist_prepend_relative(wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(rel)); it->item->before = EINA_FALSE; } else if (cmp_result < 0) { it->parent->item->items = eina_list_append_relative_list(it->parent->item->items, it, l); wd->items = eina_inlist_append_relative(wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(rel)); it->item->before = EINA_TRUE; } } else { if (!wd->state) { wd->state = eina_inlist_sorted_state_new(); eina_inlist_sorted_state_init(wd->state, wd->items); wd->requeue = EINA_FALSE; } if (it->group) wd->group_items = eina_list_append(wd->group_items, it); wd->items = eina_inlist_sorted_state_insert(wd->items, EINA_INLIST_GET(it), _elm_genlist_item_compare, wd->state); if (EINA_INLIST_GET(it)->next) { rel = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next); it->item->before = EINA_TRUE; } else if (EINA_INLIST_GET(it)->prev) { rel = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev); it->item->before = EINA_FALSE; } } if (rel) { it->item->rel = rel; it->item->rel->relcount++; } _item_queue(wd, it, _elm_genlist_item_list_compare); return it; } EAPI Elm_Gen_Item * elm_genlist_item_sorted_insert(Evas_Object *obj, const Elm_Genlist_Item_Class *itc, const void *data, Elm_Gen_Item *parent, Elm_Genlist_Item_Flags flags, Eina_Compare_Cb comp, Evas_Smart_Cb func, const void *func_data) { _elm_genlist_item_compare_data_cb = comp; return elm_genlist_item_direct_sorted_insert(obj, itc, data, parent, flags, _elm_genlist_item_compare_data, func, func_data); } static void _elm_genlist_clear(Evas_Object *obj, Eina_Bool standby) { Eina_Inlist *next, *l; ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; if (!standby) wd->generation++; if (wd->state) { eina_inlist_sorted_state_free(wd->state); wd->state = NULL; } if (wd->walking > 0) { wd->clear_me = 1; return; } evas_event_freeze(evas_object_evas_get(wd->obj)); for (l = wd->items, next = l ? l->next : NULL; l; l = next, next = next ? next->next : NULL) { Elm_Gen_Item *it = ELM_GEN_ITEM_FROM_INLIST(l); if (it->generation < wd->generation) { Elm_Gen_Item *itn = NULL; if (next) itn = ELM_GEN_ITEM_FROM_INLIST(next); if (itn) itn->walking++; /* prevent early death of subitem */ it->del_cb(it); if (itn) itn->walking--; } } wd->clear_me = 0; if (wd->calc_job) { ecore_job_del(wd->calc_job); wd->calc_job = NULL; } if (wd->selected) wd->selected = eina_list_free(wd->selected); if (wd->clear_cb) wd->clear_cb(wd); wd->pan_x = 0; wd->pan_y = 0; wd->minw = 0; wd->minh = 0; wd->count = 0; if (wd->pan_smart) { evas_object_size_hint_min_set(wd->pan_smart, wd->minw, wd->minh); evas_object_smart_callback_call(wd->pan_smart, "changed", NULL); } if (wd->sizing_cb) wd->sizing_cb(wd->obj); elm_smart_scroller_child_region_show(wd->scr, 0, 0, 0, 0); evas_event_thaw(evas_object_evas_get(wd->obj)); evas_event_thaw_eval(evas_object_evas_get(wd->obj)); } EAPI void elm_genlist_clear(Evas_Object *obj) { _elm_genlist_clear(obj, EINA_FALSE); } EAPI void elm_genlist_multi_select_set(Evas_Object *obj, Eina_Bool multi) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; wd->multi = multi; } EAPI Eina_Bool elm_genlist_multi_select_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return EINA_FALSE; return wd->multi; } EAPI Elm_Gen_Item * elm_genlist_selected_item_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) NULL; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return NULL; if (wd->selected) return wd->selected->data; return NULL; } EAPI const Eina_List * elm_genlist_selected_items_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) NULL; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return NULL; return wd->selected; } EAPI Eina_List * elm_genlist_realized_items_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) NULL; Widget_Data *wd = elm_widget_data_get(obj); Eina_List *list = NULL; Item_Block *itb; Eina_Bool done = EINA_FALSE; if (!wd) return NULL; EINA_INLIST_FOREACH(wd->blocks, itb) { if (itb->realized) { Eina_List *l; Elm_Gen_Item *it; done = 1; EINA_LIST_FOREACH(itb->items, l, it) { if (it->realized) list = eina_list_append(list, it); } } else { if (done) break; } } return list; } EAPI Elm_Gen_Item * elm_genlist_at_xy_item_get(const Evas_Object *obj, Evas_Coord x, Evas_Coord y, int *posret) { ELM_CHECK_WIDTYPE(obj, widtype) NULL; Widget_Data *wd = elm_widget_data_get(obj); Evas_Coord ox, oy, ow, oh; Item_Block *itb; Evas_Coord lasty; if (!wd) return NULL; evas_object_geometry_get(wd->pan_smart, &ox, &oy, &ow, &oh); lasty = oy; EINA_INLIST_FOREACH(wd->blocks, itb) { Eina_List *l; Elm_Gen_Item *it; if (!ELM_RECTS_INTERSECT(ox + itb->x - itb->wd->pan_x, oy + itb->y - itb->wd->pan_y, itb->w, itb->h, x, y, 1, 1)) continue; EINA_LIST_FOREACH(itb->items, l, it) { Evas_Coord itx, ity; itx = ox + itb->x + it->x - itb->wd->pan_x; ity = oy + itb->y + it->y - itb->wd->pan_y; if (ELM_RECTS_INTERSECT(itx, ity, it->item->w, it->item->h, x, y, 1, 1)) { if (posret) { if (y <= (ity + (it->item->h / 4))) *posret = -1; else if (y >= (ity + it->item->h - (it->item->h / 4))) *posret = 1; else *posret = 0; } return it; } lasty = ity + it->item->h; } } if (posret) { if (y > lasty) *posret = 1; else *posret = -1; } return NULL; } EAPI Elm_Gen_Item * elm_genlist_first_item_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) NULL; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return NULL; if (!wd->items) return NULL; Elm_Gen_Item *it = ELM_GEN_ITEM_FROM_INLIST(wd->items); while ((it) && (it->generation < wd->generation)) it = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next); return it; } EAPI Elm_Gen_Item * elm_genlist_last_item_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) NULL; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return NULL; if (!wd->items) return NULL; Elm_Gen_Item *it = ELM_GEN_ITEM_FROM_INLIST(wd->items->last); while ((it) && (it->generation < wd->generation)) it = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev); return it; } EAPI Elm_Gen_Item * elm_genlist_item_next_get(const Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL); while (it) { it = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next); if ((it) && (it->generation == it->wd->generation)) break; } return (Elm_Gen_Item *)it; } EAPI Elm_Gen_Item * elm_genlist_item_prev_get(const Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL); while (it) { it = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev); if ((it) && (it->generation == it->wd->generation)) break; } return (Elm_Gen_Item *)it; } EAPI Evas_Object * elm_genlist_item_genlist_get(const Elm_Gen_Item *it) { return _elm_genlist_item_widget_get(it); } EAPI Elm_Gen_Item * elm_genlist_item_parent_get(const Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL); return it->parent; } EAPI void elm_genlist_item_subitems_clear(Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); Eina_List *tl = NULL, *l; Elm_Gen_Item *it2; EINA_LIST_FOREACH(it->item->items, l, it2) tl = eina_list_append(tl, it2); EINA_LIST_FREE(tl, it2) elm_genlist_item_del(it2); } EAPI void elm_genlist_item_selected_set(Elm_Gen_Item *it, Eina_Bool selected) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); Widget_Data *wd = it->wd; if (!wd) return; if ((it->generation < wd->generation) || (it->disabled)) return; selected = !!selected; if (it->selected == selected) return; if (selected) { if (!wd->multi) { while (wd->selected) { if (it->unhighlight_cb) it->unhighlight_cb(wd->selected->data); it->unsel_cb(wd->selected->data); } } it->highlight_cb(it); _item_select(it); return; } if (it->unhighlight_cb) it->unhighlight_cb(it); it->unsel_cb(it); } EAPI Eina_Bool elm_genlist_item_selected_get(const Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE); return it->selected; } EAPI void elm_genlist_item_expanded_set(Elm_Gen_Item *it, Eina_Bool expanded) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); if (it->item->expanded == expanded) return; it->item->expanded = expanded; it->wd->expanded_item = it; if (it->item->expanded) { if (it->realized) edje_object_signal_emit(VIEW(it), "elm,state,expanded", "elm"); evas_object_smart_callback_call(WIDGET(it), SIG_EXPANDED, it); it->wd->auto_scroll_enabled = EINA_TRUE; } else { if (it->realized) edje_object_signal_emit(VIEW(it), "elm,state,contracted", "elm"); evas_object_smart_callback_call(WIDGET(it), SIG_CONTRACTED, it); it->wd->auto_scroll_enabled = EINA_FALSE; } } EAPI Eina_Bool elm_genlist_item_expanded_get(const Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE); return it->item->expanded; } EAPI int elm_genlist_item_expanded_depth_get(const Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, 0); return it->item->expanded_depth; } EAPI void elm_genlist_item_disabled_set(Elm_Gen_Item *it, Eina_Bool disabled) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); Eina_List *l; Evas_Object *obj; if (it->disabled == disabled) return; if (it->generation < it->wd->generation) return; it->disabled = !!disabled; if (it->selected) elm_genlist_item_selected_set(it, EINA_FALSE); if (it->realized) { if (it->disabled) edje_object_signal_emit(VIEW(it), "elm,state,disabled", "elm"); else edje_object_signal_emit(VIEW(it), "elm,state,enabled", "elm"); EINA_LIST_FOREACH(it->content_objs, l, obj) elm_widget_disabled_set(obj, disabled); } } EAPI Eina_Bool elm_genlist_item_disabled_get(const Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE); if (it->generation < it->wd->generation) return EINA_FALSE; return it->disabled; } EAPI void elm_genlist_item_display_only_set(Elm_Gen_Item *it, Eina_Bool display_only) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); if (it->display_only == display_only) return; if (it->generation < it->wd->generation) return; it->display_only = display_only; it->item->mincalcd = EINA_FALSE; it->item->updateme = EINA_TRUE; if (it->item->block) it->item->block->updateme = EINA_TRUE; if (it->wd->update_job) ecore_job_del(it->wd->update_job); it->wd->update_job = ecore_job_add(_update_job, it->wd); } EAPI Eina_Bool elm_genlist_item_display_only_get(const Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE); if (it->generation < it->wd->generation) return EINA_FALSE; return it->display_only; } EAPI void elm_genlist_item_show(Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); Evas_Coord gith = 0; if (it->generation < it->wd->generation) return; if ((it->item->queued) || (!it->item->mincalcd)) { it->wd->show_item = it; it->wd->bring_in = EINA_TRUE; it->item->showme = EINA_TRUE; return; } if (it->wd->show_item) { it->wd->show_item->item->showme = EINA_FALSE; it->wd->show_item = NULL; } if ((it->item->group_item) && (it->wd->pan_y > (it->y + it->item->block->y))) gith = it->item->group_item->item->h; elm_smart_scroller_child_region_show(it->wd->scr, it->x + it->item->block->x, it->y + it->item->block->y - gith, it->item->block->w, it->item->h); } EAPI void elm_genlist_item_promote(Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); if (it->generation < it->wd->generation) return; _item_move_before(it, elm_genlist_first_item_get(WIDGET(it))); } EAPI void elm_genlist_item_demote(Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); if (it->generation < it->wd->generation) return; _item_move_after(it, elm_genlist_last_item_get(WIDGET(it))); } EAPI void elm_genlist_item_bring_in(Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); Evas_Coord gith = 0; if (it->generation < it->wd->generation) return; if ((it->item->queued) || (!it->item->mincalcd)) { it->wd->show_item = it; it->wd->bring_in = EINA_TRUE; it->item->showme = EINA_TRUE; return; } if (it->wd->show_item) { it->wd->show_item->item->showme = EINA_FALSE; it->wd->show_item = NULL; } if ((it->item->group_item) && (it->wd->pan_y > (it->y + it->item->block->y))) gith = it->item->group_item->item->h; elm_smart_scroller_region_bring_in(it->wd->scr, it->x + it->item->block->x, it->y + it->item->block->y - gith, it->item->block->w, it->item->h); } EAPI void elm_genlist_item_top_show(Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); Evas_Coord ow, oh; Evas_Coord gith = 0; if (it->generation < it->wd->generation) return; if ((it->item->queued) || (!it->item->mincalcd)) { it->wd->show_item = it; it->wd->bring_in = EINA_TRUE; it->item->showme = EINA_TRUE; return; } if (it->wd->show_item) { it->wd->show_item->item->showme = EINA_FALSE; it->wd->show_item = NULL; } evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &ow, &oh); if (it->item->group_item) gith = it->item->group_item->item->h; elm_smart_scroller_child_region_show(it->wd->scr, it->x + it->item->block->x, it->y + it->item->block->y - gith, it->item->block->w, oh); } EAPI void elm_genlist_item_top_bring_in(Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); Evas_Coord ow, oh; Evas_Coord gith = 0; if (it->generation < it->wd->generation) return; if ((it->item->queued) || (!it->item->mincalcd)) { it->wd->show_item = it; it->wd->bring_in = EINA_TRUE; it->item->showme = EINA_TRUE; return; } if (it->wd->show_item) { it->wd->show_item->item->showme = EINA_FALSE; it->wd->show_item = NULL; } evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &ow, &oh); if (it->item->group_item) gith = it->item->group_item->item->h; elm_smart_scroller_region_bring_in(it->wd->scr, it->x + it->item->block->x, it->y + it->item->block->y - gith, it->item->block->w, oh); } EAPI void elm_genlist_item_middle_show(Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); Evas_Coord ow, oh; if (it->generation < it->wd->generation) return; if ((it->item->queued) || (!it->item->mincalcd)) { it->wd->show_item = it; it->wd->bring_in = EINA_TRUE; it->item->showme = EINA_TRUE; return; } if (it->wd->show_item) { it->wd->show_item->item->showme = EINA_FALSE; it->wd->show_item = NULL; } evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &ow, &oh); elm_smart_scroller_child_region_show(it->wd->scr, it->x + it->item->block->x, it->y + it->item->block->y - oh / 2 + it->item->h / 2, it->item->block->w, oh); } EAPI void elm_genlist_item_middle_bring_in(Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); Evas_Coord ow, oh; if (it->generation < it->wd->generation) return; if ((it->item->queued) || (!it->item->mincalcd)) { it->wd->show_item = it; it->wd->bring_in = EINA_TRUE; it->item->showme = EINA_TRUE; return; } if (it->wd->show_item) { it->wd->show_item->item->showme = EINA_FALSE; it->wd->show_item = NULL; } evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &ow, &oh); elm_smart_scroller_region_bring_in(it->wd->scr, it->x + it->item->block->x, it->y + it->item->block->y - oh / 2 + it->item->h / 2, it->item->block->w, oh); } EAPI void elm_genlist_item_del(Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); if ((it->relcount > 0) || (it->walking > 0)) { elm_genlist_item_subitems_clear(it); if (it->wd->show_item == it) it->wd->show_item = NULL; _elm_genlist_item_del_notserious(it); if (it->item->block) { if (it->realized) _elm_genlist_item_unrealize(it, EINA_FALSE); it->item->block->changed = EINA_TRUE; if (it->wd->calc_job) ecore_job_del(it->wd->calc_job); it->wd->calc_job = ecore_job_add(_calc_job, it->wd); } if (it->parent) { it->parent->item->items = eina_list_remove(it->parent->item->items, it); it->parent = NULL; } return; } _item_del(it); } EAPI void elm_genlist_item_data_set(Elm_Gen_Item *it, const void *data) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); elm_widget_item_data_set(it, data); } EAPI void * elm_genlist_item_data_get(const Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL); return elm_widget_item_data_get(it); } EAPI void elm_genlist_item_icons_orphan(Elm_Gen_Item *it) { elm_genlist_item_contents_orphan(it); } EAPI void elm_genlist_item_contents_orphan(Elm_Gen_Item *it) { Evas_Object *content; ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); EINA_LIST_FREE(it->content_objs, content) { elm_widget_sub_object_del(WIDGET(it), content); evas_object_smart_member_del(content); evas_object_hide(content); } } EAPI const Evas_Object * elm_genlist_item_object_get(const Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL); return VIEW(it); } EAPI void elm_genlist_item_update(Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); if (!it->item->block) return; if (it->generation < it->wd->generation) return; it->item->mincalcd = EINA_FALSE; it->item->updateme = EINA_TRUE; it->item->block->updateme = EINA_TRUE; if (it->wd->update_job) ecore_job_del(it->wd->update_job); it->wd->update_job = ecore_job_add(_update_job, it->wd); } EAPI void elm_genlist_item_fields_update(Elm_Genlist_Item *it, const char *parts, Elm_Genlist_Item_Field_Flags itf) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); if (!it->item->block) return; if (it->generation < it->wd->generation) return; if ((!itf) || (itf & ELM_GENLIST_ITEM_FIELD_LABEL)) _item_label_realize(it, it->base.view, &it->labels, parts); if ((!itf) || (itf & ELM_GENLIST_ITEM_FIELD_CONTENT)) { it->content_objs = _item_content_unrealize(it, it->base.view, &it->contents, parts); it->content_objs = _item_content_realize(it, it->base.view, &it->contents, parts); } if ((!itf) || (itf & ELM_GENLIST_ITEM_FIELD_STATE)) _item_state_realize(it, it->base.view, &it->states, parts); } EAPI void elm_genlist_item_item_class_update(Elm_Gen_Item *it, const Elm_Genlist_Item_Class *itc) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); if (!it->item->block) return; EINA_SAFETY_ON_NULL_RETURN(itc); if (it->generation < it->wd->generation) return; it->itc = itc; it->item->nocache = EINA_TRUE; elm_genlist_item_update(it); } EAPI const Elm_Genlist_Item_Class * elm_genlist_item_item_class_get(const Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL); if (it->generation < it->wd->generation) return NULL; return it->itc; } static Evas_Object * _elm_genlist_item_label_create(void *data, Evas_Object *obj __UNUSED__, Evas_Object *tooltip, void *it __UNUSED__) { Evas_Object *label = elm_label_add(tooltip); if (!label) return NULL; elm_object_style_set(label, "tooltip"); elm_object_text_set(label, data); return label; } static void _elm_genlist_item_label_del_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) { eina_stringshare_del(data); } EAPI void elm_genlist_item_tooltip_text_set(Elm_Gen_Item *it, const char *text) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); text = eina_stringshare_add(text); elm_genlist_item_tooltip_content_cb_set(it, _elm_genlist_item_label_create, text, _elm_genlist_item_label_del_cb); } EAPI void elm_genlist_item_tooltip_content_cb_set(Elm_Gen_Item *it, Elm_Tooltip_Item_Content_Cb func, const void *data, Evas_Smart_Cb del_cb) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_GOTO(it, error); if ((it->tooltip.content_cb == func) && (it->tooltip.data == data)) return; if (it->tooltip.del_cb) it->tooltip.del_cb((void *)it->tooltip.data, WIDGET(it), it); it->tooltip.content_cb = func; it->tooltip.data = data; it->tooltip.del_cb = del_cb; if (VIEW(it)) { elm_widget_item_tooltip_content_cb_set(it, it->tooltip.content_cb, it->tooltip.data, NULL); elm_widget_item_tooltip_style_set(it, it->tooltip.style); elm_widget_item_tooltip_window_mode_set(it, it->tooltip.free_size); } return; error: if (del_cb) del_cb((void *)data, NULL, NULL); } EAPI void elm_genlist_item_tooltip_unset(Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); if ((VIEW(it)) && (it->tooltip.content_cb)) elm_widget_item_tooltip_unset(it); if (it->tooltip.del_cb) it->tooltip.del_cb((void *)it->tooltip.data, WIDGET(it), it); it->tooltip.del_cb = NULL; it->tooltip.content_cb = NULL; it->tooltip.data = NULL; it->tooltip.free_size = EINA_FALSE; if (it->tooltip.style) elm_genlist_item_tooltip_style_set(it, NULL); } EAPI void elm_genlist_item_tooltip_style_set(Elm_Gen_Item *it, const char *style) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); eina_stringshare_replace(&it->tooltip.style, style); if (VIEW(it)) elm_widget_item_tooltip_style_set(it, style); } EAPI const char * elm_genlist_item_tooltip_style_get(const Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL); return it->tooltip.style; } EAPI Eina_Bool elm_genlist_item_tooltip_window_mode_set(Elm_Gen_Item *it, Eina_Bool disable) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE); it->tooltip.free_size = disable; if (VIEW(it)) return elm_widget_item_tooltip_window_mode_set(it, disable); return EINA_TRUE; } EAPI Eina_Bool elm_genlist_item_tooltip_window_mode_get(const Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE); return it->tooltip.free_size; } EAPI void elm_genlist_item_cursor_set(Elm_Gen_Item *it, const char *cursor) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); eina_stringshare_replace(&it->mouse_cursor, cursor); if (VIEW(it)) elm_widget_item_cursor_set(it, cursor); } EAPI const char * elm_genlist_item_cursor_get(const Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL); return elm_widget_item_cursor_get(it); } EAPI void elm_genlist_item_cursor_unset(Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); if (!it->mouse_cursor) return; if (VIEW(it)) elm_widget_item_cursor_unset(it); eina_stringshare_del(it->mouse_cursor); it->mouse_cursor = NULL; } EAPI void elm_genlist_item_cursor_style_set(Elm_Gen_Item *it, const char *style) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); elm_widget_item_cursor_style_set(it, style); } EAPI const char * elm_genlist_item_cursor_style_get(const Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL); return elm_widget_item_cursor_style_get(it); } EAPI void elm_genlist_item_cursor_engine_only_set(Elm_Gen_Item *it, Eina_Bool engine_only) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); elm_widget_item_cursor_engine_only_set(it, engine_only); } EAPI Eina_Bool elm_genlist_item_cursor_engine_only_get(const Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE); return elm_widget_item_cursor_engine_only_get(it); } EAPI void elm_genlist_horizontal_set(Evas_Object *obj, Elm_List_Mode mode) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; if (wd->mode == mode) return; wd->mode = mode; _sizing_eval(obj); } EAPI void elm_genlist_horizontal_mode_set(Evas_Object *obj, Elm_List_Mode mode) { elm_genlist_horizontal_set(obj, mode); } EAPI Elm_List_Mode elm_genlist_horizontal_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) ELM_LIST_LAST; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return ELM_LIST_LAST; return wd->mode; } EAPI Elm_List_Mode elm_genlist_horizontal_mode_get(const Evas_Object *obj) { return elm_genlist_horizontal_get(obj); } EAPI void elm_genlist_always_select_mode_set(Evas_Object *obj, Eina_Bool always_select) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; wd->always_select = always_select; } EAPI Eina_Bool elm_genlist_always_select_mode_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return EINA_FALSE; return wd->always_select; } EAPI void elm_genlist_no_select_mode_set(Evas_Object *obj, Eina_Bool no_select) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; wd->no_select = no_select; } EAPI Eina_Bool elm_genlist_no_select_mode_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return EINA_FALSE; return wd->no_select; } EAPI void elm_genlist_compress_mode_set(Evas_Object *obj, Eina_Bool compress) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; wd->compress = compress; if (!compress) elm_genlist_homogeneous_set(obj, EINA_FALSE); } EAPI Eina_Bool elm_genlist_compress_mode_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return EINA_FALSE; return wd->compress; } EAPI void elm_genlist_height_for_width_mode_set(Evas_Object *obj, Eina_Bool height_for_width) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; wd->height_for_width = !!height_for_width; if (wd->height_for_width) { elm_genlist_homogeneous_set(obj, EINA_FALSE); elm_genlist_compress_mode_set(obj, EINA_TRUE); } } EAPI Eina_Bool elm_genlist_height_for_width_mode_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return EINA_FALSE; return wd->height_for_width; } EAPI void elm_genlist_bounce_set(Evas_Object *obj, Eina_Bool h_bounce, Eina_Bool v_bounce) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce); wd->h_bounce = h_bounce; wd->v_bounce = v_bounce; } EAPI void elm_genlist_bounce_get(const Evas_Object *obj, Eina_Bool *h_bounce, Eina_Bool *v_bounce) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; if (h_bounce) *h_bounce = wd->h_bounce; if (v_bounce) *v_bounce = wd->v_bounce; } EAPI void elm_genlist_homogeneous_set(Evas_Object *obj, Eina_Bool homogeneous) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; if (homogeneous) elm_genlist_compress_mode_set(obj, EINA_TRUE); wd->homogeneous = homogeneous; } EAPI Eina_Bool elm_genlist_homogeneous_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return EINA_FALSE; return wd->homogeneous; } EAPI void elm_genlist_block_count_set(Evas_Object *obj, int n) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; wd->max_items_per_block = n; wd->item_cache_max = wd->max_items_per_block * 2; _item_cache_clean(wd); } EAPI int elm_genlist_block_count_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) 0; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return 0; return wd->max_items_per_block; } EAPI void elm_genlist_longpress_timeout_set(Evas_Object *obj, double timeout) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; wd->longpress_timeout = timeout; } EAPI double elm_genlist_longpress_timeout_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) 0; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return 0; return wd->longpress_timeout; } EAPI void elm_genlist_scroller_policy_set(Evas_Object *obj, Elm_Scroller_Policy policy_h, Elm_Scroller_Policy policy_v) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if ((!wd) || (!wd->scr)) return; if ((policy_h >= ELM_SCROLLER_POLICY_LAST) || (policy_v >= ELM_SCROLLER_POLICY_LAST)) return; elm_smart_scroller_policy_set(wd->scr, policy_h, policy_v); } EAPI void elm_genlist_scroller_policy_get(const Evas_Object *obj, Elm_Scroller_Policy *policy_h, Elm_Scroller_Policy *policy_v) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); Elm_Smart_Scroller_Policy s_policy_h, s_policy_v; if ((!wd) || (!wd->scr)) return; elm_smart_scroller_policy_get(wd->scr, &s_policy_h, &s_policy_v); if (policy_h) *policy_h = (Elm_Scroller_Policy)s_policy_h; if (policy_v) *policy_v = (Elm_Scroller_Policy)s_policy_v; } EAPI void elm_genlist_realized_items_update(Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype); Eina_List *list, *l; Elm_Gen_Item *it; list = elm_genlist_realized_items_get(obj); EINA_LIST_FOREACH(list, l, it) elm_genlist_item_update(it); } EAPI void elm_genlist_item_mode_set(Elm_Gen_Item *it, const char *mode_type, Eina_Bool mode_set) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it); Widget_Data *wd = it->wd; Eina_List *l; Elm_Gen_Item *it2; if (!wd) return; if (!mode_type) return; if ((it->generation < it->wd->generation) || (it->disabled)) return; if ((wd->mode_item == it) && (!strcmp(mode_type, wd->mode_type)) && (mode_set)) return; if (!wd->mode_item_style) return; it->mode_set = mode_set; if (wd->multi) { EINA_LIST_FOREACH(wd->selected, l, it2) if (it2->realized) elm_genlist_item_selected_set(it2, EINA_FALSE); } else { it2 = elm_genlist_selected_item_get(wd->obj); if ((it2) && (it2->realized)) elm_genlist_item_selected_set(it2, EINA_FALSE); } if (((wd->mode_type) && (strcmp(mode_type, wd->mode_type))) || (mode_set) || ((it == wd->mode_item) && (!mode_set))) _item_mode_unset(wd); eina_stringshare_replace(&wd->mode_type, mode_type); if (mode_set) _item_mode_set(it); } EAPI const char * elm_genlist_mode_item_style_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) NULL; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return NULL; return wd->mode_item_style; } EAPI void elm_genlist_mode_item_style_set(Evas_Object *obj, const char *style) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; if ((style == wd->mode_item_style) || (style && wd->mode_item_style && (!strcmp(style, wd->mode_item_style)))) return; eina_stringshare_replace(&wd->mode_item_style, style); elm_genlist_realized_items_update(obj); } EAPI const char * elm_genlist_mode_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) NULL; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return NULL; return wd->mode_type; } EAPI const Elm_Gen_Item * elm_genlist_mode_item_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) NULL; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return NULL; return wd->mode_item; } EAPI void elm_genlist_reorder_mode_set(Evas_Object *obj, Eina_Bool reorder_mode) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; wd->reorder_mode = reorder_mode; } EAPI Eina_Bool elm_genlist_reorder_mode_get(const Evas_Object *obj) { ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return EINA_FALSE; return wd->reorder_mode; } /* for gengrid as of now */ void _elm_genlist_page_relative_set(Evas_Object *obj, double h_pagerel, double v_pagerel) { Evas_Coord pagesize_h; Evas_Coord pagesize_v; ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; elm_smart_scroller_paging_get(wd->scr, NULL, NULL, &pagesize_h, &pagesize_v); elm_smart_scroller_paging_set(wd->scr, h_pagerel, v_pagerel, pagesize_h, pagesize_v); } /* for gengrid as of now */ void _elm_genlist_page_relative_get(const Evas_Object *obj, double *h_pagerel, double *v_pagerel) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; elm_smart_scroller_paging_get(wd->scr, h_pagerel, v_pagerel, NULL, NULL); } /* for gengrid as of now */ void _elm_genlist_page_size_set(Evas_Object *obj, Evas_Coord h_pagesize, Evas_Coord v_pagesize) { double pagerel_h; double pagerel_v; ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; elm_smart_scroller_paging_get(wd->scr, &pagerel_h, &pagerel_v, NULL, NULL); elm_smart_scroller_paging_set(wd->scr, pagerel_h, pagerel_v, h_pagesize, v_pagesize); } /* for gengrid as of now */ void _elm_genlist_current_page_get(const Evas_Object *obj, int *h_pagenumber, int *v_pagenumber) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; if (wd->scr) elm_smart_scroller_current_page_get(wd->scr, h_pagenumber, v_pagenumber); } /* for gengrid as of now */ void _elm_genlist_last_page_get(const Evas_Object *obj, int *h_pagenumber, int *v_pagenumber) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; if (wd->scr) elm_smart_scroller_last_page_get(wd->scr, h_pagenumber, v_pagenumber); } /* for gengrid as of now */ void _elm_genlist_page_show(const Evas_Object *obj, int h_pagenumber, int v_pagenumber) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; if (wd->scr) elm_smart_scroller_page_show(wd->scr, h_pagenumber, v_pagenumber); } /* for gengrid as of now */ void _elm_genlist_page_bring_in(const Evas_Object *obj, int h_pagenumber, int v_pagenumber) { ELM_CHECK_WIDTYPE(obj, widtype); Widget_Data *wd = elm_widget_data_get(obj); if (!wd) return; if (wd->scr) elm_smart_scroller_page_bring_in(wd->scr, h_pagenumber, v_pagenumber); } Evas_Object * _elm_genlist_item_widget_get(const Elm_Gen_Item *it) { ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL); return WIDGET(it); } void _elm_genlist_item_unrealize(Elm_Gen_Item *it, Eina_Bool calc) { Evas_Object *content; if (!it->realized) return; if (it->wd->reorder_it == it) return; evas_event_freeze(evas_object_evas_get(WIDGET(it))); if (!calc) evas_object_smart_callback_call(WIDGET(it), SIG_UNREALIZED, it); if (it->long_timer) { ecore_timer_del(it->long_timer); it->long_timer = NULL; } elm_widget_stringlist_free(it->labels); it->labels = NULL; elm_widget_stringlist_free(it->contents); it->contents = NULL; elm_widget_stringlist_free(it->states); it->states = NULL; EINA_LIST_FREE(it->content_objs, content) evas_object_del(content); it->unrealize_cb(it); it->realized = EINA_FALSE; it->want_unrealize = EINA_FALSE; evas_event_thaw(evas_object_evas_get(WIDGET(it))); evas_event_thaw_eval(evas_object_evas_get(WIDGET(it))); } void _elm_genlist_item_del_notserious(Elm_Gen_Item *it) { elm_widget_item_pre_notify_del(it); it->generation = it->wd->generation - 1; /* This means that the item is deleted */ if (it->selected) it->wd->selected = eina_list_remove(it->wd->selected, it); if (it->itc->func.del) it->itc->func.del((void *)it->base.data, WIDGET(it)); } void _elm_genlist_item_del_serious(Elm_Gen_Item *it) { _elm_genlist_item_del_notserious(it); it->wd->items = eina_inlist_remove(it->wd->items, EINA_INLIST_GET(it)); if (it->tooltip.del_cb) it->tooltip.del_cb((void *)it->tooltip.data, WIDGET(it), it); it->wd->walking -= it->walking; if (it->long_timer) ecore_timer_del(it->long_timer); if (it->group) it->wd->group_items = eina_list_remove(it->wd->group_items, it); if (it->wd->calc_job) ecore_job_del(it->wd->calc_job); it->wd->calc_job = ecore_job_add(it->wd->calc_cb, it->wd); free(it->item); it->item = NULL; elm_widget_item_del(it); }