43d1224f2d312c9703ad39c410de4fdd4f5a7489
[framework/uifw/elementary.git] / src / lib / elm_menu.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup Menu Menu
6  * @ingroup Elementary
7  *
8  * A menu is a list of items displayed above the window. Each item can
9  * have a sub-menu. The menu object can be used to display a menu on right
10  * click, in a toolbar, anywhere.
11  *
12  */
13
14 typedef struct _Widget_Data Widget_Data;
15
16 struct _Menu_Item
17 {
18    Evas_Object *menu;
19    Evas_Object *o;
20    Elm_Menu_Item *parent;
21
22    Eina_Bool separator;
23    Eina_Bool disabled;
24
25    //if classic item or submenu
26    Evas_Object *icon;
27    const char *label;
28
29    Evas_Smart_Cb func;
30    Evas_Smart_Cb del_cb;
31    const void *data;
32
33    //if submenu
34    Eina_Bool open;
35    Evas_Object *hv, *bx, *location;
36    Eina_List *items;
37 };
38
39 struct _Widget_Data
40 {
41    Evas_Object *hv, *bx, *location, *parent;
42    Eina_List *items;
43    Evas_Coord xloc, yloc;
44 };
45
46 static const char *widtype = NULL;
47 static void _del_hook(Evas_Object *obj);
48 static void _theme_hook(Evas_Object *obj);
49 static void _sizing_eval(Evas_Object *obj);
50 static void _submenu_sizing_eval(Elm_Menu_Item *parent);
51 static void _item_sizing_eval(Elm_Menu_Item *item);
52 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
53 static void _submenu_hide(Elm_Menu_Item *item);
54 static void _submenu_open(void *data, Evas_Object *obj, const char *emission, const char *source);
55 static void _parent_resize(void *data, Evas *e, Evas_Object *obj, void *event_info);
56 static void _menu_hide(void *data, Evas_Object *obj, void *event_info);
57
58 static void
59 _del_pre_hook(Evas_Object *obj)
60 {
61    Widget_Data *wd = elm_widget_data_get(obj);
62    if (!wd) return;
63    evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_RESIZE, _parent_resize, obj);
64 }
65
66 static void
67 _del_hook(Evas_Object *obj)
68 {
69    Eina_List *l, *ll = NULL;
70    Elm_Menu_Item *item;
71    Widget_Data *wd = elm_widget_data_get(obj);
72    if (!wd) return;
73    ll = eina_list_append(ll, wd->items);
74    EINA_LIST_FOREACH(ll, ll, l)
75      {
76         EINA_LIST_FREE(l, item)
77           {
78              ll = eina_list_append(ll, item->items);
79              if (item->del_cb) item->del_cb((void*)item->data, item->o, item);
80              if (item->label) eina_stringshare_del(item->label);
81              if (item->hv) evas_object_del(item->hv);
82              if (item->location) evas_object_del(item->location);
83              free(item);
84           }
85      }
86    if (wd->hv) evas_object_del(wd->hv);
87    if (wd->location) evas_object_del(wd->location);
88    free(wd);
89 }
90
91 static void
92 _theme_hook(Evas_Object *obj)
93 {
94    Eina_List *l, *_l, *ll = NULL;
95    Elm_Menu_Item *item;
96    Widget_Data *wd = elm_widget_data_get(obj);
97    if (!wd) return;
98    ll = eina_list_append(ll, wd->items);
99    EINA_LIST_FOREACH(ll, ll, l)
100      {
101         EINA_LIST_FOREACH(l, _l, item)
102           {
103              ll = eina_list_append(ll, item->items);
104              if (item->separator)
105                _elm_theme_object_set(obj, item->o, "menu", "separator",
106                                      elm_widget_style_get(obj));
107              else if (item->bx)
108                {
109                   _elm_theme_object_set(obj, item->o, "menu", "item_with_submenu",
110                                         elm_widget_style_get(obj));
111                   elm_menu_item_label_set(item, item->label);
112                   elm_menu_item_icon_set(item, item->icon);
113                }
114              else
115                {
116                   _elm_theme_object_set(obj, item->o, "menu", "item",
117                                         elm_widget_style_get(obj));
118                   elm_menu_item_label_set(item, item->label);
119                   elm_menu_item_icon_set(item, item->icon);
120                }
121              if (item->disabled)
122                edje_object_signal_emit(item->o, "elm,state,disabled", "elm");
123              else
124                edje_object_signal_emit(item->o, "elm,state,enabled", "elm");
125              edje_object_message_signal_process(item->o);
126              edje_object_scale_set(item->o, elm_widget_scale_get(obj) *
127                                    _elm_config->scale);
128           }
129      }
130    _sizing_eval(obj);
131 }
132
133 static void
134 _sizing_eval(Evas_Object *obj)
135 {
136    Eina_List *l;
137    Elm_Menu_Item *item;
138    Evas_Coord x_p, y_p, w_p, h_p, x2, y2, w2, h2, bx, by, bw, bh;
139    Widget_Data *wd = elm_widget_data_get(obj);
140    if ((!wd) || (!wd->parent)) return;
141    EINA_LIST_FOREACH(wd->items,l,item) _item_sizing_eval(item);
142    evas_object_geometry_get(wd->location, &x_p, &y_p, &w_p, &h_p);
143    evas_object_geometry_get(wd->parent, &x2, &y2, &w2, &h2);
144    evas_object_geometry_get(wd->bx, &bx, &by, &bw, &bh);
145
146    x_p = wd->xloc;
147    y_p = wd->yloc;
148
149    if (x_p+bw > x2+w2) x_p -= x_p+bw - (x2+w2);
150    if (x_p < x2) x_p += x2 - x_p;
151
152    if (y_p+h_p+bh > y2+h2) y_p -= y_p+h_p+bh - (y2+h2);
153    if (y_p < y2) y_p += y2 - y_p;
154
155    evas_object_move(wd->location, x_p, y_p);
156    evas_object_resize(wd->location, bw, h_p);
157    evas_object_size_hint_min_set(wd->location, bw, h_p);
158    evas_object_size_hint_max_set(wd->location, bw, h_p);
159    elm_hover_target_set(wd->hv, wd->location);
160
161    EINA_LIST_FOREACH(wd->items,l,item)
162      {
163         if (item->open) _submenu_sizing_eval(item);
164      }
165 }
166
167 static void
168 _submenu_sizing_eval(Elm_Menu_Item *parent)
169 {
170    Eina_List *l;
171    Elm_Menu_Item *item;
172    Evas_Coord x_p, y_p, w_p, h_p, x2, y2, w2, h2, bx, by, bw, bh, px, py, pw, ph;
173    Widget_Data *wd = elm_widget_data_get(parent->menu);
174    if (!wd) return;
175    EINA_LIST_FOREACH(parent->items,l,item) _item_sizing_eval(item);
176    evas_object_geometry_get(parent->location, &x_p, &y_p, &w_p, &h_p);
177    evas_object_geometry_get(parent->o, &x2, &y2, &w2, &h2);
178    evas_object_geometry_get(parent->bx, &bx, &by, &bw, &bh);
179    evas_object_geometry_get(wd->parent, &px, &py, &pw, &ph);
180
181    x_p = x2+w2;
182    y_p = y2;
183
184    if (x_p + bw > px + pw)
185      x_p = x2-bw;
186
187    if (y_p+bh > py+ph)
188      y_p -= y_p+bh - (py+ph);
189    if (y_p < py)
190      y_p += y_p - y_p;
191
192    evas_object_move(parent->location, x_p, y_p);
193    evas_object_resize(parent->location, bw, h_p);
194    evas_object_size_hint_min_set(parent->location, bw, h_p);
195    evas_object_size_hint_max_set(parent->location, bw, h_p);
196    elm_hover_target_set(parent->hv, parent->location);
197
198    EINA_LIST_FOREACH(parent->items,l,item)
199      {
200         if (item->open)
201           _submenu_sizing_eval(item);
202      }
203 }
204
205 static void
206 _item_sizing_eval(Elm_Menu_Item *item)
207 {
208    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
209    if (!item->separator)
210      elm_coords_finger_size_adjust(1, &minw, 1, &minh);
211    edje_object_size_min_restricted_calc(item->o, &minw, &minh, minw, minh);
212    if (!item->separator)
213      elm_coords_finger_size_adjust(1, &minw, 1, &minh);
214    evas_object_size_hint_min_set(item->o, minw, minh);
215    evas_object_size_hint_max_set(item->o, maxw, maxh);
216 }
217
218 static void
219 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
220 {
221    _sizing_eval(data);
222 }
223
224 static void
225 _menu_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
226 {
227    _sizing_eval(data);
228 }
229
230 static void
231 _parent_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
232 {
233    _sizing_eval(data);
234 }
235
236 static void
237 _item_move_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
238 {
239    Elm_Menu_Item *item = data;
240    if (item->open) _submenu_sizing_eval(item);
241 }
242
243 static void
244 _hover_clicked_cb(void *data, Evas_Object *obj, void *event_info)
245 {
246    _menu_hide(data, obj, event_info);
247    evas_object_smart_callback_call(data, "clicked", NULL);
248 }
249
250 static void
251 _menu_hide(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
252 {
253    Eina_List *l;
254    Elm_Menu_Item *item2;
255    Widget_Data *wd = elm_widget_data_get(data);
256    if (!wd) return;
257    evas_object_hide(wd->hv);
258    evas_object_hide(data);
259
260    EINA_LIST_FOREACH(wd->items, l, item2)
261      {
262         if (item2->open) _submenu_hide(item2);
263      }
264 }
265
266 static void
267 _submenu_hide(Elm_Menu_Item *item)
268 {
269    Eina_List *l;
270    Elm_Menu_Item *item2;
271    evas_object_hide(item->hv);
272    item->open = EINA_FALSE;
273    EINA_LIST_FOREACH(item->items, l, item2)
274      {
275         if (item2->open) _submenu_hide(item2);
276      }
277 }
278
279 static void
280 _menu_item_select(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
281 {
282    Elm_Menu_Item *it = data;
283    if (it->items)
284      {
285         if (!it->open) _submenu_open(it, NULL, NULL, NULL);
286         else _submenu_hide(it);
287      }
288    else
289      _menu_hide(it->menu, NULL, NULL);
290
291    if (it->func) it->func((void *)(it->data), it->menu, it);
292 }
293
294 static void
295 _menu_item_activate(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
296 {
297    Eina_List *l;
298    Elm_Menu_Item *item2;
299    Elm_Menu_Item *item = data;
300    if (item->parent)
301      {
302         EINA_LIST_FOREACH(item->parent->items, l, item2)
303           {
304              if ((item2->open) && (item2 != item)) _submenu_hide(item2);
305           }
306      }
307    else
308      {
309         Widget_Data *wd = elm_widget_data_get(item->menu);
310         EINA_LIST_FOREACH(wd->items, l, item2)
311           {
312              if ((item2->open) && (item2 != item)) _submenu_hide(item2);
313           }
314      }
315 }
316
317 static void
318 _submenu_open(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
319 {
320    Elm_Menu_Item *it = data;
321    it->open = EINA_TRUE;
322    evas_object_show(it->hv);
323    _sizing_eval(it->menu);
324 }
325
326 static void
327 _show(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
328 {
329    Widget_Data *wd = elm_widget_data_get(data);
330    if (!wd) return;
331    evas_object_show(wd->hv);
332 }
333
334 static void
335 _item_obj_create(Elm_Menu_Item *item)
336 {
337    Widget_Data *wd = elm_widget_data_get(item->menu);
338    if (!wd) return;
339    item->o = edje_object_add(evas_object_evas_get(wd->bx));
340    evas_object_size_hint_weight_set(item->o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
341    evas_object_size_hint_fill_set(item->o, EVAS_HINT_FILL, EVAS_HINT_FILL);
342    _elm_theme_object_set(item->menu, item->o, "menu", "item",  elm_widget_style_get(item->menu));
343    edje_object_signal_callback_add(item->o, "elm,action,click", "",
344                                    _menu_item_select, item);
345    edje_object_signal_callback_add(item->o, "elm,action,activate", "",
346                                    _menu_item_activate, item);
347    evas_object_show(item->o);
348 }
349
350 static void
351 _item_separator_obj_create(Elm_Menu_Item *item)
352 {
353    Widget_Data *wd = elm_widget_data_get(item->menu);
354    if (!wd) return;
355    item->o = edje_object_add(evas_object_evas_get(wd->bx));
356    evas_object_size_hint_weight_set(item->o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
357    evas_object_size_hint_fill_set(item->o, EVAS_HINT_FILL, EVAS_HINT_FILL);
358    _elm_theme_object_set(item->menu, item->o, "menu", "separator",  elm_widget_style_get(item->menu));
359    edje_object_signal_callback_add(item->o, "elm,action,activate", "",
360                                    _menu_item_activate, item);
361    evas_object_show(item->o);
362 }
363
364 static void
365 _item_submenu_obj_create(Elm_Menu_Item *item)
366 {
367    Widget_Data *wd = elm_widget_data_get(item->menu);
368    if (!wd) return;
369    item->location = elm_icon_add(wd->bx);
370    item->hv = elm_hover_add(wd->bx);
371    elm_hover_target_set(item->hv, item->location);
372    elm_hover_parent_set(item->hv, wd->parent);
373    elm_object_style_set(item->hv, "submenu");
374
375    item->bx = elm_box_add(wd->bx);
376    evas_object_size_hint_weight_set(item->bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
377    evas_object_show(item->bx);
378    elm_hover_content_set(item->hv, elm_hover_best_content_location_get(item->hv, ELM_HOVER_AXIS_VERTICAL), item->bx);
379
380    _elm_theme_object_set(item->menu, item->o, "menu", "item_with_submenu",  elm_widget_style_get(item->menu));
381    elm_menu_item_label_set(item, item->label);
382    elm_menu_item_icon_set(item, item->icon);
383
384    edje_object_signal_callback_add(item->o, "elm,action,open", "",
385                                    _submenu_open, item);
386    evas_object_event_callback_add(item->o, EVAS_CALLBACK_MOVE, _item_move_resize, item);
387    evas_object_event_callback_add(item->o, EVAS_CALLBACK_RESIZE, _item_move_resize, item);
388
389    evas_object_event_callback_add(item->bx, EVAS_CALLBACK_RESIZE, _menu_resize, item->menu);
390 }
391
392 /**
393  * Add a new menu to the parent
394  *
395  * @param parent The parent object.
396  * @return The new object or NULL if it cannot be created.
397  *
398  * @ingroup Menu
399  */
400 EAPI Evas_Object *
401 elm_menu_add(Evas_Object *parent)
402 {
403    Evas_Object *obj;
404    Evas *e;
405    Widget_Data *wd;
406
407    wd = ELM_NEW(Widget_Data);
408    e = evas_object_evas_get(parent);
409    obj = elm_widget_add(e);
410    ELM_SET_WIDTYPE(widtype, "menu");
411    elm_widget_type_set(obj, "menu");
412    elm_widget_sub_object_add(parent, obj);
413    elm_widget_data_set(obj, wd);
414    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
415    elm_widget_del_hook_set(obj, _del_hook);
416    elm_widget_theme_hook_set(obj, _theme_hook);
417
418    wd->location = elm_icon_add(obj);
419    wd->parent = parent;
420
421    wd->hv = elm_hover_add(obj);
422    elm_hover_parent_set(wd->hv, parent);
423    elm_hover_target_set(wd->hv, wd->location);
424    elm_object_style_set(wd->hv, "menu");
425    evas_object_smart_callback_add(wd->hv, "clicked", _hover_clicked_cb, obj);
426
427    wd->bx = elm_box_add(obj);
428    evas_object_size_hint_weight_set(wd->bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
429    evas_object_show(wd->bx);
430    elm_hover_content_set(wd->hv, elm_hover_best_content_location_get(wd->hv, ELM_HOVER_AXIS_VERTICAL), wd->bx);
431
432    evas_object_event_callback_add(wd->parent, EVAS_CALLBACK_RESIZE, _parent_resize, obj);
433
434    evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _show, obj);
435
436    evas_object_event_callback_add(wd->bx, EVAS_CALLBACK_RESIZE, _menu_resize, obj);
437
438    _sizing_eval(obj);
439    return obj;
440 }
441
442 /**
443  * Set the parent
444  *
445  * @param obj The menu object.
446  * @param parent The new parent.
447  * 
448  * @ingroup Menu
449  */
450 EAPI void
451 elm_menu_parent_set(Evas_Object *obj, Evas_Object *parent)
452 {
453    Eina_List *l, *_l, *ll = NULL;
454    Elm_Menu_Item *item;
455    ELM_CHECK_WIDTYPE(obj, widtype);
456    Widget_Data *wd = elm_widget_data_get(obj);
457    if (!wd) return;
458    elm_hover_parent_set(wd->hv, parent);
459    wd->parent = parent;
460
461    ll = eina_list_append(ll, wd->items);
462    EINA_LIST_FOREACH(ll, ll, l)
463      {
464         EINA_LIST_FOREACH(l, _l, item)
465           {
466              if (item->hv)
467                {
468                   elm_hover_parent_set(item->hv, parent);
469                   ll = eina_list_append(ll, item->items);
470                }
471           }
472      }
473    _sizing_eval(obj);
474 }
475
476 /**
477  * Move the menu to a new position
478  *
479  * @param obj The menu object.
480  * @param x The new position.
481  * @param y The new position.
482  * 
483  * @ingroup Menu
484  */
485 EAPI void
486 elm_menu_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
487 {
488    ELM_CHECK_WIDTYPE(obj, widtype);
489    Widget_Data *wd = elm_widget_data_get(obj);
490    if (!wd) return;
491    wd->xloc = x;
492    wd->yloc = y;
493    _sizing_eval(obj);
494 }
495
496 /**
497  * Get the Evas_Object of an Elm_Menu_Item
498  * 
499  * @param it The menu item object.
500  * 
501  * @ingroup Menu
502  */
503 EAPI Evas_Object *
504 elm_menu_object_get(const Elm_Menu_Item *it)
505 {
506    return it->o;
507 }
508
509 /**
510  * Add an item at the end
511  *
512  * @param obj The menu object.
513  * @param icon A icon display on the item. The icon will be destryed by the menu.
514  * @param label The label of the item.
515  * @param func Function called when the user select the item.
516  * @param data Data sent by the callback.
517  * @return Returns the new item.
518  * 
519  * @ingroup Menu
520  */
521 EAPI Elm_Menu_Item *
522 elm_menu_item_add(Evas_Object *obj, Elm_Menu_Item *parent, Evas_Object *icon, const char *label, Evas_Smart_Cb func, const void *data)
523 {
524    Elm_Menu_Item *subitem;
525    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
526    Widget_Data *wd = elm_widget_data_get(obj);
527
528    if (!wd) return NULL;
529    subitem = ELM_NEW(Elm_Menu_Item);
530    if (!subitem) return NULL;
531    subitem->func = func;
532    subitem->data = data;
533    subitem->menu = obj;
534    subitem->parent = parent;
535
536    _item_obj_create(subitem);
537    elm_menu_item_label_set(subitem, label);
538    elm_menu_item_icon_set(subitem, icon);
539
540    if (parent)
541      {
542         if (!parent->bx) _item_submenu_obj_create(parent);
543         elm_box_pack_end(parent->bx, subitem->o);
544         parent->items = eina_list_append(parent->items, subitem);
545      }
546    else
547      {
548         elm_box_pack_end(wd->bx, subitem->o);
549         wd->items = eina_list_append(wd->items, subitem);
550      }
551
552    _sizing_eval(obj);
553    return subitem;
554 }
555
556 /**
557  * Set the label of a menu item
558  *
559  * @param it The menu item object.
560  * @param label The label to set for @p item
561  *
562  * @ingroup Menu
563  */
564 EAPI void
565 elm_menu_item_label_set(Elm_Menu_Item *item, const char *label)
566 {
567    eina_stringshare_replace(&item->label, label);
568
569    if (label)
570      edje_object_signal_emit(item->o, "elm,state,text,visible", "elm");
571    else
572      edje_object_signal_emit(item->o, "elm,state,text,hidden", "elm");
573
574    edje_object_message_signal_process(item->o);
575    edje_object_part_text_set(item->o, "elm.text", label);
576    _sizing_eval(item->menu);
577 }
578
579 /**
580  * Get the label of a menu item
581  *
582  * @param it The menu item object.
583  * @return The label of @p item
584  *
585  * @ingroup Menu
586  */
587 EAPI const char *
588 elm_menu_item_label_get(Elm_Menu_Item *item)
589 {
590    if (!item) return NULL;
591    return item->label;
592 }
593
594 /**
595  * Set the icon of a menu item
596  *
597  * Once the icon object is set, a previously set one will be deleted.
598  *
599  * @param it The menu item object.
600  * @param icon The icon object to set for @p item
601  *
602  * @ingroup Menu
603  */
604 EAPI void
605 elm_menu_item_icon_set(Elm_Menu_Item *item, Evas_Object *icon)
606 {
607    if(item->icon == icon) return;
608    if (item->icon) evas_object_del(item->icon);
609    item->icon = icon;
610    if (icon)
611      {
612         elm_widget_sub_object_add(item->menu, icon);
613         evas_object_event_callback_add(icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
614                                         _changed_size_hints, item->menu);
615         edje_object_part_swallow(item->o, "elm.swallow.content", icon);
616         edje_object_signal_emit(item->o, "elm,state,icon,visible", "elm");
617         edje_object_message_signal_process(item->o);
618      }
619    _sizing_eval(item->menu);
620 }
621
622 /**
623  * Set the disabled state of @p item.
624  *
625  * @param it The menu item object.
626  * @param disabled The enabled/disabled state of the item
627  *
628  * @ingroup Menu
629  */
630 EAPI void
631 elm_menu_item_disabled_set(Elm_Menu_Item *item, Eina_Bool disabled)
632 {
633    if (disabled == item->disabled) return;
634    item->disabled = disabled;
635    if (disabled)
636      {
637         edje_object_signal_emit(item->o, "elm,state,disabled", "elm");
638         if (item->open) _submenu_hide(item);
639      }
640    else
641      edje_object_signal_emit(item->o, "elm,state,enabled", "elm");
642    edje_object_message_signal_process(item->o);
643 }
644
645 /**
646  * Get the disabled state of @p item.
647  * 
648  * @param it The menu item object.
649  * @return The enabled/disabled state of the item
650  * 
651  * @ingroup Menu
652  */
653 EAPI Eina_Bool
654 elm_menu_item_disabled_get(Elm_Menu_Item *item)
655 {
656    if (!item) return EINA_FALSE;
657    return item->disabled;
658 }
659
660 /**
661  * Add a separator item to menu @p obj under @p parent.
662  *
663  * @param obj The menu object
664  * @param parent The item to add the separator under
665  *
666  * @return The created item or NULL on failure
667  *
668  * @ingroup Menu
669  */
670 EAPI Elm_Menu_Item *
671 elm_menu_item_separator_add(Evas_Object *obj, Elm_Menu_Item *parent)
672 {
673    Elm_Menu_Item *subitem;
674    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
675    Widget_Data *wd = elm_widget_data_get(obj);
676    if (!wd) return NULL;
677    subitem = ELM_NEW(Elm_Menu_Item);
678    if (!subitem) return NULL;
679    subitem->menu = obj;
680    subitem->separator = 1;
681    _item_separator_obj_create(subitem);
682    if (!parent)
683      {
684         elm_box_pack_end(wd->bx, subitem->o);
685         wd->items = eina_list_append(wd->items, subitem);
686      }
687    else
688      {
689         if (!parent->bx) _item_submenu_obj_create(parent);
690         elm_box_pack_end(parent->bx, subitem->o);
691         parent->items = eina_list_append(parent->items, subitem);
692      }
693    _sizing_eval(obj);
694    return subitem;
695 }
696
697
698 /**
699  * Deletes an item from the menu.
700  *
701  * @param item The item to delete
702  *
703  * @ingroup Menu
704  */
705
706 /**
707  * Get the icon of a menu item
708  * 
709  * @param it The menu item object.
710  * @return The icon object of @p item or NULL
711  * 
712  * @ingroup Menu
713  */
714 EAPI Evas_Object *
715 elm_menu_item_icon_get(Elm_Menu_Item *item)
716 {
717    if (!item) return NULL;
718    return item->icon;
719 }
720
721 /**
722  * Returns whether @p item is a separator.
723  *
724  * @param item The item to check
725  * @return If true, @p item is a separator
726  *
727  * @ingroup Menu
728  */
729 EAPI Eina_Bool
730 elm_menu_item_is_separator(Elm_Menu_Item *item)
731 {
732    if (!item) return EINA_FALSE;
733    return item->separator;
734 }
735
736 EAPI void
737 elm_menu_item_del(Elm_Menu_Item *item)
738 {
739    Elm_Menu_Item *_item;
740
741    if (!item) return;
742    if (item->del_cb) item->del_cb((void*)item->data, item->o, item);
743
744    EINA_LIST_FREE(item->items, _item) elm_menu_item_del(_item);
745    if (item->label) eina_stringshare_del(item->label);
746    if (item->icon) evas_object_del(item->icon);
747    if (item->hv) evas_object_del(item->hv);
748    if (item->location) evas_object_del(item->location);
749    if (item->o) evas_object_del(item->o);
750
751    if (item->parent)
752      item->parent->items = eina_list_remove(item->parent->items, item);
753    else
754      {
755         Widget_Data *wd = elm_widget_data_get(item->menu);
756         wd->items = eina_list_remove(wd->items, item);
757      }
758
759    free(item);
760 }
761
762 /**
763  * Set the function called when a menu item is freed.
764  *
765  * @param it The item to set the callback on
766  * @param func The function called
767  *
768  * @ingroup Menu
769  */
770 EAPI void
771 elm_menu_item_del_cb_set(Elm_Menu_Item *it, Evas_Smart_Cb func)
772 {
773    if (!it) return;
774    it->del_cb = func;
775 }
776
777 /**
778  * Returns the data associated with menu item @p it.
779  *
780  * @param it The item
781  * @return The data associated with @p it
782  *
783  * @ingroup Menu
784  */
785 EAPI void *
786 elm_menu_item_data_get(const Elm_Menu_Item *it)
787 {
788    if (!it) return NULL;
789    return (void *)it->data;
790 }
791
792 /**
793  * Sets the data to be associated with menu item @p it.
794  *
795  * @param item The item
796  * @param data The data to be associated with @p item
797  *
798  * @ingroup Menu
799  */
800 EAPI void
801 elm_menu_item_data_set(Elm_Menu_Item *item, const void *data)
802 {
803    if (!item) return;
804    item->data = data;
805 }
806
807 /**
808  * Returns a list of @p item's subitems.
809  *
810  * @param it The item
811  * @return An Eina_List* of @p item's subitems
812  *
813  * @ingroup Menu
814  */
815 EAPI const Eina_List *
816 elm_menu_item_subitems_get(Elm_Menu_Item *item)
817 {
818    if (!item) return NULL;
819    return item->items;
820 }