1 #include <Elementary.h>
8 * A list is a very simple type of list widget. For more robust
9 * lists, @ref Genlist should probably be used.
12 typedef struct _Widget_Data Widget_Data;
16 Evas_Object *scr, *box, *self;
17 Eina_List *items, *selected, *to_delete;
19 Evas_Coord minw[2], minh[2];
21 Eina_Bool fix_pending : 1;
22 Eina_Bool on_hold : 1;
24 Eina_Bool always_select : 1;
25 Eina_Bool longpressed : 1;
26 Eina_Bool wasselected : 1;
32 Evas_Object *obj, *base;
34 Evas_Object *icon, *end;
38 Ecore_Timer *long_timer;
39 Eina_Bool deleted : 1;
41 Eina_Bool is_even : 1;
43 Eina_Bool selected : 1;
44 Eina_Bool hilighted : 1;
45 Eina_Bool dummy_icon : 1;
46 Eina_Bool dummy_end : 1;
49 static const char *widtype = NULL;
50 static void _del_hook(Evas_Object *obj);
51 static void _theme_hook(Evas_Object *obj);
52 static void _sizing_eval(Evas_Object *obj);
53 static void _on_focus_hook(void *data, Evas_Object *obj);
54 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
55 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
56 static void _fix_items(Evas_Object *obj);
57 static void _mouse_down(void *data, Evas *evas, Evas_Object *obj, void *event_info);
58 static void _mouse_up(void *data, Evas *evas, Evas_Object *obj, void *event_info);
59 static void _mouse_move(void *data, Evas *evas, Evas_Object *obj, void *event_info);
61 #define ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, ...) \
64 fprintf(stderr, "ERROR: %s:%d:%s() "#it" is NULL.\n", \
65 __FILE__, __LINE__, __FUNCTION__); \
68 else if (it->deleted) \
70 fprintf(stderr, "ERROR: %s:%d:%s() "#it" has been DELETED.\n", \
71 __FILE__, __LINE__, __FUNCTION__); \
78 _elm_list_item_call_del_cb(Elm_List_Item *it)
80 if (it->del_cb) it->del_cb((void *)it->data, it->obj, it);
84 _elm_list_item_free(Elm_List_Item *it)
86 evas_object_event_callback_del_full
87 (it->base, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, it);
88 evas_object_event_callback_del_full
89 (it->base, EVAS_CALLBACK_MOUSE_UP, _mouse_up, it);
90 evas_object_event_callback_del_full
91 (it->base, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move, it);
94 evas_object_event_callback_del_full
95 (it->icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
96 _changed_size_hints, it->obj);
99 evas_object_event_callback_del_full
100 (it->end, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
101 _changed_size_hints, it->obj);
103 eina_stringshare_del(it->label);
105 if (it->long_timer) ecore_timer_del(it->long_timer);
106 if (it->icon) evas_object_del(it->icon);
107 if (it->end) evas_object_del(it->end);
108 if (it->base) evas_object_del(it->base);
113 _elm_list_process_deletions(Widget_Data *wd)
117 wd->walking++; // avoid nested deletion and also _sub_del() fix_items
119 EINA_LIST_FREE(wd->to_delete, it)
121 _elm_list_item_call_del_cb(it);
123 wd->items = eina_list_remove_list(wd->items, it->node);
124 _elm_list_item_free(it);
131 _elm_list_walk(Widget_Data *wd)
135 fprintf(stderr, "ERROR: walking was negative. fixed!\n");
142 _elm_list_unwalk(Widget_Data *wd)
147 fprintf(stderr, "ERROR: walking became negative. fixed!\n");
155 _elm_list_process_deletions(wd);
159 wd->fix_pending = EINA_FALSE;
160 _fix_items(wd->self);
161 _sizing_eval(wd->self);
166 _del_hook(Evas_Object *obj)
168 Widget_Data *wd = elm_widget_data_get(obj);
173 if (wd->walking != 0)
174 fprintf(stderr, "ERROR: list deleted while walking.\n");
177 EINA_LIST_FOREACH(wd->items, n, it) _elm_list_item_call_del_cb(it);
178 _elm_list_unwalk(wd);
179 if (wd->to_delete) fprintf(stderr, "ERROR: leaking nodes!\n");
181 EINA_LIST_FREE(wd->items, it) _elm_list_item_free(it);
182 eina_list_free(wd->selected);
187 _sizing_eval(Evas_Object *obj)
189 Widget_Data *wd = elm_widget_data_get(obj);
190 Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
194 evas_object_size_hint_min_get(wd->scr, &minw, &minh);
195 evas_object_size_hint_max_get(wd->scr, &maxw, &maxh);
196 evas_object_size_hint_min_set(obj, minw, minh);
197 evas_object_size_hint_max_set(obj, maxw, maxh);
202 _theme_hook(Evas_Object *obj)
204 Widget_Data *wd = elm_widget_data_get(obj);
211 elm_scroller_custom_widget_base_theme_set(wd->scr, "list", "base");
212 elm_object_style_set(wd->scr, elm_widget_style_get(obj));
213 // edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale);
215 EINA_LIST_FOREACH(wd->items, n, it)
224 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
226 Widget_Data *wd = elm_widget_data_get(obj);
228 if (elm_widget_focus_get(obj))
229 evas_object_focus_set(wd->scr, 1);
231 evas_object_focus_set(wd->scr, 0);
235 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
237 Widget_Data *wd = elm_widget_data_get(data);
240 // _sizing_eval(data);
244 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
246 Widget_Data *wd = elm_widget_data_get(obj);
247 Evas_Object *sub = event_info;
252 if (sub == NULL) abort();
257 EINA_LIST_FOREACH(wd->items, l, it)
259 if ((sub == it->icon) || (sub == it->end))
261 if (it->icon == sub) it->icon = NULL;
262 if (it->end == sub) it->end = NULL;
263 evas_object_event_callback_del_full
264 (sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints,
272 wd->fix_pending = EINA_TRUE;
280 _item_hilight(Elm_List_Item *it)
282 Widget_Data *wd = elm_widget_data_get(it->obj);
283 const char *selectraise;
286 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
287 if (it->hilighted) return;
290 edje_object_signal_emit(it->base, "elm,state,selected", "elm");
291 selectraise = edje_object_data_get(it->base, "selectraise");
292 if ((selectraise) && (!strcmp(selectraise, "on")))
293 evas_object_raise(it->base);
294 it->hilighted = EINA_TRUE;
296 _elm_list_unwalk(wd);
300 _item_select(Elm_List_Item *it)
302 Widget_Data *wd = elm_widget_data_get(it->obj);
305 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
308 if (wd->always_select) goto call;
311 it->selected = EINA_TRUE;
312 wd->selected = eina_list_append(wd->selected, it);
316 if (it->func) it->func((void *)it->data, it->obj, it);
317 evas_object_smart_callback_call(it->obj, "selected", it);
319 _elm_list_unwalk(wd);
323 _item_unselect(Elm_List_Item *it)
325 Widget_Data *wd = elm_widget_data_get(it->obj);
326 const char *stacking, *selectraise;
329 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
330 if (!it->hilighted) return;
333 edje_object_signal_emit(it->base, "elm,state,unselected", "elm");
334 stacking = edje_object_data_get(it->base, "stacking");
335 selectraise = edje_object_data_get(it->base, "selectraise");
336 if ((selectraise) && (!strcmp(selectraise, "on")))
338 if ((stacking) && (!strcmp(stacking, "below")))
339 evas_object_lower(it->base);
341 it->hilighted = EINA_FALSE;
344 it->selected = EINA_FALSE;
345 wd->selected = eina_list_remove(wd->selected, it);
346 evas_object_smart_callback_call(it->obj, "unselected", it);
349 _elm_list_unwalk(wd);
353 _mouse_move(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
355 Elm_List_Item *it = data;
356 Widget_Data *wd = elm_widget_data_get(it->obj);
357 Evas_Event_Mouse_Move *ev = event_info;
360 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
361 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
365 wd->on_hold = EINA_TRUE;
368 ecore_timer_del(it->long_timer);
369 it->long_timer = NULL;
377 _long_press(void *data)
379 Elm_List_Item *it = data;
380 Widget_Data *wd = elm_widget_data_get(it->obj);
383 it->long_timer = NULL;
384 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, 0);
385 wd->longpressed = EINA_TRUE;
386 evas_object_smart_callback_call(it->obj, "longpressed", it);
391 _mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
393 Elm_List_Item *it = data;
394 Widget_Data *wd = elm_widget_data_get(it->obj);
395 Evas_Event_Mouse_Down *ev = event_info;
398 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
399 if (ev->button != 1) return;
400 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
401 else wd->on_hold = EINA_FALSE;
402 wd->wasselected = it->selected;
404 wd->longpressed = EINA_FALSE;
405 if (it->long_timer) ecore_timer_del(it->long_timer);
406 it->long_timer = ecore_timer_add(1.0, _long_press, it);
407 /* Always call the callbacks last - the user may delete our context! */
408 if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
409 evas_object_smart_callback_call(it->obj, "clicked", it);
413 _mouse_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
415 Elm_List_Item *it = data;
416 Widget_Data *wd = elm_widget_data_get(it->obj);
417 Evas_Event_Mouse_Up *ev = event_info;
420 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
421 if (ev->button != 1) return;
422 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
423 else wd->on_hold = EINA_FALSE;
424 wd->longpressed = EINA_FALSE;
427 ecore_timer_del(it->long_timer);
428 it->long_timer = NULL;
432 wd->on_hold = EINA_FALSE;
437 if (!wd->wasselected) _item_unselect(it);
442 _elm_list_walk(wd); // watch out "return" before unwalk!
451 else _item_unselect(it);
458 _item_unselect(wd->selected->data);
464 const Eina_List *l, *l_next;
467 EINA_LIST_FOREACH_SAFE(wd->selected, l, l_next, it2)
468 if (it2 != it) _item_unselect(it2);
474 _elm_list_unwalk(wd);
477 static Elm_List_Item *
478 _item_new(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
480 Widget_Data *wd = elm_widget_data_get(obj);
483 if (!wd) return NULL;
484 it = calloc(1, sizeof(Elm_List_Item));
486 it->label = eina_stringshare_add(label);
491 it->base = edje_object_add(evas_object_evas_get(obj));
492 evas_object_event_callback_add(it->base, EVAS_CALLBACK_MOUSE_DOWN,
494 evas_object_event_callback_add(it->base, EVAS_CALLBACK_MOUSE_UP,
496 evas_object_event_callback_add(it->base, EVAS_CALLBACK_MOUSE_MOVE,
498 evas_object_size_hint_weight_set(it->base, 1.0, 1.0);
499 evas_object_size_hint_align_set(it->base, -1.0, -1.0);
502 elm_widget_sub_object_add(obj, it->icon);
503 evas_object_event_callback_add(it->icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
504 _changed_size_hints, obj);
508 elm_widget_sub_object_add(obj, it->end);
509 evas_object_event_callback_add(it->end, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
510 _changed_size_hints, obj);
516 _fix_items(Evas_Object *obj)
518 Widget_Data *wd = elm_widget_data_get(obj);
521 Evas_Coord minw[2] = { 0, 0 }, minh[2] = { 0, 0 };
524 const char *style = elm_widget_style_get(obj);
529 wd->fix_pending = EINA_TRUE;
533 _elm_list_walk(wd); // watch out "return" before unwalk!
535 EINA_LIST_FOREACH(wd->items, l, it)
537 if (it->deleted) continue;
540 evas_object_size_hint_min_get(it->icon, &mw, &mh);
541 if (mw > minw[0]) minw[0] = mw;
542 if (mh > minh[0]) minh[0] = mh;
546 evas_object_size_hint_min_get(it->end, &mw, &mh);
547 if (mw > minw[1]) minw[1] = mw;
548 if (mh > minh[1]) minh[1] = mh;
551 if ((minw[0] != wd->minw[0]) || (minw[1] != wd->minw[1]) ||
552 (minw[0] != wd->minh[0]) || (minh[1] != wd->minh[1]))
554 wd->minw[0] = minw[0];
555 wd->minw[1] = minw[1];
556 wd->minh[0] = minh[0];
557 wd->minh[1] = minh[1];
561 EINA_LIST_FOREACH(wd->items, l, it)
563 if (it->deleted) continue;
565 if ((it->even != it->is_even) || (!it->fixed) || (redo))
567 const char *stacking;
569 if (wd->mode == ELM_LIST_COMPRESS)
572 _elm_theme_object_set(obj, it->base, "list", "item_compress", style);
574 _elm_theme_object_set(obj, it->base, "list", "item_compress_odd", style);
579 _elm_theme_object_set(obj, it->base, "list", "item", style);
581 _elm_theme_object_set(obj, it->base, "list", "item_odd", style);
583 stacking = edje_object_data_get(it->base, "stacking");
586 if (!strcmp(stacking, "below"))
587 evas_object_lower(it->base);
588 else if (!strcmp(stacking, "above"))
589 evas_object_raise(it->base);
591 edje_object_part_text_set(it->base, "elm.text", it->label);
592 if ((!it->icon) && (minh[0] > 0))
594 it->icon = evas_object_rectangle_add(evas_object_evas_get(it->base));
595 evas_object_color_set(it->icon, 0, 0, 0, 0);
596 it->dummy_icon = EINA_TRUE;
598 if ((!it->end) && (minh[1] > 0))
600 it->end = evas_object_rectangle_add(evas_object_evas_get(it->base));
601 evas_object_color_set(it->end, 0, 0, 0, 0);
602 it->dummy_end = EINA_TRUE;
606 evas_object_size_hint_min_set(it->icon, minw[0], minh[0]);
607 evas_object_size_hint_max_set(it->icon, 99999, 99999);
608 edje_object_part_swallow(it->base, "elm.swallow.icon", it->icon);
612 evas_object_size_hint_min_set(it->end, minw[1], minh[1]);
613 evas_object_size_hint_max_set(it->end, 99999, 99999);
614 edje_object_part_swallow(it->base, "elm.swallow.end", it->end);
618 // this may call up user and it may modify the list item
619 // but we're safe as we're flagged as walking.
620 // just don't process further
621 edje_object_message_signal_process(it->base);
625 elm_coords_finger_size_adjust(1, &mw, 1, &mh);
626 edje_object_size_min_restricted_calc(it->base, &mw, &mh, mw, mh);
627 elm_coords_finger_size_adjust(1, &mw, 1, &mh);
628 evas_object_size_hint_min_set(it->base, mw, mh);
629 evas_object_show(it->base);
631 if ((it->selected) || (it->hilighted))
633 const char *selectraise;
635 // this may call up user and it may modify the list item
636 // but we're safe as we're flagged as walking.
637 // just don't process further
638 edje_object_signal_emit(it->base, "elm,state,selected", "elm");
642 selectraise = edje_object_data_get(it->base, "selectraise");
643 if ((selectraise) && (!strcmp(selectraise, "on")))
644 evas_object_raise(it->base);
645 stacking = edje_object_data_get(it->base, "stacking");
647 it->fixed = EINA_TRUE;
648 it->is_even = it->even;
653 _elm_list_unwalk(wd);
656 evas_object_size_hint_min_get(wd->box, &mw, &mh);
659 if (wd->mode == ELM_LIST_LIMIT)
660 elm_scroller_content_min_limit(wd->scr, 1, 0);
662 elm_scroller_content_min_limit(wd->scr, 0, 0);
668 _hold_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
670 Widget_Data *wd = elm_widget_data_get(obj);
673 elm_widget_scroll_hold_push(wd->scr);
677 _hold_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
679 Widget_Data *wd = elm_widget_data_get(obj);
682 elm_widget_scroll_hold_pop(wd->scr);
686 _freeze_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
688 Widget_Data *wd = elm_widget_data_get(obj);
691 elm_widget_scroll_hold_push(wd->scr);
695 _freeze_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
697 Widget_Data *wd = elm_widget_data_get(obj);
700 elm_widget_scroll_hold_pop(wd->scr);
704 * Adds a list object.
706 * @param parent The parent object
707 * @return The created object or NULL upon failure
712 elm_list_add(Evas_Object *parent)
718 wd = ELM_NEW(Widget_Data);
719 e = evas_object_evas_get(parent);
720 wd->self = obj = elm_widget_add(e);
721 ELM_SET_WIDTYPE(widtype, "list");
722 elm_widget_type_set(obj, "list");
723 elm_widget_sub_object_add(parent, obj);
724 elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
725 elm_widget_data_set(obj, wd);
726 elm_widget_del_hook_set(obj, _del_hook);
727 elm_widget_theme_hook_set(obj, _theme_hook);
728 elm_widget_can_focus_set(obj, 1);
730 wd->scr = elm_scroller_add(parent);
731 elm_scroller_custom_widget_base_theme_set(wd->scr, "list", "base");
732 elm_widget_resize_object_set(obj, wd->scr);
734 elm_scroller_bounce_set(wd->scr, 0, 1);
736 wd->box = elm_box_add(parent);
737 elm_box_homogenous_set(wd->box, 1);
738 evas_object_size_hint_weight_set(wd->box, 1.0, 0.0);
739 evas_object_size_hint_align_set(wd->box, -1.0, 0.0);
740 elm_scroller_content_set(wd->scr, wd->box);
741 evas_object_show(wd->box);
743 wd->mode = ELM_LIST_SCROLL;
745 evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
746 evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
747 evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
748 evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
749 evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
756 * Appends an item to the list object.
758 * @param obj The list object
759 * @param label The label of the list item
760 * @param icon The icon object to use for the left side of the item
761 * @param end The icon object to use for the right side of the item
762 * @param func The function to call when the item is clicked
763 * @param data The data to associate with the item for related callbacks
765 * @return The created item or NULL upon failure
770 elm_list_item_append(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
772 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
773 Widget_Data *wd = elm_widget_data_get(obj);
774 Elm_List_Item *it = _item_new(obj, label, icon, end, func, data);
776 wd->items = eina_list_append(wd->items, it);
777 it->node = eina_list_last(wd->items);
778 elm_box_pack_end(wd->box, it->base);
783 * Prepends an item to the list object.
785 * @param obj The list object
786 * @param label The label of the list item
787 * @param icon The icon object to use for the left side of the item
788 * @param end The icon object to use for the right side of the item
789 * @param func The function to call when the item is clicked
790 * @param data The data to associate with the item for related callbacks
792 * @return The created item or NULL upon failure
797 elm_list_item_prepend(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
799 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
800 Widget_Data *wd = elm_widget_data_get(obj);
801 Elm_List_Item *it = _item_new(obj, label, icon, end, func, data);
803 wd->items = eina_list_prepend(wd->items, it);
804 it->node = wd->items;
805 elm_box_pack_start(wd->box, it->base);
810 * Inserts an item into the list object before @p before.
812 * @param obj The list object
813 * @param before The list item to insert before
814 * @param label The label of the list item
815 * @param icon The icon object to use for the left side of the item
816 * @param end The icon object to use for the right side of the item
817 * @param func The function to call when the item is clicked
818 * @param data The data to associate with the item for related callbacks
820 * @return The created item or NULL upon failure
825 elm_list_item_insert_before(Evas_Object *obj, Elm_List_Item *before, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
830 if ((!before) || (!before->node)) return NULL;
831 ELM_LIST_ITEM_CHECK_DELETED_RETURN(before, NULL);
833 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
834 wd = elm_widget_data_get(obj);
835 if (!wd) return NULL;
836 it = _item_new(obj, label, icon, end, func, data);
837 wd->items = eina_list_prepend_relative_list(wd->items, it, before->node);
838 it->node = before->node->prev;
839 elm_box_pack_before(wd->box, it->base, before->base);
844 * Inserts an item into the list object after @p after.
846 * @param obj The list object
847 * @param after The list item to insert after
848 * @param label The label of the list item
849 * @param icon The icon object to use for the left side of the item
850 * @param end The icon object to use for the right side of the item
851 * @param func The function to call when the item is clicked
852 * @param data The data to associate with the item for related callbacks
854 * @return The created item or NULL upon failure
859 elm_list_item_insert_after(Evas_Object *obj, Elm_List_Item *after, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
864 if ((!after) || (!after->node)) return NULL;
865 ELM_LIST_ITEM_CHECK_DELETED_RETURN(after, NULL);
867 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
868 wd = elm_widget_data_get(obj);
869 if (!wd) return NULL;
870 it = _item_new(obj, label, icon, end, func, data);
871 wd->items = eina_list_append_relative_list(wd->items, it, after->node);
872 it->node = after->node->next;
873 elm_box_pack_after(wd->box, it->base, after->base);
878 * Insert a new item into the sorted list object.
880 * @param obj The list object
881 * @param label The label of the list item
882 * @param icon The icon object to use for the left side of the item
883 * @param end The icon object to use for the right side of the item
884 * @param func The function to call when the item is clicked
885 * @param data The data to associate with the item for related callbacks
886 * @param cmp_func The function called for the sort.
888 * @return The created item or NULL upon failure
893 elm_list_item_sorted_insert(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data, Eina_Compare_Cb cmp_func)
895 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
896 Widget_Data *wd = elm_widget_data_get(obj);
897 Elm_List_Item *it = _item_new(obj, label, icon, end, func, data);
900 wd->items = eina_list_sorted_insert(wd->items, cmp_func, it);
901 l = eina_list_data_find_list(wd->items, it);
902 l = eina_list_next(l);
905 it->node = eina_list_last(wd->items);
906 elm_box_pack_end(wd->box, it->base);
910 Elm_List_Item *before = eina_list_data_get(l);
911 it->node = before->node->prev;
912 elm_box_pack_before(wd->box, it->base, before->base);
918 * Clears a list of all items.
920 * @param obj The list object
925 elm_list_clear(Evas_Object *obj)
927 ELM_CHECK_WIDTYPE(obj, widtype);
928 Widget_Data *wd = elm_widget_data_get(obj);
932 if (!wd->items) return;
934 eina_list_free(wd->selected);
941 EINA_LIST_FOREACH(wd->items, n, it)
943 if (it->deleted) continue;
944 it->deleted = EINA_TRUE;
945 wd->to_delete = eina_list_append(wd->to_delete, it);
952 EINA_LIST_FREE(wd->items, it)
954 _elm_list_item_call_del_cb(it);
955 _elm_list_item_free(it);
958 _elm_list_unwalk(wd);
965 * Starts the list. Call before running show() on the list object.
967 * @param obj The list object
972 elm_list_go(Evas_Object *obj)
974 ELM_CHECK_WIDTYPE(obj, widtype);
975 Widget_Data *wd = elm_widget_data_get(obj);
981 * Enables/disables the state of multi-select on the list object.
983 * @param obj The list object
984 * @param multi If true, multi-select is enabled
989 elm_list_multi_select_set(Evas_Object *obj, Eina_Bool multi)
991 ELM_CHECK_WIDTYPE(obj, widtype);
992 Widget_Data *wd = elm_widget_data_get(obj);
998 * Gets the state of multi-select on the list object.
1000 * @param obj The list object
1001 * @return If true, multi-select is enabled
1006 elm_list_multi_select_get(const Evas_Object *obj)
1008 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1009 Widget_Data *wd = elm_widget_data_get(obj);
1010 if (!wd) return EINA_FALSE;
1015 * Enables/disables horizontal mode of the list
1017 * @param obj The list object
1018 * @param mode If true, horizontale mode is enabled
1023 elm_list_horizontal_mode_set(Evas_Object *obj, Elm_List_Mode mode)
1025 ELM_CHECK_WIDTYPE(obj, widtype);
1026 Widget_Data *wd = elm_widget_data_get(obj);
1028 if (wd->mode == mode) return;
1032 if (wd->mode == ELM_LIST_LIMIT)
1033 elm_scroller_content_min_limit(wd->scr, 1, 0);
1035 elm_scroller_content_min_limit(wd->scr, 0, 0);
1040 * Gets the state of horizontal mode of the list
1042 * @param obj The list object
1043 * @return If true, horizontale mode is enabled
1048 elm_list_horizontal_mode_get(const Evas_Object *obj)
1050 ELM_CHECK_WIDTYPE(obj, widtype) ELM_LIST_SCROLL;
1051 Widget_Data *wd = elm_widget_data_get(obj);
1052 if (!wd) return ELM_LIST_SCROLL;
1057 * Enables/disables the state of always_select, meaning that
1058 * an item will always be selected.
1060 * @param obj The list object
1061 * @param always_select If true, always_select is enabled
1066 elm_list_always_select_mode_set(Evas_Object *obj, Eina_Bool always_select)
1068 ELM_CHECK_WIDTYPE(obj, widtype);
1069 Widget_Data *wd = elm_widget_data_get(obj);
1071 wd->always_select = always_select;
1075 * Gets the state of always_select.
1076 * See also elm_list_always_select_mode_set()
1078 * @param obj The list object
1079 * @return If true, always_select is enabled
1084 elm_list_always_select_mode_get(const Evas_Object *obj)
1086 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1087 Widget_Data *wd = elm_widget_data_get(obj);
1088 if (!wd) return EINA_FALSE;
1089 return wd->always_select;
1093 * Returns a list of all the list items.
1095 * @param obj The list object
1096 * @return An Eina_List* of the list items, or NULL on failure
1100 EAPI const Eina_List *
1101 elm_list_items_get(const Evas_Object *obj)
1103 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1104 Widget_Data *wd = elm_widget_data_get(obj);
1105 if (!wd) return NULL;
1110 * Returns the currently selected list item.
1112 * @param obj The list object
1113 * @return The selected list item, or NULL on failure
1117 EAPI Elm_List_Item *
1118 elm_list_selected_item_get(const Evas_Object *obj)
1120 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1121 Widget_Data *wd = elm_widget_data_get(obj);
1122 if (!wd) return NULL;
1123 if (wd->selected) return wd->selected->data;
1128 * Returns a list of the currently selected list items.
1130 * @param obj The list object
1131 * @return An Eina_List* of the selected list items, or NULL on failure
1135 EAPI const Eina_List *
1136 elm_list_selected_items_get(const Evas_Object *obj)
1138 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1139 Widget_Data *wd = elm_widget_data_get(obj);
1140 if (!wd) return NULL;
1141 return wd->selected;
1145 * Sets the selected state of @p it.
1147 * @param it The list item
1148 * @param selected Enables/disables the selected state
1153 elm_list_item_selected_set(Elm_List_Item *it, Eina_Bool selected)
1155 Widget_Data *wd = elm_widget_data_get(it->obj);
1157 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1158 selected = !!selected;
1159 if (it->selected == selected) return;
1167 while (wd->selected)
1168 _item_unselect(wd->selected->data);
1176 _elm_list_unwalk(wd);
1180 * Gets the selected state of @p it.
1182 * @param it The list item
1183 * @return If true, the item is selected
1188 elm_list_item_selected_get(Elm_List_Item *it)
1190 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, EINA_FALSE);
1191 return it->selected;
1195 * Brings @p it to the center of the list view.
1197 * @param it The list item
1202 elm_list_item_show(Elm_List_Item *it)
1204 Widget_Data *wd = elm_widget_data_get(it->obj);
1205 Evas_Coord bx, by, bw, bh;
1206 Evas_Coord x, y, w, h;
1208 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1209 evas_object_geometry_get(wd->box, &bx, &by, &bw, &bh);
1210 evas_object_geometry_get(it->base, &x, &y, &w, &h);
1214 elm_scroller_region_show(wd->scr, x, y, w, h);
1218 * Deletes item @p it from the list.
1220 * @param it The list item to delete
1225 elm_list_item_del(Elm_List_Item *it)
1227 Widget_Data *wd = elm_widget_data_get(it->obj);
1229 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1231 if (it->selected) _item_unselect(it);
1233 if (wd->walking > 0)
1235 if (it->deleted) return;
1236 it->deleted = EINA_TRUE;
1237 wd->to_delete = eina_list_append(wd->to_delete, it);
1241 wd->items = eina_list_remove_list(wd->items, it->node);
1245 _elm_list_item_call_del_cb(it);
1246 _elm_list_item_free(it);
1248 _elm_list_unwalk(wd);
1252 * Set the function called when a list item is freed.
1254 * @param it The item to set the callback on
1255 * @param func The function called
1260 elm_list_item_del_cb_set(Elm_List_Item *it, Evas_Smart_Cb func)
1262 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1267 * Returns the data associated with the item.
1269 * @param it The list item
1270 * @return The data associated with @p it
1275 elm_list_item_data_get(const Elm_List_Item *it)
1277 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1278 return (void *)it->data;
1282 * Returns the left side icon associated with the item.
1284 * @param it The list item
1285 * @return The left side icon associated with @p it
1290 elm_list_item_icon_get(const Elm_List_Item *it)
1292 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1293 if (it->dummy_icon) return NULL;
1298 * Sets the left side icon associated with the item.
1300 * @param it The list item
1301 * @param icon The left side icon object to associate with @p it
1306 elm_list_item_icon_set(Elm_List_Item *it, Evas_Object *icon)
1308 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1309 if (it->icon == icon) return;
1310 if (it->dummy_icon && !icon) return;
1311 if (it->dummy_icon) evas_object_del(it->icon);
1314 icon = evas_object_rectangle_add(evas_object_evas_get(it->obj));
1315 evas_object_color_set(icon, 0, 0, 0, 0);
1316 it->dummy_icon = EINA_TRUE;
1320 edje_object_part_swallow(it->base, "elm.swallow.icon", icon);
1324 * Gets the right side icon associated with the item.
1326 * @param it The list item
1327 * @return The right side icon object associated with @p it
1332 elm_list_item_end_get(const Elm_List_Item *it)
1334 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1335 if (it->dummy_end) return NULL;
1340 * Gets the right side icon associated with the item.
1342 * @param it The list item
1343 * @param icon The right side icon object to associate with @p it
1348 elm_list_item_end_set(Elm_List_Item *it, Evas_Object *end)
1350 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1351 if (it->end == end) return;
1352 if (it->dummy_end && !end) return;
1353 if (it->dummy_end) evas_object_del(it->end);
1356 end = evas_object_rectangle_add(evas_object_evas_get(it->obj));
1357 evas_object_color_set(end, 0, 0, 0, 0);
1358 it->dummy_end = EINA_TRUE;
1362 edje_object_part_swallow(it->base, "elm.swallow.end", end);
1366 * Gets the base object of the item.
1368 * @param it The list item
1369 * @return The base object associated with @p it
1374 elm_list_item_base_get(const Elm_List_Item *it)
1376 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1381 * Gets the label of the item.
1383 * @param it The list item
1384 * @return The label of @p it
1389 elm_list_item_label_get(const Elm_List_Item *it)
1391 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1396 * Sets the label of the item.
1398 * @param it The list item
1399 * @param text The label of @p it
1404 elm_list_item_label_set(Elm_List_Item *it, const char *text)
1406 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1407 if (!eina_stringshare_replace(&it->label, text)) return;
1409 edje_object_part_text_set(it->base, "elm.text", it->label);
1413 * Gets the item before @p it in the list.
1415 * @param it The list item
1416 * @return The item before @p it, or NULL on failure
1420 EAPI Elm_List_Item *
1421 elm_list_item_prev(const Elm_List_Item *it)
1423 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1424 if (it->node->prev) return it->node->prev->data;
1429 * Gets the item after @p it in the list.
1431 * @param it The list item
1432 * @return The item after @p it, or NULL on failure
1436 EAPI Elm_List_Item *
1437 elm_list_item_next(const Elm_List_Item *it)
1439 ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1440 if (it->node->next) return it->node->next->data;
1447 * This will enable or disable the scroller bounce mode for the list. See
1448 * elm_scroller_bounce_set() for details
1450 * @param obj The list object
1451 * @param h_bounce Allow bounce horizontally
1452 * @param v_bounce Allow bounce vertically
1457 elm_list_bounce_set(Evas_Object *obj, Eina_Bool h_bounce, Eina_Bool v_bounce)
1459 ELM_CHECK_WIDTYPE(obj, widtype);
1460 Widget_Data *wd = elm_widget_data_get(obj);
1463 elm_scroller_bounce_set(wd->scr, h_bounce, v_bounce);
1467 * Set the scrollbar policy
1469 * This sets the scrollbar visibility policy for the given scroller.
1470 * ELM_SMART_SCROLLER_POLICY_AUTO means the scrollber is made visible if it
1471 * is needed, and otherwise kept hidden. ELM_SMART_SCROLLER_POLICY_ON turns
1472 * it on all the time, and ELM_SMART_SCROLLER_POLICY_OFF always keeps it off.
1473 * This applies respectively for the horizontal and vertical scrollbars.
1475 * @param obj The list object
1476 * @param policy_h Horizontal scrollbar policy
1477 * @param policy_v Vertical scrollbar policy
1482 elm_list_scroller_policy_set(Evas_Object *obj, Elm_Scroller_Policy policy_h, Elm_Scroller_Policy policy_v)
1484 ELM_CHECK_WIDTYPE(obj, widtype);
1485 Widget_Data *wd = elm_widget_data_get(obj);
1488 elm_scroller_policy_set(wd->scr, policy_h, policy_v);
1492 elm_list_scroller_policy_get(const Evas_Object *obj, Elm_Scroller_Policy *policy_h, Elm_Scroller_Policy *policy_v)
1494 ELM_CHECK_WIDTYPE(obj, widtype);
1495 Widget_Data *wd = elm_widget_data_get(obj);
1498 elm_scroller_policy_get(wd->scr, policy_h, policy_v);