8eca311479e5bf4b4a94ee8577583de235cd6149
[platform/framework/web/livebox-viewer.git] / live.viewer / src / scroller.c
1 /*
2  * Copyright 2012  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.tizenopensource.org/license
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <Elementary.h>
18
19 #include <dlog.h>
20
21 #include "util.h"
22 #include "live_scroller.h"
23 #include "scroller.h"
24 #include "debug.h"
25
26 #define FOCAL_DIST 800
27 #define FLICK_COND 100
28
29 struct cb_item {
30         int (*cb)(Evas_Object *sc, void *data);
31         void *data;
32 };
33
34 struct scroll_info {
35         int locked;
36         Eina_Bool scrolling;
37         int focal;
38         Eina_Bool quick;
39
40         Evas_Map *map;
41
42         Ecore_Idler *bg_changer;
43         Eina_List *cb_list;
44 };
45
46 void scroller_lock(Evas_Object *sc)
47 {
48         struct scroll_info *scinfo;
49
50         scinfo = evas_object_data_get(sc, "scinfo");
51         if (!scinfo) {
52                 ErrPrint("scinfo is not valid\n");
53                 return;
54         }
55
56         if (!scinfo->locked)
57                 live_scroller_freeze(sc);
58
59         scinfo->locked++;
60 }
61
62 void scroller_unlock(Evas_Object *sc)
63 {
64         struct scroll_info *scinfo;
65
66         scinfo = evas_object_data_get(sc, "scinfo");
67         if (!scinfo) {
68                 ErrPrint("scinfo is not valid\n");
69                 return;
70         }
71
72         if (scinfo->locked == 0)
73                 return;
74
75         scinfo->locked--;
76
77         if (scinfo->locked == 0)
78                 live_scroller_thaw(sc);
79 }
80
81 static void sc_anim_stop(void *data, Evas_Object *obj, void *event_info)
82 {
83         Eina_List *l;
84         Eina_List *tmp;
85         struct cb_item *item;
86         struct scroll_info *scinfo;
87
88         scinfo = evas_object_data_get(obj, "scinfo");
89         if (!scinfo) {
90                 ErrPrint("scinfo is not valid\n");
91                 return;
92         }
93         /*!
94          * \TODO
95          * Do what you want at here when the scroller is stopped
96          */
97
98         scinfo->scrolling = EINA_FALSE;
99         EINA_LIST_FOREACH_SAFE(scinfo->cb_list, l, tmp, item) {
100                 if (item->cb(obj, item->data) == ECORE_CALLBACK_CANCEL) {
101                         if (eina_list_data_find(scinfo->cb_list, item)) {
102                                 scinfo->cb_list = eina_list_remove(scinfo->cb_list, item);
103                                 free(item);
104                         }
105                 }
106         }
107 }
108
109 static inline void sc_drag_start(void *data, Evas_Object *obj, void *event_info)
110 {
111         struct scroll_info *scinfo;
112
113         scinfo = evas_object_data_get(obj, "scinfo");
114         if (!scinfo) {
115                 ErrPrint("scinfo is not valid\n");
116                 return;
117         }
118
119         scinfo->scrolling = EINA_TRUE;
120 }
121
122 static inline void sc_drag_stop(void *data, Evas_Object *scroller, void *event_info)
123 {
124         struct live_sc_drag_info *info;
125         int offset = 0;
126         int ret;
127
128         info = event_info;
129
130         if (info->dx > FLICK_COND)
131                 offset = -1;
132         else if (info->dx < -FLICK_COND)
133                 offset = 1;
134
135         ret = live_scroller_anim_to(scroller, 0.016f, offset);
136         if (ret < 0) {
137                 struct scroll_info *scinfo;
138                 scinfo = evas_object_data_get(scroller, "scinfo");
139                 if (scinfo)
140                         scinfo->scrolling = EINA_FALSE;
141         }
142 }
143
144 static Eina_Bool bg_change_cb(void *data)
145 {
146         Evas_Object *sc = data;
147         struct scroll_info *scinfo;
148
149         scinfo = evas_object_data_get(sc, "scinfo");
150         if (scinfo)
151                 scinfo->bg_changer = NULL;
152
153         /*!
154          * \note:
155          *  Here,
156          *  Filename of background image handling code is only
157          *  used to demonstrates UX concept and estimates its perfomance.
158          *  So, I'll change this if it should be appled to
159          *  main branch.
160          */
161         DbgPrint("Change the background image (%p)\n", sc);
162         return ECORE_CALLBACK_CANCEL;
163 }
164
165 static void sc_anim_start(void *data, Evas_Object *obj, void *event_info)
166 {
167         struct scroll_info *scinfo;
168
169         scinfo = evas_object_data_get(obj, "scinfo");
170         if (!scinfo) {
171                 ErrPrint("scinfo is not valid\n");
172                 return;
173         }
174
175         /*!
176          * \note
177          * without drag,start
178          * anim start can be invoked by the scroller_anim_to
179          */
180         scinfo->scrolling = EINA_TRUE;
181
182         if (scinfo->bg_changer)
183                 ecore_idler_del(scinfo->bg_changer);
184
185         scinfo->bg_changer = ecore_idler_add(bg_change_cb, obj);
186         if (!scinfo->bg_changer)
187                 DbgPrint("Failed to add an idler\n");
188 }
189
190 static void sc_item_moved(void *data, Evas_Object *obj, void *event_info)
191 {
192         struct live_sc_move_info *evt = event_info;
193         int color;
194         int focal;
195         Evas_Coord y, sx, sw;
196         double ftmp;
197         struct scroll_info *scinfo;
198
199         scinfo = evas_object_data_get(obj, "scinfo");
200         if (!scinfo) {
201                 ErrPrint("Has no scinfo\n");
202                 return;
203         }
204
205         ftmp = fabsl(evt->relx);
206         if (ftmp >= 1.0f) {
207                 evas_object_map_enable_set(evt->item, EINA_FALSE);
208                 evas_object_hide(evt->item);
209                 return;
210         }
211
212         color = 255 * (1.0f - ftmp);
213         if (scinfo->quick) {
214                 if (color < 100)
215                         color = 100;
216
217                 focal = scinfo->focal;
218         } else {
219                 if (color == 0) {
220                         evas_object_map_enable_set(evt->item, EINA_FALSE);
221                         evas_object_hide(evt->item);
222                         return;
223                 }
224
225                 focal = -ftmp * 200.0f + scinfo->focal;
226         }
227
228         evas_object_geometry_get(data, &sx, NULL, &sw, NULL);
229         
230         /* LEFT */
231         evas_map_point_coord_set(scinfo->map, 0, evt->x, evt->y, 0);
232         evas_map_point_image_uv_set(scinfo->map, 0, 0, 0);
233         evas_map_point_color_set(scinfo->map, 0, color, color, color, color);
234
235         /* RIGHT */
236         evas_map_point_coord_set(scinfo->map, 1, evt->x + evt->w, evt->y, 0);
237         evas_map_point_image_uv_set(scinfo->map, 1, evt->w, 0);
238         evas_map_point_color_set(scinfo->map, 1, color, color, color, color);
239
240         /* BOTTOM-RIGHT */
241         evas_map_point_coord_set(scinfo->map, 2, evt->x + evt->w, evt->y + evt->h, 0);
242         evas_map_point_image_uv_set(scinfo->map, 2, evt->w, evt->h);
243         evas_map_point_color_set(scinfo->map, 2, color, color, color, color);
244
245         /* BOTTOM-LEFT */
246         evas_map_point_coord_set(scinfo->map, 3, evt->x, evt->y + evt->h, 0);
247         evas_map_point_image_uv_set(scinfo->map, 3, 0, evt->h);
248         evas_map_point_color_set(scinfo->map, 3, color, color, color, color);
249
250         y = evt->y + (evt->h >> 1);
251         evas_map_util_3d_rotate(scinfo->map, 0.0f, -30.0f * evt->relx, 0.0f, evt->x + (evt->w >> 1), y, 0);
252         evas_map_util_3d_perspective(scinfo->map, sx + (sw >> 1), y, focal, FOCAL_DIST);
253         evas_object_map_set(evt->item, scinfo->map);
254         evas_object_map_enable_set(evt->item, EINA_TRUE);
255         evas_object_show(evt->item);
256         return;
257 }
258
259 static void sc_page_changed(void *data, Evas_Object *obj, void *event_info)
260 {
261         DbgPrint("Page is changed %d\n", (int)event_info);
262 }
263
264 int scroller_add_stop_cb(Evas_Object *scroller,
265                         int (*cb)(Evas_Object *sc, void *data), void *data)
266 {
267         struct cb_item *item;
268         struct scroll_info *scinfo;
269
270         scinfo = evas_object_data_get(scroller, "scinfo");
271         if (!scinfo) {
272                 ErrPrint("scinfo is not valid\n");
273                 return -EINVAL;
274         }
275
276         item = calloc(1, sizeof(*item));
277         if (!item) {
278                 ErrPrint("Error: %s\n", strerror(errno));
279                 return EXIT_FAILURE;
280         }
281
282         item->cb = cb;
283         item->data = data;
284
285         scinfo->cb_list = eina_list_append(scinfo->cb_list, item);
286         return EXIT_SUCCESS;
287 }
288
289 void scroller_del_stop_cb(Evas_Object *scroller,
290                         int (*cb)(Evas_Object *sc, void *data), void *data)
291 {
292         struct cb_item *item;
293         Eina_List *l;
294         Eina_List *tmp;
295         struct scroll_info *scinfo;
296
297         scinfo = evas_object_data_get(scroller, "scinfo");
298         if (!scinfo) {
299                 ErrPrint("Failed to get scinfo\n");
300                 return;
301         }
302
303         EINA_LIST_FOREACH_SAFE(scinfo->cb_list, l, tmp, item) {
304                 if (item->cb == cb && item->data == data) {
305                         scinfo->cb_list = eina_list_remove(scinfo->cb_list, item);
306                         free(item);
307                         break;
308                 }
309         }
310 }
311
312 Evas_Object *scroller_create(Evas_Object *ctrl)
313 {
314         Evas_Object *sc;
315         struct scroll_info *scinfo;
316
317         scinfo = calloc(1, sizeof(*scinfo));
318         if (!scinfo) {
319                 ErrPrint("Heap: %s\n", strerror(errno));
320                 return NULL;
321         }
322
323         sc = live_scroller_add(ctrl);
324         if (!sc) {
325                 DbgPrint("Failed to create flip object\n");
326                 free(scinfo);
327                 return NULL;
328         }
329
330         evas_object_data_set(sc, "scinfo", scinfo);
331
332         scinfo->map = evas_map_new(4);
333         if (!scinfo->map) {
334                 ErrPrint("Failed to create a map object\n");
335                 evas_object_del(sc);
336                 free(scinfo);
337                 return NULL;
338         }
339
340         evas_map_smooth_set(scinfo->map, EINA_TRUE);
341         evas_map_alpha_set(scinfo->map, EINA_TRUE);
342
343         evas_object_size_hint_weight_set(sc, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
344         evas_object_smart_callback_add(sc, "drag,start", sc_drag_start, NULL);
345         evas_object_smart_callback_add(sc, "drag,stop", sc_drag_stop, NULL);
346         evas_object_smart_callback_add(sc, "anim,stop", sc_anim_stop, NULL);
347         evas_object_smart_callback_add(sc, "anim,start", sc_anim_start, NULL);
348         evas_object_smart_callback_add(sc, "page,changed", sc_page_changed, NULL);
349         evas_object_smart_callback_add(sc, "item,moved", sc_item_moved, NULL);
350         live_scroller_loop_set(sc, EINA_TRUE);
351         evas_object_show(sc);
352
353         return sc;
354 }
355
356 int scroller_append(Evas_Object *sc, Evas_Object *child)
357 {
358         return live_scroller_append(sc, child);
359 }
360
361 int scroller_get_page_index(Evas_Object *sc, Evas_Object *page)
362 {
363         return live_scroller_get_item_index(sc, page);
364 }
365
366 Evas_Object *scroller_get_page(Evas_Object *sc, int idx)
367 {
368         return live_scroller_get_item(sc, idx);
369 }
370
371 Evas_Object *scroller_peek_by_idx(Evas_Object *sc, int idx)
372 {
373         return live_scroller_remove(sc, idx);
374 }
375
376 int scroller_peek_by_obj(Evas_Object *sc, Evas_Object *page)
377 {
378         return live_scroller_remove_by_obj(sc, page);
379 }
380
381 int scroller_get_current_idx(Evas_Object *sc)
382 {
383         return live_scroller_get_current(sc);
384 }
385
386 int scroller_is_scrolling(Evas_Object *sc)
387 {
388         struct scroll_info *scinfo;
389
390         scinfo = evas_object_data_get(sc, "scinfo");
391         if (!scinfo) {
392                 ErrPrint("scinfo is not valid\n");
393                 return -EINVAL;
394         }
395
396         return scinfo->scrolling;
397 }
398
399 int scroller_get_page_count(Evas_Object *sc)
400 {
401         return live_scroller_get_item_count(sc);
402 }
403
404 int scroller_scroll_to(Evas_Object *sc, int idx)
405 {
406         int curidx;
407         int cnt;
408         register int i;
409         int next_offset;
410         int prev_offset;
411         struct scroll_info *scinfo;
412
413         scinfo = evas_object_data_get(sc, "scinfo");
414         if (!scinfo) {
415                 ErrPrint("scinfo is not valid\n");
416                 return -EINVAL;
417         }
418
419         if (scinfo->scrolling) {
420                 DbgPrint("Scroller is scrolling\n");
421                 return -EINVAL;
422         }
423
424         curidx = live_scroller_get_current(sc);
425         cnt = live_scroller_get_item_count(sc);
426
427         i = curidx;
428         next_offset = 0;
429         while (i != idx && i >= 0 && i < cnt) {
430                 i++;
431                 if (i >= cnt)
432                         i = 0;
433
434                 next_offset++;
435         }
436
437         i = curidx;
438         prev_offset = 0;
439         while (i != idx && i >= 0 && i < cnt) {
440                 i--;
441                 if (i < 0)
442                         i = cnt - 1;
443
444                 prev_offset--;
445         }
446
447         idx = next_offset < -prev_offset ? next_offset : prev_offset;
448         live_scroller_anim_to(sc, 0.016f, idx);
449         return 0;
450 }
451
452 int scroller_jump_to(Evas_Object *sc, int idx)
453 {
454         live_scroller_go_to(sc, idx);
455         return 0;
456 }
457
458 int scroller_destroy(Evas_Object *sc)
459 {
460         int cnt;
461         struct scroll_info *scinfo;
462         struct cb_item *item;
463
464         scinfo = evas_object_data_del(sc, "scinfo");
465         if (!scinfo)
466                 return -EFAULT;
467
468         if (scinfo->bg_changer)
469                 ecore_idler_del(scinfo->bg_changer);
470
471         EINA_LIST_FREE(scinfo->cb_list, item) {
472                 free(item);
473         }
474
475         cnt = live_scroller_get_item_count(sc);
476         if (cnt)
477                 DbgPrint("Children is not cleared (%d)\n", cnt);
478
479         evas_object_del(sc);
480         evas_map_free(scinfo->map);
481         free(scinfo);
482         return 0;
483 }
484
485 int scroller_update(Evas_Object *sc, void *data)
486 {
487         struct scroll_info *scinfo;
488
489         scinfo = evas_object_data_get(sc, "scinfo");
490         if (!scinfo) {
491                 ErrPrint("scinfo is not valid\n");
492                 return -EFAULT;
493         }
494
495         scinfo->focal = (int)data;
496         live_scroller_update(sc);
497         return EXIT_SUCCESS;
498 }
499
500 int scroller_fast_scroll(Evas_Object *sc, int idx)
501 {
502         idx -= scroller_get_current_idx(sc);
503         live_scroller_anim_to(sc, 0.016f, idx);
504         return 0;
505 }
506
507 void scroller_loop_set(Evas_Object *sc, Eina_Bool val)
508 {
509         live_scroller_loop_set(sc, val);
510 }
511
512 void scroller_quick_navi(Evas_Object *sc, Eina_Bool val)
513 {
514         struct scroll_info *scinfo;
515         scinfo = evas_object_data_get(sc, "scinfo");
516         if (!scinfo) {
517                 ErrPrint("scinfo is not valid\n");
518                 return;
519         }
520
521         scinfo->quick = val;
522 }
523
524 /* End of a file */