Merge "[scroller] add gravitity feature"
[framework/uifw/elementary.git] / src / lib / els_pan.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 #define SMART_NAME "elm_pan"
5 #define API_ENTRY Smart_Data *sd; sd = evas_object_smart_data_get(obj); if ((!obj) || (!sd) || (evas_object_type_get(obj) && strcmp(evas_object_type_get(obj), SMART_NAME)))
6 #define INTERNAL_ENTRY Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return;
7 typedef struct _Smart_Data Smart_Data;
8
9 struct _Smart_Data
10 {
11    Evas_Object *smart_obj;
12    Evas_Object *child_obj;
13    Evas_Coord   x, y, w, h;
14    Evas_Coord   child_w, child_h, px, py;
15    double       gravity_x, gravity_y;
16    Evas_Coord   prev_cw, prev_ch, delta_posx, delta_posy;
17 };
18
19 /* local subsystem functions */
20 static void _smart_child_del_hook(void *data, Evas *e, Evas_Object *obj, void *event_info);
21 static void _smart_child_resize_hook(void *data, Evas *e, Evas_Object *obj, void *event_info);
22
23 static void _smart_reconfigure(Smart_Data *sd);
24 static void _smart_add(Evas_Object *obj);
25 static void _smart_del(Evas_Object *obj);
26 static void _smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
27 static void _smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h);
28 static void _smart_show(Evas_Object *obj);
29 static void _smart_hide(Evas_Object *obj);
30 static void _smart_color_set(Evas_Object *obj, int r, int g, int b, int a);
31 static void _smart_clip_set(Evas_Object *obj, Evas_Object * clip);
32 static void _smart_clip_unset(Evas_Object *obj);
33 static void _smart_init(void);
34
35 /* local subsystem globals */
36 static Evas_Smart *_smart = NULL;
37
38 /* externally accessible functions */
39 Evas_Object *
40 _elm_smart_pan_add(Evas *evas)
41 {
42    _smart_init();
43    return evas_object_smart_add(evas, _smart);
44 }
45
46 void
47 _elm_smart_pan_child_set(Evas_Object *obj, Evas_Object *child)
48 {
49    API_ENTRY return;
50    if (child == sd->child_obj) return;
51    if (sd->child_obj)
52      {
53         evas_object_clip_unset(sd->child_obj);
54         evas_object_smart_member_del(sd->child_obj);
55         evas_object_event_callback_del_full(sd->child_obj, EVAS_CALLBACK_FREE, _smart_child_del_hook, sd);
56         evas_object_event_callback_del_full(sd->child_obj, EVAS_CALLBACK_RESIZE, _smart_child_resize_hook, sd);
57         sd->child_obj = NULL;
58      }
59    if (child)
60      {
61         Evas_Coord w, h;
62         int r, g, b, a;
63
64         sd->child_obj = child;
65         evas_object_smart_member_add(sd->child_obj, sd->smart_obj);
66         evas_object_geometry_get(sd->child_obj, NULL, NULL, &w, &h);
67         sd->child_w = w;
68         sd->child_h = h;
69         evas_object_event_callback_add(child, EVAS_CALLBACK_FREE, _smart_child_del_hook, sd);
70         evas_object_event_callback_add(child, EVAS_CALLBACK_RESIZE, _smart_child_resize_hook, sd);
71         evas_object_color_get(sd->smart_obj, &r, &g, &b, &a);
72         evas_object_color_set(sd->child_obj, r, g, b, a);
73         evas_object_clip_set(sd->child_obj, evas_object_clip_get(sd->smart_obj));
74         if (evas_object_visible_get(sd->smart_obj)) evas_object_show(sd->child_obj);
75         else evas_object_hide(sd->child_obj);
76         _smart_reconfigure(sd);
77      }
78    evas_object_smart_callback_call(sd->smart_obj, "changed", NULL);
79 }
80
81 Evas_Object *
82 _elm_smart_pan_child_get(Evas_Object *obj)
83 {
84    API_ENTRY return NULL;
85    return sd->child_obj;
86 }
87
88 void
89 _elm_smart_pan_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
90 {
91    API_ENTRY return;
92    //   if (x > (sd->child_w - sd->w)) x = sd->child_w - sd->w;
93    //   if (y > (sd->child_h - sd->h)) y = sd->child_h - sd->h;
94    //   if (x < 0) x = 0;
95    //   if (y < 0) y = 0;
96    if ((x == sd->px) && (y == sd->py)) return;
97    sd->px = x;
98    sd->py = y;
99    _smart_reconfigure(sd);
100    evas_object_smart_callback_call(sd->smart_obj, "changed", NULL);
101 }
102
103 void
104 _elm_smart_pan_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
105 {
106    API_ENTRY return;
107    if (x) *x = sd->px;
108    if (y) *y = sd->py;
109 }
110
111 void
112 _elm_smart_pan_max_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
113 {
114    API_ENTRY return;
115    if (x)
116      {
117         if (sd->w < sd->child_w) *x = sd->child_w - sd->w;
118         else *x = 0;
119      }
120    if (y)
121      {
122         if (sd->h < sd->child_h) *y = sd->child_h - sd->h;
123         else *y = 0;
124      }
125 }
126
127 void
128 _elm_smart_pan_min_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
129 {
130    API_ENTRY return;
131    if (x)
132       *x = 0;
133    if (y)
134       *y = 0;
135 }
136
137 void
138 _elm_smart_pan_child_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
139 {
140    API_ENTRY return;
141    if (w) *w = sd->child_w;
142    if (h) *h = sd->child_h;
143 }
144
145 void
146 _elm_smart_pan_gravity_set(Evas_Object *obj, double x, double y)
147 {
148    API_ENTRY return;
149    sd->gravity_x = x;
150    sd->gravity_y = y;
151    sd->prev_cw = sd->child_w;
152    sd->prev_ch = sd->child_h;
153    sd->delta_posx = 0;
154    sd->delta_posy = 0;
155 }
156
157 void
158 _elm_smart_pan_gravity_get(Evas_Object *obj, double *x, double *y)
159 {
160    API_ENTRY return;
161    if (x) *x = sd->gravity_x;
162    if (y) *y = sd->gravity_y;
163 }
164
165 /* local subsystem functions */
166 static void
167 _smart_child_del_hook(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
168 {
169    Smart_Data *sd;
170
171    sd = data;
172    sd->child_obj = NULL;
173    evas_object_smart_callback_call(sd->smart_obj, "changed", NULL);
174 }
175
176 static void
177 _smart_child_resize_hook(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
178 {
179    Smart_Data *sd;
180    Evas_Coord w, h;
181
182    sd = data;
183    evas_object_geometry_get(sd->child_obj, NULL, NULL, &w, &h);
184    if ((w != sd->child_w) || (h != sd->child_h))
185      {
186         sd->child_w = w;
187         sd->child_h = h;
188         _smart_reconfigure(sd);
189      }
190    evas_object_smart_callback_call(sd->smart_obj, "changed", NULL);
191 }
192
193 static void
194 _smart_reconfigure(Smart_Data *sd)
195 {
196    if (sd->gravity_x || sd->gravity_y)
197      {
198         sd->delta_posx += sd->child_w - sd->prev_cw;
199         sd->prev_cw = sd->child_w;
200         sd->delta_posy += sd->child_h - sd->prev_ch;
201         sd->prev_ch = sd->child_h;
202
203         evas_object_move(sd->child_obj,
204                          sd->x - sd->px - (sd->delta_posx*sd->gravity_x),
205                          sd->y - sd->py - (sd->delta_posy*sd->gravity_y));
206         sd->px += sd->delta_posx*sd->gravity_x;
207         sd->py += sd->delta_posy*sd->gravity_y;
208
209      }
210    else
211      evas_object_move(sd->child_obj, sd->x - sd->px, sd->y - sd->py);
212 }
213
214 static void
215 _smart_add(Evas_Object *obj)
216 {
217    Smart_Data *sd;
218
219    sd = calloc(1, sizeof(Smart_Data));
220    if (!sd) return;
221    sd->smart_obj = obj;
222    sd->x = 0;
223    sd->y = 0;
224    sd->w = 0;
225    sd->h = 0;
226    sd->gravity_x = 0.0;
227    sd->gravity_y = 0.0;
228    evas_object_smart_data_set(obj, sd);
229 }
230
231 static void
232 _smart_del(Evas_Object *obj)
233 {
234    INTERNAL_ENTRY;
235    _elm_smart_pan_child_set(obj, NULL);
236    free(sd);
237 }
238
239 static void
240 _smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
241 {
242    INTERNAL_ENTRY;
243    sd->x = x;
244    sd->y = y;
245    _smart_reconfigure(sd);
246 }
247
248 static void
249 _smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
250 {
251    INTERNAL_ENTRY;
252    sd->w = w;
253    sd->h = h;
254    _smart_reconfigure(sd);
255    evas_object_smart_callback_call(sd->smart_obj, "changed", NULL);
256 }
257
258 static void
259 _smart_show(Evas_Object *obj)
260 {
261    INTERNAL_ENTRY;
262    if (sd->child_obj)
263      evas_object_show(sd->child_obj);
264 }
265
266 static void
267 _smart_hide(Evas_Object *obj)
268 {
269    INTERNAL_ENTRY;
270    if (sd->child_obj)
271      evas_object_hide(sd->child_obj);
272 }
273
274 static void
275 _smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
276 {
277    INTERNAL_ENTRY;
278    if (sd->child_obj)
279      evas_object_color_set(sd->child_obj, r, g, b, a);
280 }
281
282 static void
283 _smart_clip_set(Evas_Object *obj, Evas_Object *clip)
284 {
285    INTERNAL_ENTRY;
286    if (sd->child_obj)
287      evas_object_clip_set(sd->child_obj, clip);
288 }
289
290 static void
291 _smart_clip_unset(Evas_Object *obj)
292 {
293    INTERNAL_ENTRY;
294    if (sd->child_obj)
295      evas_object_clip_unset(sd->child_obj);
296 }
297
298 /* never need to touch this */
299
300 static void
301 _smart_init(void)
302 {
303    if (_smart) return;
304      {
305         static const Evas_Smart_Class sc =
306           {
307              SMART_NAME,
308              EVAS_SMART_CLASS_VERSION,
309              _smart_add,
310              _smart_del,
311              _smart_move,
312              _smart_resize,
313              _smart_show,
314              _smart_hide,
315              _smart_color_set,
316              _smart_clip_set,
317              _smart_clip_unset,
318              NULL,
319              NULL,
320              NULL,
321              NULL,
322              NULL,
323              NULL,
324              NULL
325           };
326         _smart = evas_smart_class_new(&sc);
327      }
328 }
329