diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/elementary/src/lib/elm_list.c | 2004 |
1 files changed, 2004 insertions, 0 deletions
diff --git a/libraries/elementary/src/lib/elm_list.c b/libraries/elementary/src/lib/elm_list.c new file mode 100644 index 0000000..d370baa --- /dev/null +++ b/libraries/elementary/src/lib/elm_list.c | |||
@@ -0,0 +1,2004 @@ | |||
1 | #include <Elementary.h> | ||
2 | #include "elm_priv.h" | ||
3 | #include "els_scroller.h" | ||
4 | |||
5 | #define SWIPE_MOVES 12 | ||
6 | |||
7 | typedef struct _Widget_Data Widget_Data; | ||
8 | typedef struct _Elm_List_Item Elm_List_Item; | ||
9 | |||
10 | struct _Widget_Data | ||
11 | { | ||
12 | Evas_Object *scr, *box, *self; | ||
13 | Eina_List *items, *selected, *to_delete; | ||
14 | Elm_Object_Item *last_selected_item; | ||
15 | Elm_List_Mode mode; | ||
16 | Elm_List_Mode h_mode; | ||
17 | Evas_Coord minw[2], minh[2]; | ||
18 | Elm_Object_Select_Mode select_mode; | ||
19 | int walking; | ||
20 | int movements; | ||
21 | struct | ||
22 | { | ||
23 | Evas_Coord x, y; | ||
24 | } history[SWIPE_MOVES]; | ||
25 | Eina_Bool scr_minw : 1; | ||
26 | Eina_Bool scr_minh : 1; | ||
27 | Eina_Bool swipe : 1; | ||
28 | Eina_Bool fix_pending : 1; | ||
29 | Eina_Bool on_hold : 1; | ||
30 | Eina_Bool multi : 1; | ||
31 | Eina_Bool longpressed : 1; | ||
32 | Eina_Bool wasselected : 1; | ||
33 | }; | ||
34 | |||
35 | struct _Elm_List_Item | ||
36 | { | ||
37 | ELM_WIDGET_ITEM; | ||
38 | Widget_Data *wd; | ||
39 | Eina_List *node; | ||
40 | const char *label; | ||
41 | Evas_Object *icon, *end; | ||
42 | Evas_Smart_Cb func; | ||
43 | Ecore_Timer *long_timer; | ||
44 | Ecore_Timer *swipe_timer; | ||
45 | Eina_Bool deleted : 1; | ||
46 | Eina_Bool even : 1; | ||
47 | Eina_Bool is_even : 1; | ||
48 | Eina_Bool is_separator : 1; | ||
49 | Eina_Bool fixed : 1; | ||
50 | Eina_Bool selected : 1; | ||
51 | Eina_Bool highlighted : 1; | ||
52 | Eina_Bool dummy_icon : 1; | ||
53 | Eina_Bool dummy_end : 1; | ||
54 | }; | ||
55 | |||
56 | static const char *widtype = NULL; | ||
57 | static void _del_hook(Evas_Object *obj); | ||
58 | static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl); | ||
59 | static void _theme_hook(Evas_Object *obj); | ||
60 | static void _sizing_eval(Evas_Object *obj); | ||
61 | static void _disable_hook(Evas_Object *obj); | ||
62 | static void _on_focus_hook(void *data, Evas_Object *obj); | ||
63 | static void _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source); | ||
64 | static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info); | ||
65 | static void _sub_del(void *data, Evas_Object *obj, void *event_info); | ||
66 | static void _fix_items(Evas_Object *obj); | ||
67 | static void _mouse_down(void *data, Evas *evas, Evas_Object *obj, void *event_info); | ||
68 | static void _mouse_up(void *data, Evas *evas, Evas_Object *obj, void *event_info); | ||
69 | static void _mouse_move(void *data, Evas *evas, Evas_Object *obj, void *event_info); | ||
70 | static void _edge_left(void *data, Evas_Object *scr, void *event_info); | ||
71 | static void _edge_right(void *data, Evas_Object *scr, void *event_info); | ||
72 | static void _edge_top(void *data, Evas_Object *scr, void *event_info); | ||
73 | static void _edge_bottom(void *data, Evas_Object *scr, void *event_info); | ||
74 | static Eina_Bool _item_multi_select_up(Widget_Data *wd); | ||
75 | static Eina_Bool _item_multi_select_down(Widget_Data *wd); | ||
76 | static Eina_Bool _item_single_select_up(Widget_Data *wd); | ||
77 | static Eina_Bool _item_single_select_down(Widget_Data *wd); | ||
78 | static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src, | ||
79 | Evas_Callback_Type type, void *event_info); | ||
80 | static Eina_Bool _deselect_all_items(Widget_Data *wd); | ||
81 | |||
82 | static const char SIG_ACTIVATED[] = "activated"; | ||
83 | static const char SIG_CLICKED_DOUBLE[] = "clicked,double"; | ||
84 | static const char SIG_SELECTED[] = "selected"; | ||
85 | static const char SIG_UNSELECTED[] = "unselected"; | ||
86 | static const char SIG_LONGPRESSED[] = "longpressed"; | ||
87 | static const char SIG_EDGE_TOP[] = "edge,top"; | ||
88 | static const char SIG_EDGE_BOTTOM[] = "edge,bottom"; | ||
89 | static const char SIG_EDGE_LEFT[] = "edge,left"; | ||
90 | static const char SIG_EDGE_RIGHT[] = "edge,right"; | ||
91 | |||
92 | static const Evas_Smart_Cb_Description _signals[] = { | ||
93 | {SIG_ACTIVATED, ""}, | ||
94 | {SIG_CLICKED_DOUBLE, ""}, | ||
95 | {SIG_SELECTED, ""}, | ||
96 | {SIG_UNSELECTED, ""}, | ||
97 | {SIG_LONGPRESSED, ""}, | ||
98 | {SIG_EDGE_TOP, ""}, | ||
99 | {SIG_EDGE_BOTTOM, ""}, | ||
100 | {SIG_EDGE_LEFT, ""}, | ||
101 | {SIG_EDGE_RIGHT, ""}, | ||
102 | {NULL, NULL} | ||
103 | }; | ||
104 | |||
105 | #define ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, ...) \ | ||
106 | ELM_OBJ_ITEM_CHECK_OR_RETURN(it, __VA_ARGS__); \ | ||
107 | if (((Elm_List_Item *)it)->deleted) \ | ||
108 | { \ | ||
109 | ERR("ERROR: "#it" has been DELETED.\n"); \ | ||
110 | return __VA_ARGS__; \ | ||
111 | } | ||
112 | |||
113 | static inline void | ||
114 | _elm_list_item_free(Elm_List_Item *it) | ||
115 | { | ||
116 | evas_object_event_callback_del_full | ||
117 | (VIEW(it), EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, it); | ||
118 | evas_object_event_callback_del_full | ||
119 | (VIEW(it), EVAS_CALLBACK_MOUSE_UP, _mouse_up, it); | ||
120 | evas_object_event_callback_del_full | ||
121 | (VIEW(it), EVAS_CALLBACK_MOUSE_MOVE, _mouse_move, it); | ||
122 | |||
123 | if (it->icon) | ||
124 | evas_object_event_callback_del_full | ||
125 | (it->icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS, | ||
126 | _changed_size_hints, WIDGET(it)); | ||
127 | |||
128 | if (it->end) | ||
129 | evas_object_event_callback_del_full | ||
130 | (it->end, EVAS_CALLBACK_CHANGED_SIZE_HINTS, | ||
131 | _changed_size_hints, WIDGET(it)); | ||
132 | |||
133 | eina_stringshare_del(it->label); | ||
134 | |||
135 | if (it->swipe_timer) ecore_timer_del(it->swipe_timer); | ||
136 | it->swipe_timer = NULL; | ||
137 | if (it->long_timer) ecore_timer_del(it->long_timer); | ||
138 | it->long_timer = NULL; | ||
139 | if (it->icon) evas_object_del(it->icon); | ||
140 | if (it->end) evas_object_del(it->end); | ||
141 | } | ||
142 | |||
143 | static Eina_Bool | ||
144 | _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info) | ||
145 | { | ||
146 | if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE; | ||
147 | Evas_Event_Key_Down *ev = event_info; | ||
148 | Widget_Data *wd = elm_widget_data_get(obj); | ||
149 | if (!wd) return EINA_FALSE; | ||
150 | if (!wd->items) return EINA_FALSE; | ||
151 | if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE; | ||
152 | if (elm_widget_disabled_get(obj)) return EINA_FALSE; | ||
153 | |||
154 | Elm_List_Item *it = NULL; | ||
155 | Evas_Coord x = 0; | ||
156 | Evas_Coord y = 0; | ||
157 | Evas_Coord step_x = 0; | ||
158 | Evas_Coord step_y = 0; | ||
159 | Evas_Coord v_w = 0; | ||
160 | Evas_Coord v_h = 0; | ||
161 | Evas_Coord page_x = 0; | ||
162 | Evas_Coord page_y = 0; | ||
163 | |||
164 | elm_smart_scroller_child_pos_get(wd->scr, &x, &y); | ||
165 | elm_smart_scroller_step_size_get(wd->scr, &step_x, &step_y); | ||
166 | elm_smart_scroller_page_size_get(wd->scr, &page_x, &page_y); | ||
167 | elm_smart_scroller_child_viewport_size_get(wd->scr, &v_w, &v_h); | ||
168 | |||
169 | /* TODO: fix logic for horizontal mode */ | ||
170 | if ((!strcmp(ev->keyname, "Left")) || | ||
171 | ((!strcmp(ev->keyname, "KP_Left")) && !ev->string)) | ||
172 | { | ||
173 | if ((wd->h_mode) && | ||
174 | (((evas_key_modifier_is_set(ev->modifiers, "Shift")) && | ||
175 | (_item_multi_select_up(wd))) | ||
176 | || (_item_single_select_up(wd)))) | ||
177 | { | ||
178 | ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; | ||
179 | return EINA_TRUE; | ||
180 | } | ||
181 | else | ||
182 | x -= step_x; | ||
183 | } | ||
184 | else if ((!strcmp(ev->keyname, "Right")) || | ||
185 | ((!strcmp(ev->keyname, "KP_Right")) && !ev->string)) | ||
186 | { | ||
187 | if ((wd->h_mode) && | ||
188 | (((evas_key_modifier_is_set(ev->modifiers, "Shift")) && | ||
189 | (_item_multi_select_down(wd))) | ||
190 | || (_item_single_select_down(wd)))) | ||
191 | { | ||
192 | ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; | ||
193 | return EINA_TRUE; | ||
194 | } | ||
195 | else | ||
196 | x += step_x; | ||
197 | } | ||
198 | else if ((!strcmp(ev->keyname, "Up")) || | ||
199 | ((!strcmp(ev->keyname, "KP_Up")) && !ev->string)) | ||
200 | { | ||
201 | if ((!wd->h_mode) && | ||
202 | (((evas_key_modifier_is_set(ev->modifiers, "Shift")) && | ||
203 | (_item_multi_select_up(wd))) | ||
204 | || (_item_single_select_up(wd)))) | ||
205 | { | ||
206 | ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; | ||
207 | return EINA_TRUE; | ||
208 | } | ||
209 | else | ||
210 | y -= step_y; | ||
211 | } | ||
212 | else if ((!strcmp(ev->keyname, "Down")) || | ||
213 | ((!strcmp(ev->keyname, "KP_Down")) && !ev->string)) | ||
214 | { | ||
215 | if ((!wd->h_mode) && | ||
216 | (((evas_key_modifier_is_set(ev->modifiers, "Shift")) && | ||
217 | (_item_multi_select_down(wd))) | ||
218 | || (_item_single_select_down(wd)))) | ||
219 | { | ||
220 | ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; | ||
221 | return EINA_TRUE; | ||
222 | } | ||
223 | else | ||
224 | y += step_y; | ||
225 | } | ||
226 | else if ((!strcmp(ev->keyname, "Home")) || | ||
227 | ((!strcmp(ev->keyname, "KP_Home")) && !ev->string)) | ||
228 | { | ||
229 | it = eina_list_data_get(wd->items); | ||
230 | elm_list_item_bring_in((Elm_Object_Item *)it); | ||
231 | ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; | ||
232 | return EINA_TRUE; | ||
233 | } | ||
234 | else if ((!strcmp(ev->keyname, "End")) || | ||
235 | ((!strcmp(ev->keyname, "KP_End")) && !ev->string)) | ||
236 | { | ||
237 | it = eina_list_data_get(eina_list_last(wd->items)); | ||
238 | elm_list_item_bring_in((Elm_Object_Item *)it); | ||
239 | ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; | ||
240 | return EINA_TRUE; | ||
241 | } | ||
242 | else if ((!strcmp(ev->keyname, "Prior")) || | ||
243 | ((!strcmp(ev->keyname, "KP_Prior")) && !ev->string)) | ||
244 | { | ||
245 | if (wd->h_mode) | ||
246 | { | ||
247 | if (page_x < 0) | ||
248 | x -= -(page_x * v_w) / 100; | ||
249 | else | ||
250 | x -= page_x; | ||
251 | } | ||
252 | else | ||
253 | { | ||
254 | if (page_y < 0) | ||
255 | y -= -(page_y * v_h) / 100; | ||
256 | else | ||
257 | y -= page_y; | ||
258 | } | ||
259 | } | ||
260 | else if ((!strcmp(ev->keyname, "Next")) || | ||
261 | ((!strcmp(ev->keyname, "KP_Next")) && !ev->string)) | ||
262 | { | ||
263 | if (wd->h_mode) | ||
264 | { | ||
265 | if (page_x < 0) | ||
266 | x += -(page_x * v_w) / 100; | ||
267 | else | ||
268 | x += page_x; | ||
269 | } | ||
270 | else | ||
271 | { | ||
272 | if (page_y < 0) | ||
273 | y += -(page_y * v_h) / 100; | ||
274 | else | ||
275 | y += page_y; | ||
276 | } | ||
277 | } | ||
278 | else if (((!strcmp(ev->keyname, "Return")) || | ||
279 | (!strcmp(ev->keyname, "KP_Enter")) || | ||
280 | (!strcmp(ev->keyname, "space"))) | ||
281 | && (!wd->multi) && (wd->selected)) | ||
282 | { | ||
283 | it = (Elm_List_Item *) elm_list_selected_item_get(obj); | ||
284 | evas_object_smart_callback_call(WIDGET(it), SIG_ACTIVATED, it); | ||
285 | } | ||
286 | else if (!strcmp(ev->keyname, "Escape")) | ||
287 | { | ||
288 | if (!_deselect_all_items(wd)) return EINA_FALSE; | ||
289 | ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; | ||
290 | return EINA_TRUE; | ||
291 | } | ||
292 | else return EINA_FALSE; | ||
293 | |||
294 | ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; | ||
295 | elm_smart_scroller_child_pos_set(wd->scr, x, y); | ||
296 | return EINA_TRUE; | ||
297 | } | ||
298 | |||
299 | static void | ||
300 | _translate_hook(Evas_Object *obj) | ||
301 | { | ||
302 | evas_object_smart_callback_call(obj, "language,changed", NULL); | ||
303 | } | ||
304 | |||
305 | static Eina_Bool | ||
306 | _deselect_all_items(Widget_Data *wd) | ||
307 | { | ||
308 | if (!wd->selected) return EINA_FALSE; | ||
309 | while (wd->selected) | ||
310 | elm_list_item_selected_set((Elm_Object_Item *) wd->selected->data, | ||
311 | EINA_FALSE); | ||
312 | |||
313 | return EINA_TRUE; | ||
314 | } | ||
315 | |||
316 | static Eina_Bool | ||
317 | _item_multi_select_up(Widget_Data *wd) | ||
318 | { | ||
319 | if (!wd->selected) return EINA_FALSE; | ||
320 | if (!wd->multi) return EINA_FALSE; | ||
321 | |||
322 | Elm_Object_Item *prev = elm_list_item_prev(wd->last_selected_item); | ||
323 | if (!prev) return EINA_TRUE; | ||
324 | |||
325 | if (elm_list_item_selected_get(prev)) | ||
326 | { | ||
327 | elm_list_item_selected_set(wd->last_selected_item, EINA_FALSE); | ||
328 | wd->last_selected_item = prev; | ||
329 | elm_list_item_show(wd->last_selected_item); | ||
330 | } | ||
331 | else | ||
332 | { | ||
333 | elm_list_item_selected_set(prev, EINA_TRUE); | ||
334 | elm_list_item_show(prev); | ||
335 | } | ||
336 | return EINA_TRUE; | ||
337 | } | ||
338 | |||
339 | static Eina_Bool | ||
340 | _item_multi_select_down(Widget_Data *wd) | ||
341 | { | ||
342 | if (!wd->selected) return EINA_FALSE; | ||
343 | if (!wd->multi) return EINA_FALSE; | ||
344 | |||
345 | Elm_Object_Item *next = elm_list_item_next(wd->last_selected_item); | ||
346 | if (!next) return EINA_TRUE; | ||
347 | |||
348 | if (elm_list_item_selected_get(next)) | ||
349 | { | ||
350 | elm_list_item_selected_set(wd->last_selected_item, EINA_FALSE); | ||
351 | wd->last_selected_item = next; | ||
352 | elm_list_item_show(wd->last_selected_item); | ||
353 | } | ||
354 | else | ||
355 | { | ||
356 | elm_list_item_selected_set(next, EINA_TRUE); | ||
357 | elm_list_item_show(next); | ||
358 | } | ||
359 | return EINA_TRUE; | ||
360 | } | ||
361 | |||
362 | static Eina_Bool | ||
363 | _item_single_select_up(Widget_Data *wd) | ||
364 | { | ||
365 | Elm_Object_Item *prev; | ||
366 | |||
367 | if (!wd->selected) prev = eina_list_data_get(eina_list_last(wd->items)); | ||
368 | else prev = elm_list_item_prev(wd->last_selected_item); | ||
369 | if (!prev) return EINA_FALSE; | ||
370 | |||
371 | _deselect_all_items(wd); | ||
372 | |||
373 | elm_list_item_selected_set(prev, EINA_TRUE); | ||
374 | elm_list_item_show(prev); | ||
375 | return EINA_TRUE; | ||
376 | } | ||
377 | |||
378 | static Eina_Bool | ||
379 | _item_single_select_down(Widget_Data *wd) | ||
380 | { | ||
381 | Elm_Object_Item *next; | ||
382 | |||
383 | if (!wd->selected) next = eina_list_data_get(wd->items); | ||
384 | else next = elm_list_item_next(wd->last_selected_item); | ||
385 | if (!next) return EINA_FALSE; | ||
386 | |||
387 | _deselect_all_items(wd); | ||
388 | |||
389 | elm_list_item_selected_set(next, EINA_TRUE); | ||
390 | elm_list_item_show(next); | ||
391 | return EINA_TRUE; | ||
392 | } | ||
393 | |||
394 | static void | ||
395 | _elm_list_process_deletions(Widget_Data *wd) | ||
396 | { | ||
397 | Elm_List_Item *it; | ||
398 | |||
399 | wd->walking++; // avoid nested deletion and also _sub_del() fix_items | ||
400 | |||
401 | EINA_LIST_FREE(wd->to_delete, it) | ||
402 | { | ||
403 | wd->items = eina_list_remove_list(wd->items, it->node); | ||
404 | _elm_list_item_free(it); | ||
405 | elm_widget_item_free(it); | ||
406 | } | ||
407 | |||
408 | wd->walking--; | ||
409 | } | ||
410 | |||
411 | static inline void | ||
412 | _elm_list_walk(Widget_Data *wd) | ||
413 | { | ||
414 | if (wd->walking < 0) | ||
415 | { | ||
416 | ERR("ERROR: walking was negative. fixed!\n"); | ||
417 | wd->walking = 0; | ||
418 | } | ||
419 | wd->walking++; | ||
420 | } | ||
421 | |||
422 | static inline void | ||
423 | _elm_list_unwalk(Widget_Data *wd) | ||
424 | { | ||
425 | wd->walking--; | ||
426 | if (wd->walking < 0) | ||
427 | { | ||
428 | ERR("ERROR: walking became negative. fixed!\n"); | ||
429 | wd->walking = 0; | ||
430 | } | ||
431 | |||
432 | if (wd->walking) | ||
433 | return; | ||
434 | |||
435 | if (wd->to_delete) | ||
436 | _elm_list_process_deletions(wd); | ||
437 | |||
438 | if (wd->fix_pending) | ||
439 | { | ||
440 | wd->fix_pending = EINA_FALSE; | ||
441 | _fix_items(wd->self); | ||
442 | _sizing_eval(wd->self); | ||
443 | } | ||
444 | } | ||
445 | |||
446 | static void | ||
447 | _del_pre_hook(Evas_Object *obj) | ||
448 | { | ||
449 | Widget_Data *wd = elm_widget_data_get(obj); | ||
450 | const Eina_List *l; | ||
451 | Elm_List_Item *it; | ||
452 | |||
453 | evas_object_smart_callback_del(obj, "sub-object-del", _sub_del); | ||
454 | |||
455 | if (!wd) return; | ||
456 | |||
457 | EINA_LIST_FOREACH(wd->items, l, it) | ||
458 | { | ||
459 | if (it->icon) | ||
460 | evas_object_event_callback_del(it->icon, | ||
461 | EVAS_CALLBACK_CHANGED_SIZE_HINTS, | ||
462 | _changed_size_hints); | ||
463 | if (it->end) | ||
464 | evas_object_event_callback_del(it->end, | ||
465 | EVAS_CALLBACK_CHANGED_SIZE_HINTS, | ||
466 | _changed_size_hints); | ||
467 | } | ||
468 | |||
469 | evas_object_event_callback_del(wd->scr, | ||
470 | EVAS_CALLBACK_CHANGED_SIZE_HINTS, | ||
471 | _changed_size_hints); | ||
472 | evas_object_event_callback_del(wd->box, | ||
473 | EVAS_CALLBACK_CHANGED_SIZE_HINTS, | ||
474 | _changed_size_hints); | ||
475 | } | ||
476 | |||
477 | static void | ||
478 | _del_hook(Evas_Object *obj) | ||
479 | { | ||
480 | Widget_Data *wd = elm_widget_data_get(obj); | ||
481 | Elm_List_Item *it; | ||
482 | Eina_List *n; | ||
483 | |||
484 | if (!wd) return; | ||
485 | if (wd->walking) | ||
486 | ERR("ERROR: list deleted while walking.\n"); | ||
487 | |||
488 | _elm_list_walk(wd); | ||
489 | EINA_LIST_FOREACH(wd->items, n, it) elm_widget_item_pre_notify_del(it); | ||
490 | _elm_list_unwalk(wd); | ||
491 | if (wd->to_delete) | ||
492 | ERR("ERROR: leaking nodes!\n"); | ||
493 | |||
494 | EINA_LIST_FREE(wd->items, it) | ||
495 | { | ||
496 | _elm_list_item_free(it); | ||
497 | elm_widget_item_free(it); | ||
498 | } | ||
499 | eina_list_free(wd->selected); | ||
500 | free(wd); | ||
501 | } | ||
502 | |||
503 | static void | ||
504 | _show_region_hook(void *data, Evas_Object *obj) | ||
505 | { | ||
506 | Widget_Data *wd = elm_widget_data_get(data); | ||
507 | Evas_Coord x, y, w, h; | ||
508 | if (!wd) return; | ||
509 | elm_widget_show_region_get(obj, &x, &y, &w, &h); | ||
510 | elm_smart_scroller_child_region_set(wd->scr, x, y, w, h); | ||
511 | } | ||
512 | |||
513 | static void | ||
514 | _disable_hook(Evas_Object *obj) | ||
515 | { | ||
516 | Widget_Data *wd = elm_widget_data_get(obj); | ||
517 | if (!wd) return; | ||
518 | if (elm_widget_disabled_get(obj)) | ||
519 | { | ||
520 | _signal_emit_hook(obj, "elm,state,disabled", "elm"); | ||
521 | elm_widget_scroll_freeze_push(obj); | ||
522 | elm_widget_scroll_hold_push(obj); | ||
523 | /* FIXME: if we get to have a way to only un-highlight items | ||
524 | * in the future, keeping them selected... */ | ||
525 | _deselect_all_items(wd); | ||
526 | } | ||
527 | else | ||
528 | { | ||
529 | _signal_emit_hook(obj, "elm,state,enabled", "elm"); | ||
530 | elm_widget_scroll_freeze_pop(obj); | ||
531 | elm_widget_scroll_hold_pop(obj); | ||
532 | } | ||
533 | } | ||
534 | |||
535 | static void | ||
536 | _sizing_eval(Evas_Object *obj) | ||
537 | { | ||
538 | |||
539 | Widget_Data *wd = elm_widget_data_get(obj); | ||
540 | if (!wd) return; | ||
541 | Evas_Coord vw, vh, minw, minh, maxw, maxh, w, h, vmw, vmh; | ||
542 | double xw, yw; | ||
543 | |||
544 | evas_object_size_hint_min_get(wd->box, &minw, &minh); | ||
545 | evas_object_size_hint_max_get(wd->box, &maxw, &maxh); | ||
546 | evas_object_size_hint_weight_get(wd->box, &xw, &yw); | ||
547 | if (!wd->scr) return; | ||
548 | elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh); | ||
549 | if (xw > 0.0) | ||
550 | { | ||
551 | if ((minw > 0) && (vw < minw)) vw = minw; | ||
552 | else if ((maxw > 0) && (vw > maxw)) vw = maxw; | ||
553 | } | ||
554 | else if (minw > 0) vw = minw; | ||
555 | if (yw > 0.0) | ||
556 | { | ||
557 | if ((minh > 0) && (vh < minh)) vh = minh; | ||
558 | else if ((maxh > 0) && (vh > maxh)) vh = maxh; | ||
559 | } | ||
560 | else if (minh > 0) vh = minh; | ||
561 | evas_object_resize(wd->box, vw, vh); | ||
562 | w = -1; | ||
563 | h = -1; | ||
564 | edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr), | ||
565 | &vmw, &vmh); | ||
566 | if (wd->scr_minw) w = vmw + minw; | ||
567 | if (wd->scr_minh) h = vmh + minh; | ||
568 | |||
569 | evas_object_size_hint_max_get(obj, &maxw, &maxh); | ||
570 | if ((maxw > 0) && (w > maxw)) | ||
571 | w = maxw; | ||
572 | if ((maxh > 0) && (h > maxh)) | ||
573 | h = maxh; | ||
574 | |||
575 | evas_object_size_hint_min_set(obj, w, h); | ||
576 | } | ||
577 | |||
578 | static void | ||
579 | _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source) | ||
580 | { | ||
581 | Widget_Data *wd = elm_widget_data_get(obj); | ||
582 | edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), | ||
583 | emission, source); | ||
584 | } | ||
585 | |||
586 | static void | ||
587 | _signal_callback_add_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data) | ||
588 | { | ||
589 | Widget_Data *wd = elm_widget_data_get(obj); | ||
590 | edje_object_signal_callback_add(elm_smart_scroller_edje_object_get(wd->scr), | ||
591 | emission, source, func_cb, data); | ||
592 | } | ||
593 | |||
594 | static void | ||
595 | _signal_callback_del_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data) | ||
596 | { | ||
597 | Widget_Data *wd = elm_widget_data_get(obj); | ||
598 | edje_object_signal_callback_del_full( | ||
599 | elm_smart_scroller_edje_object_get(wd->scr), | ||
600 | emission, source, func_cb, data); | ||
601 | } | ||
602 | |||
603 | static void | ||
604 | _mirrored_set(Evas_Object *obj, Eina_Bool rtl) | ||
605 | { | ||
606 | Widget_Data *wd = elm_widget_data_get(obj); | ||
607 | Elm_List_Item *it; | ||
608 | Eina_List *n; | ||
609 | |||
610 | if (!wd) return; | ||
611 | if (wd->scr) | ||
612 | elm_smart_scroller_mirrored_set(wd->scr, rtl); | ||
613 | |||
614 | EINA_LIST_FOREACH(wd->items, n, it) | ||
615 | edje_object_mirrored_set(VIEW(it), rtl); | ||
616 | } | ||
617 | |||
618 | static void | ||
619 | _theme_hook(Evas_Object *obj) | ||
620 | { | ||
621 | Widget_Data *wd = elm_widget_data_get(obj); | ||
622 | Elm_List_Item *it; | ||
623 | Eina_List *n; | ||
624 | |||
625 | if (!wd) return; | ||
626 | _elm_widget_mirrored_reload(obj); | ||
627 | _mirrored_set(obj, elm_widget_mirrored_get(obj)); | ||
628 | |||
629 | if (wd->scr) | ||
630 | { | ||
631 | Evas_Object *edj; | ||
632 | const char *str; | ||
633 | |||
634 | elm_smart_scroller_object_theme_set(obj, wd->scr, "list", "base", | ||
635 | elm_widget_style_get(obj)); | ||
636 | // edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale); | ||
637 | edj = elm_smart_scroller_edje_object_get(wd->scr); | ||
638 | str = edje_object_data_get(edj, "focus_highlight"); | ||
639 | if ((str) && (!strcmp(str, "on"))) | ||
640 | elm_widget_highlight_in_theme_set(obj, EINA_TRUE); | ||
641 | else | ||
642 | elm_widget_highlight_in_theme_set(obj, EINA_FALSE); | ||
643 | elm_object_style_set(wd->scr, elm_widget_style_get(obj)); | ||
644 | } | ||
645 | EINA_LIST_FOREACH(wd->items, n, it) | ||
646 | { | ||
647 | edje_object_scale_set(VIEW(it), elm_widget_scale_get(obj) * _elm_config->scale); | ||
648 | it->fixed = 0; | ||
649 | } | ||
650 | _fix_items(obj); | ||
651 | _sizing_eval(obj); | ||
652 | } | ||
653 | |||
654 | static void | ||
655 | _on_focus_hook(void *data __UNUSED__, Evas_Object *obj) | ||
656 | { | ||
657 | Widget_Data *wd = elm_widget_data_get(obj); | ||
658 | if (!wd) return; | ||
659 | if (elm_widget_focus_get(obj)) | ||
660 | { | ||
661 | edje_object_signal_emit(wd->self, "elm,action,focus", "elm"); | ||
662 | evas_object_focus_set(wd->self, EINA_TRUE); | ||
663 | |||
664 | if ((wd->selected) && (!wd->last_selected_item)) | ||
665 | wd->last_selected_item = eina_list_data_get(wd->selected); | ||
666 | } | ||
667 | else | ||
668 | { | ||
669 | edje_object_signal_emit(wd->self, "elm,action,unfocus", "elm"); | ||
670 | evas_object_focus_set(wd->self, EINA_FALSE); | ||
671 | } | ||
672 | } | ||
673 | |||
674 | static void | ||
675 | _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) | ||
676 | { | ||
677 | Widget_Data *wd = elm_widget_data_get(data); | ||
678 | if (!wd) return; | ||
679 | _fix_items(data); | ||
680 | _sizing_eval(data); | ||
681 | } | ||
682 | |||
683 | static void | ||
684 | _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info) | ||
685 | { | ||
686 | Widget_Data *wd = elm_widget_data_get(obj); | ||
687 | Evas_Object *sub = event_info; | ||
688 | const Eina_List *l; | ||
689 | Elm_List_Item *it; | ||
690 | |||
691 | if (!wd) return; | ||
692 | if (!sub) abort(); | ||
693 | if ((sub == wd->box) || (sub == wd->scr)) return; | ||
694 | |||
695 | EINA_LIST_FOREACH(wd->items, l, it) | ||
696 | { | ||
697 | if ((sub == it->icon) || (sub == it->end)) | ||
698 | { | ||
699 | if (it->icon == sub) it->icon = NULL; | ||
700 | if (it->end == sub) it->end = NULL; | ||
701 | evas_object_event_callback_del_full | ||
702 | (sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, | ||
703 | obj); | ||
704 | if (!wd->walking) | ||
705 | { | ||
706 | _fix_items(obj); | ||
707 | _sizing_eval(obj); | ||
708 | } | ||
709 | else | ||
710 | wd->fix_pending = EINA_TRUE; | ||
711 | break; | ||
712 | } | ||
713 | } | ||
714 | } | ||
715 | |||
716 | static void | ||
717 | _item_highlight(Elm_List_Item *it) | ||
718 | { | ||
719 | Evas_Object *obj = WIDGET(it); | ||
720 | Widget_Data *wd = elm_widget_data_get(obj); | ||
721 | const char *selectraise; | ||
722 | |||
723 | if (!wd) return; | ||
724 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it); | ||
725 | if ((it->highlighted) || (it->base.disabled) || | ||
726 | (wd->select_mode == ELM_OBJECT_SELECT_MODE_NONE)) return; | ||
727 | |||
728 | evas_object_ref(obj); | ||
729 | _elm_list_walk(wd); | ||
730 | |||
731 | edje_object_signal_emit(VIEW(it), "elm,state,selected", "elm"); | ||
732 | selectraise = edje_object_data_get(VIEW(it), "selectraise"); | ||
733 | if ((selectraise) && (!strcmp(selectraise, "on"))) | ||
734 | evas_object_raise(VIEW(it)); | ||
735 | it->highlighted = EINA_TRUE; | ||
736 | |||
737 | _elm_list_unwalk(wd); | ||
738 | evas_object_unref(obj); | ||
739 | } | ||
740 | |||
741 | static void | ||
742 | _item_select(Elm_List_Item *it) | ||
743 | { | ||
744 | Evas_Object *obj = WIDGET(it); | ||
745 | Widget_Data *wd = elm_widget_data_get(obj); | ||
746 | |||
747 | if (!wd) return; | ||
748 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it); | ||
749 | if (it->base.disabled || (wd->select_mode == ELM_OBJECT_SELECT_MODE_NONE)) return; | ||
750 | if (it->selected) | ||
751 | { | ||
752 | if (wd->select_mode == ELM_OBJECT_SELECT_MODE_ALWAYS) goto call; | ||
753 | return; | ||
754 | } | ||
755 | it->selected = EINA_TRUE; | ||
756 | wd->selected = eina_list_append(wd->selected, it); | ||
757 | |||
758 | call: | ||
759 | evas_object_ref(obj); | ||
760 | _elm_list_walk(wd); | ||
761 | |||
762 | if (it->func) it->func((void *)it->base.data, WIDGET(it), it); | ||
763 | evas_object_smart_callback_call(obj, SIG_SELECTED, it); | ||
764 | it->wd->last_selected_item = (Elm_Object_Item *)it; | ||
765 | |||
766 | _elm_list_unwalk(wd); | ||
767 | evas_object_unref(obj); | ||
768 | } | ||
769 | |||
770 | static void | ||
771 | _item_unselect(Elm_List_Item *it) | ||
772 | { | ||
773 | Evas_Object *obj = WIDGET(it); | ||
774 | Widget_Data *wd = elm_widget_data_get(obj); | ||
775 | const char *stacking, *selectraise; | ||
776 | |||
777 | if (!wd) return; | ||
778 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it); | ||
779 | if (!it->highlighted) return; | ||
780 | |||
781 | evas_object_ref(obj); | ||
782 | _elm_list_walk(wd); | ||
783 | |||
784 | edje_object_signal_emit(VIEW(it), "elm,state,unselected", "elm"); | ||
785 | stacking = edje_object_data_get(VIEW(it), "stacking"); | ||
786 | selectraise = edje_object_data_get(VIEW(it), "selectraise"); | ||
787 | if ((selectraise) && (!strcmp(selectraise, "on"))) | ||
788 | { | ||
789 | if ((stacking) && (!strcmp(stacking, "below"))) | ||
790 | evas_object_lower(VIEW(it)); | ||
791 | } | ||
792 | it->highlighted = EINA_FALSE; | ||
793 | if (it->selected) | ||
794 | { | ||
795 | it->selected = EINA_FALSE; | ||
796 | wd->selected = eina_list_remove(wd->selected, it); | ||
797 | evas_object_smart_callback_call(WIDGET(it), SIG_UNSELECTED, it); | ||
798 | } | ||
799 | |||
800 | _elm_list_unwalk(wd); | ||
801 | evas_object_unref(obj); | ||
802 | } | ||
803 | |||
804 | static Eina_Bool | ||
805 | _swipe_cancel(void *data) | ||
806 | { | ||
807 | Elm_List_Item *it = data; | ||
808 | Widget_Data *wd = elm_widget_data_get(WIDGET(it)); | ||
809 | |||
810 | if (!wd) return ECORE_CALLBACK_CANCEL; | ||
811 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, ECORE_CALLBACK_CANCEL); | ||
812 | wd->swipe = EINA_FALSE; | ||
813 | wd->movements = 0; | ||
814 | return ECORE_CALLBACK_RENEW; | ||
815 | } | ||
816 | |||
817 | static void | ||
818 | _mouse_move(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) | ||
819 | { | ||
820 | Elm_List_Item *it = data; | ||
821 | Evas_Object *obj2 = WIDGET(it); | ||
822 | Widget_Data *wd = elm_widget_data_get(obj2); | ||
823 | Evas_Event_Mouse_Move *ev = event_info; | ||
824 | |||
825 | if (!wd) return; | ||
826 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it); | ||
827 | |||
828 | evas_object_ref(obj2); | ||
829 | _elm_list_walk(wd); | ||
830 | |||
831 | if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) | ||
832 | { | ||
833 | if (!wd->on_hold) | ||
834 | { | ||
835 | wd->on_hold = EINA_TRUE; | ||
836 | if (it->long_timer) | ||
837 | { | ||
838 | ecore_timer_del(it->long_timer); | ||
839 | it->long_timer = NULL; | ||
840 | } | ||
841 | if (!wd->wasselected) | ||
842 | _item_unselect(it); | ||
843 | } | ||
844 | if (wd->movements == SWIPE_MOVES) wd->swipe = EINA_TRUE; | ||
845 | else | ||
846 | { | ||
847 | wd->history[wd->movements].x = ev->cur.canvas.x; | ||
848 | wd->history[wd->movements].y = ev->cur.canvas.y; | ||
849 | if (abs((wd->history[wd->movements].x - wd->history[0].x)) > 40) | ||
850 | wd->swipe = EINA_TRUE; | ||
851 | else | ||
852 | wd->movements++; | ||
853 | } | ||
854 | } | ||
855 | |||
856 | _elm_list_unwalk(wd); | ||
857 | evas_object_unref(obj2); | ||
858 | } | ||
859 | |||
860 | static void | ||
861 | _edge_left(void *data, Evas_Object *scr __UNUSED__, void *event_info __UNUSED__) | ||
862 | { | ||
863 | Evas_Object *obj = data; | ||
864 | evas_object_smart_callback_call(obj, SIG_EDGE_LEFT, NULL); | ||
865 | } | ||
866 | |||
867 | static void | ||
868 | _edge_right(void *data, Evas_Object *scr __UNUSED__, void *event_info __UNUSED__) | ||
869 | { | ||
870 | Evas_Object *obj = data; | ||
871 | evas_object_smart_callback_call(obj, SIG_EDGE_RIGHT, NULL); | ||
872 | } | ||
873 | |||
874 | static void | ||
875 | _edge_top(void *data, Evas_Object *scr __UNUSED__, void *event_info __UNUSED__) | ||
876 | { | ||
877 | Evas_Object *obj = data; | ||
878 | evas_object_smart_callback_call(obj, SIG_EDGE_TOP, NULL); | ||
879 | } | ||
880 | |||
881 | static void | ||
882 | _edge_bottom(void *data, Evas_Object *scr __UNUSED__, void *event_info __UNUSED__) | ||
883 | { | ||
884 | Evas_Object *obj = data; | ||
885 | evas_object_smart_callback_call(obj, SIG_EDGE_BOTTOM, NULL); | ||
886 | } | ||
887 | |||
888 | static Eina_Bool | ||
889 | _long_press(void *data) | ||
890 | { | ||
891 | Elm_List_Item *it = data; | ||
892 | Evas_Object *obj = WIDGET(it); | ||
893 | Widget_Data *wd = elm_widget_data_get(obj); | ||
894 | |||
895 | if (!wd) goto end; | ||
896 | |||
897 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, ECORE_CALLBACK_CANCEL); | ||
898 | it->long_timer = NULL; | ||
899 | if (it->base.disabled) goto end; | ||
900 | |||
901 | wd->longpressed = EINA_TRUE; | ||
902 | evas_object_smart_callback_call(WIDGET(it), SIG_LONGPRESSED, it); | ||
903 | |||
904 | end: | ||
905 | return ECORE_CALLBACK_CANCEL; | ||
906 | } | ||
907 | |||
908 | static void | ||
909 | _swipe(Elm_List_Item *it) | ||
910 | { | ||
911 | int i, sum = 0; | ||
912 | Widget_Data *wd = elm_widget_data_get(WIDGET(it)); | ||
913 | |||
914 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it); | ||
915 | if (!wd) return; | ||
916 | wd->swipe = EINA_FALSE; | ||
917 | for (i = 0; i < wd->movements; i++) | ||
918 | { | ||
919 | sum += wd->history[i].x; | ||
920 | if (abs(wd->history[0].y - wd->history[i].y) > 10) return; | ||
921 | } | ||
922 | |||
923 | sum /= wd->movements; | ||
924 | if (abs(sum - wd->history[0].x) <= 10) return; | ||
925 | evas_object_smart_callback_call(WIDGET(it), "swipe", it); | ||
926 | } | ||
927 | |||
928 | static void | ||
929 | _mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) | ||
930 | { | ||
931 | Elm_List_Item *it = data; | ||
932 | Evas_Object *obj2 = WIDGET(it); | ||
933 | Widget_Data *wd = elm_widget_data_get(obj2); | ||
934 | Evas_Event_Mouse_Down *ev = event_info; | ||
935 | |||
936 | if (!wd) return; | ||
937 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it); | ||
938 | if (ev->button != 1) return; | ||
939 | if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE; | ||
940 | else wd->on_hold = EINA_FALSE; | ||
941 | if (wd->on_hold) return; | ||
942 | wd->wasselected = it->selected; | ||
943 | |||
944 | evas_object_ref(obj2); | ||
945 | _elm_list_walk(wd); | ||
946 | |||
947 | _item_highlight(it); | ||
948 | wd->longpressed = EINA_FALSE; | ||
949 | if (it->long_timer) ecore_timer_del(it->long_timer); | ||
950 | it->long_timer = ecore_timer_add(_elm_config->longpress_timeout, _long_press, it); | ||
951 | if (it->swipe_timer) ecore_timer_del(it->swipe_timer); | ||
952 | it->swipe_timer = ecore_timer_add(0.4, _swipe_cancel, it); | ||
953 | /* Always call the callbacks last - the user may delete our context! */ | ||
954 | if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK) | ||
955 | { | ||
956 | evas_object_smart_callback_call(WIDGET(it), SIG_CLICKED_DOUBLE, it); | ||
957 | evas_object_smart_callback_call(WIDGET(it), SIG_ACTIVATED, it); | ||
958 | } | ||
959 | wd->swipe = EINA_FALSE; | ||
960 | wd->movements = 0; | ||
961 | |||
962 | _elm_list_unwalk(wd); | ||
963 | evas_object_unref(obj2); | ||
964 | } | ||
965 | |||
966 | static void | ||
967 | _mouse_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) | ||
968 | { | ||
969 | Elm_List_Item *it = data; | ||
970 | Evas_Object *obj2 = WIDGET(it); | ||
971 | Widget_Data *wd = elm_widget_data_get(obj2); | ||
972 | Evas_Event_Mouse_Up *ev = event_info; | ||
973 | |||
974 | if (!wd) return; | ||
975 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it); | ||
976 | if (ev->button != 1) return; | ||
977 | if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE; | ||
978 | else wd->on_hold = EINA_FALSE; | ||
979 | wd->longpressed = EINA_FALSE; | ||
980 | if (it->long_timer) | ||
981 | { | ||
982 | ecore_timer_del(it->long_timer); | ||
983 | it->long_timer = NULL; | ||
984 | } | ||
985 | if (it->swipe_timer) | ||
986 | { | ||
987 | ecore_timer_del(it->swipe_timer); | ||
988 | it->swipe_timer = NULL; | ||
989 | } | ||
990 | if (wd->on_hold) | ||
991 | { | ||
992 | if (wd->swipe) _swipe(data); | ||
993 | wd->on_hold = EINA_FALSE; | ||
994 | return; | ||
995 | } | ||
996 | if (wd->longpressed) | ||
997 | { | ||
998 | if (!wd->wasselected) _item_unselect(it); | ||
999 | wd->wasselected = 0; | ||
1000 | return; | ||
1001 | } | ||
1002 | |||
1003 | if (it->base.disabled) | ||
1004 | return; | ||
1005 | if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; | ||
1006 | |||
1007 | evas_object_ref(obj2); | ||
1008 | _elm_list_walk(wd); | ||
1009 | |||
1010 | if (wd->multi) | ||
1011 | { | ||
1012 | if (!it->selected) | ||
1013 | { | ||
1014 | _item_highlight(it); | ||
1015 | _item_select(it); | ||
1016 | } | ||
1017 | else _item_unselect(it); | ||
1018 | } | ||
1019 | else | ||
1020 | { | ||
1021 | if (!it->selected) | ||
1022 | { | ||
1023 | while (wd->selected) | ||
1024 | _item_unselect(wd->selected->data); | ||
1025 | _item_highlight(it); | ||
1026 | _item_select(it); | ||
1027 | } | ||
1028 | else | ||
1029 | { | ||
1030 | const Eina_List *l, *l_next; | ||
1031 | Elm_List_Item *it2; | ||
1032 | |||
1033 | EINA_LIST_FOREACH_SAFE(wd->selected, l, l_next, it2) | ||
1034 | if (it2 != it) _item_unselect(it2); | ||
1035 | _item_highlight(it); | ||
1036 | _item_select(it); | ||
1037 | } | ||
1038 | } | ||
1039 | |||
1040 | _elm_list_unwalk(wd); | ||
1041 | evas_object_unref(obj2); | ||
1042 | } | ||
1043 | |||
1044 | static void | ||
1045 | _item_disable(Elm_Object_Item *it) | ||
1046 | { | ||
1047 | Elm_List_Item *item = (Elm_List_Item *)it; | ||
1048 | if (item->base.disabled) | ||
1049 | edje_object_signal_emit(VIEW(item), "elm,state,disabled", "elm"); | ||
1050 | else | ||
1051 | edje_object_signal_emit(VIEW(item), "elm,state,enabled", "elm"); | ||
1052 | } | ||
1053 | |||
1054 | static void | ||
1055 | _item_content_set_hook(Elm_Object_Item *it, const char *part, Evas_Object *content) | ||
1056 | { | ||
1057 | Elm_List_Item *item = (Elm_List_Item *)it; | ||
1058 | Evas_Object **icon_p = NULL; | ||
1059 | Eina_Bool dummy = EINA_FALSE; | ||
1060 | |||
1061 | if ((!part) || (!strcmp(part, "start"))) | ||
1062 | { | ||
1063 | icon_p = &(item->icon); | ||
1064 | dummy = item->dummy_icon; | ||
1065 | if (!content) item->dummy_icon = EINA_TRUE; | ||
1066 | else item->dummy_icon = EINA_FALSE; | ||
1067 | } | ||
1068 | else if (!strcmp(part, "end")) | ||
1069 | { | ||
1070 | icon_p = &(item->end); | ||
1071 | dummy = item->dummy_end; | ||
1072 | if (!content) item->dummy_end = EINA_TRUE; | ||
1073 | else item->dummy_end = EINA_FALSE; | ||
1074 | } | ||
1075 | else | ||
1076 | return; | ||
1077 | |||
1078 | if (content == *icon_p) return; | ||
1079 | if ((dummy) && (!content)) return; | ||
1080 | if (dummy) evas_object_del(*icon_p); | ||
1081 | if (!content) | ||
1082 | { | ||
1083 | content = evas_object_rectangle_add(evas_object_evas_get(WIDGET(item))); | ||
1084 | evas_object_color_set(content, 0, 0, 0, 0); | ||
1085 | } | ||
1086 | if (*icon_p) | ||
1087 | { | ||
1088 | evas_object_del(*icon_p); | ||
1089 | *icon_p = NULL; | ||
1090 | } | ||
1091 | *icon_p = content; | ||
1092 | if (VIEW(item)) | ||
1093 | edje_object_part_swallow(VIEW(item), "elm.swallow.icon", content); | ||
1094 | } | ||
1095 | |||
1096 | static Evas_Object * | ||
1097 | _item_content_get_hook(const Elm_Object_Item *it, const char *part) | ||
1098 | { | ||
1099 | Elm_List_Item *item = (Elm_List_Item *)it; | ||
1100 | |||
1101 | if ((!part) || (!strcmp(part, "start"))) | ||
1102 | { | ||
1103 | if (item->dummy_icon) return NULL; | ||
1104 | return item->icon; | ||
1105 | } | ||
1106 | else if (!strcmp(part, "end")) | ||
1107 | { | ||
1108 | if (item->dummy_end) return NULL; | ||
1109 | return item->end; | ||
1110 | } | ||
1111 | return NULL; | ||
1112 | } | ||
1113 | |||
1114 | static Evas_Object * | ||
1115 | _item_content_unset_hook(const Elm_Object_Item *it, const char *part) | ||
1116 | { | ||
1117 | Elm_List_Item *item = (Elm_List_Item *)it; | ||
1118 | |||
1119 | if ((!part) || (!strcmp(part, "start"))) | ||
1120 | { | ||
1121 | Evas_Object *obj = item->icon; | ||
1122 | _item_content_set_hook((Elm_Object_Item *)it, part, NULL); | ||
1123 | return obj; | ||
1124 | } | ||
1125 | else if (!strcmp(part, "end")) | ||
1126 | { | ||
1127 | Evas_Object *obj = item->end; | ||
1128 | _item_content_set_hook((Elm_Object_Item *)it, part, NULL); | ||
1129 | return obj; | ||
1130 | } | ||
1131 | return NULL; | ||
1132 | } | ||
1133 | |||
1134 | static void | ||
1135 | _item_text_set_hook(Elm_Object_Item *it, const char *part, const char *text) | ||
1136 | { | ||
1137 | Elm_List_Item *list_it = (Elm_List_Item *)it; | ||
1138 | if (part && strcmp(part, "default")) return; | ||
1139 | if (!eina_stringshare_replace(&list_it->label, text)) return; | ||
1140 | if (VIEW(list_it)) | ||
1141 | edje_object_part_text_escaped_set(VIEW(list_it), "elm.text", text); | ||
1142 | } | ||
1143 | |||
1144 | static const char * | ||
1145 | _item_text_get_hook(const Elm_Object_Item *it, const char *part) | ||
1146 | { | ||
1147 | if (part && strcmp(part, "default")) return NULL; | ||
1148 | return ((Elm_List_Item *)it)->label; | ||
1149 | } | ||
1150 | |||
1151 | static Eina_Bool | ||
1152 | _item_del_pre_hook(Elm_Object_Item *it) | ||
1153 | { | ||
1154 | Evas_Object *obj = WIDGET(it); | ||
1155 | Elm_List_Item *item = (Elm_List_Item *)it; | ||
1156 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1157 | if (!wd) return EINA_FALSE; | ||
1158 | |||
1159 | if (item->selected) _item_unselect(item); | ||
1160 | |||
1161 | if (wd->walking > 0) | ||
1162 | { | ||
1163 | if (item->deleted) return EINA_FALSE; | ||
1164 | item->deleted = EINA_TRUE; | ||
1165 | wd->to_delete = eina_list_append(wd->to_delete, item); | ||
1166 | return EINA_FALSE; | ||
1167 | } | ||
1168 | |||
1169 | wd->items = eina_list_remove_list(wd->items, item->node); | ||
1170 | |||
1171 | evas_object_ref(obj); | ||
1172 | _elm_list_walk(wd); | ||
1173 | |||
1174 | _elm_list_item_free(item); | ||
1175 | |||
1176 | _elm_list_unwalk(wd); | ||
1177 | evas_object_unref(obj); | ||
1178 | |||
1179 | return EINA_TRUE; | ||
1180 | } | ||
1181 | |||
1182 | static Elm_List_Item * | ||
1183 | _item_new(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data) | ||
1184 | { | ||
1185 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1186 | Elm_List_Item *it; | ||
1187 | |||
1188 | if (!wd) return NULL; | ||
1189 | it = elm_widget_item_new(obj, Elm_List_Item); | ||
1190 | it->wd = wd; | ||
1191 | it->label = eina_stringshare_add(label); | ||
1192 | it->icon = icon; | ||
1193 | it->end = end; | ||
1194 | it->func = func; | ||
1195 | it->base.data = data; | ||
1196 | VIEW(it) = edje_object_add(evas_object_evas_get(obj)); | ||
1197 | edje_object_mirrored_set(VIEW(it), elm_widget_mirrored_get(obj)); | ||
1198 | evas_object_event_callback_add(VIEW(it), EVAS_CALLBACK_MOUSE_DOWN, | ||
1199 | _mouse_down, it); | ||
1200 | evas_object_event_callback_add(VIEW(it), EVAS_CALLBACK_MOUSE_UP, | ||
1201 | _mouse_up, it); | ||
1202 | evas_object_event_callback_add(VIEW(it), EVAS_CALLBACK_MOUSE_MOVE, | ||
1203 | _mouse_move, it); | ||
1204 | evas_object_size_hint_weight_set(VIEW(it), EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); | ||
1205 | evas_object_size_hint_align_set(VIEW(it), EVAS_HINT_FILL, EVAS_HINT_FILL); | ||
1206 | if (it->icon) | ||
1207 | { | ||
1208 | elm_widget_sub_object_add(obj, it->icon); | ||
1209 | evas_object_event_callback_add(it->icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS, | ||
1210 | _changed_size_hints, obj); | ||
1211 | } | ||
1212 | if (it->end) | ||
1213 | { | ||
1214 | elm_widget_sub_object_add(obj, it->end); | ||
1215 | evas_object_event_callback_add(it->end, EVAS_CALLBACK_CHANGED_SIZE_HINTS, | ||
1216 | _changed_size_hints, obj); | ||
1217 | } | ||
1218 | elm_widget_item_disable_hook_set(it, _item_disable); | ||
1219 | elm_widget_item_content_set_hook_set(it, _item_content_set_hook); | ||
1220 | elm_widget_item_content_get_hook_set(it, _item_content_get_hook); | ||
1221 | elm_widget_item_content_unset_hook_set(it, _item_content_unset_hook); | ||
1222 | elm_widget_item_text_set_hook_set(it, _item_text_set_hook); | ||
1223 | elm_widget_item_text_get_hook_set(it, _item_text_get_hook); | ||
1224 | elm_widget_item_del_pre_hook_set(it, _item_del_pre_hook); | ||
1225 | return it; | ||
1226 | } | ||
1227 | |||
1228 | static void | ||
1229 | _elm_list_mode_set_internal(Widget_Data *wd) | ||
1230 | { | ||
1231 | if (!wd->scr) | ||
1232 | return; | ||
1233 | |||
1234 | if (wd->mode == ELM_LIST_LIMIT) | ||
1235 | { | ||
1236 | if (!wd->h_mode) | ||
1237 | { | ||
1238 | wd->scr_minw = EINA_TRUE; | ||
1239 | wd->scr_minh = EINA_FALSE; | ||
1240 | } | ||
1241 | else | ||
1242 | { | ||
1243 | wd->scr_minw = EINA_FALSE; | ||
1244 | wd->scr_minh = EINA_TRUE; | ||
1245 | } | ||
1246 | } | ||
1247 | else if (wd->mode == ELM_LIST_EXPAND) | ||
1248 | { | ||
1249 | wd->scr_minw = EINA_TRUE; | ||
1250 | wd->scr_minh = EINA_TRUE; | ||
1251 | } | ||
1252 | else | ||
1253 | { | ||
1254 | wd->scr_minw = EINA_FALSE; | ||
1255 | wd->scr_minh = EINA_FALSE; | ||
1256 | } | ||
1257 | |||
1258 | _sizing_eval(wd->self); | ||
1259 | } | ||
1260 | |||
1261 | static void | ||
1262 | _fix_items(Evas_Object *obj) | ||
1263 | { | ||
1264 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1265 | if (!wd) return; | ||
1266 | const Eina_List *l; | ||
1267 | Elm_List_Item *it; | ||
1268 | Evas_Coord minw[2] = { 0, 0 }, minh[2] = { 0, 0 }; | ||
1269 | Evas_Coord mw, mh; | ||
1270 | int i, redo = 0; | ||
1271 | const char *style = elm_widget_style_get(obj); | ||
1272 | const char *it_plain = wd->h_mode ? "h_item" : "item"; | ||
1273 | const char *it_odd = wd->h_mode ? "h_item_odd" : "item_odd"; | ||
1274 | const char *it_compress = wd->h_mode ? "h_item_compress" : "item_compress"; | ||
1275 | const char *it_compress_odd = wd->h_mode ? "h_item_compress_odd" : "item_compress_odd"; | ||
1276 | |||
1277 | if (wd->walking) | ||
1278 | { | ||
1279 | wd->fix_pending = EINA_TRUE; | ||
1280 | return; | ||
1281 | } | ||
1282 | |||
1283 | evas_object_ref(obj); | ||
1284 | _elm_list_walk(wd); // watch out "return" before unwalk! | ||
1285 | |||
1286 | EINA_LIST_FOREACH(wd->items, l, it) | ||
1287 | { | ||
1288 | if (it->deleted) continue; | ||
1289 | if (it->icon) | ||
1290 | { | ||
1291 | evas_object_size_hint_min_get(it->icon, &mw, &mh); | ||
1292 | if (mw > minw[0]) minw[0] = mw; | ||
1293 | if (mh > minh[0]) minh[0] = mh; | ||
1294 | } | ||
1295 | if (it->end) | ||
1296 | { | ||
1297 | evas_object_size_hint_min_get(it->end, &mw, &mh); | ||
1298 | if (mw > minw[1]) minw[1] = mw; | ||
1299 | if (mh > minh[1]) minh[1] = mh; | ||
1300 | } | ||
1301 | } | ||
1302 | |||
1303 | if ((minw[0] != wd->minw[0]) || (minw[1] != wd->minw[1]) || | ||
1304 | (minw[0] != wd->minh[0]) || (minh[1] != wd->minh[1])) | ||
1305 | { | ||
1306 | wd->minw[0] = minw[0]; | ||
1307 | wd->minw[1] = minw[1]; | ||
1308 | wd->minh[0] = minh[0]; | ||
1309 | wd->minh[1] = minh[1]; | ||
1310 | redo = 1; | ||
1311 | } | ||
1312 | i = 0; | ||
1313 | EINA_LIST_FOREACH(wd->items, l, it) | ||
1314 | { | ||
1315 | if (it->deleted) | ||
1316 | continue; | ||
1317 | |||
1318 | it->even = i & 0x1; | ||
1319 | if ((it->even != it->is_even) || (!it->fixed) || (redo)) | ||
1320 | { | ||
1321 | const char *stacking; | ||
1322 | |||
1323 | /* FIXME: separators' themes seem to be b0rked */ | ||
1324 | if (it->is_separator) | ||
1325 | _elm_theme_object_set(obj, VIEW(it), "separator", | ||
1326 | wd->h_mode ? "horizontal" : "vertical", | ||
1327 | style); | ||
1328 | else if (wd->mode == ELM_LIST_COMPRESS) | ||
1329 | { | ||
1330 | if (it->even) | ||
1331 | _elm_theme_object_set(obj, VIEW(it), "list", | ||
1332 | it_compress, style); | ||
1333 | else | ||
1334 | _elm_theme_object_set(obj, VIEW(it), "list", | ||
1335 | it_compress_odd, style); | ||
1336 | } | ||
1337 | else | ||
1338 | { | ||
1339 | if (it->even) | ||
1340 | _elm_theme_object_set(obj, VIEW(it), "list", it_plain, | ||
1341 | style); | ||
1342 | else | ||
1343 | _elm_theme_object_set(obj, VIEW(it), "list", it_odd, | ||
1344 | style); | ||
1345 | } | ||
1346 | stacking = edje_object_data_get(VIEW(it), "stacking"); | ||
1347 | if (stacking) | ||
1348 | { | ||
1349 | if (!strcmp(stacking, "below")) | ||
1350 | evas_object_lower(VIEW(it)); | ||
1351 | else if (!strcmp(stacking, "above")) | ||
1352 | evas_object_raise(VIEW(it)); | ||
1353 | } | ||
1354 | edje_object_part_text_escaped_set(VIEW(it), "elm.text", it->label); | ||
1355 | |||
1356 | if ((!it->icon) && (minh[0] > 0)) | ||
1357 | { | ||
1358 | it->icon = evas_object_rectangle_add(evas_object_evas_get(VIEW(it))); | ||
1359 | evas_object_color_set(it->icon, 0, 0, 0, 0); | ||
1360 | it->dummy_icon = EINA_TRUE; | ||
1361 | } | ||
1362 | if ((!it->end) && (minh[1] > 0)) | ||
1363 | { | ||
1364 | it->end = evas_object_rectangle_add(evas_object_evas_get(VIEW(it))); | ||
1365 | evas_object_color_set(it->end, 0, 0, 0, 0); | ||
1366 | it->dummy_end = EINA_TRUE; | ||
1367 | } | ||
1368 | if (it->icon) | ||
1369 | { | ||
1370 | evas_object_size_hint_min_set(it->icon, minw[0], minh[0]); | ||
1371 | evas_object_size_hint_max_set(it->icon, 99999, 99999); | ||
1372 | edje_object_part_swallow(VIEW(it), "elm.swallow.icon", it->icon); | ||
1373 | } | ||
1374 | if (it->end) | ||
1375 | { | ||
1376 | evas_object_size_hint_min_set(it->end, minw[1], minh[1]); | ||
1377 | evas_object_size_hint_max_set(it->end, 99999, 99999); | ||
1378 | edje_object_part_swallow(VIEW(it), "elm.swallow.end", it->end); | ||
1379 | } | ||
1380 | if (!it->fixed) | ||
1381 | { | ||
1382 | // this may call up user and it may modify the list item | ||
1383 | // but we're safe as we're flagged as walking. | ||
1384 | // just don't process further | ||
1385 | edje_object_message_signal_process(VIEW(it)); | ||
1386 | if (it->deleted) | ||
1387 | continue; | ||
1388 | mw = mh = -1; | ||
1389 | elm_coords_finger_size_adjust(1, &mw, 1, &mh); | ||
1390 | edje_object_size_min_restricted_calc(VIEW(it), &mw, &mh, mw, mh); | ||
1391 | elm_coords_finger_size_adjust(1, &mw, 1, &mh); | ||
1392 | evas_object_size_hint_min_set(VIEW(it), mw, mh); | ||
1393 | evas_object_show(VIEW(it)); | ||
1394 | } | ||
1395 | if ((it->selected) || (it->highlighted)) | ||
1396 | { | ||
1397 | const char *selectraise; | ||
1398 | |||
1399 | // this may call up user and it may modify the list item | ||
1400 | // but we're safe as we're flagged as walking. | ||
1401 | // just don't process further | ||
1402 | edje_object_signal_emit(VIEW(it), "elm,state,selected", "elm"); | ||
1403 | if (it->deleted) | ||
1404 | continue; | ||
1405 | |||
1406 | selectraise = edje_object_data_get(VIEW(it), "selectraise"); | ||
1407 | if ((selectraise) && (!strcmp(selectraise, "on"))) | ||
1408 | evas_object_raise(VIEW(it)); | ||
1409 | } | ||
1410 | if (it->base.disabled) | ||
1411 | edje_object_signal_emit(VIEW(it), "elm,state,disabled", | ||
1412 | "elm"); | ||
1413 | |||
1414 | it->fixed = EINA_TRUE; | ||
1415 | it->is_even = it->even; | ||
1416 | } | ||
1417 | i++; | ||
1418 | } | ||
1419 | |||
1420 | mw = 0; mh = 0; | ||
1421 | evas_object_size_hint_min_get(wd->box, &mw, &mh); | ||
1422 | |||
1423 | _elm_list_mode_set_internal(wd); | ||
1424 | |||
1425 | _elm_list_unwalk(wd); | ||
1426 | evas_object_unref(obj); | ||
1427 | } | ||
1428 | |||
1429 | static void | ||
1430 | _hold_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__) | ||
1431 | { | ||
1432 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1433 | if (!wd) return; | ||
1434 | if (wd->scr) | ||
1435 | elm_smart_scroller_hold_set(wd->scr, EINA_TRUE); | ||
1436 | } | ||
1437 | |||
1438 | static void | ||
1439 | _hold_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__) | ||
1440 | { | ||
1441 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1442 | if (!wd) return; | ||
1443 | if (wd->scr) | ||
1444 | elm_smart_scroller_hold_set(wd->scr, EINA_FALSE); | ||
1445 | } | ||
1446 | |||
1447 | static void | ||
1448 | _freeze_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__) | ||
1449 | { | ||
1450 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1451 | if (!wd) return; | ||
1452 | if (wd->scr) | ||
1453 | elm_smart_scroller_freeze_set(wd->scr, EINA_TRUE); | ||
1454 | } | ||
1455 | |||
1456 | static void | ||
1457 | _freeze_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__) | ||
1458 | { | ||
1459 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1460 | if (!wd) return; | ||
1461 | if (wd->scr) | ||
1462 | elm_smart_scroller_freeze_set(wd->scr, EINA_FALSE); | ||
1463 | } | ||
1464 | |||
1465 | static void | ||
1466 | _resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) | ||
1467 | { | ||
1468 | _sizing_eval(data); | ||
1469 | } | ||
1470 | |||
1471 | EAPI Evas_Object * | ||
1472 | elm_list_add(Evas_Object *parent) | ||
1473 | { | ||
1474 | Evas_Object *obj; | ||
1475 | Evas *e; | ||
1476 | Widget_Data *wd; | ||
1477 | Evas_Coord minw, minh; | ||
1478 | |||
1479 | ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL); | ||
1480 | |||
1481 | ELM_SET_WIDTYPE(widtype, "list"); | ||
1482 | elm_widget_type_set(obj, "list"); | ||
1483 | elm_widget_sub_object_add(parent, obj); | ||
1484 | elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL); | ||
1485 | elm_widget_data_set(obj, wd); | ||
1486 | elm_widget_del_pre_hook_set(obj, _del_pre_hook); | ||
1487 | elm_widget_del_hook_set(obj, _del_hook); | ||
1488 | elm_widget_theme_hook_set(obj, _theme_hook); | ||
1489 | elm_widget_disable_hook_set(obj, _disable_hook); | ||
1490 | elm_widget_can_focus_set(obj, EINA_TRUE); | ||
1491 | elm_widget_signal_emit_hook_set(obj, _signal_emit_hook); | ||
1492 | elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook); | ||
1493 | elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook); | ||
1494 | elm_widget_event_hook_set(obj, _event_hook); | ||
1495 | elm_widget_translate_hook_set(obj, _translate_hook); | ||
1496 | |||
1497 | wd->self = obj; | ||
1498 | wd->scr = elm_smart_scroller_add(e); | ||
1499 | elm_smart_scroller_widget_set(wd->scr, obj); | ||
1500 | elm_widget_resize_object_set(obj, wd->scr); | ||
1501 | evas_object_event_callback_add(wd->scr, EVAS_CALLBACK_CHANGED_SIZE_HINTS, | ||
1502 | _changed_size_hints, obj); | ||
1503 | edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr), &minw, &minh); | ||
1504 | evas_object_size_hint_min_set(obj, minw, minh); | ||
1505 | evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize, obj); | ||
1506 | |||
1507 | elm_smart_scroller_bounce_allow_set(wd->scr, EINA_FALSE, | ||
1508 | _elm_config->thumbscroll_bounce_enable); | ||
1509 | |||
1510 | wd->box = elm_box_add(parent); | ||
1511 | elm_box_homogeneous_set(wd->box, 1); | ||
1512 | evas_object_size_hint_weight_set(wd->box, EVAS_HINT_EXPAND, 0.0); | ||
1513 | evas_object_size_hint_align_set(wd->box, EVAS_HINT_FILL, 0.0); | ||
1514 | elm_widget_on_show_region_hook_set(wd->box, _show_region_hook, obj); | ||
1515 | elm_widget_sub_object_add(obj, wd->box); | ||
1516 | elm_smart_scroller_child_set(wd->scr, wd->box); | ||
1517 | evas_object_event_callback_add(wd->box, EVAS_CALLBACK_CHANGED_SIZE_HINTS, | ||
1518 | _changed_size_hints, obj); | ||
1519 | |||
1520 | evas_object_show(wd->box); | ||
1521 | |||
1522 | _theme_hook(obj); | ||
1523 | |||
1524 | wd->mode = ELM_LIST_SCROLL; | ||
1525 | |||
1526 | evas_object_smart_callback_add(wd->scr, "edge,left", _edge_left, obj); | ||
1527 | evas_object_smart_callback_add(wd->scr, "edge,right", _edge_right, obj); | ||
1528 | evas_object_smart_callback_add(wd->scr, "edge,top", _edge_top, obj); | ||
1529 | evas_object_smart_callback_add(wd->scr, "edge,bottom", _edge_bottom, obj); | ||
1530 | |||
1531 | evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj); | ||
1532 | evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj); | ||
1533 | evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj); | ||
1534 | evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj); | ||
1535 | evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj); | ||
1536 | |||
1537 | evas_object_smart_callbacks_descriptions_set(obj, _signals); | ||
1538 | |||
1539 | _mirrored_set(obj, elm_widget_mirrored_get(obj)); | ||
1540 | _sizing_eval(obj); | ||
1541 | return obj; | ||
1542 | } | ||
1543 | |||
1544 | EAPI void | ||
1545 | elm_list_go(Evas_Object *obj) | ||
1546 | { | ||
1547 | ELM_CHECK_WIDTYPE(obj, widtype); | ||
1548 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1549 | if (!wd) return; | ||
1550 | _fix_items(obj); | ||
1551 | } | ||
1552 | |||
1553 | EAPI void | ||
1554 | elm_list_multi_select_set(Evas_Object *obj, Eina_Bool multi) | ||
1555 | { | ||
1556 | ELM_CHECK_WIDTYPE(obj, widtype); | ||
1557 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1558 | if (!wd) return; | ||
1559 | wd->multi = multi; | ||
1560 | } | ||
1561 | |||
1562 | EAPI Eina_Bool | ||
1563 | elm_list_multi_select_get(const Evas_Object *obj) | ||
1564 | { | ||
1565 | ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; | ||
1566 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1567 | if (!wd) return EINA_FALSE; | ||
1568 | return wd->multi; | ||
1569 | } | ||
1570 | |||
1571 | EAPI void | ||
1572 | elm_list_mode_set(Evas_Object *obj, Elm_List_Mode mode) | ||
1573 | { | ||
1574 | ELM_CHECK_WIDTYPE(obj, widtype); | ||
1575 | |||
1576 | Widget_Data *wd; | ||
1577 | |||
1578 | wd = elm_widget_data_get(obj); | ||
1579 | if (!wd) | ||
1580 | return; | ||
1581 | if (wd->mode == mode) | ||
1582 | return; | ||
1583 | wd->mode = mode; | ||
1584 | |||
1585 | _elm_list_mode_set_internal(wd); | ||
1586 | } | ||
1587 | |||
1588 | EAPI Elm_List_Mode | ||
1589 | elm_list_mode_get(const Evas_Object *obj) | ||
1590 | { | ||
1591 | ELM_CHECK_WIDTYPE(obj, widtype) ELM_LIST_LAST; | ||
1592 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1593 | if (!wd) return ELM_LIST_LAST; | ||
1594 | return wd->mode; | ||
1595 | } | ||
1596 | |||
1597 | EAPI void | ||
1598 | elm_list_horizontal_set(Evas_Object *obj, Eina_Bool horizontal) | ||
1599 | { | ||
1600 | ELM_CHECK_WIDTYPE(obj, widtype); | ||
1601 | |||
1602 | Widget_Data *wd; | ||
1603 | Eina_Bool bounce = _elm_config->thumbscroll_bounce_enable; | ||
1604 | |||
1605 | wd = elm_widget_data_get(obj); | ||
1606 | if (!wd) | ||
1607 | return; | ||
1608 | |||
1609 | if (wd->h_mode == horizontal) | ||
1610 | return; | ||
1611 | |||
1612 | wd->h_mode = horizontal; | ||
1613 | elm_box_horizontal_set(wd->box, horizontal); | ||
1614 | |||
1615 | if (horizontal) | ||
1616 | { | ||
1617 | evas_object_size_hint_weight_set(wd->box, 0.0, EVAS_HINT_EXPAND); | ||
1618 | evas_object_size_hint_align_set(wd->box, 0.0, EVAS_HINT_FILL); | ||
1619 | elm_smart_scroller_bounce_allow_set(wd->scr, bounce, EINA_FALSE); | ||
1620 | } | ||
1621 | else | ||
1622 | { | ||
1623 | evas_object_size_hint_weight_set(wd->box, EVAS_HINT_EXPAND, 0.0); | ||
1624 | evas_object_size_hint_align_set(wd->box, EVAS_HINT_FILL, 0.0); | ||
1625 | elm_smart_scroller_bounce_allow_set(wd->scr, EINA_FALSE, bounce); | ||
1626 | } | ||
1627 | |||
1628 | _elm_list_mode_set_internal(wd); | ||
1629 | } | ||
1630 | |||
1631 | EAPI Eina_Bool | ||
1632 | elm_list_horizontal_get(const Evas_Object *obj) | ||
1633 | { | ||
1634 | ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; | ||
1635 | |||
1636 | Widget_Data *wd; | ||
1637 | |||
1638 | wd = elm_widget_data_get(obj); | ||
1639 | if (!wd) | ||
1640 | return EINA_FALSE; | ||
1641 | |||
1642 | return wd->h_mode; | ||
1643 | } | ||
1644 | |||
1645 | EAPI void | ||
1646 | elm_list_select_mode_set(Evas_Object *obj, Elm_Object_Select_Mode mode) | ||
1647 | { | ||
1648 | ELM_CHECK_WIDTYPE(obj, widtype); | ||
1649 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1650 | if (!wd) return; | ||
1651 | if (mode >= ELM_OBJECT_SELECT_MODE_MAX) | ||
1652 | return; | ||
1653 | if (wd->select_mode != mode) | ||
1654 | wd->select_mode = mode; | ||
1655 | } | ||
1656 | |||
1657 | EAPI Elm_Object_Select_Mode | ||
1658 | elm_list_select_mode_get(const Evas_Object *obj) | ||
1659 | { | ||
1660 | ELM_CHECK_WIDTYPE(obj, widtype) ELM_OBJECT_SELECT_MODE_MAX; | ||
1661 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1662 | if (!wd) return ELM_OBJECT_SELECT_MODE_MAX; | ||
1663 | return wd->select_mode; | ||
1664 | } | ||
1665 | |||
1666 | EAPI void | ||
1667 | elm_list_bounce_set(Evas_Object *obj, Eina_Bool h_bounce, Eina_Bool v_bounce) | ||
1668 | { | ||
1669 | ELM_CHECK_WIDTYPE(obj, widtype); | ||
1670 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1671 | if (!wd) return; | ||
1672 | if (wd->scr) | ||
1673 | elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce); | ||
1674 | } | ||
1675 | |||
1676 | EAPI void | ||
1677 | elm_list_bounce_get(const Evas_Object *obj, Eina_Bool *h_bounce, Eina_Bool *v_bounce) | ||
1678 | { | ||
1679 | ELM_CHECK_WIDTYPE(obj, widtype); | ||
1680 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1681 | if (!wd) return; | ||
1682 | elm_smart_scroller_bounce_allow_get(wd->scr, h_bounce, v_bounce); | ||
1683 | } | ||
1684 | |||
1685 | EAPI void | ||
1686 | elm_list_scroller_policy_set(Evas_Object *obj, Elm_Scroller_Policy policy_h, Elm_Scroller_Policy policy_v) | ||
1687 | { | ||
1688 | ELM_CHECK_WIDTYPE(obj, widtype); | ||
1689 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1690 | if ((!wd) || (!wd->scr)) return; | ||
1691 | if ((policy_h >= ELM_SCROLLER_POLICY_LAST) || | ||
1692 | (policy_v >= ELM_SCROLLER_POLICY_LAST)) | ||
1693 | return; | ||
1694 | elm_smart_scroller_policy_set(wd->scr, policy_h, policy_v); | ||
1695 | } | ||
1696 | |||
1697 | EAPI void | ||
1698 | elm_list_scroller_policy_get(const Evas_Object *obj, Elm_Scroller_Policy *policy_h, Elm_Scroller_Policy *policy_v) | ||
1699 | { | ||
1700 | ELM_CHECK_WIDTYPE(obj, widtype); | ||
1701 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1702 | Elm_Smart_Scroller_Policy s_policy_h, s_policy_v; | ||
1703 | if ((!wd) || (!wd->scr)) return; | ||
1704 | elm_smart_scroller_policy_get(wd->scr, &s_policy_h, &s_policy_v); | ||
1705 | if (policy_h) *policy_h = (Elm_Scroller_Policy) s_policy_h; | ||
1706 | if (policy_v) *policy_v = (Elm_Scroller_Policy) s_policy_v; | ||
1707 | } | ||
1708 | |||
1709 | EAPI void | ||
1710 | elm_list_clear(Evas_Object *obj) | ||
1711 | { | ||
1712 | ELM_CHECK_WIDTYPE(obj, widtype); | ||
1713 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1714 | Elm_List_Item *it; | ||
1715 | |||
1716 | if (!wd) return; | ||
1717 | if (!wd->items) return; | ||
1718 | |||
1719 | eina_list_free(wd->selected); | ||
1720 | wd->selected = NULL; | ||
1721 | |||
1722 | if (wd->walking > 0) | ||
1723 | { | ||
1724 | Eina_List *n; | ||
1725 | |||
1726 | EINA_LIST_FOREACH(wd->items, n, it) | ||
1727 | { | ||
1728 | if (it->deleted) continue; | ||
1729 | it->deleted = EINA_TRUE; | ||
1730 | wd->to_delete = eina_list_append(wd->to_delete, it); | ||
1731 | } | ||
1732 | return; | ||
1733 | } | ||
1734 | |||
1735 | evas_object_ref(obj); | ||
1736 | _elm_list_walk(wd); | ||
1737 | |||
1738 | EINA_LIST_FREE(wd->items, it) | ||
1739 | { | ||
1740 | _elm_list_item_free(it); | ||
1741 | elm_widget_item_free(it); | ||
1742 | } | ||
1743 | |||
1744 | _elm_list_unwalk(wd); | ||
1745 | |||
1746 | _fix_items(obj); | ||
1747 | _sizing_eval(obj); | ||
1748 | evas_object_unref(obj); | ||
1749 | } | ||
1750 | |||
1751 | EAPI const Eina_List * | ||
1752 | elm_list_items_get(const Evas_Object *obj) | ||
1753 | { | ||
1754 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
1755 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1756 | if (!wd) return NULL; | ||
1757 | return wd->items; | ||
1758 | } | ||
1759 | |||
1760 | EAPI Elm_Object_Item * | ||
1761 | elm_list_selected_item_get(const Evas_Object *obj) | ||
1762 | { | ||
1763 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
1764 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1765 | if (!wd) return NULL; | ||
1766 | if (wd->selected) return (Elm_Object_Item *) wd->selected->data; | ||
1767 | return NULL; | ||
1768 | } | ||
1769 | |||
1770 | EAPI const Eina_List * | ||
1771 | elm_list_selected_items_get(const Evas_Object *obj) | ||
1772 | { | ||
1773 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
1774 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1775 | if (!wd) return NULL; | ||
1776 | return wd->selected; | ||
1777 | } | ||
1778 | |||
1779 | EAPI Elm_Object_Item * | ||
1780 | elm_list_item_append(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data) | ||
1781 | { | ||
1782 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
1783 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1784 | Elm_List_Item *it = _item_new(obj, label, icon, end, func, data); | ||
1785 | |||
1786 | wd->items = eina_list_append(wd->items, it); | ||
1787 | it->node = eina_list_last(wd->items); | ||
1788 | elm_box_pack_end(wd->box, VIEW(it)); | ||
1789 | return (Elm_Object_Item *)it; | ||
1790 | } | ||
1791 | |||
1792 | EAPI Elm_Object_Item * | ||
1793 | elm_list_item_prepend(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data) | ||
1794 | { | ||
1795 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
1796 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1797 | Elm_List_Item *it = _item_new(obj, label, icon, end, func, data); | ||
1798 | |||
1799 | wd->items = eina_list_prepend(wd->items, it); | ||
1800 | it->node = wd->items; | ||
1801 | elm_box_pack_start(wd->box, VIEW(it)); | ||
1802 | return (Elm_Object_Item *)it; | ||
1803 | } | ||
1804 | |||
1805 | EAPI Elm_Object_Item * | ||
1806 | elm_list_item_insert_before(Evas_Object *obj, Elm_Object_Item *before, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data) | ||
1807 | { | ||
1808 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
1809 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(before, NULL); | ||
1810 | |||
1811 | Widget_Data *wd; | ||
1812 | Elm_List_Item *it, *before_it; | ||
1813 | |||
1814 | wd = elm_widget_data_get(obj); | ||
1815 | if (!wd) return NULL; | ||
1816 | |||
1817 | before_it = (Elm_List_Item *) before; | ||
1818 | if (!before_it->node) return NULL; | ||
1819 | |||
1820 | it = _item_new(obj, label, icon, end, func, data); | ||
1821 | wd->items = eina_list_prepend_relative_list(wd->items, it, before_it->node); | ||
1822 | it->node = before_it->node->prev; | ||
1823 | elm_box_pack_before(wd->box, VIEW(it), VIEW(before_it)); | ||
1824 | return (Elm_Object_Item *)it; | ||
1825 | } | ||
1826 | |||
1827 | EAPI Elm_Object_Item * | ||
1828 | elm_list_item_insert_after(Evas_Object *obj, Elm_Object_Item *after, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data) | ||
1829 | { | ||
1830 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
1831 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(after, NULL); | ||
1832 | |||
1833 | Widget_Data *wd; | ||
1834 | Elm_List_Item *it, *after_it; | ||
1835 | |||
1836 | wd = elm_widget_data_get(obj); | ||
1837 | if (!wd) return NULL; | ||
1838 | |||
1839 | after_it = (Elm_List_Item *) after; | ||
1840 | if (!after_it->node) return NULL; | ||
1841 | |||
1842 | it = _item_new(obj, label, icon, end, func, data); | ||
1843 | wd->items = eina_list_append_relative_list(wd->items, it, after_it->node); | ||
1844 | it->node = after_it->node->next; | ||
1845 | elm_box_pack_after(wd->box, VIEW(it), VIEW(after_it)); | ||
1846 | return (Elm_Object_Item *)it; | ||
1847 | } | ||
1848 | |||
1849 | EAPI Elm_Object_Item * | ||
1850 | 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) | ||
1851 | { | ||
1852 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
1853 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1854 | Elm_List_Item *it = _item_new(obj, label, icon, end, func, data); | ||
1855 | Eina_List *l; | ||
1856 | |||
1857 | wd->items = eina_list_sorted_insert(wd->items, cmp_func, it); | ||
1858 | l = eina_list_data_find_list(wd->items, it); | ||
1859 | l = eina_list_next(l); | ||
1860 | if (!l) | ||
1861 | { | ||
1862 | it->node = eina_list_last(wd->items); | ||
1863 | elm_box_pack_end(wd->box, VIEW(it)); | ||
1864 | } | ||
1865 | else | ||
1866 | { | ||
1867 | Elm_List_Item *before = eina_list_data_get(l); | ||
1868 | it->node = before->node->prev; | ||
1869 | elm_box_pack_before(wd->box, VIEW(it), VIEW(before)); | ||
1870 | } | ||
1871 | return (Elm_Object_Item *)it; | ||
1872 | } | ||
1873 | |||
1874 | EAPI void | ||
1875 | elm_list_item_separator_set(Elm_Object_Item *it, Eina_Bool setting) | ||
1876 | { | ||
1877 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it); | ||
1878 | ((Elm_List_Item *)it)->is_separator = !!setting; | ||
1879 | } | ||
1880 | |||
1881 | EAPI Eina_Bool | ||
1882 | elm_list_item_separator_get(const Elm_Object_Item *it) | ||
1883 | { | ||
1884 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, EINA_FALSE); | ||
1885 | return ((Elm_List_Item *)it)->is_separator; | ||
1886 | } | ||
1887 | |||
1888 | EAPI void | ||
1889 | elm_list_item_selected_set(Elm_Object_Item *it, Eina_Bool selected) | ||
1890 | { | ||
1891 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it); | ||
1892 | Evas_Object *obj = WIDGET(it); | ||
1893 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1894 | Elm_List_Item *item = (Elm_List_Item *)it; | ||
1895 | if (!wd) return; | ||
1896 | |||
1897 | selected = !!selected; | ||
1898 | if (item->selected == selected) return; | ||
1899 | |||
1900 | evas_object_ref(obj); | ||
1901 | _elm_list_walk(wd); | ||
1902 | |||
1903 | if (selected) | ||
1904 | { | ||
1905 | if (!wd->multi) | ||
1906 | { | ||
1907 | while (wd->selected) | ||
1908 | _item_unselect(wd->selected->data); | ||
1909 | } | ||
1910 | _item_highlight(item); | ||
1911 | _item_select(item); | ||
1912 | } | ||
1913 | else | ||
1914 | _item_unselect(item); | ||
1915 | |||
1916 | _elm_list_unwalk(wd); | ||
1917 | evas_object_unref(obj); | ||
1918 | } | ||
1919 | |||
1920 | EAPI Eina_Bool | ||
1921 | elm_list_item_selected_get(const Elm_Object_Item *it) | ||
1922 | { | ||
1923 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, EINA_FALSE); | ||
1924 | return ((Elm_List_Item *)it)->selected; | ||
1925 | } | ||
1926 | |||
1927 | EAPI void | ||
1928 | elm_list_item_show(Elm_Object_Item *it) | ||
1929 | { | ||
1930 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it); | ||
1931 | Widget_Data *wd = elm_widget_data_get(WIDGET(it)); | ||
1932 | if (!wd) return; | ||
1933 | Evas_Coord bx, by, bw, bh; | ||
1934 | Evas_Coord x, y, w, h; | ||
1935 | |||
1936 | evas_smart_objects_calculate(evas_object_evas_get(wd->box)); | ||
1937 | evas_object_geometry_get(wd->box, &bx, &by, &bw, &bh); | ||
1938 | evas_object_geometry_get(VIEW(it), &x, &y, &w, &h); | ||
1939 | x -= bx; | ||
1940 | y -= by; | ||
1941 | if (wd->scr) elm_smart_scroller_child_region_show(wd->scr, x, y, w, h); | ||
1942 | } | ||
1943 | |||
1944 | EAPI void | ||
1945 | elm_list_item_bring_in(Elm_Object_Item *it) | ||
1946 | { | ||
1947 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it); | ||
1948 | Widget_Data *wd = elm_widget_data_get(WIDGET(it)); | ||
1949 | if (!wd) return; | ||
1950 | Evas_Coord bx, by, bw, bh; | ||
1951 | Evas_Coord x, y, w, h; | ||
1952 | |||
1953 | evas_smart_objects_calculate(evas_object_evas_get(wd->box)); | ||
1954 | evas_object_geometry_get(wd->box, &bx, &by, &bw, &bh); | ||
1955 | evas_object_geometry_get(VIEW(it), &x, &y, &w, &h); | ||
1956 | x -= bx; | ||
1957 | y -= by; | ||
1958 | if (wd->scr) elm_smart_scroller_region_bring_in(wd->scr, x, y, w, h); | ||
1959 | } | ||
1960 | |||
1961 | EAPI Evas_Object * | ||
1962 | elm_list_item_object_get(const Elm_Object_Item *it) | ||
1963 | { | ||
1964 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL); | ||
1965 | return VIEW(it); | ||
1966 | } | ||
1967 | |||
1968 | EAPI Elm_Object_Item * | ||
1969 | elm_list_item_prev(const Elm_Object_Item *it) | ||
1970 | { | ||
1971 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL); | ||
1972 | Elm_List_Item *item = (Elm_List_Item *)it; | ||
1973 | if (item->node->prev) return item->node->prev->data; | ||
1974 | else return NULL; | ||
1975 | } | ||
1976 | |||
1977 | EAPI Elm_Object_Item * | ||
1978 | elm_list_item_next(const Elm_Object_Item *it) | ||
1979 | { | ||
1980 | ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL); | ||
1981 | Elm_List_Item *item = (Elm_List_Item *)it; | ||
1982 | if (item->node->next) return item->node->next->data; | ||
1983 | else return NULL; | ||
1984 | } | ||
1985 | |||
1986 | EAPI Elm_Object_Item * | ||
1987 | elm_list_first_item_get(const Evas_Object *obj) | ||
1988 | { | ||
1989 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
1990 | Widget_Data *wd = elm_widget_data_get(obj); | ||
1991 | if (!wd) return NULL; | ||
1992 | if (!wd->items) return NULL; | ||
1993 | return eina_list_data_get(wd->items); | ||
1994 | } | ||
1995 | |||
1996 | EAPI Elm_Object_Item * | ||
1997 | elm_list_last_item_get(const Evas_Object *obj) | ||
1998 | { | ||
1999 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
2000 | Widget_Data *wd = elm_widget_data_get(obj); | ||
2001 | if (!wd) return NULL; | ||
2002 | if (!wd->items) return NULL; | ||
2003 | return eina_list_data_get(eina_list_last(wd->items)); | ||
2004 | } | ||