[elm_navigationbar]: check added if the button being added is same then dont delete it.
[framework/uifw/elementary.git] / src / lib / elm_hor_scroller.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "els_scroller.h"
4
5 /**
6  * @defgroup Scroller Scroller
7  * @ingroup Elementary
8  *
9  * A scroller holds a single object and "scrolls it around". This means that
10  * it allows the user to use a scrollbar (or a finger) to drag the viewable
11  * region around, allowing to move through a much larger object that is
12  * contained in the scroller. The scroiller will always have a small minimum
13  * size by default as it won't be limited by the contents of the scroller.
14  *
15  * Signals that you can add callbacks for are:
16  *
17  * edge,left - the left edge of the content has been reached
18  *
19  * edge,right - the right edge of the content has been reached
20  *
21  * edge,top - the top edge of the content has been reached
22  *
23  * edge,bottom - the bottom edge of the content has been reached
24  *
25  * scroll - the content has been scrolled (moved)
26  *
27  * scroll,anim,start - scrolling animation has started
28  *
29  * scroll,anim,stop - scrolling animation has stopped
30  *
31  * scroll,drag,start - dragging the contents around has started
32  *
33  * scroll,drag,stop - dragging the contents around has stopped
34  */
35 typedef struct _Widget_Data Widget_Data;
36
37 struct _Widget_Data
38 {
39    Evas_Object *scr;
40    Evas_Object *content;
41    const char *widget_name, *widget_base;
42    Eina_Bool min_w : 1;
43    Eina_Bool min_h : 1;
44    double pagerel_h, pagerel_v;
45    Evas_Coord pagesize_h, pagesize_v;
46 };
47
48 static void _del_hook(Evas_Object *obj);
49 static void _theme_hook(Evas_Object *obj);
50 static void _show_region_hook(void *data, Evas_Object *obj);
51 static void _sizing_eval(Evas_Object *obj);
52 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
53
54 static void
55 _del_hook(Evas_Object *obj)
56 {
57    Widget_Data *wd = elm_widget_data_get(obj);
58    if (!wd) return;
59    free(wd);
60 }
61
62 static void
63 _theme_hook(Evas_Object *obj)
64 {
65    Widget_Data *wd = elm_widget_data_get(obj);
66    if (!wd) return;
67    if (wd->scr)
68    {
69 //        elm_smart_scroller_theme_set(wd->scr, "scroller", "base", elm_widget_style_get(obj));
70           hor_elm_smart_scroller_theme_set(obj, wd->scr,
71                                                 wd->widget_name,
72                                                 wd->widget_base,
73                                                 elm_widget_style_get(obj));
74 //        edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale);
75    }
76    _sizing_eval(obj);
77 }
78
79 static void
80 _show_region_hook(void *data, Evas_Object *obj)
81 {
82    Widget_Data *wd = elm_widget_data_get(data);
83    Evas_Coord x, y, w, h;
84    if (!wd) return;
85    elm_widget_show_region_get(obj, &x, &y, &w, &h);
86    hor_elm_smart_scroller_child_region_show(wd->scr, x, y, w, h);
87 }
88
89 static void
90 _sizing_eval(Evas_Object *obj)
91 {
92    Widget_Data *wd = elm_widget_data_get(obj);
93    Evas_Coord  vw, vh, minw, minh, maxw, maxh, w, h, vmw, vmh;
94    double xw, xy;
95
96    if (!wd) return;
97    evas_object_size_hint_min_get(wd->content, &minw, &minh);
98    evas_object_size_hint_max_get(wd->content, &maxw, &maxh);
99    evas_object_size_hint_weight_get(wd->content, &xw, &xy);
100    hor_elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh);
101    if (xw > 0.0)
102      {
103         if ((minw > 0) && (vw < minw)) vw = minw;
104         else if ((maxw > 0) && (vw > maxw)) vw = maxw;
105      }
106    else if (minw > 0) vw = minw;
107    if (xy > 0.0)
108      {
109         if ((minh > 0) && (vh < minh)) vh = minh;
110         else if ((maxh > 0) && (vh > maxh)) vh = maxh;
111      }
112    else if (minh > 0) vh = minh;
113    evas_object_resize(wd->content, vw, vh);
114    w = -1;
115    h = -1;
116    edje_object_size_min_calc(hor_elm_smart_scroller_edje_object_get(wd->scr), &vmw, &vmh);
117    if (wd->min_w) w = vmw + minw;
118    if (wd->min_h) h = vmh + minh;
119    evas_object_size_hint_min_set(obj, w, h);
120 }
121
122 static void
123 _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info)
124 {
125    _sizing_eval(data);
126 }
127
128 static void
129 _sub_del(void *data, Evas_Object *obj, void *event_info)
130 {
131    Widget_Data *wd = elm_widget_data_get(obj);
132    Evas_Object *sub = event_info;
133
134    if (!wd) return;
135    if (sub == wd->content)
136      {
137         elm_widget_on_show_region_hook_set(wd->content, NULL, NULL);
138         evas_object_event_callback_del_full (sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
139            _changed_size_hints, obj);
140         wd->content = NULL;
141         _sizing_eval(obj);
142      }
143 }
144
145 static void
146 _hold_on(void *data, Evas_Object *obj, void *event_info)
147 {
148    Widget_Data *wd = elm_widget_data_get(obj);
149
150    if (!wd) return;
151    hor_elm_smart_scroller_hold_set(wd->scr, 1);
152 }
153
154 static void
155 _hold_off(void *data, Evas_Object *obj, void *event_info)
156 {
157    Widget_Data *wd = elm_widget_data_get(obj);
158
159    if (!wd) return;
160    hor_elm_smart_scroller_hold_set(wd->scr, 0);
161 }
162
163 static void
164 _freeze_on(void *data, Evas_Object *obj, void *event_info)
165 {
166    Widget_Data *wd = elm_widget_data_get(obj);
167
168    if (!wd) return;
169    hor_elm_smart_scroller_freeze_set(wd->scr, 1);
170 }
171
172 static void
173 _freeze_off(void *data, Evas_Object *obj, void *event_info)
174 {
175    Widget_Data *wd = elm_widget_data_get(obj);
176
177    if (!wd) return;
178    hor_elm_smart_scroller_freeze_set(wd->scr, 0);
179 }
180
181 static void
182 _resize(void *data, Evas *e, Evas_Object *obj, void *event_info)
183 {
184    _sizing_eval(data);
185 }
186
187 static void
188 _edge_left(void *data, Evas_Object *obj, void *event_info)
189 {
190    evas_object_smart_callback_call(data, "edge,left", NULL);
191 }
192
193 static void
194 _edge_right(void *data, Evas_Object *obj, void *event_info)
195 {
196    evas_object_smart_callback_call(data, "edge,right", NULL);
197 }
198
199 static void
200 _edge_top(void *data, Evas_Object *obj, void *event_info)
201 {
202    evas_object_smart_callback_call(data, "edge,top", NULL);
203 }
204
205 static void
206 _edge_bottom(void *data, Evas_Object *obj, void *event_info)
207 {
208    evas_object_smart_callback_call(data, "edge,bottom", NULL);
209 }
210
211 static void
212 _scroll(void *data, Evas_Object *obj, void *event_info)
213 {
214    evas_object_smart_callback_call(data, "scroll", NULL);
215 }
216
217 static void
218 _scroll_anim_start(void *data, Evas_Object *obj, void *event_info)
219 {
220    evas_object_smart_callback_call(data, "scroll,anim,start", NULL);
221 }
222
223 static void
224 _scroll_anim_stop(void *data, Evas_Object *obj, void *event_info)
225 {
226    evas_object_smart_callback_call(data, "scroll,anim,stop", NULL);
227 }
228
229 static void
230 _scroll_drag_start(void *data, Evas_Object *obj, void *event_info)
231 {
232    evas_object_smart_callback_call(data, "scroll,drag,start", NULL);
233 }
234
235 static void
236 _scroll_drag_stop(void *data, Evas_Object *obj, void *event_info)
237 {
238    evas_object_smart_callback_call(data, "scroll,drag,stop", NULL);
239 }
240
241 /**
242  * Add a new scroller to the parent
243  *
244  * @param parent The parent object
245  * @return The new object or NULL if it cannot be created
246  *
247  * @ingroup Scroller
248  */
249 EAPI Evas_Object *
250 hor_elm_scroller_add(Evas_Object *parent)
251 {
252    Evas_Object *obj;
253    Evas *e;
254    Widget_Data *wd;
255    Evas_Coord minw, minh;
256
257    wd = ELM_NEW(Widget_Data);
258    e = evas_object_evas_get(parent);
259    obj = elm_widget_add(e);
260    elm_widget_type_set(obj, "scroller");
261    elm_widget_sub_object_add(parent, obj);
262    elm_widget_data_set(obj, wd);
263    elm_widget_del_hook_set(obj, _del_hook);
264    elm_widget_theme_hook_set(obj, _theme_hook);
265    wd->widget_name = eina_stringshare_add("scroller");
266    wd->widget_base = eina_stringshare_add("base");
267
268    wd->scr = hor_elm_smart_scroller_add(e);
269    elm_widget_resize_object_set(obj, wd->scr);
270    evas_object_event_callback_add(wd->scr, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
271                                   _changed_size_hints, obj);
272
273    edje_object_size_min_calc(hor_elm_smart_scroller_edje_object_get(wd->scr), &minw, &minh);
274    evas_object_size_hint_min_set(obj, minw, minh);
275    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize, obj);
276
277    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
278    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
279    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
280    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
281    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
282
283    evas_object_smart_callback_add(wd->scr, "edge,left", _edge_left, obj);
284    evas_object_smart_callback_add(wd->scr, "edge,right", _edge_right, obj);
285    evas_object_smart_callback_add(wd->scr, "edge,top", _edge_top, obj);
286    evas_object_smart_callback_add(wd->scr, "edge,bottom", _edge_bottom, obj);
287    evas_object_smart_callback_add(wd->scr, "scroll", _scroll, obj);
288    evas_object_smart_callback_add(wd->scr, "animate,start", _scroll_anim_start, obj);
289    evas_object_smart_callback_add(wd->scr, "animate,stop", _scroll_anim_stop, obj);
290    evas_object_smart_callback_add(wd->scr, "drag,start", _scroll_drag_start, obj);
291    evas_object_smart_callback_add(wd->scr, "drag,stop", _scroll_drag_stop, obj);
292
293    _sizing_eval(obj);
294    return obj;
295 }
296
297 /**
298  * Set the content object
299  *
300  * XXX
301  *
302  * @param obj The scroller object
303  * @param content The new content object
304  *
305  * @ingroup Scroller
306  */
307 EAPI void
308 hor_elm_scroller_content_set(Evas_Object *obj, Evas_Object *content)
309 {
310    Widget_Data *wd = elm_widget_data_get(obj);
311    if (!wd) return;
312    if ((wd->content != content) && (wd->content))
313      elm_widget_sub_object_del(obj, wd->content);
314    wd->content = content;
315    if (content)
316      {
317         elm_widget_on_show_region_hook_set(content, _show_region_hook, obj);
318         elm_widget_sub_object_add(obj, content);
319         hor_elm_smart_scroller_child_set(wd->scr, content);
320         evas_object_event_callback_add(content, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
321                                        _changed_size_hints, obj);
322         _sizing_eval(obj);
323      }
324 }
325
326 /**
327  * Set custom theme elements for the scroller
328  *
329  * @param obj The scroller object
330  * @param widget The widget name to use (default is "scroller")
331  * @param base The base name to use (default is "base")
332  */
333 EAPI void
334 hor_elm_scroller_custom_widget_base_theme_set(Evas_Object *obj, const char *widget, const char *base)
335 {
336         Widget_Data *wd = elm_widget_data_get(obj);
337         if (!wd) return;
338         if ((!widget) || (!base)) return;
339         if (eina_stringshare_replace(&wd->widget_name, widget) |
340             eina_stringshare_replace(&wd->widget_base, base))
341                 _theme_hook(obj);
342 }
343
344 /**
345  * Make the scroller minimum size limited to the minimum size of the content
346  *
347  * By default the scroller will be as small as its design allows, irrespective
348  * of its content. This will make the scroller minimum size the right size
349  * horizontally and/or vertically to perfectly fit its content.
350  *
351  * @param obj The scroller object
352  * @param w Enable limiting minimum size horizontally
353  * @param h Enable limiting minimum size vertically
354  *
355  * @ingroup Scroller
356  */
357 EAPI void
358 hor_elm_scroller_content_min_limit(Evas_Object *obj, Eina_Bool w, Eina_Bool h)
359 {
360    Widget_Data *wd = elm_widget_data_get(obj);
361    if (!wd) return;
362    wd->min_w = w;
363    wd->min_h = h;
364    _sizing_eval(obj);
365 }
366
367 /**
368  * Show a specific virtual region within the scroller content object
369  *
370  * This will ensure all (or part if it does not fit) of the designated
371  * region in the virtual content object (0, 0 starting at the top-left of the
372  * virtual content object) is shown within the scroller.
373  *
374  * @param obj The scroller object
375  * @param x X coordinate of the region
376  * @param y Y coordinate of the region
377  * @param w Width of the region
378  * @param h Height of the region
379  *
380  * @ingroup Scroller
381  */
382 EAPI void
383 hor_elm_scroller_region_show(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
384 {
385    Widget_Data *wd = elm_widget_data_get(obj);
386    if (!wd) return;
387    hor_elm_smart_scroller_child_region_show(wd->scr, x, y, w, h);
388 }
389
390 /**
391  * Set the scroller scrollbar policy
392  *
393  * This sets the scrollbar visibility policy for the given scroller.
394  * ELM_SMART_SCROLLER_POLICY_AUTO means the scrollber is made visible if it
395  * is needed, and otherwise kept hidden. ELM_SMART_SCROLLER_POLICY_ON turns
396  * it on all the time, and ELM_SMART_SCROLLER_POLICY_OFF always keeps it off.
397  * This applies respectively for the horizontal and vertical scrollbars.
398  *
399  * @param obj The scroller object
400  * @param policy_h Horizontal scrollbar policy
401  * @param policy_v Vertical scrollbar policy
402  *
403  * @ingroup Scroller
404  */
405 EAPI void
406 hor_elm_scroller_policy_set(Evas_Object *obj, Elm_Scroller_Policy policy_h, Elm_Scroller_Policy policy_v)
407 {
408    Widget_Data *wd = elm_widget_data_get(obj);
409    const Elm_Scroller_Policy map[3] =
410      {
411         ELM_SMART_SCROLLER_POLICY_AUTO,
412           ELM_SMART_SCROLLER_POLICY_ON,
413           ELM_SMART_SCROLLER_POLICY_OFF
414      };
415    if (!wd) return;
416    if ((policy_h < 0) || (policy_h >= 3) || (policy_v < 0) || (policy_v >= 3))
417      return;
418    hor_elm_smart_scroller_policy_set(wd->scr, map[policy_h], map[policy_v]);
419 }
420
421 /**
422  * Get the currently visible content region
423  *
424  * This gets the current region in the content object that is visible through
425  * the scroller. Also see elm_scroller_region_show(). The region co-ordinates
426  * are returned in the @p x, @p y, @p w, @p h values pointed to.
427  *
428  * @param obj The scroller object
429  * @param x X coordinate of the region
430  * @param y Y coordinate of the region
431  * @param w Width of the region
432  * @param h Height of the region
433  *
434  * @ingroup Scroller
435  */
436 EAPI void
437 hor_elm_scroller_region_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
438 {
439    Widget_Data *wd = elm_widget_data_get(obj);
440    if (!wd) return;
441    if ((x) && (y)) hor_elm_smart_scroller_child_pos_get(wd->scr, x, y);
442    if ((w) && (h)) hor_elm_smart_scroller_child_viewport_size_get(wd->scr, w, h);
443 }
444
445 /**
446  * Get the size of the content child object
447  *
448  * This gets the size of the child object of the scroller. Actually the
449  * content of a scroller doesn't specifically need to be an actual object
450  * as it can be virtual and defined purely by callbacks.
451  *
452  * @param obj The scroller object
453  * @param w Width return
454  * @param h Height return
455  *
456  * @ingroup Scroller
457  */
458 EAPI void
459 hor_elm_scroller_child_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
460 {
461    Widget_Data *wd = elm_widget_data_get(obj);
462    if (!wd) return;
463    evas_object_geometry_get(wd->content, NULL, NULL, w, h);
464 }
465
466 /**
467  * Set bouncing behavior
468  *
469  * When scrolling, the scroller may "bounce" when reaching an edge of the child
470  * object. This is a visual way to indicate the end has been reached. This is
471  * enabled by default for both axes. This will set if it is enabled for that
472  * axis with the boolean parameers for each axis.
473  *
474  * @param obj The scroller object
475  * @param h_bounce Will the scroller bounce horizontally or not
476  y Y coordinate of the region
477  w Width of the region
478  h Height of the region
479
480  EAPI void elm_scroller_region_show ( Evas_Object *  obj, * @param v_bounce Will the scroller bounce vertically or not
481  *
482  * @ingroup Scroller
483  */
484 EAPI void
485 hor_elm_scroller_bounce_set(Evas_Object *obj, Eina_Bool h_bounce, Eina_Bool v_bounce)
486 {
487    Widget_Data *wd = elm_widget_data_get(obj);
488    if (!wd) return;
489    hor_elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce);
490 }
491
492 /**
493  * Set scroll page size relative to viewport size
494  *
495  * The scroller is sapale of limiting scrolling by the user to "pages". That
496  * is to jump by and only show a "whole page" at a time as if the continuous
497  * area of the scroller conent is split into page sized pieces. This sets
498  * the size of a page relative to the viewport of the scroller. 1.0 is "1
499  * viewport" is size (horizontally or vertically). 0.0 turns it off in that
500  * axis. This is mutually exclusive with page size
501  * (see elm_scroller_page_size_set()  for more information). likewise 0.5
502  * is "half a viewport". Sane usable valus are normally between 0.0 and 1.0
503  * including 1.0. If you only want 1 axis to be page "limited", use 0.0 for
504  * the other axis.
505  *
506  * @param obj The scroller object
507  * @param h_pagerel The horizontal page relative size
508  * @param v_pagerel The vertical page relative size
509  *
510  * @ingroup Scroller
511  */
512 EAPI void
513 hor_elm_scroller_page_relative_set(Evas_Object *obj, double h_pagerel, double v_pagerel)
514 {
515    Widget_Data *wd = elm_widget_data_get(obj);
516    if (!wd) return;
517    wd->pagerel_h = h_pagerel;
518    wd->pagerel_v = v_pagerel;
519    hor_elm_smart_scroller_paging_set(wd->scr, wd->pagerel_h, wd->pagerel_v,
520                                  wd->pagesize_h, wd->pagesize_v);
521 }
522
523 /**
524  * Set scroll page size
525  *
526  * See also elm_scroller_page_relative_set(). This, instead of a page size
527  * being relaive to the viewport, sets it to an absolute fixed value, with
528  * 0 turning it off for that axis.
529  *
530  * @param obj The scroller object
531  * @param h_pagesize The horizontal page size
532  * @param v_pagesize The vertical page size
533  *
534  * @ingroup Scroller
535  */
536 EAPI void
537 hor_elm_scroller_page_size_set(Evas_Object *obj, Evas_Coord h_pagesize, Evas_Coord v_pagesize)
538 {
539    Widget_Data *wd = elm_widget_data_get(obj);
540    if (!wd) return;
541    wd->pagesize_h = h_pagesize;
542    wd->pagesize_v = v_pagesize;
543    hor_elm_smart_scroller_paging_set(wd->scr, wd->pagerel_h, wd->pagerel_v,
544                                  wd->pagesize_h, wd->pagesize_v);
545 }
546
547 /**
548  * Show a specific virtual region within the scroller content object
549  *
550  * This will ensure all (or part if it does not fit) of the designated
551  * region in the virtual content object (0, 0 starting at the top-left of the
552  * virtual content object) is shown within the scroller. Unlike
553  * elm_scroller_region_show(), this allow the scroller to "smoothly slide"
554  * to this location (if configuration in general calls for transitions). It
555  * may not jump immediately to the new location and make take a while and
556  * show other content along the way.
557  *
558  * @param obj The scroller object
559  * @param x X coordinate of the region
560  * @param y Y coordinate of the region
561  * @param w Width of the region
562  * @param h Height of the region
563  *
564  * @ingroup Scroller
565  */
566 EAPI void
567 hor_elm_scroller_region_bring_in(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
568 {
569    Widget_Data *wd = elm_widget_data_get(obj);
570    if (!wd) return;
571    hor_elm_smart_scroller_region_bring_in(wd->scr, x, y, w, h);
572 }