Tizen 2.1 release
[platform/core/uifw/e17.git] / src / bin / e_widget_toolbar.c
1 #include "e.h"
2
3 typedef struct _E_Widget_Data E_Widget_Data;
4 typedef struct _Item Item;
5 struct _E_Widget_Data
6 {
7    Evas_Object *o_base, *o_box;
8    int icon_w, icon_h;
9    Eina_List *items;
10    Eina_Bool scrollable : 1;
11    Eina_Bool focus_steal : 1;
12 };
13
14 struct _Item
15 {
16    Evas_Object *o_toolbar, *o_base, *o_icon;
17    void (*func) (void *data1, void *data2);
18    const void *data1, *data2;
19    Eina_Bool selected : 1;
20 };
21
22 static void _e_wid_del_hook(Evas_Object *obj);
23 static void _e_wid_focus_hook(Evas_Object *obj);
24 static void _e_wid_focus_steal(void *data, Evas *e, Evas_Object *obj, void *event_info);
25 static void _e_wid_disable_hook(Evas_Object *obj);
26 static void _e_wid_signal_cb1(void *data, Evas_Object *obj, const char *emission, const char *source);
27 static void _e_wid_cb_scrollframe_resize(void *data, Evas *e, Evas_Object *obj, void *event_info);
28 static void _e_wid_cb_key_down(void *data, Evas *evas, Evas_Object *obj, void *event_info);
29 static void _e_wid_signal_prev(void *data, Evas_Object *obj, const char *emission, const char *source);
30 static void _e_wid_signal_next(void *data, Evas_Object *obj, const char *emission, const char *source);
31 static void _item_show(Item *it);
32 static void _item_select(Item *it);
33 static void _item_unselect(Item *it);
34
35 /* local subsystem functions */
36
37 /* externally accessible functions */
38 EAPI Evas_Object *
39 e_widget_toolbar_add(Evas *evas, int icon_w, int icon_h)
40 {
41    Evas_Object *obj, *o;
42    E_Widget_Data *wd;
43    Evas_Coord mw = 0, mh = 0;
44
45    obj = e_widget_add(evas);
46
47    e_widget_del_hook_set(obj, _e_wid_del_hook);
48    e_widget_focus_hook_set(obj, _e_wid_focus_hook);
49    e_widget_disable_hook_set(obj, _e_wid_disable_hook);
50    wd = E_NEW(E_Widget_Data, 1);
51    e_widget_data_set(obj, wd);
52    wd->icon_w = icon_w;
53    wd->icon_h = icon_h;
54    wd->focus_steal = EINA_TRUE;
55
56    o = e_scrollframe_add(evas);
57    wd->o_base = o;
58    o = e_box_add(evas);
59    wd->o_box = o;
60    o = wd->o_base;
61    e_scrollframe_custom_theme_set(o, "base/theme/widgets", "e/widgets/toolbar");
62    e_scrollframe_single_dir_set(o, 1);
63    e_scrollframe_policy_set(o, E_SCROLLFRAME_POLICY_AUTO,
64                             E_SCROLLFRAME_POLICY_OFF);
65    e_scrollframe_thumbscroll_force(o, 1);
66    evas_object_event_callback_add(o, EVAS_CALLBACK_RESIZE,
67                                   _e_wid_cb_scrollframe_resize, obj);
68    evas_object_event_callback_add(e_scrollframe_edje_object_get(wd->o_base),
69                                   EVAS_CALLBACK_MOUSE_DOWN,
70                                   _e_wid_focus_steal, obj);
71    evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_DOWN,
72                                   _e_wid_cb_key_down, obj);
73
74    edje_object_signal_callback_add(e_scrollframe_edje_object_get(o),
75                                    "e,action,prev", "e",
76                                    _e_wid_signal_prev, obj);
77    edje_object_signal_callback_add(e_scrollframe_edje_object_get(o),
78                                    "e,action,next", "e",
79                                    _e_wid_signal_next, obj);
80    evas_object_show(o);
81    e_widget_sub_object_add(obj, o);
82    e_widget_resize_object_set(obj, o);
83
84    o = wd->o_box;
85    e_box_orientation_set(o, 1);
86    e_box_homogenous_set(o, 1);
87    e_scrollframe_child_set(wd->o_base, o);
88    e_widget_sub_object_add(obj, o);
89    evas_object_show(o);
90
91    edje_object_size_min_calc(e_scrollframe_edje_object_get(wd->o_base),
92                              &mw, &mh);
93    e_widget_size_min_set(obj, mw, mh);
94
95    return obj;
96 }
97
98 EAPI const Eina_List *
99 e_widget_toolbar_items_get(Evas_Object *obj)
100 {
101    E_Widget_Data *wd;
102    if (!obj) return NULL;
103    if (!(wd = e_widget_data_get(obj))) return NULL;
104    return wd->items;
105 }
106
107 EAPI unsigned int
108 e_widget_toolbar_items_count(Evas_Object *obj)
109 {
110    E_Widget_Data *wd;
111    if (!obj) return 0;
112    if (!(wd = e_widget_data_get(obj))) return 0;
113    return eina_list_count(wd->items);
114 }
115
116 EAPI const char *
117 e_widget_toolbar_item_label_get(void *item)
118 {
119    Item *it = item;
120    if (!it) return NULL;
121    return edje_object_part_text_get(it->o_base, "e.text.label");
122 }
123
124 EAPI void
125 e_widget_toolbar_item_append(Evas_Object *obj, Evas_Object *icon, const char *label, void (*func) (void *data1, void *data2), const void *data1, const void *data2)
126 {
127    E_Widget_Data *wd;
128    Evas_Object *o;
129    Item *it;
130    Evas_Coord mw = 0, mh = 0, vw = 0, vh = 0;
131
132    if (!obj) return;
133    if (!(wd = e_widget_data_get(obj))) return;
134    o = edje_object_add(evas_object_evas_get(obj));
135    e_theme_edje_object_set(o, "base/theme/widgets",
136                            "e/widgets/toolbar/item");
137    it = E_NEW(Item, 1);
138    it->o_toolbar = obj;
139    it->o_base = o;
140    it->o_icon = icon;
141    it->func = func;
142    it->data1 = data1;
143    it->data2 = data2;
144    wd->items = eina_list_append(wd->items, it);
145
146    edje_object_signal_callback_add(o, "e,action,click", "e",
147                                    _e_wid_signal_cb1, it);
148    edje_extern_object_min_size_set(icon, wd->icon_w, wd->icon_h);
149    edje_object_part_swallow(o, "e.swallow.icon", icon);
150    evas_object_show(icon);
151    edje_object_part_text_set(o, "e.text.label", label);
152    edje_object_size_min_calc(o, &mw, &mh);
153    e_widget_sub_object_add(obj, o);
154    e_box_pack_end(wd->o_box, o);
155    e_box_pack_options_set(o,
156                           1, 1, /* fill */
157                           0, 0, /* expand */
158                           0.5, 0.5, /* align */
159                           mw, mh, /* min */
160                           9999, 9999 /* max */
161                           );
162    evas_object_show(o);
163    e_box_size_min_get(wd->o_box, &mw, &mh);
164    evas_object_resize(wd->o_box, mw, mh);
165    evas_object_resize(wd->o_base, 500, 500);
166    e_scrollframe_child_viewport_size_get(wd->o_base, &vw, &vh);
167    if (wd->scrollable)
168      e_widget_size_min_set(obj, 500 - vw, mh + (500 - vh));
169    else
170      e_widget_size_min_set(obj, mw + (500 - vw), mh + (500 - vh));
171    evas_object_resize(wd->o_box, mw, mh);
172 }
173
174 EAPI void
175 e_widget_toolbar_item_remove(Evas_Object *obj, int num)
176 {
177    E_Widget_Data *wd;
178    Item *it;
179
180    if (!obj) return;
181    if (!(wd = e_widget_data_get(obj))) return;
182    it = eina_list_nth(wd->items, num);
183    if (it)
184      {
185         evas_object_del(it->o_base);
186         if (it->o_icon) evas_object_del(it->o_icon);
187         wd->items = eina_list_remove(wd->items, it);
188         E_FREE(it);
189      }
190 }
191
192 EAPI void
193 e_widget_toolbar_item_select(Evas_Object *obj, int num)
194 {
195    E_Widget_Data *wd = NULL;
196    Eina_List *l = NULL;
197    Item *it = NULL;
198    int i = 0;
199
200    if (!obj) return;
201    if (!(wd = e_widget_data_get(obj))) return;
202    EINA_LIST_FOREACH(wd->items, l, it)
203      {
204         if (i == num)
205           {
206              if (!it->selected) _item_select(it);
207           }
208         else
209           {
210              if (it->selected) _item_unselect(it);
211           }
212         i++;
213      }
214 }
215
216 EAPI void
217 e_widget_toolbar_item_label_set(Evas_Object *obj, int num, const char *label)
218 {
219    E_Widget_Data *wd = NULL;
220    Item *it = NULL;
221
222    if (!obj) return;
223    if (!(wd = e_widget_data_get(obj))) return;
224    it = eina_list_nth(wd->items, num);
225    if (it)
226      {
227         int mw, mh;
228
229         edje_object_part_text_set(it->o_base, "e.text.label", label);
230         edje_object_size_min_calc(it->o_base, &mw, &mh);
231         e_box_pack_options_set(it->o_base,
232                                1, 1, /* fill */
233                                0, 0, /* expand */
234                                0.5, 0.5, /* align */
235                                mw, mh, /* min */
236                                9999, 9999 /* max */
237                                );
238      }
239 }
240
241 EAPI void
242 e_widget_toolbar_scrollable_set(Evas_Object *obj, Eina_Bool scrollable)
243 {
244    E_Widget_Data *wd;
245    Evas_Coord mw = 0, mh = 0, vw = 0, vh = 0;
246
247    if (!obj) return;
248    if (!(wd = e_widget_data_get(obj))) return;
249    wd->scrollable = scrollable;
250    e_box_size_min_get(wd->o_box, &mw, &mh);
251    evas_object_resize(wd->o_box, mw, mh);
252    evas_object_resize(wd->o_base, 500, 500);
253    e_scrollframe_child_viewport_size_get(wd->o_base, &vw, &vh);
254    if (wd->scrollable)
255      e_widget_size_min_set(obj, 500 - vw, mh + (500 - vh));
256    else
257      e_widget_size_min_set(obj, mw + (500 - vw), mh + (500 - vh));
258    evas_object_resize(wd->o_box, mw, mh);
259 }
260
261 EAPI void
262 e_widget_toolbar_focus_steal_set(Evas_Object *obj, Eina_Bool steal)
263 {
264    E_Widget_Data *wd;
265
266    if (!obj) return;
267    if (!(wd = e_widget_data_get(obj))) return;
268    if (wd->focus_steal == steal) return;
269    if (steal)
270      {
271         evas_object_event_callback_add(e_scrollframe_edje_object_get(wd->o_base),
272                                        EVAS_CALLBACK_MOUSE_DOWN,
273                                        _e_wid_focus_steal, obj);
274         wd->focus_steal = EINA_TRUE;
275      }
276    else
277      {
278         evas_object_event_callback_del(e_scrollframe_edje_object_get(wd->o_base),
279                                        EVAS_CALLBACK_MOUSE_DOWN,
280                                        _e_wid_focus_steal);
281         wd->focus_steal = EINA_FALSE;
282      }
283 }
284
285 EAPI void
286 e_widget_toolbar_clear(Evas_Object *obj)
287 {
288    E_Widget_Data *wd = NULL;
289    Item *it = NULL;
290
291    if (!obj) return;
292    if (!(wd = e_widget_data_get(obj))) return;
293    EINA_LIST_FREE(wd->items, it)
294      {
295         evas_object_del(it->o_base);
296         if (it->o_icon) evas_object_del(it->o_icon);
297         E_FREE(it);
298      }
299 }
300
301 EAPI int
302 e_widget_toolbar_item_selected_get(Evas_Object *obj)
303 {
304    E_Widget_Data *wd = NULL;
305    Eina_List *l = NULL;
306    Item *it = NULL;
307    int i = 0;
308
309    if (!obj) return 0;
310    if (!(wd = e_widget_data_get(obj))) return 0;
311    EINA_LIST_FOREACH(wd->items, l, it)
312      {
313         if (it->selected) return i;
314         i++;
315      }
316    return 0;
317 }
318
319 /* local functions */
320 static void
321 _e_wid_del_hook(Evas_Object *obj)
322 {
323    E_Widget_Data *wd;
324    Item *it;
325
326    if (!obj) return;
327    if (!(wd = e_widget_data_get(obj))) return;
328    EINA_LIST_FREE(wd->items, it)
329      {
330         evas_object_del(it->o_base);
331         if (it->o_icon) evas_object_del(it->o_icon);
332         E_FREE(it);
333      }
334    E_FREE(wd);
335 }
336
337 static void
338 _e_wid_disable_hook(Evas_Object *obj)
339 {
340    E_Widget_Data *wd;
341
342    if (!obj) return;
343    if (!(wd = e_widget_data_get(obj))) return;
344    if (e_widget_disabled_get(obj))
345      edje_object_signal_emit(e_scrollframe_edje_object_get(wd->o_base),
346                              "e,state,disabled", "e");
347    else
348      edje_object_signal_emit(e_scrollframe_edje_object_get(wd->o_base),
349                              "e,state,enabled", "e");
350 }
351
352 static void
353 _e_wid_signal_cb1(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
354 {
355    Item *it, *it2;
356    E_Widget_Data *wd;
357    Eina_List *l;
358
359    if (!(it = data)) return;
360    if (it->selected) return;
361    wd = e_widget_data_get(it->o_toolbar);
362    EINA_LIST_FOREACH(wd->items, l, it2)
363      {
364         if (it2->selected)
365           {
366              _item_unselect(it2);
367              break;
368           }
369      }
370    _item_select(it);
371 }
372
373 static void
374 _e_wid_signal_prev(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
375 {
376    E_Widget_Data *wd;
377    Eina_List *l, *l2;
378    Item *it = NULL, *it2 = NULL;
379
380    if (!(wd = e_widget_data_get(data))) return;
381    if ((!wd->o_base) || (!wd->o_box)) return;
382    EINA_LIST_FOREACH(wd->items, l, it)
383      {
384         if (it->selected)
385           {
386              l2 = eina_list_prev(l);
387              if (l2) it2 = eina_list_data_get(l2);
388              break;
389           }
390      }
391    if ((it) && (it2) && (it != it2))
392      {
393         _item_unselect(it);
394         _item_select(it2);
395      }
396 }
397
398 static void
399 _e_wid_signal_next(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
400 {
401    E_Widget_Data *wd;
402    Eina_List *l, *l2;
403    Item *it = NULL, *it2 = NULL;
404
405    if (!(wd = e_widget_data_get(data))) return;
406    if ((!wd->o_base) || (!wd->o_box)) return;
407    EINA_LIST_FOREACH(wd->items, l, it)
408      {
409         if (it->selected)
410           {
411              l2 = eina_list_next(l);
412              if (l2) it2 = eina_list_data_get(l2);
413              break;
414           }
415      }
416    if ((it) && (it2) && (it != it2))
417      {
418         _item_unselect(it);
419         _item_select(it2);
420      }
421 }
422
423 static void
424 _e_wid_cb_scrollframe_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
425 {
426    E_Widget_Data *wd;
427    Evas_Coord mw, mh, vw, vh, w, h;
428    Eina_List *l;
429    Item *it;
430
431    if (!(wd = e_widget_data_get(data))) return;
432    if ((!wd->o_base) || (!wd->o_box)) return;
433
434    e_scrollframe_child_viewport_size_get(wd->o_base, &vw, &vh);
435    e_box_size_min_get(wd->o_box, &mw, &mh);
436    evas_object_geometry_get(wd->o_box, NULL, NULL, &w, &h);
437    if (vw >= mw)
438      {
439         if (w != vw) evas_object_resize(wd->o_box, vw, h);
440      }
441    EINA_LIST_FOREACH(wd->items, l, it)
442      {
443         if (it->selected)
444           {
445              _item_show(it);
446              break;
447           }
448      }
449 }
450
451 static void
452 _e_wid_cb_key_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
453 {
454    Evas_Event_Key_Down *ev;
455    E_Widget_Data *wd;
456    Eina_List *l, *l2;
457    Item *it = NULL, *it2 = NULL;
458
459    ev = event_info;
460    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
461    wd = e_widget_data_get(data);
462    if ((!strcmp(ev->keyname, "Up")) || (!strcmp(ev->keyname, "KP_Up")) ||
463        (!strcmp(ev->keyname, "Left")) || (!strcmp(ev->keyname, "KP_Left")))
464      {
465         EINA_LIST_FOREACH(wd->items, l, it)
466           {
467              if (it->selected)
468                {
469                   l2 = eina_list_prev(l);
470                   if (l2) it2 = eina_list_data_get(l2);
471                   break;
472                }
473           }
474      }
475    else if ((!strcmp(ev->keyname, "Down")) ||
476             (!strcmp(ev->keyname, "KP_Down")) ||
477             (!strcmp(ev->keyname, "Right")) ||
478             (!strcmp(ev->keyname, "KP_Right")))
479      {
480         EINA_LIST_FOREACH(wd->items, l, it)
481           {
482              if (it->selected)
483                {
484                   l2 = eina_list_next(l);
485                   if (l2) it2 = eina_list_data_get(l2);
486                   break;
487                }
488           }
489      }
490    else if ((!strcmp(ev->keyname, "Home")) ||
491             (!strcmp(ev->keyname, "KP_Home")))
492      {
493         EINA_LIST_FOREACH(wd->items, l, it)
494           {
495              if (it->selected)
496                {
497                   it2 = eina_list_data_get(wd->items);
498                   break;
499                }
500           }
501      }
502    else if ((!strcmp(ev->keyname, "End")) || (!strcmp(ev->keyname, "KP_End")))
503      {
504         EINA_LIST_FOREACH(wd->items, l, it)
505           {
506              if (it->selected)
507                {
508                   it2 = eina_list_data_get(eina_list_last(wd->items));
509                   break;
510                }
511           }
512      }
513    if ((it) && (it2) && (it != it2))
514      {
515         _item_unselect(it);
516         _item_select(it2);
517      }
518 }
519
520 static void
521 _e_wid_focus_hook(Evas_Object *obj)
522 {
523    E_Widget_Data *wd;
524
525    if (!obj) return;
526    if (!(wd = e_widget_data_get(obj))) return;
527    if (e_widget_focus_get(obj))
528      {
529         edje_object_signal_emit(wd->o_base, "e,state,focused", "e");
530         evas_object_focus_set(obj, EINA_TRUE);
531      }
532    else
533      {
534         edje_object_signal_emit(wd->o_base, "e,state,unfocused", "e");
535         evas_object_focus_set(obj, EINA_FALSE);
536      }
537 }
538
539 static void
540 _e_wid_focus_steal(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
541 {
542    e_widget_focus_steal(data);
543 }
544
545 static void
546 _item_show(Item *it)
547 {
548    E_Widget_Data *wd;
549    Evas_Coord x, y, w, h, bx, by;
550
551    wd = e_widget_data_get(it->o_toolbar);
552    evas_object_geometry_get(wd->o_box, &bx, &by, NULL, NULL);
553    evas_object_geometry_get(it->o_base, &x, &y, &w, &h);
554    e_scrollframe_child_region_show(wd->o_base, x - bx, y - by, w, h);
555 }
556
557 static void
558 _item_select(Item *it)
559 {
560    it->selected = EINA_TRUE;
561    edje_object_signal_emit(it->o_base, "e,state,selected", "e");
562    if (it->o_icon)
563      {
564         if (strcmp(evas_object_type_get(it->o_icon), "e_icon"))
565           edje_object_signal_emit(it->o_icon, "e,state,selected", "e");
566         else
567           e_icon_selected_set(it->o_icon, EINA_TRUE);
568      }
569    _item_show(it);
570    if (it->func) it->func((void *)it->data1, (void *)it->data2);
571 }
572
573 static void
574 _item_unselect(Item *it)
575 {
576    it->selected = EINA_FALSE;
577    edje_object_signal_emit(it->o_base, "e,state,unselected", "e");
578    if (it->o_icon)
579      {
580         if (strcmp(evas_object_type_get(it->o_icon), "e_icon"))
581           edje_object_signal_emit(it->o_icon, "e,state,unselected", "e");
582         else
583           e_icon_selected_set(it->o_icon, EINA_FALSE);
584      }
585 }