3e5076ef0903f595e1ae65f2b3c9eb79ed433f6c
[framework/uifw/elementary.git] / src / lib / elm_pagecontrol.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4 #include <Elementary.h>
5 #include "elm_priv.h"
6
7 /**
8  * @defgroup PageControl PageControl
9  * @ingroup Elementary
10  *
11  *  A page control is a succession of dots centered in the control.
12  *  Each dot corresponds to a page in the application's document (or other data-model entity),
13  *  with the white dot indicating the currently viewed page.
14  */
15
16 typedef struct _Widget_Data Widget_Data;
17 typedef struct _Page_Item Page_Item;
18
19 struct _Widget_Data
20 {
21    Evas_Object *base;
22    Evas_Object *hbox;
23    unsigned int page_count;
24    Eina_List *page_list;
25    unsigned int cur_page_id;
26    Evas_Object *parent;
27    double scale_factor;
28 };
29
30 struct _Page_Item
31 {
32    Evas_Object *obj;
33    Evas_Object *base;
34    unsigned int page_id;
35 };
36
37
38 static void 
39 _theme_hook(Evas_Object *obj)
40 {
41    Widget_Data *wd = elm_widget_data_get(obj);
42    _elm_theme_object_set(obj, wd->base, "pagecontrol", "base", elm_widget_style_get(obj));
43 }
44
45 static void 
46 _sizing_eval(Evas_Object *obj)
47 {
48    Widget_Data *wd = elm_widget_data_get(obj);
49    Evas_Coord minw = -1, minh = -1;
50
51    if (!wd) return;
52    
53    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
54    edje_object_size_min_restricted_calc(wd->base, &minw, &minh, minw, minh);
55    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
56    evas_object_size_hint_min_set(obj, -1, -1);
57    evas_object_size_hint_max_set(obj, -1, -1);
58 }
59
60 static void 
61 _item_free(Evas_Object *obj, Page_Item *it)
62 {
63    Widget_Data *wd = elm_widget_data_get(obj);
64    if (!wd) return;
65
66    if (wd->page_list)
67      wd->page_list = eina_list_remove(wd->page_list, it);
68
69    if (it->base) evas_object_del(it->base);
70    
71    if (it) free(it);
72    it = NULL;
73
74    return;
75 }
76
77 static void 
78 _del_hook(Evas_Object *obj)
79 {
80    Widget_Data *wd = elm_widget_data_get(obj);
81    Page_Item *it;
82    Eina_List *l, *clear = NULL;
83    
84    EINA_LIST_FOREACH(wd->page_list, l, it) clear = eina_list_append(clear, it);
85    EINA_LIST_FREE(clear, it) _item_free(obj, it);
86    
87    if (wd) free(wd);
88    wd = NULL;
89    
90    return;
91 }
92
93 static Page_Item *
94 _page_find(Evas_Object *obj, unsigned int index)
95 {
96    Widget_Data *wd = elm_widget_data_get(obj);
97    if (!wd) return NULL;
98
99    Page_Item *it;
100    Eina_List *l;
101    
102    unsigned int i = 0;
103    EINA_LIST_FOREACH(wd->page_list, l, it)
104      {
105         if (i == index) return it;
106         i++;
107      }
108
109    return NULL;
110 }
111
112 static void 
113 _indicator_clicked_cb(void *data, Evas_Object *obj,
114                       const char *emission __UNUSED__,
115                       const char *source __UNUSED__)
116 {
117    Evas_Object *wd_obj = (Evas_Object *)data;
118    Widget_Data *wd = elm_widget_data_get(wd_obj);
119    if (!wd) return;
120
121    Page_Item *it;
122    Eina_List *l;
123
124    unsigned int page_id = 0;
125    EINA_LIST_FOREACH(wd->page_list, l, it)
126      {
127         if (it->base == obj)
128           page_id = it->page_id;
129      }
130
131    if (page_id == wd->cur_page_id) return;
132
133    it = _page_find(wd_obj, wd->cur_page_id);
134    if (!it) return;
135
136    edje_object_signal_emit(it->base, "elm,state,indicator,off", "elm");
137
138    it = _page_find(wd_obj, page_id);
139    if (!it) return;
140
141    edje_object_signal_emit(it->base, "elm,state,indicator,on", "elm");
142    wd->cur_page_id = page_id;
143    evas_object_smart_callback_call(it->obj, "changed", NULL);
144 }
145
146 static Page_Item *
147 _create_item(Evas_Object *obj, unsigned int page_id)
148 {
149    Page_Item *it;
150    Evas_Coord mw, mh;
151    it = calloc(1, sizeof(Page_Item));
152    if (!it) return NULL;
153    
154    it->obj = obj;
155    it->page_id = page_id;
156    
157    it->base = edje_object_add(evas_object_evas_get(obj));
158    
159    char pi_name[128];
160    sprintf(pi_name, "default_%d", page_id+1);
161    _elm_theme_object_set(obj, it->base, "page", "item", pi_name);
162    edje_object_size_min_restricted_calc(it->base, &mw, &mh, 0, 0);
163    evas_object_size_hint_weight_set(it->base, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
164    evas_object_size_hint_align_set(it->base, EVAS_HINT_FILL, EVAS_HINT_FILL);
165    
166    evas_object_resize(it->base, mw, mh);
167    evas_object_size_hint_min_set(it->base, mw, mh);
168    evas_object_size_hint_max_set(it->base, mw, mh);
169    
170    edje_object_signal_callback_add(it->base, "clicked", "indicator_clicked", _indicator_clicked_cb, obj);
171    
172    return it;
173 }
174
175 static void 
176 _layout(Evas_Object *o, Evas_Object_Box_Data *priv, void *data)
177 {
178    Widget_Data *wd = data;
179    
180    if (!wd) return;
181
182    _els_box_layout(o, priv, 1, 0, elm_widget_mirrored_get(o)); /* making box layout non homogenous */
183
184    return;
185 }
186
187 /**
188  * Add a new pagecontrol to the parent
189  * @param parent The parent object
190  * @return The new object or NULL if it cannot be created
191  *
192  * @ingroup PageControl
193  */
194 EAPI Evas_Object *
195 elm_page_control_add(Evas_Object *parent)
196 {
197    if (!parent) return NULL;
198    
199    Evas_Object *obj;
200    Evas *e;
201    Widget_Data *wd;
202    
203    wd = ELM_NEW(Widget_Data);
204    e = evas_object_evas_get(parent);
205    obj = elm_widget_add(e);
206    elm_widget_type_set(obj, "pagecontrol");
207    elm_widget_sub_object_add(parent, obj);
208    elm_widget_data_set(obj, wd);
209    elm_widget_del_hook_set(obj, _del_hook);
210    elm_widget_theme_hook_set(obj, _theme_hook);
211    
212    wd->base = edje_object_add(e);
213    _elm_theme_object_set(obj, wd->base, "pagecontrol", "base", "default");
214    elm_widget_resize_object_set(obj, wd->base);
215    
216    wd->scale_factor = elm_scale_get();
217    if ( wd->scale_factor == 0.0 ) 
218      wd->scale_factor = 1.0;
219    
220    wd->hbox = evas_object_box_add(e);
221    evas_object_size_hint_weight_set(wd->hbox, 0, 0);
222    
223    evas_object_box_layout_set(wd->hbox, _layout, wd, NULL);
224    elm_widget_sub_object_add(obj, wd->hbox);
225    
226    edje_object_part_swallow(wd->base, "elm.swallow.page", wd->hbox);
227    
228    evas_object_show(wd->hbox);
229    
230    wd->parent = parent;
231    wd->page_count = 0;
232    wd->cur_page_id = 0;
233    
234    _sizing_eval(obj);
235    
236    return obj;
237 }
238
239 /**
240  * The number of pages for the pagecontrol to show as dots.
241  * @param obj The pagecontrol object
242  * @param page_count  Number of pages
243  *
244  * @ingroup PageControl
245  */
246 EAPI void 
247 elm_page_control_page_count_set(Evas_Object *obj, unsigned int page_count)
248 {
249    Widget_Data *wd = elm_widget_data_get(obj);
250    if (!wd) return;
251    if (!page_count) return;
252
253    Page_Item *it;
254    Evas_Coord mw, mh;
255    
256    unsigned int i;
257    for (i = 0; i < page_count; i++)
258      {
259         it = _create_item(obj, i);
260         wd->page_list = eina_list_append(wd->page_list, it);
261         if (i == 0)
262           {
263              edje_object_signal_emit(it->base, "elm,state,indicator,on", "elm");
264              evas_object_geometry_get(it->base, NULL, NULL, &mw, &mh);
265           }
266         
267         evas_object_show(it->base);
268         
269         evas_object_box_append(wd->hbox, it->base);
270         evas_object_smart_calculate(wd->hbox);
271      }
272    
273    int width = mw*page_count;
274    evas_object_resize(wd->hbox, width, mh);
275    evas_object_size_hint_min_set(wd->hbox, width, mh);
276    evas_object_size_hint_max_set(wd->hbox, width, mh);
277    evas_object_smart_calculate(wd->hbox);
278    wd->page_count = page_count;
279 }
280
281 /**
282  * Set current/displayed page to given page number or id.
283  * @param obj The pagecontrol object
284  * @param page_id  Page number or Page Id
285  *
286  * @ingroup PageControl
287  */
288 EAPI void 
289 elm_page_control_page_id_set(Evas_Object *obj, unsigned int page_id)
290 {
291    Widget_Data *wd = elm_widget_data_get(obj);
292    if (!wd) return;
293    
294    if(page_id >= wd->page_count || page_id == wd->cur_page_id) return;
295    
296    Page_Item *it;
297    it = _page_find(obj, wd->cur_page_id);
298    if (!it) return;
299    
300    edje_object_signal_emit(it->base, "elm,state,indicator,off", "elm");
301    it = _page_find(obj, page_id);
302    if (!it) return;
303    
304    edje_object_signal_emit(it->base, "elm,state,indicator,on", "elm");
305    wd->cur_page_id=page_id;
306 }
307
308 /**
309  * Get current/displayed page number or id.
310  * @param obj The pagecontrol object
311  * @return The current/displayed page id/number.
312  *
313  * @ingroup PageControl
314  */
315 EAPI unsigned int 
316 elm_page_control_page_id_get(Evas_Object *obj)
317 {
318    Widget_Data *wd = elm_widget_data_get(obj);
319    if (!wd) return -1;
320    
321    return wd->cur_page_id;
322 }
323