Merge branch 'master' into svn_merge
[framework/uifw/elementary.git] / src / lib / elm_carousel.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 // FIXME: this is NOT the carousel - yet!
5
6 typedef struct _Widget_Data Widget_Data;
7
8 struct _Widget_Data
9 {
10    Evas_Object *scr, *bx;
11    Eina_List *items;
12    int icon_size;
13 };
14
15 struct _Elm_Carousel_Item
16 {
17    Evas_Object *obj, *base, *icon;
18    const char *label;
19    Evas_Smart_Cb func;
20    const void *data;
21    Eina_Bool selected : 1;
22 };
23
24 static const char *widtype = NULL;
25 static void _del_hook(Evas_Object *obj);
26 static void _theme_hook(Evas_Object *obj);
27 static void _sizing_eval(Evas_Object *obj);
28
29 static void
30 _item_show(Elm_Carousel_Item *it)
31 {
32    Widget_Data *wd = elm_widget_data_get(it->obj);
33    Evas_Coord x, y, w, h, bx, by;
34    if (!wd) return;
35    evas_object_geometry_get(wd->bx, &bx, &by, NULL, NULL);
36    evas_object_geometry_get(it->base, &x, &y, &w, &h);
37    elm_smart_scroller_child_region_show(wd->scr, x - bx, y - by, w, h);
38 }
39
40 static void
41 _item_select(Elm_Carousel_Item *it)
42 {
43    Elm_Carousel_Item *it2;
44    Widget_Data *wd = elm_widget_data_get(it->obj);
45    Evas_Object *obj2;
46    const Eina_List *l;
47    if (!wd) return;
48    if (it->selected) return;
49    EINA_LIST_FOREACH(wd->items, l, it2)
50      {
51         if (it2->selected)
52           {
53              it2->selected = EINA_FALSE;
54              edje_object_signal_emit(it2->base, "elm,state,unselected", "elm");
55              break;
56           }
57      }
58    it->selected = EINA_TRUE;
59    edje_object_signal_emit(it->base, "elm,state,selected", "elm");
60    _item_show(it);
61    obj2 = it->obj;
62    if (it->func) it->func((void *)(it->data), it->obj, it);
63    evas_object_smart_callback_call(obj2, "clicked", it);
64 }
65
66 static void
67 _del_hook(Evas_Object *obj)
68 {
69    Widget_Data *wd = elm_widget_data_get(obj);
70    if (!wd) return;
71    free(wd);
72 }
73
74 static void
75 _theme_hook(Evas_Object *obj)
76 {
77    Widget_Data *wd = elm_widget_data_get(obj);
78    const Eina_List *l;
79    const Elm_Carousel_Item *it;
80    if (!wd) return;
81    EINA_LIST_FOREACH(wd->items, l, it)
82      {
83         Evas_Coord mw, mh;
84
85         if (it->selected)
86           edje_object_signal_emit(it->base, "elm,state,selected", "elm");
87         _elm_theme_object_set(obj, it->base, "carousel", "item", elm_widget_style_get(obj));
88         edje_object_scale_set(it->base, elm_widget_scale_get(obj) * _elm_config->scale);
89         if (it->icon)
90           {
91              edje_extern_object_min_size_set(it->icon,
92                                              (double)wd->icon_size * _elm_config->scale,
93                                              (double)wd->icon_size * _elm_config->scale);
94              edje_object_part_swallow(it->base, "elm.swallow.icon", it->icon);
95           }
96         edje_object_part_text_set(it->base, "elm.text", it->label);
97         edje_object_size_min_calc(it->base, &mw, &mh);
98         evas_object_size_hint_min_set(it->base, mw, mh);
99         evas_object_size_hint_max_set(it->base, 9999, mh);
100      }
101    _sizing_eval(obj);
102 }
103
104 static void
105 _sizing_eval(Evas_Object *obj)
106 {
107    Widget_Data *wd = elm_widget_data_get(obj);
108    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
109    Evas_Coord vw = 0, vh = 0;
110    if (!wd) return;
111    edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr), &minw, &minh);
112    evas_object_resize(wd->scr, 500, 500);
113    evas_object_size_hint_min_get(wd->bx, &minw, &minh);
114    evas_object_resize(wd->bx, minw, minh);
115    elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh);
116    minw = minw + (500 - vw);
117    minh = minh + (500 - vh);
118    evas_object_size_hint_min_set(obj, minw, minh);
119    evas_object_size_hint_max_set(obj, maxw, maxh);
120 }
121
122 static void
123 _resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
124 {
125    Widget_Data *wd = elm_widget_data_get(data);
126    Evas_Coord mw, mh, vw, vh, w, h;
127    const Eina_List *l;
128    Elm_Carousel_Item *it;
129    if (!wd) return;
130    elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh);
131    evas_object_size_hint_min_get(wd->bx, &mw, &mh);
132    evas_object_geometry_get(wd->bx, NULL, NULL, &w, &h);
133    if (vw >= mw)
134      {
135         if (w != vw) evas_object_resize(wd->bx, vw, h);
136      }
137    EINA_LIST_FOREACH(wd->items, l, it)
138      {
139         if (it->selected)
140           {
141              _item_show(it);
142              break;
143           }
144      }
145
146 }
147
148 static void
149 _select(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
150 {
151    _item_select(data);
152 }
153
154 EAPI Evas_Object *
155 elm_carousel_add(Evas_Object *parent)
156 {
157    Evas_Object *obj;
158    Evas *e;
159    Widget_Data *wd;
160
161    wd = ELM_NEW(Widget_Data);
162    e = evas_object_evas_get(parent);
163    obj = elm_widget_add(e);
164    ELM_SET_WIDTYPE(widtype, "carousel");
165    elm_widget_type_set(obj, "carousel");
166    elm_widget_sub_object_add(parent, obj);
167    elm_widget_data_set(obj, wd);
168    elm_widget_del_hook_set(obj, _del_hook);
169    elm_widget_theme_hook_set(obj, _theme_hook);
170    elm_widget_can_focus_set(obj, 0);
171
172    wd->scr = elm_smart_scroller_add(e);
173    elm_smart_scroller_widget_set(wd->scr, obj);
174    elm_smart_scroller_object_theme_set(obj, wd->scr, "carousel", "base", "default");
175    elm_widget_resize_object_set(obj, wd->scr);
176    elm_smart_scroller_policy_set(wd->scr,
177                                  ELM_SMART_SCROLLER_POLICY_AUTO,
178                                  ELM_SMART_SCROLLER_POLICY_OFF);
179
180    wd->icon_size = 32;
181
182    wd->bx = evas_object_box_add(e);
183    evas_object_box_layout_set(wd->bx,
184                    evas_object_box_layout_homogeneous_horizontal, NULL, NULL);
185    elm_widget_sub_object_add(obj, wd->bx);
186    elm_smart_scroller_child_set(wd->scr, wd->bx);
187    evas_object_show(wd->bx);
188
189    evas_object_event_callback_add(wd->scr, EVAS_CALLBACK_RESIZE,
190                                   _resize, obj);
191
192    _sizing_eval(obj);
193    return obj;
194 }
195
196 EAPI Elm_Carousel_Item *
197 elm_carousel_item_add(Evas_Object *obj, Evas_Object *icon, const char *label, Evas_Smart_Cb func, const void *data)
198 {
199    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
200    Widget_Data *wd = elm_widget_data_get(obj);
201    if (!wd) return NULL;
202    Evas_Coord mw, mh;
203    Elm_Carousel_Item *it = calloc(1, sizeof(Elm_Carousel_Item));
204
205    if (!it) return NULL;
206    wd->items = eina_list_append(wd->items, it);
207    it->obj = obj;
208    it->label = eina_stringshare_add(label);
209    it->icon = icon;
210    it->func = func;
211    it->data = data;
212    it->base = edje_object_add(evas_object_evas_get(obj));
213    _elm_theme_object_set(obj, it->base, "carousel", "item", elm_widget_style_get(obj));
214    edje_object_signal_callback_add(it->base, "elm,action,click", "elm",
215                                    _select, it);
216    elm_widget_sub_object_add(obj, it->base);
217    if (it->icon)
218      {
219         edje_extern_object_min_size_set(it->icon,
220                                         (double)wd->icon_size * _elm_config->scale,
221                                         (double)wd->icon_size * _elm_config->scale);
222         edje_object_part_swallow(it->base, "elm.swallow.icon", it->icon);
223         evas_object_show(it->icon);
224         elm_widget_sub_object_add(obj, it->icon);
225      }
226    edje_object_part_text_set(it->base, "elm.text", it->label);
227    edje_object_size_min_calc(it->base, &mw, &mh);
228    evas_object_size_hint_weight_set(it->base, 0.0, 0.0);
229    evas_object_size_hint_align_set(it->base, EVAS_HINT_FILL, EVAS_HINT_FILL);
230    evas_object_size_hint_min_set(it->base, mw, mh);
231    evas_object_size_hint_max_set(it->base, 9999, mh);
232    evas_object_box_append(wd->bx, it->base);
233    evas_object_show(it->base);
234    _sizing_eval(obj);
235    return it;
236 }
237
238 EAPI void
239 elm_carousel_item_del(Elm_Carousel_Item *it)
240 {
241    Widget_Data *wd = elm_widget_data_get(it->obj);
242    Evas_Object *obj2 = it->obj;
243    if (!wd) return;
244    wd->items = eina_list_remove(wd->items, it);
245    eina_stringshare_del(it->label);
246    if (it->icon) evas_object_del(it->icon);
247    evas_object_del(it->base);
248    free(it);
249    _theme_hook(obj2);
250 }
251
252 EAPI void
253 elm_carousel_item_select(Elm_Carousel_Item *item)
254 {
255    _item_select(item);
256 }