1 #include <Elementary.h>
2 #include <Elementary_Cursor.h>
4 #include "els_scroller.h"
8 #undef ELM_CHECK_WIDTYPE
9 #define ELM_CHECK_WIDTYPE(obj, widtype) \
10 if ((!obj) || (!elm_gen_type_check((obj), __func__))) return
11 #undef ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN
12 #define ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, ...) \
13 ELM_WIDGET_ITEM_CHECK_OR_RETURN((Elm_Widget_Item *)it, __VA_ARGS__); \
14 ELM_CHECK_WIDTYPE(WIDGET((it)), widtype) __VA_ARGS__;
16 static const char *_gengrid = NULL;
17 static const char *_genlist = NULL;
21 Eina_Inlist_Sorted_State *state;
23 Evas_Object *scr; /* a smart scroller object which is used internally in genlist */
24 Evas_Object *pan_smart; /* "elm_genlist_pan" evas smart object. this is an extern pan of smart scroller(scr). */
26 Eina_List *group_items;
27 Eina_Inlist *items; /* inlist of all items */
28 Elm_Gen_Item *reorder_it; /* item currently being repositioned */
29 Elm_Gen_Item *last_selected_item;
30 Pan *pan; /* pan_smart object's smart data */
33 int item_width, item_height;
34 int group_item_width, group_item_height;
37 Evas_Coord pan_x, pan_y;
38 Eina_Bool reorder_mode : 1;
39 Eina_Bool on_hold : 1;
41 Eina_Bool no_select : 1;
42 Eina_Bool wasselected : 1;
43 Eina_Bool always_select : 1;
44 Eina_Bool clear_me : 1;
45 Eina_Bool h_bounce : 1;
46 Eina_Bool v_bounce : 1;
47 Ecore_Cb del_cb, calc_cb, sizing_cb;
51 static const char SIG_ACTIVATED[] = "activated";
52 static const char SIG_CLICKED_DOUBLE[] = "clicked,double";
53 static const char SIG_SELECTED[] = "selected";
54 static const char SIG_UNSELECTED[] = "unselected";
55 static const char SIG_EXPANDED[] = "expanded";
56 static const char SIG_CONTRACTED[] = "contracted";
57 static const char SIG_EXPAND_REQUEST[] = "expand,request";
58 static const char SIG_CONTRACT_REQUEST[] = "contract,request";
59 static const char SIG_REALIZED[] = "realized";
60 static const char SIG_UNREALIZED[] = "unrealized";
61 static const char SIG_DRAG_START_UP[] = "drag,start,up";
62 static const char SIG_DRAG_START_DOWN[] = "drag,start,down";
63 static const char SIG_DRAG_START_LEFT[] = "drag,start,left";
64 static const char SIG_DRAG_START_RIGHT[] = "drag,start,right";
65 static const char SIG_DRAG_STOP[] = "drag,stop";
66 static const char SIG_DRAG[] = "drag";
67 static const char SIG_LONGPRESSED[] = "longpressed";
68 static const char SIG_SCROLL_ANIM_START[] = "scroll,anim,start";
69 static const char SIG_SCROLL_ANIM_STOP[] = "scroll,anim,stop";
70 static const char SIG_SCROLL_DRAG_START[] = "scroll,drag,start";
71 static const char SIG_SCROLL_DRAG_STOP[] = "scroll,drag,stop";
72 static const char SIG_SCROLL_EDGE_TOP[] = "scroll,edge,top"; // TODO : remove this
73 static const char SIG_SCROLL_EDGE_BOTTOM[] = "scroll,edge,bottom"; // TODO : remove this
74 static const char SIG_SCROLL_EDGE_LEFT[] = "scroll,edge,left"; // TODO : remove this
75 static const char SIG_SCROLL_EDGE_RIGHT[] = "scroll,edge,right"; // TODO : remove this
76 static const char SIG_EDGE_TOP[] = "edge,top";
77 static const char SIG_EDGE_BOTTOM[] = "edge,bottom";
78 static const char SIG_EDGE_LEFT[] = "edge,left";
79 static const char SIG_EDGE_RIGHT[] = "edge,right";
80 static const char SIG_MULTI_SWIPE_LEFT[] = "multi,swipe,left";
81 static const char SIG_MULTI_SWIPE_RIGHT[] = "multi,swipe,right";
82 static const char SIG_MULTI_SWIPE_UP[] = "multi,swipe,up";
83 static const char SIG_MULTI_SWIPE_DOWN[] = "multi,swipe,down";
84 static const char SIG_MULTI_PINCH_OUT[] = "multi,pinch,out";
85 static const char SIG_MULTI_PINCH_IN[] = "multi,pinch,in";
86 static const char SIG_SWIPE[] = "swipe";
87 static const char SIG_MOVED[] = "moved";
89 /* THIS FUNCTION IS HACKY AND TEMPORARY!!! */
91 elm_gen_type_check(const Evas_Object *obj,
94 const char *provided, *expected = "(unknown)";
95 static int abort_on_warn = -1;
96 provided = elm_widget_type_get(obj);
97 if (!_genlist) _genlist = eina_stringshare_add("genlist");
98 if (!_gengrid) _gengrid = eina_stringshare_add("gengrid");
99 if (EINA_LIKELY(provided == _genlist) || EINA_LIKELY(provided == _gengrid))
101 if ((!provided) || (!provided[0]))
103 provided = evas_object_type_get(obj);
104 if ((!provided) || (!provided[0]))
105 provided = "(unknown)";
107 ERR("Passing Object: %p in function: %s, of type: '%s' when expecting type: '%s'", obj, func, provided, expected);
108 if (abort_on_warn == -1)
110 if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
111 else abort_on_warn = 0;
113 if (abort_on_warn == 1) abort();
118 _item_text_hook(Elm_Gen_Item *it, const char *part)
120 if (!it->itc->func.text_get) return NULL;
121 return edje_object_part_text_get(VIEW(it), part);
125 _item_content_get_hook(Elm_Gen_Item *it, const char *part)
127 return edje_object_part_swallow_get(VIEW(it), part);
131 _item_content_set_hook(Elm_Gen_Item *it, const char *part, Evas_Object *content)
133 edje_object_part_swallow(VIEW(it), part, content);
137 _item_content_unset_hook(Elm_Gen_Item *it, const char *part)
141 obj = edje_object_part_swallow_get(VIEW(it), part);
142 if (!obj) return NULL;
143 edje_object_part_unswallow(VIEW(it), obj);
149 _deselect_all_items(Widget_Data *wd)
151 if (!wd->selected) return EINA_FALSE;
153 elm_gengrid_item_selected_set(wd->selected->data, EINA_FALSE);
159 _item_multi_select_left(Widget_Data *wd)
161 if (!wd->selected) return EINA_FALSE;
163 Elm_Gengrid_Item *prev = elm_gengrid_item_prev_get(wd->last_selected_item);
164 if (!prev) return EINA_TRUE;
165 if (elm_gengrid_item_selected_get(prev))
167 elm_gengrid_item_selected_set(wd->last_selected_item, EINA_FALSE);
168 wd->last_selected_item = prev;
169 elm_gengrid_item_show(wd->last_selected_item);
173 elm_gengrid_item_selected_set(prev, EINA_TRUE);
174 elm_gengrid_item_show(prev);
181 _item_multi_select_right(Widget_Data *wd)
183 if (!wd->selected) return EINA_FALSE;
185 Elm_Gengrid_Item *next = elm_gengrid_item_next_get(wd->last_selected_item);
186 if (!next) return EINA_TRUE;
187 if (elm_gengrid_item_selected_get(next))
189 elm_gengrid_item_selected_set(wd->last_selected_item, EINA_FALSE);
190 wd->last_selected_item = next;
191 elm_gengrid_item_show(wd->last_selected_item);
195 elm_gengrid_item_selected_set(next, EINA_TRUE);
196 elm_gengrid_item_show(next);
203 _item_multi_select_up(Widget_Data *wd)
206 Eina_Bool r = EINA_TRUE;
208 if (!wd->selected) return EINA_FALSE;
210 for (i = 0; (r) && (i < wd->nmax); i++)
211 r &= _item_multi_select_left(wd);
217 _item_multi_select_down(Widget_Data *wd)
220 Eina_Bool r = EINA_TRUE;
222 if (!wd->selected) return EINA_FALSE;
224 for (i = 0; (r) && (i < wd->nmax); i++)
225 r &= _item_multi_select_right(wd);
231 _item_single_select_up(Widget_Data *wd)
235 Elm_Gengrid_Item *prev;
239 prev = ELM_GENGRID_ITEM_FROM_INLIST(wd->items->last);
240 while ((prev) && (prev->delete_me))
241 prev = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(prev)->prev);
242 elm_gengrid_item_selected_set(prev, EINA_TRUE);
243 elm_gengrid_item_show(prev);
246 else prev = elm_gengrid_item_prev_get(wd->last_selected_item);
248 if (!prev) return EINA_FALSE;
250 for (i = 1; i < wd->nmax; i++)
252 Elm_Gengrid_Item *tmp = elm_gengrid_item_prev_get(prev);
253 if (!tmp) return EINA_FALSE;
257 _deselect_all_items(wd);
259 elm_gengrid_item_selected_set(prev, EINA_TRUE);
260 elm_gengrid_item_show(prev);
265 _item_single_select_down(Widget_Data *wd)
269 Elm_Gengrid_Item *next;
273 next = ELM_GENGRID_ITEM_FROM_INLIST(wd->items);
274 while ((next) && (next->delete_me))
275 next = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(next)->next);
276 elm_gengrid_item_selected_set(next, EINA_TRUE);
277 elm_gengrid_item_show(next);
280 else next = elm_gengrid_item_next_get(wd->last_selected_item);
282 if (!next) return EINA_FALSE;
284 for (i = 1; i < wd->nmax; i++)
286 Elm_Gengrid_Item *tmp = elm_gengrid_item_next_get(next);
287 if (!tmp) return EINA_FALSE;
291 _deselect_all_items(wd);
293 elm_gengrid_item_selected_set(next, EINA_TRUE);
294 elm_gengrid_item_show(next);
299 _item_single_select_left(Widget_Data *wd)
301 Elm_Gengrid_Item *prev;
304 prev = ELM_GENGRID_ITEM_FROM_INLIST(wd->items->last);
305 while ((prev) && (prev->delete_me))
306 prev = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(prev)->prev);
308 else prev = elm_gengrid_item_prev_get(wd->last_selected_item);
310 if (!prev) return EINA_FALSE;
312 _deselect_all_items(wd);
314 elm_gengrid_item_selected_set(prev, EINA_TRUE);
315 elm_gengrid_item_show(prev);
320 _item_single_select_right(Widget_Data *wd)
322 Elm_Gengrid_Item *next;
325 next = ELM_GENGRID_ITEM_FROM_INLIST(wd->items);
326 while ((next) && (next->delete_me))
327 next = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(next)->next);
329 else next = elm_gengrid_item_next_get(wd->last_selected_item);
331 if (!next) return EINA_FALSE;
333 _deselect_all_items(wd);
335 elm_gengrid_item_selected_set(next, EINA_TRUE);
336 elm_gengrid_item_show(next);
343 _item_select(Elm_Gen_Item *it)
345 if ((it->wd->no_select) || (it->delete_me) || (it->mode_set)) return;
348 it->selected = EINA_TRUE;
349 it->wd->selected = eina_list_append(it->wd->selected, it);
351 else if (!it->wd->always_select) return;
353 evas_object_ref(WIDGET(it));
356 if (it->func.func) it->func.func((void *)it->func.data, WIDGET(it), it);
358 evas_object_smart_callback_call(WIDGET(it), SIG_SELECTED, it);
361 evas_object_unref(WIDGET(it));
362 if ((it->wd->clear_me) && (!it->wd->walking))
363 elm_gen_clear(WIDGET(it));
366 if ((!it->walking) && (it->delete_me))
368 if (!it->relcount) it->del_cb(it);
371 it->wd->last_selected_item = it;
374 /******************************************************************************/
376 elm_gen_item_unrealize(Elm_Gen_Item *it,
379 Evas_Object *content;
381 if (!it->realized) return;
382 if (it->wd->reorder_it == it) return;
383 evas_event_freeze(evas_object_evas_get(WIDGET(it)));
385 evas_object_smart_callback_call(WIDGET(it), SIG_UNREALIZED, it);
388 ecore_timer_del(it->long_timer);
389 it->long_timer = NULL;
392 elm_widget_stringlist_free(it->labels);
394 elm_widget_stringlist_free(it->contents);
396 elm_widget_stringlist_free(it->states);
399 EINA_LIST_FREE(it->content_objs, content)
400 evas_object_del(content);
402 it->unrealize_cb(it);
404 it->realized = EINA_FALSE;
405 it->want_unrealize = EINA_FALSE;
406 evas_event_thaw(evas_object_evas_get(WIDGET(it)));
407 evas_event_thaw_eval(evas_object_evas_get(WIDGET(it)));
411 elm_gen_item_del_notserious(Elm_Gen_Item *it)
413 elm_widget_item_pre_notify_del(it);
414 it->delete_me = EINA_TRUE;
415 if (it->selected) it->wd->selected = eina_list_remove(it->wd->selected, it);
417 if (it->itc->func.del)
418 it->itc->func.del((void *)it->base.data, WIDGET(it));
422 elm_gen_item_del_serious(Elm_Gen_Item *it)
424 elm_gen_item_del_notserious(it);
425 it->wd->items = eina_inlist_remove(it->wd->items, EINA_INLIST_GET(it));
426 if (it->tooltip.del_cb)
427 it->tooltip.del_cb((void *)it->tooltip.data, WIDGET(it), it);
428 it->wd->walking -= it->walking;
429 if (it->long_timer) ecore_timer_del(it->long_timer);
431 it->wd->group_items = eina_list_remove(it->wd->group_items, it);
433 if (it->wd->calc_job) ecore_job_del(it->wd->calc_job);
434 it->wd->calc_job = ecore_job_add(it->wd->calc_cb, it->wd);
437 elm_widget_item_del(it);
441 elm_gen_item_new(Widget_Data *wd,
442 const Elm_Gen_Item_Class *itc,
444 Elm_Gen_Item *parent,
446 const void *func_data)
450 it = elm_widget_item_new(wd->obj, Elm_Gen_Item);
451 if (!it) return NULL;
454 it->base.data = data;
456 it->func.func = func;
457 it->func.data = func_data;
458 elm_widget_item_content_get_hook_set(it, _item_content_get_hook);
459 elm_widget_item_content_set_hook_set(it, _item_content_set_hook);
460 elm_widget_item_content_unset_hook_set(it, _item_content_unset_hook);
462 it->sel_cb = (Ecore_Cb)_item_select;
464 elm_widget_item_text_get_hook_set(it, _item_text_hook);
467 /******************************************************************************/
470 elm_gen_item_selected_set(Elm_Gen_Item *it,
473 ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
474 Widget_Data *wd = it->wd;
476 if ((it->delete_me) || (it->disabled)) return;
477 selected = !!selected;
478 if (it->selected == selected) return;
486 if (it->unhighlight_cb) it->unhighlight_cb(wd->selected->data);
487 it->unsel_cb(wd->selected->data);
490 it->highlight_cb(it);
494 if (it->unhighlight_cb) it->unhighlight_cb(it);
499 elm_gen_clear(Evas_Object *obj)
501 ELM_CHECK_WIDTYPE(obj, widtype);
502 Widget_Data *wd = elm_widget_data_get(obj);
507 eina_inlist_sorted_state_free(wd->state);
515 EINA_INLIST_FOREACH(wd->items, it)
519 evas_event_freeze(evas_object_evas_get(wd->obj));
522 Elm_Gen_Item *it = ELM_GEN_ITEM_FROM_INLIST(wd->items);
528 ecore_job_del(wd->calc_job);
531 if (wd->selected) wd->selected = eina_list_free(wd->selected);
532 if (wd->clear_cb) wd->clear_cb(wd);
540 evas_object_size_hint_min_set(wd->pan_smart, wd->minw, wd->minh);
541 evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
543 if (wd->sizing_cb) wd->sizing_cb(wd->obj);
544 elm_smart_scroller_child_region_show(wd->scr, 0, 0, 0, 0);
545 evas_event_thaw(evas_object_evas_get(wd->obj));
546 evas_event_thaw_eval(evas_object_evas_get(wd->obj));
550 elm_gen_item_selected_get(const Elm_Gen_Item *it)
552 ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
557 elm_gen_always_select_mode_set(Evas_Object *obj,
558 Eina_Bool always_select)
560 ELM_CHECK_WIDTYPE(obj, widtype);
561 Widget_Data *wd = elm_widget_data_get(obj);
563 wd->always_select = always_select;
567 elm_gen_always_select_mode_get(const Evas_Object *obj)
569 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
570 Widget_Data *wd = elm_widget_data_get(obj);
571 if (!wd) return EINA_FALSE;
572 return wd->always_select;
576 elm_gen_no_select_mode_set(Evas_Object *obj,
579 ELM_CHECK_WIDTYPE(obj, widtype);
580 Widget_Data *wd = elm_widget_data_get(obj);
582 wd->no_select = no_select;
586 elm_gen_no_select_mode_get(const Evas_Object *obj)
588 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
589 Widget_Data *wd = elm_widget_data_get(obj);
590 if (!wd) return EINA_FALSE;
591 return wd->no_select;
595 elm_gen_bounce_set(Evas_Object *obj,
599 ELM_CHECK_WIDTYPE(obj, widtype);
600 Widget_Data *wd = elm_widget_data_get(obj);
602 elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce);
603 wd->h_bounce = h_bounce;
604 wd->v_bounce = v_bounce;
608 elm_gen_bounce_get(const Evas_Object *obj,
612 ELM_CHECK_WIDTYPE(obj, widtype);
613 Widget_Data *wd = elm_widget_data_get(obj);
615 if (h_bounce) *h_bounce = wd->h_bounce;
616 if (v_bounce) *v_bounce = wd->v_bounce;
620 elm_gen_page_relative_set(Evas_Object *obj,
624 Evas_Coord pagesize_h;
625 Evas_Coord pagesize_v;
627 ELM_CHECK_WIDTYPE(obj, widtype);
628 Widget_Data *wd = elm_widget_data_get(obj);
631 elm_smart_scroller_paging_get(wd->scr, NULL, NULL, &pagesize_h, &pagesize_v);
632 elm_smart_scroller_paging_set(wd->scr, h_pagerel, v_pagerel, pagesize_h,
637 elm_gen_page_relative_get(const Evas_Object *obj, double *h_pagerel, double *v_pagerel)
639 ELM_CHECK_WIDTYPE(obj, widtype);
640 Widget_Data *wd = elm_widget_data_get(obj);
643 elm_smart_scroller_paging_get(wd->scr, h_pagerel, v_pagerel, NULL, NULL);
647 elm_gen_page_size_set(Evas_Object *obj,
648 Evas_Coord h_pagesize,
649 Evas_Coord v_pagesize)
654 ELM_CHECK_WIDTYPE(obj, widtype);
655 Widget_Data *wd = elm_widget_data_get(obj);
657 elm_smart_scroller_paging_get(wd->scr, &pagerel_h, &pagerel_v, NULL, NULL);
658 elm_smart_scroller_paging_set(wd->scr, pagerel_h, pagerel_v, h_pagesize,
663 elm_gen_current_page_get(const Evas_Object *obj, int *h_pagenumber, int *v_pagenumber)
665 ELM_CHECK_WIDTYPE(obj, widtype);
666 Widget_Data *wd = elm_widget_data_get(obj);
669 elm_smart_scroller_current_page_get(wd->scr, h_pagenumber, v_pagenumber);
673 elm_gen_last_page_get(const Evas_Object *obj, int *h_pagenumber, int *v_pagenumber)
675 ELM_CHECK_WIDTYPE(obj, widtype);
676 Widget_Data *wd = elm_widget_data_get(obj);
679 elm_smart_scroller_last_page_get(wd->scr, h_pagenumber, v_pagenumber);
683 elm_gen_page_show(const Evas_Object *obj, int h_pagenumber, int v_pagenumber)
685 ELM_CHECK_WIDTYPE(obj, widtype);
686 Widget_Data *wd = elm_widget_data_get(obj);
689 elm_smart_scroller_page_show(wd->scr, h_pagenumber, v_pagenumber);
693 elm_gen_page_bring_in(const Evas_Object *obj, int h_pagenumber, int v_pagenumber)
695 ELM_CHECK_WIDTYPE(obj, widtype);
696 Widget_Data *wd = elm_widget_data_get(obj);
699 elm_smart_scroller_page_bring_in(wd->scr, h_pagenumber, v_pagenumber);
703 elm_gen_first_item_get(const Evas_Object *obj)
705 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
706 Widget_Data *wd = elm_widget_data_get(obj);
707 if (!wd) return NULL;
708 if (!wd->items) return NULL;
709 Elm_Gen_Item *it = ELM_GEN_ITEM_FROM_INLIST(wd->items);
710 while ((it) && (it->delete_me))
711 it = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
716 elm_gen_last_item_get(const Evas_Object *obj)
718 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
719 Widget_Data *wd = elm_widget_data_get(obj);
720 if (!wd) return NULL;
721 if (!wd->items) return NULL;
722 Elm_Gen_Item *it = ELM_GEN_ITEM_FROM_INLIST(wd->items->last);
723 while ((it) && (it->delete_me))
724 it = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev);
729 elm_gen_item_next_get(const Elm_Gen_Item *it)
731 ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
734 it = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
735 if ((it) && (!it->delete_me)) break;
737 return (Elm_Gen_Item *)it;
741 elm_gen_item_prev_get(const Elm_Gen_Item *it)
743 ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
746 it = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev);
747 if ((it) && (!it->delete_me)) break;
749 return (Elm_Gen_Item *)it;
753 elm_gen_item_widget_get(const Elm_Gen_Item *it)
755 ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);