842ac8e963c432fa02d0d355d77f64298625aa9e
[framework/uifw/elementary.git] / src / lib / elm_toolbar.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup Toolbar Toolbar
6  * @ingroup Elementary
7  *
8  * A toolbar is a widget that displays a list of buttons inside
9  * a box.  It is scrollable, and only one item can be selected at a time.
10  */
11
12 typedef struct _Widget_Data Widget_Data;
13
14 struct _Widget_Data
15 {
16    Evas_Object *scr, *bx;
17    Eina_List *items;
18    int icon_size;
19    Eina_Bool scrollable : 1;
20    Evas_Object *menu_parent;
21    Eina_Bool homogeneous : 1;
22    double align;
23 };
24
25 struct _Elm_Toolbar_Item
26 {
27    Evas_Object *obj;
28    Evas_Object *base;
29    const char *label;
30    Evas_Object *icon;
31    Evas_Smart_Cb func;
32    Evas_Smart_Cb del_cb;
33    const void *data;
34    Eina_Bool selected : 1;
35    Eina_Bool disabled : 1;
36    Eina_Bool separator : 1;
37    Eina_Bool menu : 1;
38    Evas_Object *o_menu;
39 };
40
41 static const char *widtype = NULL;
42 static void _item_show(Elm_Toolbar_Item *it);
43 static void _item_select(Elm_Toolbar_Item *it);
44 static void _item_disable(Elm_Toolbar_Item *it, Eina_Bool disabled);
45 static void _del_pre_hook(Evas_Object *obj);
46 static void _del_hook(Evas_Object *obj);
47 static void _theme_hook(Evas_Object *obj);
48 static void _sizing_eval(Evas_Object *obj);
49 static void _resize(void *data, Evas *e, Evas_Object *obj, void *event_info);
50 static void _menu_move_resize(void *data, Evas *e, Evas_Object *obj, void *event_info);
51 static void _menu_hide(void *data, Evas *e, Evas_Object *obj, void *event_info);
52 static void _layout(Evas_Object *o, Evas_Object_Box_Data *priv, void *data);
53
54 static void
55 _item_show(Elm_Toolbar_Item *it)
56 {
57    Widget_Data *wd = elm_widget_data_get(it->obj);
58    Evas_Coord x, y, w, h, bx, by;
59
60    if (!wd) return;
61    evas_object_geometry_get(wd->bx, &bx, &by, NULL, NULL);
62    evas_object_geometry_get(it->base, &x, &y, &w, &h);
63    elm_smart_scroller_child_region_show(wd->scr, x - bx, y - by, w, h);
64 }
65
66 static void
67 _item_select(Elm_Toolbar_Item *it)
68 {
69    Elm_Toolbar_Item *it2;
70    Widget_Data *wd = elm_widget_data_get(it->obj);
71    Evas_Object *obj2;
72    const Eina_List *l;
73
74    if (!wd) return;
75    if ((it->selected) || (it->disabled) || (it->separator)) return;
76    EINA_LIST_FOREACH(wd->items, l, it2)
77      {
78         if (it2->selected)
79           {
80              it2->selected = EINA_FALSE;
81              edje_object_signal_emit(it2->base, "elm,state,unselected", "elm");
82              break;
83           }
84      }
85    it->selected = EINA_TRUE;
86    edje_object_signal_emit(it->base, "elm,state,selected", "elm");
87    _item_show(it);
88    obj2 = it->obj;
89    if(it->menu)
90      {
91         evas_object_show(it->o_menu);
92         evas_object_event_callback_add(it->base, EVAS_CALLBACK_RESIZE,
93                                        _menu_move_resize, it);
94         evas_object_event_callback_add(it->base, EVAS_CALLBACK_MOVE,
95                                        _menu_move_resize, it);
96
97         _menu_move_resize(it, NULL, NULL, NULL);
98      }
99    if (it->func) it->func((void *)(it->data), it->obj, it);
100    evas_object_smart_callback_call(obj2, "clicked", it);
101 }
102
103 static void
104 _menu_hide(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
105 {
106    Elm_Toolbar_Item *it = data;
107    elm_toolbar_item_unselect_all(it->obj);
108 }
109
110 static void
111 _menu_del(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
112 {
113    // avoid hide being emitted during object deletion
114    evas_object_event_callback_del_full
115      (obj, EVAS_CALLBACK_HIDE, _menu_hide, data);
116 }
117
118 static void
119 _menu_move_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
120 {
121     Elm_Toolbar_Item *it = data;
122     Evas_Coord x,y,w,h;
123     Widget_Data *wd = elm_widget_data_get(it->obj);
124
125     if ((!wd) || (!wd->menu_parent)) return;
126     evas_object_geometry_get(it->base, &x, &y, &w, &h);
127     elm_menu_move(it->o_menu, x, y+h);
128 }
129
130 static void
131 _item_disable(Elm_Toolbar_Item *it, Eina_Bool disabled)
132 {
133    Widget_Data *wd = elm_widget_data_get(it->obj);
134
135    if (!wd) return;
136    if (it->disabled == disabled) return;
137    it->disabled = disabled;
138    if (it->disabled)
139      edje_object_signal_emit(it->base, "elm,state,disabled", "elm");
140    else
141      edje_object_signal_emit(it->base, "elm,state,enabled", "elm");
142 }
143
144 static void
145 _del_pre_hook(Evas_Object *obj)
146 {
147    Widget_Data *wd = elm_widget_data_get(obj);
148    Elm_Toolbar_Item *it;
149
150    if (!wd) return;
151    EINA_LIST_FREE(wd->items, it)
152      {
153         if (it->del_cb) it->del_cb((void *)it->data, it->obj, it);
154         eina_stringshare_del(it->label);
155         if (it->icon) evas_object_del(it->icon);
156         if ((!wd->menu_parent) && (it->o_menu)) evas_object_del(it->o_menu);
157         evas_object_del(it->base);
158         free(it);
159      }
160 }
161
162 static void
163 _del_hook(Evas_Object *obj)
164 {
165    Widget_Data *wd = elm_widget_data_get(obj);
166
167    if (!wd) return;
168    free(wd);
169 }
170
171 static void
172 _theme_hook(Evas_Object *obj)
173 {
174    Widget_Data *wd = elm_widget_data_get(obj);
175    const Eina_List *l;
176    Elm_Toolbar_Item *it;
177    const char *style = elm_widget_style_get(obj);
178    double scale = 0;
179
180    if (!wd) return;
181    elm_smart_scroller_object_theme_set(obj, wd->scr, "toolbar", "base", elm_widget_style_get(obj));
182    scale = (elm_widget_scale_get(obj) * _elm_config->scale);
183 //   edje_object_scale_set(wd->scr, scale);
184    EINA_LIST_FOREACH(wd->items, l, it)
185      {
186         Evas_Coord mw, mh;
187
188         edje_object_scale_set(it->base, scale);
189         if (!it->separator)
190           {
191              if (it->selected)
192                edje_object_signal_emit(it->base, "elm,state,selected", "elm");
193              if (it->disabled)
194                edje_object_signal_emit(it->base, "elm,state,disabled", "elm");
195              _elm_theme_object_set(obj, it->base, "toolbar", "item", style);
196              if (it->icon)
197                {
198                   int ms = 0;
199
200                   ms = ((double)wd->icon_size * _elm_config->scale);
201                   evas_object_size_hint_min_set(it->icon, ms, ms);
202                   evas_object_size_hint_max_set(it->icon, ms, ms);
203                   edje_object_part_swallow(it->base, "elm.swallow.icon",
204                                            it->icon);
205                }
206              edje_object_part_text_set(it->base, "elm.text", it->label);
207           }
208         else
209           _elm_theme_object_set(obj, it->base, "toolbar", "separator", style);
210
211         mw = mh = -1;
212         if (!it->separator)
213           elm_coords_finger_size_adjust(1, &mw, 1, &mh);
214         edje_object_size_min_restricted_calc(it->base, &mw, &mh, mw, mh);
215         if (!it->separator)
216           elm_coords_finger_size_adjust(1, &mw, 1, &mh);
217         evas_object_size_hint_min_set(it->base, mw, mh);
218      }
219    _sizing_eval(obj);
220 }
221
222 static void
223 _sizing_eval(Evas_Object *obj)
224 {
225    Widget_Data *wd = elm_widget_data_get(obj);
226    Evas_Coord minw = -1, minh = -1;
227    Evas_Coord vw = 0, vh = 0;
228    Evas_Coord w, h;
229
230    if (!wd) return;
231    evas_object_smart_calculate(wd->bx);
232    edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr),
233                              &minw, &minh);
234    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
235    if (w < minw) w = minw;
236    if (h < minh) h = minh;
237
238    evas_object_resize(wd->scr, w, h);
239
240    evas_object_size_hint_min_get(wd->bx, &minw, &minh);
241    if (w > minw) minw = w;
242    evas_object_resize(wd->bx, minw, minh);
243    elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh);
244    if (wd->scrollable)
245      minw = w - vw;
246    else
247      minw = minw + (w - vw);
248    minh = minh + (h - vh);
249    evas_object_size_hint_min_set(obj, minw, minh);
250    evas_object_size_hint_max_set(obj, -1, -1);
251 }
252
253 static void
254 _resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
255 {
256    Widget_Data *wd = elm_widget_data_get(data);
257    Evas_Coord mw, mh, vw, vh, w, h;
258    const Eina_List *l;
259    Elm_Toolbar_Item *it;
260
261    if (!wd) return;
262    elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh);
263    evas_object_size_hint_min_get(wd->bx, &mw, &mh);
264    evas_object_geometry_get(wd->bx, NULL, NULL, &w, &h);
265    if (vw >= mw)
266      {
267         if (w != vw) evas_object_resize(wd->bx, vw, h);
268      }
269    EINA_LIST_FOREACH(wd->items, l, it)
270      {
271         if (it->selected)
272           {
273              _item_show(it);
274              break;
275           }
276      }
277 }
278
279 static void
280 _select(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
281 {
282    _item_select(data);
283 }
284
285 static void
286 _layout(Evas_Object *o, Evas_Object_Box_Data *priv, void *data)
287 {
288    Widget_Data *wd = data;
289    if (!wd) return;
290    _els_box_layout(o, priv, 1, wd->homogeneous);
291 }
292
293 /**
294  * Add a toolbar object to @p parent.
295  *
296  * @param parent The parent object
297  *
298  * @return The created object, or NULL on failure
299  *
300  * @ingroup Toolbar
301  */
302 EAPI Evas_Object *
303 elm_toolbar_add(Evas_Object *parent)
304 {
305    Evas_Object *obj;
306    Evas *e;
307    Widget_Data *wd;
308
309    wd = ELM_NEW(Widget_Data);
310    e = evas_object_evas_get(parent);
311    obj = elm_widget_add(e);
312    ELM_SET_WIDTYPE(widtype, "toolbar");
313    elm_widget_type_set(obj, "toolbar");
314    elm_widget_sub_object_add(parent, obj);
315    elm_widget_data_set(obj, wd);
316    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
317    elm_widget_del_hook_set(obj, _del_hook);
318    elm_widget_theme_hook_set(obj, _theme_hook);
319    elm_widget_can_focus_set(obj, 0);
320
321    wd->scr = elm_smart_scroller_add(e);
322    elm_smart_scroller_widget_set(wd->scr, obj);
323    elm_smart_scroller_object_theme_set(obj, wd->scr, "toolbar", "base", "default");
324    elm_smart_scroller_bounce_allow_set(wd->scr, 1, 0);
325    elm_widget_resize_object_set(obj, wd->scr);
326    elm_smart_scroller_policy_set(wd->scr,
327                                  ELM_SMART_SCROLLER_POLICY_AUTO,
328                                  ELM_SMART_SCROLLER_POLICY_OFF);
329
330    wd->icon_size = 32;
331    wd->scrollable = EINA_TRUE;
332    wd->homogeneous = EINA_TRUE;
333    wd->align = 0.5;
334
335    wd->bx = evas_object_box_add(e);
336    evas_object_size_hint_align_set(wd->bx, wd->align, 0.5);
337    evas_object_box_layout_set(wd->bx, _layout, wd, NULL);
338    elm_widget_sub_object_add(obj, wd->bx);
339    elm_smart_scroller_child_set(wd->scr, wd->bx);
340    evas_object_show(wd->bx);
341
342    evas_object_event_callback_add(wd->scr, EVAS_CALLBACK_RESIZE, _resize, obj);
343
344    _sizing_eval(obj);
345    return obj;
346 }
347
348 /**
349  * Set the icon size (in pixels) for the toolbar.
350  *
351  * @param obj The toolbar object
352  * @param icon_size The icon size in pixels
353  *
354  * @ingroup Toolbar
355  */
356 EAPI void
357 elm_toolbar_icon_size_set(Evas_Object *obj, int icon_size)
358 {
359    ELM_CHECK_WIDTYPE(obj, widtype);
360    Widget_Data *wd = elm_widget_data_get(obj);
361    if (!wd) return;
362    if (icon_size > 48) return;
363    if (wd->icon_size == icon_size) return;
364    wd->icon_size = icon_size;
365    _theme_hook(obj);
366 }
367
368 /**
369  * Get the icon size (in pixels) for the toolbar.
370  *
371  * @param obj The toolbar object
372  * @return The icon size in pixels
373  *
374  * @ingroup Toolbar
375  */
376 EAPI int
377 elm_toolbar_icon_size_get(const Evas_Object *obj)
378 {
379    ELM_CHECK_WIDTYPE(obj, widtype) 0;
380    Widget_Data *wd = elm_widget_data_get(obj);
381    if (!wd) return 0;
382    return wd->icon_size;
383 }
384
385 /**
386  * Add an item to the toolbar.
387  *
388  * @param obj The toolbar object
389  * @param icon The icon object of the item
390  * @param label The label of the item
391  * @param func The function to call when the item is clicked
392  * @param data The data to associate with the item
393  *
394  * @return The toolbar item, or NULL upon failure
395  *
396  * @ingroup Toolbar
397  */
398 EAPI Elm_Toolbar_Item *
399 elm_toolbar_item_add(Evas_Object *obj, Evas_Object *icon, const char *label, Evas_Smart_Cb func, const void *data)
400 {
401    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
402    Widget_Data *wd = elm_widget_data_get(obj);
403    Evas_Coord mw, mh;
404    Elm_Toolbar_Item *it;
405
406    if (!wd) return NULL;
407    it = ELM_NEW(Elm_Toolbar_Item);
408    if (!it) return NULL;
409    wd->items = eina_list_append(wd->items, it);
410    it->obj = obj;
411    it->label = eina_stringshare_add(label);
412    it->icon = icon;
413    it->func = func;
414    it->data = data;
415    it->separator = EINA_FALSE;
416    it->base = edje_object_add(evas_object_evas_get(obj));
417    _elm_theme_object_set(obj, it->base, "toolbar", "item", elm_widget_style_get(obj));
418    edje_object_signal_callback_add(it->base, "elm,action,click", "elm",
419                                    _select, it);
420    elm_widget_sub_object_add(obj, it->base);
421    if (it->icon)
422      {
423         int ms = 0;
424
425         ms = ((double)wd->icon_size * _elm_config->scale);
426         evas_object_size_hint_min_set(it->icon, ms, ms);
427         evas_object_size_hint_max_set(it->icon, ms, ms);
428         edje_object_part_swallow(it->base, "elm.swallow.icon", it->icon);
429         evas_object_show(it->icon);
430         elm_widget_sub_object_add(obj, it->icon);
431      }
432    edje_object_part_text_set(it->base, "elm.text", it->label);
433    mw = mh = -1;
434    elm_coords_finger_size_adjust(1, &mw, 1, &mh);
435    edje_object_size_min_restricted_calc(it->base, &mw, &mh, mw, mh);
436    elm_coords_finger_size_adjust(1, &mw, 1, &mh);
437    evas_object_size_hint_weight_set(it->base, -1.0, EVAS_HINT_EXPAND);
438    evas_object_size_hint_align_set(it->base, 0.5, EVAS_HINT_FILL);
439    evas_object_size_hint_min_set(it->base, mw, mh);
440    evas_object_box_append(wd->bx, it->base);
441    evas_object_show(it->base);
442    _sizing_eval(obj);
443    return it;
444 }
445
446 /**
447  * Get the icon associated with @p item.
448  *
449  * @param item The toolbar item
450  * @return The icon object
451  *
452  * @ingroup Toolbar
453  */
454 EAPI Evas_Object *
455 elm_toolbar_item_icon_get(Elm_Toolbar_Item *item)
456 {
457    if (!item) return NULL;
458    return item->icon;
459 }
460
461 /**
462  * Get the label associated with @p item.
463  *
464  * @param item The toolbar item
465  * @return The label
466  *
467  * @ingroup Toolbar
468  */
469 EAPI const char *
470 elm_toolbar_item_label_get(const Elm_Toolbar_Item *item)
471 {
472    if (!item) return NULL;
473    return item->label;
474 }
475
476 /**
477  * Get the selected state of @p item.
478  *
479  * @param item The toolbar item
480  * @return If true, the item is selected
481  *
482  * @ingroup Toolbar
483  */
484 EAPI Eina_Bool
485 elm_toolbar_item_selected_get(const Elm_Toolbar_Item *item)
486 {
487    if (!item) return EINA_FALSE;
488    return item->selected;
489 }
490
491 /**
492  * Set the label associated with @p item.
493  *
494  * @param item The toolbar item
495  * @param label The label of @p item
496  *
497  * @ingroup Toolbar
498  */
499 EAPI void
500 elm_toolbar_item_label_set(Elm_Toolbar_Item *item, const char *label)
501 {
502    Evas_Coord mw = -1, mh = -1;
503
504    if (!item) return;
505    eina_stringshare_replace(&item->label, label);
506    edje_object_part_text_set(item->base, "elm.text", item->label);
507
508    elm_coords_finger_size_adjust(1, &mw, 1, &mh);
509    edje_object_size_min_restricted_calc(item->base, &mw, &mh, mw, mh);
510    elm_coords_finger_size_adjust(1, &mw, 1, &mh);
511    evas_object_size_hint_weight_set(item->base, -1.0, EVAS_HINT_EXPAND);
512    evas_object_size_hint_align_set(item->base, 0.5, EVAS_HINT_FILL);
513    evas_object_size_hint_min_set(item->base, mw, mh);
514 }
515
516
517 /**
518  * Delete a toolbar item.
519  *
520  * @param it The toolbar item
521  *
522  * @ingroup Toolbar
523  */
524 EAPI void
525 elm_toolbar_item_del(Elm_Toolbar_Item *it)
526 {
527    Widget_Data *wd = elm_widget_data_get(it->obj);
528    Evas_Object *obj2 = it->obj;
529
530    if ((!wd) || (!it)) return;
531    if (it->del_cb) it->del_cb((void *)it->data, it->obj, it);
532    wd->items = eina_list_remove(wd->items, it);
533    eina_stringshare_del(it->label);
534    if (it->icon) evas_object_del(it->icon);
535    evas_object_del(it->base);
536    free(it);
537    _theme_hook(obj2);
538 }
539
540 /**
541  * Set the function called when a toolbar item is freed.
542  *
543  * @param it The item to set the callback on
544  * @param func The function called
545  *
546  * @ingroup Toolbar
547  */
548 EAPI void
549 elm_toolbar_item_del_cb_set(Elm_Toolbar_Item *it, Evas_Smart_Cb func)
550 {
551    it->del_cb = func;
552 }
553
554 /**
555  * Select the toolbar item @p item.
556  *
557  * @param item The toolbar item
558  *
559  * @ingroup Toolbar
560  */
561 EAPI void
562 elm_toolbar_item_select(Elm_Toolbar_Item *item)
563 {
564    if (!item) return;
565    _item_select(item);
566 }
567
568 /**
569  * Get the disabled state of @p item.
570  *
571  * @param item The toolbar item
572  * @return If true, the item is disabled
573  *
574  * @ingroup Toolbar
575  */
576 EAPI Eina_Bool
577 elm_toolbar_item_disabled_get(Elm_Toolbar_Item *item)
578 {
579    if (!item) return EINA_FALSE;
580    return item->disabled;
581 }
582
583 /**
584  * Set the disabled state of @p item.
585  *
586  * @param item The toolbar item
587  * @param disabled If true, the item is disabled
588  *
589  * @ingroup Toolbar
590  */
591 EAPI void
592 elm_toolbar_item_disabled_set(Elm_Toolbar_Item *item, Eina_Bool disabled)
593 {
594    if (!item) return;
595    _item_disable(item, disabled);
596 }
597
598 /**
599  * Get the separator state of @p item.
600  *
601  * @param item The toolbar item
602  * @param separator If true, the item is a separator
603  *
604  * @ingroup Toolbar
605  */
606 EAPI void
607 elm_toolbar_item_separator_set(Elm_Toolbar_Item *item, Eina_Bool separator)
608 {
609    if (!item) return;
610    if (item->separator == separator) return;
611    item->separator = separator;
612    _theme_hook(item->obj);
613 }
614
615 /**
616  * Set the separator state of @p item.
617  *
618  * @param item The toolbar item
619  * @return If true, the item is a separator
620  *
621  * @ingroup Toolbar
622  */
623 EAPI Eina_Bool
624 elm_toolbar_item_separator_get(Elm_Toolbar_Item *item)
625 {
626    if (!item) return EINA_FALSE;
627    return item->separator;
628 }
629
630 /**
631  * Set the scrollable state of toolbar @p obj.
632  *
633  * @param obj The toolbar object
634  * @param scrollable If true, the toolbar will be scrollable
635  *
636  * @ingroup Toolbar
637  */
638 EAPI void
639 elm_toolbar_scrollable_set(Evas_Object *obj, Eina_Bool scrollable)
640 {
641    ELM_CHECK_WIDTYPE(obj, widtype);
642    Widget_Data *wd = elm_widget_data_get(obj);
643
644    if (!wd) return;
645    wd->scrollable = scrollable;
646    elm_smart_scroller_bounce_allow_set(wd->scr, wd->scrollable, 0);
647    _sizing_eval(obj);
648 }
649
650 /**
651  * Get the scrollable state of toolbar @p obj.
652  *
653  * @param obj The toolbar object
654  * @return If true, the toolbar is scrollable
655  *
656  * @ingroup Toolbar
657  */
658 EAPI Eina_Bool
659 elm_toolbar_scrollable_get(Evas_Object *obj)
660 {
661    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
662    Widget_Data *wd = elm_widget_data_get(obj);
663
664    if (!wd) return EINA_FALSE;
665    return wd->scrollable;
666 }
667
668 /**
669  * Set the homogenous mode of toolbar @p obj.
670  *
671  * @param obj The toolbar object
672  * @param homogenous If true, the toolbar items will be uniform in size
673  *
674  * @ingroup Toolbar
675  */
676 EAPI void
677 elm_toolbar_homogenous_set(Evas_Object *obj, Eina_Bool homogenous)
678 {
679    ELM_CHECK_WIDTYPE(obj, widtype);
680    Widget_Data *wd = elm_widget_data_get(obj);
681
682    if (!wd) return;
683    wd->homogeneous = !!homogenous;
684    evas_object_smart_calculate(wd->bx);
685 }
686
687 /**
688  * Get the homogenous mode of toolbar @p obj.
689  *
690  * @param obj The toolbar object
691  * @return If true, the toolbar items are uniform in size
692  *
693  * @ingroup Toolbar
694  */
695 EAPI Eina_Bool
696 elm_toolbar_homogenous_get(Evas_Object *obj)
697 {
698    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
699    Widget_Data *wd = elm_widget_data_get(obj);
700
701    if (!wd) return EINA_FALSE;
702    return wd->homogeneous;
703 }
704
705 /**
706  * Set the parent object of the toolbar menu
707  *
708  * @param obj The toolbar object
709  * @param parent The parent of the menu object
710  *
711  * @ingroup Toolbar
712  */
713 EAPI void
714 elm_toolbar_menu_parent_set(Evas_Object *obj, Evas_Object *parent)
715 {
716    Eina_List *l;
717    Elm_Toolbar_Item *it;
718    ELM_CHECK_WIDTYPE(obj, widtype);
719    Widget_Data *wd = elm_widget_data_get(obj);
720
721    if ((!wd) || (!parent)) return;
722    wd->menu_parent = parent;
723    EINA_LIST_FOREACH(wd->items, l, it)
724      {
725         if (it->o_menu)
726           elm_menu_parent_set(it->o_menu, wd->menu_parent);
727      }
728 }
729
730 /**
731  * Get the parent object of the toolbar menu
732  *
733  * @param obj The toolbar object
734  * @return The parent of the menu object
735  *
736  * @ingroup Toolbar
737  */
738 EAPI Evas_Object *
739 elm_toolbar_menu_parent_get(Evas_Object *obj)
740 {
741    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
742    Widget_Data *wd = elm_widget_data_get(obj);
743    if (!wd) return NULL;
744
745    return wd->menu_parent;
746 }
747
748 /**
749  * Unselect all of the items in the toolbar.
750  *
751  * @param obj The toolbar object
752  *
753  * @ingroup Toolbar
754  */
755 EAPI void
756 elm_toolbar_item_unselect_all(Evas_Object *obj)
757 {
758    Eina_List *l;
759    Elm_Toolbar_Item *it;
760    ELM_CHECK_WIDTYPE(obj, widtype);
761    Widget_Data *wd = elm_widget_data_get(obj);
762
763    if (!wd) return;
764    EINA_LIST_FOREACH(wd->items, l, it)
765      {
766         if (it->selected)
767           {
768              it->selected = EINA_FALSE;
769              edje_object_signal_emit(it->base, "elm,state,unselected", "elm");
770              break;
771           }
772      }
773 }
774
775 /**
776  * Unselect the specified toolbar item.
777  *
778  * @param item The toolbar item
779  *
780  * @ingroup Toolbar
781  */
782 EAPI void
783 elm_toolbar_item_unselect(Elm_Toolbar_Item *item)
784 {
785    if ((!item) || (!item->selected)) return;
786    item->selected = EINA_FALSE;
787    edje_object_signal_emit(item->base, "elm,state,unselected", "elm");
788 }
789
790 /**
791  * Set the alignment of the items.
792  *
793  * @param obj The toolbar object
794  * @param align The new alignment. (left) 0.0 ... 1.0 (right)
795  *
796  * @ingroup Toolbar
797  */
798 EAPI void
799 elm_toolbar_align_set(Evas_Object *obj, double align)
800 {
801    ELM_CHECK_WIDTYPE(obj, widtype);
802    Widget_Data *wd = elm_widget_data_get(obj);
803
804    if (!wd) return;
805    if (wd->align != align)
806      evas_object_size_hint_align_set(wd->bx, align, 0.5);
807    wd->align = align;
808 }
809
810 /**
811  * Get the alignment of the items.
812  *
813  * @param obj The toolbar object
814  * @return The alignment. (left) 0.0 ... 1.0 (right)
815  *
816  * @ingroup Toolbar
817  */
818 EAPI double
819 elm_toolbar_align_get(const Evas_Object *obj)
820 {
821    ELM_CHECK_WIDTYPE(obj, widtype) 0.0;
822    Widget_Data *wd = elm_widget_data_get(obj);
823
824    if (!wd) return 0.0;
825    return wd->align;
826 }
827
828 /**
829  * Set whether the toolbar item opens a menu.
830  *
831  * @param item The toolbar item
832  * @param menu If true, @p item will open a menu when selected
833  *
834  * @ingroup Toolbar
835  */
836 EAPI void
837 elm_toolbar_item_menu_set(Elm_Toolbar_Item *item, Eina_Bool menu)
838 {
839    if(!item) return;
840    Widget_Data *wd = elm_widget_data_get(item->obj);
841
842    if (!wd) return;
843    if (item->menu == menu) return;
844    item->menu = menu;
845    if (menu)
846      {
847         item->o_menu = elm_menu_add(item->base);
848         if (wd->menu_parent)
849           elm_menu_parent_set(item->o_menu, wd->menu_parent);
850         evas_object_event_callback_add(item->o_menu, EVAS_CALLBACK_HIDE,
851                                        _menu_hide, item);
852         evas_object_event_callback_add(item->o_menu, EVAS_CALLBACK_DEL,
853                                        _menu_del, item);
854      }
855    else if (item->o_menu)
856      {
857         evas_object_del(item->o_menu);
858      }
859 }
860
861
862 /**
863  * Get whether the toolbar item opens a menu.
864  *
865  * @param item The toolbar item
866  * @return If true, @p item opens a menu when selected
867  *
868  * @ingroup Toolbar
869  */
870 EAPI Evas_Object *
871 elm_toolbar_item_menu_get(Elm_Toolbar_Item *item)
872 {
873    if (!item) return NULL;
874    Widget_Data *wd = elm_widget_data_get(item->obj);
875    if (!wd) return NULL;
876    elm_toolbar_item_menu_set(item, 1);
877    return item->o_menu;
878 }
879
880 /**
881  * Return a list of all toolbar items.
882  *
883  * @param obj The toolbar object
884  *
885  * @return An Eina_List* of the toolbar items in @p obj
886  *
887  * @ingroup Toolbar
888  */
889 EAPI Eina_List *
890 elm_toolbar_item_get_all(Evas_Object *obj)
891 {
892    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
893    Widget_Data *wd = elm_widget_data_get(obj);
894    if (!wd) return NULL;
895
896    return wd->items;
897 }
898
899 /**
900  * Return the first toolbar item in the list of toolbar items.
901  *
902  * @param obj The toolbar object
903  *
904  * @return The first toolbar item, or NULL on failure
905  *
906  * @ingroup Toolbar
907  */
908 EAPI Elm_Toolbar_Item *
909 elm_toolbar_item_get_first(Evas_Object *obj)
910 {
911    Elm_Toolbar_Item *it;
912    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
913    Widget_Data *wd = elm_widget_data_get(obj);
914    if (!wd) return NULL;
915    if (!(it = eina_list_data_get(wd->items))) return NULL;
916
917    return it;
918 }
919
920 /**
921  * Return the last toolbar item in the list of toolbar items.
922  *
923  * @param obj The toolbar object
924  *
925  * @return The last toolbar item, or NULL on failure
926  *
927  * @ingroup Toolbar
928  */
929 EAPI Elm_Toolbar_Item *
930 elm_toolbar_item_get_last(Evas_Object *obj)
931 {
932    Eina_List *last;
933    Elm_Toolbar_Item *it;
934    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
935    Widget_Data *wd = elm_widget_data_get(obj);
936    if (!wd) return NULL;
937    if (!(last = eina_list_last(wd->items))) return NULL;
938    it = eina_list_data_get(last);
939
940    return it;
941 }
942
943 /**
944  * Return the next toolbar item (relative to the currently selected
945  * toolbar item) in the list of toolbar items.
946  *
947  * @param obj The toolbar object
948  *
949  * @return The next toolbar item, or NULL on failure
950  *
951  * @ingroup Toolbar
952  */
953 EAPI Elm_Toolbar_Item *
954 elm_toolbar_item_get_next(Evas_Object *obj)
955 {
956    Eina_List *l, *l2;
957    Elm_Toolbar_Item *it, *next;
958    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
959    Widget_Data *wd = elm_widget_data_get(obj);
960
961    if (!wd) return NULL;
962    EINA_LIST_FOREACH_SAFE(wd->items, l, l2, it)
963      {
964         if (it->selected)
965           {
966              if (!(next = eina_list_data_get(l2))) return NULL;
967              return next;
968           }
969      }
970    return NULL;
971 }
972
973 /**
974  * Selects the next non-disabled, non-separator toolbar item in the list
975  * of toolbar items.
976  *
977  * @param obj The toolbar object
978  *
979  * @return The newly selected toolbar item, or NULL on failure
980  *
981  * @ingroup Toolbar
982  */
983 EAPI Elm_Toolbar_Item *
984 elm_toolbar_item_select_next(Evas_Object *obj)
985 {
986    Eina_List *l, *l2;
987    Elm_Toolbar_Item *it, *next;
988    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
989    Widget_Data *wd = elm_widget_data_get(obj);
990
991    if (!wd) return NULL;
992    EINA_LIST_FOREACH(wd->items, l, it)
993      {
994         if (it->selected)
995           {
996              EINA_LIST_FOREACH(l, l2, next)
997                if ((!next->disabled) && (next->separator))
998                  {
999                     _item_select(next);
1000                     return next;
1001                  }
1002           }
1003      }
1004   return NULL;
1005 }
1006
1007 /**
1008  * Selects the first non-disabled, non-separator toolbar item in the list
1009  * of toolbar items.
1010  *
1011  * @param obj The toolbar object
1012  *
1013  * @return The newly selected toolbar item, or NULL on failure
1014  *
1015  * @ingroup Toolbar
1016  */
1017 EAPI Elm_Toolbar_Item *
1018 elm_toolbar_item_select_first(Evas_Object *obj)
1019 {
1020    Eina_List *l;
1021    Elm_Toolbar_Item *it;
1022    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1023    Widget_Data *wd = elm_widget_data_get(obj);
1024    if (!wd) return NULL;
1025    EINA_LIST_FOREACH(wd->items, l, it)
1026      {
1027         if ((!it->disabled) && (!it->separator))
1028           {
1029              _item_select(it);
1030              return it;
1031           }
1032      }
1033
1034    return NULL;
1035 }
1036
1037 /**
1038  * Selects the last non-disabled, non-separator toolbar item in the list
1039  * of toolbar items.
1040  *
1041  * @param obj The toolbar object
1042  *
1043  * @return The newly selected toolbar item, or NULL on failure
1044  *
1045  * @ingroup Toolbar
1046  */
1047 EAPI Elm_Toolbar_Item *
1048 elm_toolbar_item_select_last(Evas_Object *obj)
1049 {
1050    Eina_List *l;
1051    Elm_Toolbar_Item *it;
1052    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1053    Widget_Data *wd = elm_widget_data_get(obj);
1054    if (!wd) return NULL;
1055    EINA_LIST_REVERSE_FOREACH(wd->items, l, it)
1056      {
1057         if ((!it->disabled) && (!it->separator))
1058           {
1059              _item_select(it);
1060              return it;
1061           }
1062      }
1063  
1064    return NULL;
1065 }
1066
1067 /**
1068  * Returns a pointer to a toolbar item by its label
1069  *
1070  * @param obj The toolbar object
1071  * @param label The label of the item to find
1072  *
1073  * @return The pointer to the toolbar item matching @p label
1074  * Returns NULL on failure.
1075  *
1076  * @ingroup Toolbar
1077  */
1078 EAPI Elm_Toolbar_Item *
1079 elm_toolbar_item_find_by_label(Evas_Object *obj, const char *label)
1080 {
1081    Eina_List *l;
1082    Elm_Toolbar_Item *it;
1083    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1084    Widget_Data *wd = elm_widget_data_get(obj);
1085    
1086    if (!wd) return NULL;
1087    EINA_LIST_FOREACH(wd->items, l, it)
1088      {
1089         if (!strcmp(it->label, label)) return it;
1090      }
1091
1092    return NULL;
1093 }