diff options
Diffstat (limited to 'libraries/elementary/src/lib/elm_menu.c')
-rw-r--r-- | libraries/elementary/src/lib/elm_menu.c | 968 |
1 files changed, 968 insertions, 0 deletions
diff --git a/libraries/elementary/src/lib/elm_menu.c b/libraries/elementary/src/lib/elm_menu.c new file mode 100644 index 0000000..0cb0da0 --- /dev/null +++ b/libraries/elementary/src/lib/elm_menu.c | |||
@@ -0,0 +1,968 @@ | |||
1 | #include <Elementary.h> | ||
2 | #include "elm_priv.h" | ||
3 | |||
4 | typedef struct _Widget_Data Widget_Data; | ||
5 | typedef struct _Elm_Menu_Item Elm_Menu_Item; | ||
6 | |||
7 | struct _Elm_Menu_Item | ||
8 | { | ||
9 | ELM_WIDGET_ITEM; | ||
10 | Elm_Menu_Item *parent; | ||
11 | Evas_Object *content; | ||
12 | const char *icon_str; | ||
13 | const char *label; | ||
14 | Evas_Smart_Cb func; | ||
15 | unsigned int idx; | ||
16 | |||
17 | struct | ||
18 | { | ||
19 | Evas_Object *hv, *bx, *location; | ||
20 | Eina_List *items; | ||
21 | Eina_Bool open : 1; | ||
22 | } submenu; | ||
23 | |||
24 | Eina_Bool separator : 1; | ||
25 | Eina_Bool selected : 1; | ||
26 | Eina_Bool object_item : 1; | ||
27 | }; | ||
28 | |||
29 | struct _Widget_Data | ||
30 | { | ||
31 | Evas_Object *hv, *bx, *location, *parent, *obj; | ||
32 | Eina_List *items; | ||
33 | Evas_Coord xloc, yloc; | ||
34 | }; | ||
35 | |||
36 | static const char *widtype = NULL; | ||
37 | static void _del_hook(Evas_Object *obj); | ||
38 | static void _theme_hook(Evas_Object *obj); | ||
39 | static void _item_disable_hook(Elm_Object_Item *it); | ||
40 | static void _sizing_eval(Evas_Object *obj); | ||
41 | static void _submenu_sizing_eval(Elm_Menu_Item *parent); | ||
42 | static void _item_sizing_eval(Elm_Menu_Item *item); | ||
43 | static void _submenu_hide(Elm_Menu_Item *item); | ||
44 | static void _submenu_open(void *data, Evas_Object *obj, const char *emission, const char *source); | ||
45 | static void _parent_resize(void *data, Evas *e, Evas_Object *obj, void *event_info); | ||
46 | static void _parent_del(void *data, Evas *e, Evas_Object *obj, void *event_info); | ||
47 | static void _menu_hide(void *data, Evas_Object *obj, void *event_info); | ||
48 | |||
49 | static const char SIG_CLICKED[] = "clicked"; | ||
50 | |||
51 | static const Evas_Smart_Cb_Description _signals[] = { | ||
52 | {SIG_CLICKED, ""}, | ||
53 | {NULL, NULL} | ||
54 | }; | ||
55 | |||
56 | |||
57 | static void | ||
58 | _del_item(Elm_Menu_Item *item) | ||
59 | { | ||
60 | Elm_Menu_Item *child; | ||
61 | |||
62 | EINA_LIST_FREE(item->submenu.items, child) | ||
63 | _del_item(child); | ||
64 | |||
65 | if (item->label) eina_stringshare_del(item->label); | ||
66 | if (item->submenu.hv) evas_object_del(item->submenu.hv); | ||
67 | if (item->submenu.location) evas_object_del(item->submenu.location); | ||
68 | if (item->icon_str) eina_stringshare_del(item->icon_str); | ||
69 | elm_widget_item_free(item); | ||
70 | } | ||
71 | |||
72 | static void | ||
73 | _del_pre_hook(Evas_Object *obj) | ||
74 | { | ||
75 | Elm_Menu_Item *item; | ||
76 | Widget_Data *wd = elm_widget_data_get(obj); | ||
77 | if (!wd) return; | ||
78 | |||
79 | evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_RESIZE, _parent_resize, obj); | ||
80 | evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_DEL, _parent_del, wd); | ||
81 | |||
82 | EINA_LIST_FREE(wd->items, item) | ||
83 | _del_item(item); | ||
84 | |||
85 | if (wd->hv) evas_object_del(wd->hv); | ||
86 | if (wd->location) evas_object_del(wd->location); | ||
87 | } | ||
88 | |||
89 | static void | ||
90 | _del_hook(Evas_Object *obj) | ||
91 | { | ||
92 | Widget_Data *wd = elm_widget_data_get(obj); | ||
93 | free(wd); | ||
94 | } | ||
95 | |||
96 | static void | ||
97 | _theme_hook(Evas_Object *obj) | ||
98 | { | ||
99 | Eina_List *l, *_l, *_ll, *ll = NULL; | ||
100 | Elm_Menu_Item *item; | ||
101 | Widget_Data *wd = elm_widget_data_get(obj); | ||
102 | if (!wd) return; | ||
103 | _elm_widget_mirrored_reload(obj); | ||
104 | ll = eina_list_append(ll, wd->items); | ||
105 | EINA_LIST_FOREACH(ll, _ll, l) | ||
106 | { | ||
107 | EINA_LIST_FOREACH(l, _l, item) | ||
108 | { | ||
109 | edje_object_mirrored_set(VIEW(item), elm_widget_mirrored_get(obj)); | ||
110 | ll = eina_list_append(ll, item->submenu.items); | ||
111 | if (item->separator) | ||
112 | _elm_theme_object_set(obj, VIEW(item), "menu", "separator", | ||
113 | elm_widget_style_get(obj)); | ||
114 | else if (item->submenu.bx) | ||
115 | { | ||
116 | _elm_theme_object_set | ||
117 | (obj, VIEW(item), "menu", "item_with_submenu", | ||
118 | elm_widget_style_get(obj)); | ||
119 | elm_object_item_text_set((Elm_Object_Item *)item, | ||
120 | item->label); | ||
121 | elm_menu_item_icon_name_set((Elm_Object_Item *)item, | ||
122 | item->icon_str); | ||
123 | } | ||
124 | else | ||
125 | { | ||
126 | _elm_theme_object_set(obj, VIEW(item), "menu", "item", | ||
127 | elm_widget_style_get(obj)); | ||
128 | elm_object_item_text_set((Elm_Object_Item *)item, | ||
129 | item->label); | ||
130 | elm_menu_item_icon_name_set((Elm_Object_Item *)item, | ||
131 | item->icon_str); | ||
132 | } | ||
133 | _item_disable_hook((Elm_Object_Item *)item); | ||
134 | edje_object_scale_set(VIEW(item), elm_widget_scale_get(obj) * | ||
135 | _elm_config->scale); | ||
136 | } | ||
137 | } | ||
138 | _sizing_eval(obj); | ||
139 | } | ||
140 | |||
141 | static void | ||
142 | _item_text_set_hook(Elm_Object_Item *it, | ||
143 | const char *part, | ||
144 | const char *label) | ||
145 | { | ||
146 | Elm_Menu_Item *item; | ||
147 | |||
148 | if (part && strcmp(part, "default")) return; | ||
149 | |||
150 | item = (Elm_Menu_Item *)it; | ||
151 | |||
152 | eina_stringshare_replace(&item->label, label); | ||
153 | |||
154 | if (label) | ||
155 | edje_object_signal_emit(VIEW(item), "elm,state,text,visible", "elm"); | ||
156 | else | ||
157 | edje_object_signal_emit(VIEW(item), "elm,state,text,hidden", "elm"); | ||
158 | |||
159 | edje_object_message_signal_process(VIEW(item)); | ||
160 | edje_object_part_text_set(VIEW(item), "elm.text", label); | ||
161 | _sizing_eval(WIDGET(item)); | ||
162 | } | ||
163 | |||
164 | static const char * | ||
165 | _item_text_get_hook(const Elm_Object_Item *it, const char *part) | ||
166 | { | ||
167 | if (part && strcmp(part, "default")) return NULL; | ||
168 | return ((Elm_Menu_Item *)it)->label; | ||
169 | } | ||
170 | |||
171 | static void | ||
172 | _item_content_set_hook(Elm_Object_Item *it, | ||
173 | const char *part, | ||
174 | Evas_Object *content) | ||
175 | { | ||
176 | Elm_Menu_Item *item; | ||
177 | if (part && strcmp(part, "default")) return; | ||
178 | |||
179 | item = (Elm_Menu_Item *)it; | ||
180 | if (content == item->content) return; | ||
181 | |||
182 | if (item->content) evas_object_del(item->content); | ||
183 | |||
184 | item->content = content; | ||
185 | elm_widget_sub_object_add(WIDGET(item), item->content); | ||
186 | if (item->content) | ||
187 | edje_object_part_swallow(VIEW(item), "elm.swallow.content", item->content); | ||
188 | _sizing_eval(WIDGET(item)); | ||
189 | } | ||
190 | |||
191 | static Evas_Object * | ||
192 | _item_content_get_hook(const Elm_Object_Item *it, const char *part) | ||
193 | { | ||
194 | if (part && strcmp(part, "default")) return NULL; | ||
195 | return ((Elm_Menu_Item *)it)->content; | ||
196 | } | ||
197 | |||
198 | static void | ||
199 | _item_disable_hook(Elm_Object_Item *it) | ||
200 | { | ||
201 | Elm_Menu_Item *item = (Elm_Menu_Item *)it; | ||
202 | |||
203 | if (elm_widget_item_disabled_get(item)) | ||
204 | { | ||
205 | edje_object_signal_emit(VIEW(item), "elm,state,disabled", "elm"); | ||
206 | if (item->submenu.open) _submenu_hide(item); | ||
207 | } | ||
208 | else | ||
209 | edje_object_signal_emit(VIEW(item), "elm,state,enabled", "elm"); | ||
210 | |||
211 | edje_object_message_signal_process(VIEW(item)); | ||
212 | } | ||
213 | |||
214 | static void | ||
215 | _sizing_eval(Evas_Object *obj) | ||
216 | { | ||
217 | Eina_List *l; | ||
218 | Elm_Menu_Item *item; | ||
219 | Evas_Coord x_p, y_p, w_p, h_p, x2, y2, w2, h2, bx, by, bw, bh; | ||
220 | Widget_Data *wd = elm_widget_data_get(obj); | ||
221 | if ((!wd) || (!wd->parent)) return; | ||
222 | EINA_LIST_FOREACH(wd->items,l,item) _item_sizing_eval(item); | ||
223 | evas_object_geometry_get(wd->location, &x_p, &y_p, &w_p, &h_p); | ||
224 | evas_object_geometry_get(wd->parent, &x2, &y2, &w2, &h2); | ||
225 | evas_object_geometry_get(wd->bx, &bx, &by, &bw, &bh); | ||
226 | |||
227 | x_p = wd->xloc; | ||
228 | y_p = wd->yloc; | ||
229 | |||
230 | if (elm_widget_mirrored_get(obj)) | ||
231 | x_p -= w_p; | ||
232 | |||
233 | if (x_p+bw > x2+w2) x_p -= x_p+bw - (x2+w2); | ||
234 | if (x_p < x2) x_p += x2 - x_p; | ||
235 | |||
236 | if (y_p+h_p+bh > y2+h2) y_p -= y_p+h_p+bh - (y2+h2); | ||
237 | if (y_p < y2) y_p += y2 - y_p; | ||
238 | |||
239 | |||
240 | evas_object_move(wd->location, x_p, y_p); | ||
241 | evas_object_resize(wd->location, bw, h_p); | ||
242 | evas_object_size_hint_min_set(wd->location, bw, h_p); | ||
243 | evas_object_size_hint_max_set(wd->location, bw, h_p); | ||
244 | elm_hover_target_set(wd->hv, wd->location); | ||
245 | |||
246 | EINA_LIST_FOREACH(wd->items,l,item) | ||
247 | { | ||
248 | if (item->submenu.open) _submenu_sizing_eval(item); | ||
249 | } | ||
250 | } | ||
251 | |||
252 | static void | ||
253 | _submenu_sizing_eval(Elm_Menu_Item *parent) | ||
254 | { | ||
255 | Eina_List *l; | ||
256 | Elm_Menu_Item *item; | ||
257 | Evas_Coord x_p, y_p, w_p, h_p, x2, y2, w2, h2, bx, by, bw, bh, px, py, pw, ph; | ||
258 | Widget_Data *wd = elm_widget_data_get(WIDGET(parent)); | ||
259 | if (!wd) return; | ||
260 | EINA_LIST_FOREACH(parent->submenu.items, l, item) _item_sizing_eval(item); | ||
261 | evas_object_geometry_get(parent->submenu.location, &x_p, &y_p, &w_p, &h_p); | ||
262 | evas_object_geometry_get(VIEW(parent), &x2, &y2, &w2, &h2); | ||
263 | evas_object_geometry_get(parent->submenu.bx, &bx, &by, &bw, &bh); | ||
264 | evas_object_geometry_get(wd->parent, &px, &py, &pw, &ph); | ||
265 | |||
266 | x_p = x2+w2; | ||
267 | y_p = y2; | ||
268 | |||
269 | /* If it overflows on the right, adjust the x */ | ||
270 | if ((x_p + bw > px + pw) || elm_widget_mirrored_get(WIDGET(parent))) | ||
271 | x_p = x2-bw; | ||
272 | |||
273 | /* If it overflows on the left, adjust the x - usually only happens | ||
274 | * with an RTL interface */ | ||
275 | if (x_p < px) | ||
276 | x_p = x2 + w2; | ||
277 | |||
278 | /* If after all the adjustments it still overflows, fix it */ | ||
279 | if (x_p + bw > px + pw) | ||
280 | x_p = x2-bw; | ||
281 | |||
282 | if (y_p+bh > py+ph) | ||
283 | y_p -= y_p+bh - (py+ph); | ||
284 | if (y_p < py) | ||
285 | y_p += y_p - y_p; | ||
286 | |||
287 | evas_object_move(parent->submenu.location, x_p, y_p); | ||
288 | evas_object_resize(parent->submenu.location, bw, h_p); | ||
289 | evas_object_size_hint_min_set(parent->submenu.location, bw, h_p); | ||
290 | evas_object_size_hint_max_set(parent->submenu.location, bw, h_p); | ||
291 | elm_hover_target_set(parent->submenu.hv, parent->submenu.location); | ||
292 | |||
293 | EINA_LIST_FOREACH(parent->submenu.items, l, item) | ||
294 | { | ||
295 | if (item->submenu.open) | ||
296 | _submenu_sizing_eval(item); | ||
297 | } | ||
298 | } | ||
299 | |||
300 | static void | ||
301 | _item_sizing_eval(Elm_Menu_Item *item) | ||
302 | { | ||
303 | Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1; | ||
304 | if (!item->separator) | ||
305 | elm_coords_finger_size_adjust(1, &minw, 1, &minh); | ||
306 | edje_object_size_min_restricted_calc(VIEW(item), &minw, &minh, minw, minh); | ||
307 | if (!item->separator) | ||
308 | elm_coords_finger_size_adjust(1, &minw, 1, &minh); | ||
309 | evas_object_size_hint_min_set(VIEW(item), minw, minh); | ||
310 | evas_object_size_hint_max_set(VIEW(item), maxw, maxh); | ||
311 | } | ||
312 | |||
313 | static void | ||
314 | _menu_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) | ||
315 | { | ||
316 | _sizing_eval(data); | ||
317 | } | ||
318 | |||
319 | static void | ||
320 | _parent_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) | ||
321 | { | ||
322 | _sizing_eval(data); | ||
323 | } | ||
324 | |||
325 | static void | ||
326 | _parent_del(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__) | ||
327 | { | ||
328 | Widget_Data *wd = data; | ||
329 | evas_object_event_callback_del_full(obj, EVAS_CALLBACK_RESIZE, _parent_resize, wd->obj); | ||
330 | wd->parent = NULL; | ||
331 | } | ||
332 | |||
333 | static void | ||
334 | _item_move_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) | ||
335 | { | ||
336 | Elm_Menu_Item *item = data; | ||
337 | if (item->submenu.open) _submenu_sizing_eval(item); | ||
338 | } | ||
339 | |||
340 | static void | ||
341 | _hover_clicked_cb(void *data, Evas_Object *obj, void *event_info) | ||
342 | { | ||
343 | _menu_hide(data, obj, event_info); | ||
344 | evas_object_smart_callback_call(data, SIG_CLICKED, NULL); | ||
345 | } | ||
346 | |||
347 | static void | ||
348 | _menu_hide(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) | ||
349 | { | ||
350 | Eina_List *l; | ||
351 | Elm_Menu_Item *item2; | ||
352 | Widget_Data *wd = elm_widget_data_get(data); | ||
353 | if (!wd) return; | ||
354 | evas_object_hide(wd->hv); | ||
355 | evas_object_hide(data); | ||
356 | |||
357 | EINA_LIST_FOREACH(wd->items, l, item2) | ||
358 | { | ||
359 | if (item2->submenu.open) _submenu_hide(item2); | ||
360 | } | ||
361 | } | ||
362 | |||
363 | static void | ||
364 | _submenu_hide(Elm_Menu_Item *item) | ||
365 | { | ||
366 | Eina_List *l; | ||
367 | Elm_Menu_Item *item2; | ||
368 | evas_object_hide(item->submenu.hv); | ||
369 | item->submenu.open = EINA_FALSE; | ||
370 | EINA_LIST_FOREACH(item->submenu.items, l, item2) | ||
371 | { | ||
372 | if (item2->submenu.open) _submenu_hide(item2); | ||
373 | } | ||
374 | } | ||
375 | |||
376 | static void | ||
377 | _menu_item_select(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) | ||
378 | { | ||
379 | Elm_Menu_Item *item = data; | ||
380 | if (item->submenu.items) | ||
381 | { | ||
382 | if (!item->submenu.open) _submenu_open(item, NULL, NULL, NULL); | ||
383 | else _submenu_hide(item); | ||
384 | } | ||
385 | else | ||
386 | _menu_hide(WIDGET(item), NULL, NULL); | ||
387 | |||
388 | if (item->func) item->func((void *)(item->base.data), WIDGET(item), item); | ||
389 | } | ||
390 | |||
391 | static void | ||
392 | _menu_item_activate(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) | ||
393 | { | ||
394 | Eina_List *l; | ||
395 | Elm_Menu_Item *item2; | ||
396 | Elm_Menu_Item *item = data; | ||
397 | item->selected = 1; | ||
398 | if (item->parent) | ||
399 | { | ||
400 | EINA_LIST_FOREACH(item->parent->submenu.items, l, item2) | ||
401 | { | ||
402 | if (item2 != item) | ||
403 | elm_menu_item_selected_set((Elm_Object_Item *)item2, 0); | ||
404 | } | ||
405 | } | ||
406 | else | ||
407 | { | ||
408 | Widget_Data *wd = elm_widget_data_get(WIDGET(item)); | ||
409 | EINA_LIST_FOREACH(wd->items, l, item2) | ||
410 | { | ||
411 | if (item2 != item) | ||
412 | elm_menu_item_selected_set((Elm_Object_Item *)item2, 0); | ||
413 | } | ||
414 | } | ||
415 | } | ||
416 | |||
417 | static void | ||
418 | _menu_item_inactivate(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) | ||
419 | { | ||
420 | Elm_Menu_Item *item = data; | ||
421 | item->selected = 0; | ||
422 | if (item->submenu.open) _submenu_hide(item); | ||
423 | } | ||
424 | |||
425 | static void | ||
426 | _submenu_open(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__) | ||
427 | { | ||
428 | Elm_Menu_Item *item = data; | ||
429 | item->submenu.open = EINA_TRUE; | ||
430 | evas_object_show(item->submenu.hv); | ||
431 | _submenu_sizing_eval(item); | ||
432 | } | ||
433 | |||
434 | static void | ||
435 | _show(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) | ||
436 | { | ||
437 | Widget_Data *wd = elm_widget_data_get(data); | ||
438 | if (!wd) return; | ||
439 | evas_object_show(wd->hv); | ||
440 | } | ||
441 | |||
442 | static void | ||
443 | _item_obj_create(Elm_Menu_Item *item) | ||
444 | { | ||
445 | Widget_Data *wd = elm_widget_data_get(WIDGET(item)); | ||
446 | if (!wd) return; | ||
447 | VIEW(item) = edje_object_add(evas_object_evas_get(wd->bx)); | ||
448 | edje_object_mirrored_set(VIEW(item), elm_widget_mirrored_get(WIDGET(item))); | ||
449 | evas_object_size_hint_weight_set(VIEW(item), EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); | ||
450 | evas_object_size_hint_fill_set(VIEW(item), EVAS_HINT_FILL, EVAS_HINT_FILL); | ||
451 | _elm_theme_object_set(WIDGET(item), VIEW(item), "menu", "item", elm_widget_style_get(WIDGET(item))); | ||
452 | edje_object_signal_callback_add(VIEW(item), "elm,action,click", "", | ||
453 | _menu_item_select, item); | ||
454 | edje_object_signal_callback_add(VIEW(item), "elm,action,activate", "", | ||
455 | _menu_item_activate, item); | ||
456 | edje_object_signal_callback_add(VIEW(item), "elm,action,inactivate", "", | ||
457 | _menu_item_inactivate, item); | ||
458 | evas_object_show(VIEW(item)); | ||
459 | } | ||
460 | |||
461 | static void | ||
462 | _item_separator_obj_create(Elm_Menu_Item *item) | ||
463 | { | ||
464 | Widget_Data *wd = elm_widget_data_get(WIDGET(item)); | ||
465 | if (!wd) return; | ||
466 | VIEW(item) = edje_object_add(evas_object_evas_get(wd->bx)); | ||
467 | evas_object_size_hint_weight_set(VIEW(item), EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); | ||
468 | evas_object_size_hint_fill_set(VIEW(item), EVAS_HINT_FILL, EVAS_HINT_FILL); | ||
469 | _elm_theme_object_set(WIDGET(item), VIEW(item), "menu", "separator", elm_widget_style_get(WIDGET(item))); | ||
470 | edje_object_signal_callback_add(VIEW(item), "elm,action,activate", "", | ||
471 | _menu_item_activate, item); | ||
472 | evas_object_show(VIEW(item)); | ||
473 | } | ||
474 | |||
475 | static void | ||
476 | _item_submenu_obj_create(Elm_Menu_Item *item) | ||
477 | { | ||
478 | Widget_Data *wd = elm_widget_data_get(WIDGET(item)); | ||
479 | if (!wd) return; | ||
480 | item->submenu.location = elm_icon_add(wd->bx); | ||
481 | item->submenu.hv = elm_hover_add(wd->bx); | ||
482 | elm_widget_mirrored_set(item->submenu.hv, EINA_FALSE); | ||
483 | elm_hover_target_set(item->submenu.hv, item->submenu.location); | ||
484 | elm_hover_parent_set(item->submenu.hv, wd->parent); | ||
485 | elm_object_style_set(item->submenu.hv, "submenu"); | ||
486 | |||
487 | item->submenu.bx = elm_box_add(wd->bx); | ||
488 | elm_widget_mirrored_set(item->submenu.bx, EINA_FALSE); | ||
489 | evas_object_size_hint_weight_set(item->submenu.bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); | ||
490 | evas_object_show(item->submenu.bx); | ||
491 | elm_object_part_content_set(item->submenu.hv, elm_hover_best_content_location_get(item->submenu.hv, ELM_HOVER_AXIS_VERTICAL), item->submenu.bx); | ||
492 | |||
493 | edje_object_mirrored_set(VIEW(item), elm_widget_mirrored_get(WIDGET(item))); | ||
494 | _elm_theme_object_set(WIDGET(item), VIEW(item), "menu", "item_with_submenu", elm_widget_style_get(WIDGET(item))); | ||
495 | elm_object_item_text_set((Elm_Object_Item *)item, | ||
496 | item->label); | ||
497 | if (item->icon_str) | ||
498 | elm_menu_item_icon_name_set((Elm_Object_Item *)item, | ||
499 | item->icon_str); | ||
500 | edje_object_signal_callback_add(VIEW(item), "elm,action,open", "", | ||
501 | _submenu_open, item); | ||
502 | evas_object_event_callback_add(VIEW(item), EVAS_CALLBACK_MOVE, _item_move_resize, item); | ||
503 | evas_object_event_callback_add(VIEW(item), EVAS_CALLBACK_RESIZE, _item_move_resize, item); | ||
504 | |||
505 | evas_object_event_callback_add(item->submenu.bx, EVAS_CALLBACK_RESIZE, _menu_resize, WIDGET(item)); | ||
506 | } | ||
507 | |||
508 | EAPI Evas_Object * | ||
509 | elm_menu_add(Evas_Object *parent) | ||
510 | { | ||
511 | Evas_Object *obj; | ||
512 | Evas *e; | ||
513 | Widget_Data *wd; | ||
514 | |||
515 | ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL); | ||
516 | |||
517 | ELM_SET_WIDTYPE(widtype, "menu"); | ||
518 | elm_widget_type_set(obj, "menu"); | ||
519 | elm_widget_sub_object_add(parent, obj); | ||
520 | elm_widget_data_set(obj, wd); | ||
521 | elm_widget_del_pre_hook_set(obj, _del_pre_hook); | ||
522 | elm_widget_del_hook_set(obj, _del_hook); | ||
523 | elm_widget_theme_hook_set(obj, _theme_hook); | ||
524 | elm_widget_can_focus_set(obj, EINA_FALSE); | ||
525 | |||
526 | wd->location = elm_icon_add(obj); | ||
527 | wd->parent = parent; | ||
528 | wd->obj = obj; | ||
529 | |||
530 | wd->hv = elm_hover_add(obj); | ||
531 | elm_widget_mirrored_set(wd->hv, EINA_FALSE); | ||
532 | elm_hover_parent_set(wd->hv, parent); | ||
533 | elm_hover_target_set(wd->hv, wd->location); | ||
534 | elm_object_style_set(wd->hv, "menu"); | ||
535 | evas_object_smart_callback_add(wd->hv, "clicked", _hover_clicked_cb, obj); | ||
536 | |||
537 | wd->bx = elm_box_add(obj); | ||
538 | elm_widget_mirrored_set(wd->bx, EINA_FALSE); | ||
539 | evas_object_size_hint_weight_set(wd->bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); | ||
540 | evas_object_show(wd->bx); | ||
541 | elm_object_part_content_set(wd->hv, elm_hover_best_content_location_get(wd->hv, ELM_HOVER_AXIS_VERTICAL), wd->bx); | ||
542 | |||
543 | evas_object_event_callback_add(wd->parent, EVAS_CALLBACK_RESIZE, _parent_resize, wd->obj); | ||
544 | evas_object_event_callback_add(wd->parent, EVAS_CALLBACK_DEL, _parent_del, wd); | ||
545 | |||
546 | evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _show, obj); | ||
547 | |||
548 | evas_object_event_callback_add(wd->bx, EVAS_CALLBACK_RESIZE, _menu_resize, obj); | ||
549 | |||
550 | evas_object_smart_callbacks_descriptions_set(obj, _signals); | ||
551 | |||
552 | _sizing_eval(obj); | ||
553 | return obj; | ||
554 | } | ||
555 | |||
556 | EAPI void | ||
557 | elm_menu_parent_set(Evas_Object *obj, Evas_Object *parent) | ||
558 | { | ||
559 | Eina_List *l, *_l, *_ll, *ll = NULL; | ||
560 | Elm_Menu_Item *item; | ||
561 | ELM_CHECK_WIDTYPE(obj, widtype); | ||
562 | Widget_Data *wd = elm_widget_data_get(obj); | ||
563 | if (!wd) return; | ||
564 | |||
565 | if (wd->parent == parent) return; | ||
566 | if (wd->parent) | ||
567 | { | ||
568 | evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_RESIZE, _parent_resize, wd->obj); | ||
569 | evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_DEL, _parent_del, wd); | ||
570 | } | ||
571 | wd->parent = parent; | ||
572 | if (wd->parent) | ||
573 | { | ||
574 | evas_object_event_callback_add(wd->parent, EVAS_CALLBACK_RESIZE, _parent_resize, wd->obj); | ||
575 | evas_object_event_callback_add(wd->parent, EVAS_CALLBACK_DEL, _parent_del, wd); | ||
576 | } | ||
577 | elm_hover_parent_set(wd->hv, parent); | ||
578 | |||
579 | ll = eina_list_append(ll, wd->items); | ||
580 | EINA_LIST_FOREACH(ll, _ll, l) | ||
581 | { | ||
582 | EINA_LIST_FOREACH(l, _l, item) | ||
583 | { | ||
584 | if (item->submenu.hv) | ||
585 | { | ||
586 | elm_hover_parent_set(item->submenu.hv, parent); | ||
587 | ll = eina_list_append(ll, item->submenu.items); | ||
588 | } | ||
589 | } | ||
590 | } | ||
591 | _sizing_eval(obj); | ||
592 | } | ||
593 | |||
594 | EAPI Evas_Object * | ||
595 | elm_menu_parent_get(const Evas_Object *obj) | ||
596 | { | ||
597 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
598 | Widget_Data *wd = elm_widget_data_get(obj); | ||
599 | if (!wd) return NULL; | ||
600 | return wd->parent; | ||
601 | } | ||
602 | |||
603 | EAPI void | ||
604 | elm_menu_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y) | ||
605 | { | ||
606 | ELM_CHECK_WIDTYPE(obj, widtype); | ||
607 | Widget_Data *wd = elm_widget_data_get(obj); | ||
608 | if (!wd) return; | ||
609 | wd->xloc = x; | ||
610 | wd->yloc = y; | ||
611 | _sizing_eval(obj); | ||
612 | } | ||
613 | |||
614 | EAPI void | ||
615 | elm_menu_close(Evas_Object *obj) | ||
616 | { | ||
617 | ELM_CHECK_WIDTYPE(obj, widtype); | ||
618 | Widget_Data *wd = elm_widget_data_get(obj); | ||
619 | _menu_hide(obj, wd->hv, NULL); | ||
620 | } | ||
621 | |||
622 | EAPI Evas_Object * | ||
623 | elm_menu_item_object_get(const Elm_Object_Item *it) | ||
624 | { | ||
625 | return VIEW(((Elm_Menu_Item *)it)); | ||
626 | } | ||
627 | |||
628 | static void | ||
629 | _item_clone(Evas_Object *obj, Elm_Menu_Item *parent, Elm_Menu_Item *item) | ||
630 | { | ||
631 | Elm_Object_Item *new_item; | ||
632 | Elm_Menu_Item *subitem; | ||
633 | Eina_List *iter; | ||
634 | |||
635 | if (item->separator) | ||
636 | new_item = elm_menu_item_separator_add(obj, (Elm_Object_Item *) parent); | ||
637 | else | ||
638 | new_item = elm_menu_item_add(obj, | ||
639 | (Elm_Object_Item *) parent, | ||
640 | item->icon_str, | ||
641 | item->label, | ||
642 | item->func, | ||
643 | item->base.data); | ||
644 | elm_object_item_disabled_set(new_item, | ||
645 | elm_widget_item_disabled_get(item)); | ||
646 | |||
647 | EINA_LIST_FOREACH(item->submenu.items, iter, subitem) | ||
648 | _item_clone(obj, (Elm_Menu_Item *) new_item, subitem); | ||
649 | } | ||
650 | |||
651 | void | ||
652 | elm_menu_clone(Evas_Object *from_menu, Evas_Object *to_menu, Elm_Object_Item *parent) | ||
653 | { | ||
654 | ELM_CHECK_WIDTYPE(from_menu, widtype); | ||
655 | ELM_CHECK_WIDTYPE(to_menu, widtype); | ||
656 | Widget_Data *from_wd = elm_widget_data_get(from_menu); | ||
657 | Eina_List *iter; | ||
658 | Elm_Menu_Item *item; | ||
659 | |||
660 | if (!from_wd) return; | ||
661 | EINA_LIST_FOREACH(from_wd->items, iter, item) | ||
662 | _item_clone(to_menu, (Elm_Menu_Item *) parent, item); | ||
663 | } | ||
664 | |||
665 | static void | ||
666 | _elm_menu_item_add_helper(Evas_Object *obj, Elm_Menu_Item *parent, Elm_Menu_Item *subitem, Widget_Data *wd) | ||
667 | { | ||
668 | if (parent) | ||
669 | { | ||
670 | if (!parent->submenu.bx) _item_submenu_obj_create(parent); | ||
671 | elm_box_pack_end(parent->submenu.bx, VIEW(subitem)); | ||
672 | parent->submenu.items = eina_list_append(parent->submenu.items, subitem); | ||
673 | subitem->idx = eina_list_count(parent->submenu.items) - 1; | ||
674 | } | ||
675 | else | ||
676 | { | ||
677 | elm_box_pack_end(wd->bx, VIEW(subitem)); | ||
678 | wd->items = eina_list_append(wd->items, subitem); | ||
679 | subitem->idx = eina_list_count(wd->items) - 1; | ||
680 | } | ||
681 | |||
682 | _sizing_eval(obj); | ||
683 | } | ||
684 | |||
685 | static Eina_Bool | ||
686 | _item_del_pre_hook(Elm_Object_Item *it) | ||
687 | { | ||
688 | Elm_Menu_Item *item = (Elm_Menu_Item *)it; | ||
689 | Elm_Object_Item *_item; | ||
690 | |||
691 | EINA_LIST_FREE(item->submenu.items, _item) elm_object_item_del(_item); | ||
692 | if (item->label) eina_stringshare_del(item->label); | ||
693 | if (item->content) evas_object_del(item->content); | ||
694 | if (item->submenu.hv) evas_object_del(item->submenu.hv); | ||
695 | if (item->submenu.location) evas_object_del(item->submenu.location); | ||
696 | |||
697 | if (item->parent) | ||
698 | item->parent->submenu.items = eina_list_remove(item->parent->submenu.items, item); | ||
699 | else | ||
700 | { | ||
701 | Widget_Data *wd = elm_widget_data_get(WIDGET(item)); | ||
702 | wd->items = eina_list_remove(wd->items, item); | ||
703 | } | ||
704 | |||
705 | return EINA_TRUE; | ||
706 | } | ||
707 | |||
708 | EAPI Elm_Object_Item * | ||
709 | elm_menu_item_add(Evas_Object *obj, Elm_Object_Item *parent, const char *icon, const char *label, Evas_Smart_Cb func, const void *data) | ||
710 | { | ||
711 | Elm_Menu_Item *subitem; | ||
712 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
713 | Widget_Data *wd = elm_widget_data_get(obj); | ||
714 | Evas_Object *icon_obj; | ||
715 | |||
716 | if (!wd) return NULL; | ||
717 | icon_obj = elm_icon_add(obj); | ||
718 | if (!icon_obj) return NULL; | ||
719 | subitem = elm_widget_item_new(obj, Elm_Menu_Item); | ||
720 | if (!subitem) | ||
721 | { | ||
722 | evas_object_del(icon_obj); | ||
723 | return NULL; | ||
724 | } | ||
725 | |||
726 | elm_widget_item_del_pre_hook_set(subitem, _item_del_pre_hook); | ||
727 | elm_widget_item_disable_hook_set(subitem, _item_disable_hook); | ||
728 | elm_widget_item_text_set_hook_set(subitem, _item_text_set_hook); | ||
729 | elm_widget_item_text_get_hook_set(subitem, _item_text_get_hook); | ||
730 | elm_widget_item_content_set_hook_set(subitem, _item_content_set_hook); | ||
731 | elm_widget_item_content_get_hook_set(subitem, _item_content_get_hook); | ||
732 | |||
733 | subitem->base.data = data; | ||
734 | subitem->func = func; | ||
735 | subitem->parent = (Elm_Menu_Item *) parent; | ||
736 | subitem->content = icon_obj; | ||
737 | |||
738 | _item_obj_create(subitem); | ||
739 | elm_object_item_text_set((Elm_Object_Item *) subitem, label); | ||
740 | |||
741 | elm_widget_sub_object_add(WIDGET(subitem), subitem->content); | ||
742 | edje_object_part_swallow(VIEW(subitem), "elm.swallow.content", subitem->content); | ||
743 | if (icon) | ||
744 | elm_menu_item_icon_name_set((Elm_Object_Item *) subitem, icon); | ||
745 | |||
746 | _elm_menu_item_add_helper(obj, (Elm_Menu_Item *) parent, subitem, wd); | ||
747 | |||
748 | return (Elm_Object_Item *) subitem; | ||
749 | } | ||
750 | |||
751 | EAPI unsigned int | ||
752 | elm_menu_item_index_get(const Elm_Object_Item *it) | ||
753 | { | ||
754 | ELM_OBJ_ITEM_CHECK_OR_RETURN(it, 0); | ||
755 | return ((Elm_Menu_Item *)it)->idx; | ||
756 | } | ||
757 | |||
758 | EAPI void | ||
759 | elm_menu_item_icon_name_set(Elm_Object_Item *it, const char *icon) | ||
760 | { | ||
761 | ELM_OBJ_ITEM_CHECK_OR_RETURN(it); | ||
762 | EINA_SAFETY_ON_NULL_RETURN(icon); | ||
763 | char icon_tmp[512]; | ||
764 | Elm_Menu_Item *item = (Elm_Menu_Item *)it; | ||
765 | |||
766 | if (!*icon) return; | ||
767 | if ((item->icon_str) && (!strcmp(item->icon_str, icon))) return; | ||
768 | if ((snprintf(icon_tmp, sizeof(icon_tmp), "menu/%s", icon) > 0) && | ||
769 | (elm_icon_standard_set(item->content, icon_tmp) || | ||
770 | elm_icon_standard_set(item->content, icon))) | ||
771 | { | ||
772 | eina_stringshare_replace(&item->icon_str, icon); | ||
773 | edje_object_signal_emit(VIEW(item), "elm,state,icon,visible", "elm"); | ||
774 | } | ||
775 | else | ||
776 | edje_object_signal_emit(VIEW(item), "elm,state,icon,hidden", "elm"); | ||
777 | edje_object_message_signal_process(VIEW(item)); | ||
778 | _sizing_eval(WIDGET(item)); | ||
779 | } | ||
780 | |||
781 | EAPI Elm_Object_Item * | ||
782 | elm_menu_item_separator_add(Evas_Object *obj, Elm_Object_Item *parent) | ||
783 | { | ||
784 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
785 | Elm_Menu_Item *subitem; | ||
786 | Widget_Data *wd = elm_widget_data_get(obj); | ||
787 | Elm_Menu_Item *p_item = (Elm_Menu_Item *) parent; | ||
788 | if (!wd) return NULL; | ||
789 | /* don't add a separator as the first item */ | ||
790 | if (!wd->items) return NULL; | ||
791 | /* don't allow adding more than one separator in a row */ | ||
792 | if (p_item) subitem = eina_list_last(p_item->submenu.items)->data; | ||
793 | else subitem = eina_list_last(wd->items)->data; | ||
794 | if (subitem->separator) return NULL; | ||
795 | |||
796 | subitem = elm_widget_item_new(obj, Elm_Menu_Item); | ||
797 | if (!subitem) return NULL; | ||
798 | |||
799 | elm_widget_item_del_pre_hook_set(subitem, _item_del_pre_hook); | ||
800 | elm_widget_item_disable_hook_set(subitem, _item_disable_hook); | ||
801 | elm_widget_item_text_set_hook_set(subitem, _item_text_set_hook); | ||
802 | elm_widget_item_text_get_hook_set(subitem, _item_text_get_hook); | ||
803 | elm_widget_item_content_set_hook_set(subitem, _item_content_set_hook); | ||
804 | elm_widget_item_content_get_hook_set(subitem, _item_content_get_hook); | ||
805 | |||
806 | subitem->separator = EINA_TRUE; | ||
807 | _item_separator_obj_create(subitem); | ||
808 | if (!p_item) | ||
809 | { | ||
810 | elm_box_pack_end(wd->bx, VIEW(subitem)); | ||
811 | wd->items = eina_list_append(wd->items, subitem); | ||
812 | } | ||
813 | else | ||
814 | { | ||
815 | if (!p_item->submenu.bx) _item_submenu_obj_create(p_item); | ||
816 | elm_box_pack_end(p_item->submenu.bx, VIEW(subitem)); | ||
817 | p_item->submenu.items = eina_list_append(p_item->submenu.items, | ||
818 | subitem); | ||
819 | } | ||
820 | _sizing_eval(obj); | ||
821 | return (Elm_Object_Item *) subitem; | ||
822 | } | ||
823 | |||
824 | EAPI const char * | ||
825 | elm_menu_item_icon_name_get(const Elm_Object_Item *it) | ||
826 | { | ||
827 | ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL); | ||
828 | return ((Elm_Menu_Item *)it)->icon_str; | ||
829 | } | ||
830 | |||
831 | EAPI Eina_Bool | ||
832 | elm_menu_item_is_separator(Elm_Object_Item *it) | ||
833 | { | ||
834 | ELM_OBJ_ITEM_CHECK_OR_RETURN(it, EINA_FALSE); | ||
835 | return ((Elm_Menu_Item *)it)->separator; | ||
836 | } | ||
837 | |||
838 | EAPI const Eina_List * | ||
839 | elm_menu_item_subitems_get(const Elm_Object_Item *it) | ||
840 | { | ||
841 | ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL); | ||
842 | return ((Elm_Menu_Item *)it)->submenu.items; | ||
843 | } | ||
844 | |||
845 | EAPI const Eina_List * | ||
846 | elm_menu_items_get(const Evas_Object * obj) | ||
847 | { | ||
848 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
849 | Widget_Data *wd = elm_widget_data_get(obj); | ||
850 | return wd->items; | ||
851 | } | ||
852 | |||
853 | EAPI void | ||
854 | elm_menu_item_selected_set(Elm_Object_Item *it, Eina_Bool selected) | ||
855 | { | ||
856 | ELM_OBJ_ITEM_CHECK_OR_RETURN(it); | ||
857 | Elm_Menu_Item *item = (Elm_Menu_Item *)it; | ||
858 | |||
859 | if (selected == item->selected) return; | ||
860 | item->selected = selected; | ||
861 | if (selected) | ||
862 | { | ||
863 | edje_object_signal_emit(VIEW(item), "elm,state,selected", "elm"); | ||
864 | _menu_item_activate(item, NULL, NULL, NULL); | ||
865 | } | ||
866 | else | ||
867 | { | ||
868 | edje_object_signal_emit(VIEW(item), "elm,state,unselected", "elm"); | ||
869 | _menu_item_inactivate(item, NULL, NULL, NULL); | ||
870 | } | ||
871 | edje_object_message_signal_process(VIEW(item)); | ||
872 | } | ||
873 | |||
874 | EAPI Eina_Bool | ||
875 | elm_menu_item_selected_get(const Elm_Object_Item *it) | ||
876 | { | ||
877 | ELM_OBJ_ITEM_CHECK_OR_RETURN(it, EINA_FALSE); | ||
878 | return ((Elm_Menu_Item *)it)->selected; | ||
879 | } | ||
880 | |||
881 | EAPI Elm_Object_Item * | ||
882 | elm_menu_item_prev_get(const Elm_Object_Item *it) | ||
883 | { | ||
884 | ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL); | ||
885 | Elm_Menu_Item *item = (Elm_Menu_Item *)it; | ||
886 | |||
887 | if (item->parent) | ||
888 | { | ||
889 | Eina_List *l = eina_list_data_find_list(item->parent->submenu.items, | ||
890 | item); | ||
891 | l = eina_list_prev(l); | ||
892 | if (!l) return NULL; | ||
893 | return l->data; | ||
894 | } | ||
895 | else | ||
896 | { | ||
897 | Widget_Data *wd = elm_widget_data_get(WIDGET(item)); | ||
898 | if (!wd || !wd->items) return NULL; | ||
899 | Eina_List *l = eina_list_data_find_list(wd->items, item); | ||
900 | l = eina_list_prev(l); | ||
901 | if (!l) return NULL; | ||
902 | return l->data; | ||
903 | } | ||
904 | return NULL; | ||
905 | } | ||
906 | |||
907 | EAPI Elm_Object_Item * | ||
908 | elm_menu_item_next_get(const Elm_Object_Item *it) | ||
909 | { | ||
910 | ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL); | ||
911 | Elm_Menu_Item *item = (Elm_Menu_Item *)it; | ||
912 | |||
913 | if (item->parent) | ||
914 | { | ||
915 | Eina_List *l = eina_list_data_find_list(item->parent->submenu.items, | ||
916 | item); | ||
917 | l = eina_list_next(l); | ||
918 | if (!l) return NULL; | ||
919 | return l->data; | ||
920 | } | ||
921 | else | ||
922 | { | ||
923 | Widget_Data *wd = elm_widget_data_get(WIDGET(item)); | ||
924 | if (!wd || !wd->items) return NULL; | ||
925 | Eina_List *l = eina_list_data_find_list(wd->items, item); | ||
926 | l = eina_list_next(l); | ||
927 | if (!l) return NULL; | ||
928 | return l->data; | ||
929 | } | ||
930 | return NULL; | ||
931 | } | ||
932 | |||
933 | EAPI Elm_Object_Item * | ||
934 | elm_menu_first_item_get(const Evas_Object * obj) | ||
935 | { | ||
936 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
937 | Widget_Data *wd = elm_widget_data_get(obj); | ||
938 | if (!wd) return NULL; | ||
939 | if (wd->items) return wd->items->data; | ||
940 | return NULL; | ||
941 | } | ||
942 | |||
943 | EAPI Elm_Object_Item * | ||
944 | elm_menu_last_item_get(const Evas_Object * obj) | ||
945 | { | ||
946 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
947 | Widget_Data *wd = elm_widget_data_get(obj); | ||
948 | if (!wd) return NULL; | ||
949 | Eina_List *l = eina_list_last(wd->items); | ||
950 | if (l) return l->data; | ||
951 | return NULL; | ||
952 | } | ||
953 | |||
954 | EAPI Elm_Object_Item * | ||
955 | elm_menu_selected_item_get(const Evas_Object * obj) | ||
956 | { | ||
957 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
958 | Widget_Data *wd = elm_widget_data_get(obj); | ||
959 | if (!wd) return NULL; | ||
960 | Eina_List *l; | ||
961 | Elm_Menu_Item *item; | ||
962 | EINA_LIST_FOREACH(wd->items, l, item) | ||
963 | { | ||
964 | if (item->selected) return ((Elm_Object_Item *)item); | ||
965 | } | ||
966 | return NULL; | ||
967 | } | ||
968 | |||