2 * Copyright 2012 Samsung Electronics Co., Ltd
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
8 * http://www.tizenopensource.org/license
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.
17 #include <Elementary.h>
21 #include "live_scroller.h"
26 #define EVT_PERIOD 0.016 /* 60 fps */
27 #define EVT_SAMPLE_PERIOD 9
32 struct item_list_entry {
33 struct item_list_entry *prev;
34 struct item_list_entry *next;
45 unsigned int timestamp;
49 struct evt_info ei[SAMPLE_MAX];
53 unsigned int old_timestamp;
60 struct item_list_entry *item_list;
63 struct item_list_entry *curlist;
64 struct item_list_entry *tolist;
66 Eina_Bool drag_started;
71 Ecore_Timer *sc_anim_timer;
75 Evas_Object *evt_layer;
76 Evas_Object *scroller;
81 struct evt_queue evtq;
82 Ecore_Timer *evt_emulator;
84 unsigned int prev_timestamp;
88 #define PROFILE_START() \
89 static int _exec_cnt = 0; \
90 struct timeval _stv, _etv; \
92 gettimeofday(&_stv, NULL);
94 #define PROFILE_END() \
97 gettimeofday(&_etv, NULL); \
98 _elapsed = (_etv.tv_sec - _stv.tv_sec) * 1000000l + (_etv.tv_usec - _stv.tv_usec); \
99 DbgPrint("[%d] Elapsed time: %lu\n", _exec_cnt, _elapsed); \
102 #define PROFILE_START()
103 #define PROFILE_END()
106 #define LIST_NEXT(list) ((list)->next)
107 #define LIST_PREV(list) ((list)->prev)
108 #define LIST_DATA(list) ((list) ? (list)->data : NULL)
110 static inline void LIST_ITEM_GEO_SET(struct item_list_entry *list, int x, int y, int w, int h)
118 static inline void LIST_ITEM_GEO_GET(struct item_list_entry *list, int *x, int *y, int *w, int *h)
130 static inline struct item_list_entry *list_item_append(struct item_list_entry *list, void *obj)
132 struct item_list_entry *item;
134 item = malloc(sizeof(*item));
141 list->prev->next = item;
142 item->prev = list->prev;
155 static inline void *list_item_nth(struct item_list_entry *list, int idx)
166 static inline struct item_list_entry *list_item_nth_list(struct item_list_entry *list, int idx)
177 static inline struct item_list_entry *list_item_find(struct item_list_entry *list, void *data)
179 struct item_list_entry *item;
186 if (LIST_DATA(item) == data)
189 item = LIST_NEXT(item);
190 } while (item != list);
195 static inline struct item_list_entry *list_item_remove(struct item_list_entry *list, void *data)
197 struct item_list_entry *item;
200 ErrPrint("List is not valid\n");
207 if (LIST_DATA(item) == data) {
208 DbgPrint("ITEM is removed\n");
210 if (list == LIST_NEXT(list))
213 list = LIST_NEXT(list);
216 item->prev->next = item->next;
217 item->next->prev = item->prev;
222 item = LIST_NEXT(item);
223 } while (item != list);
229 static inline void *list_item_last(struct item_list_entry *list)
234 return list->prev->data;
237 static inline struct item_list_entry *list_item_last_list(struct item_list_entry *list)
245 static inline int list_item_count(struct item_list_entry *list)
247 struct item_list_entry *n;
263 static inline int list_item_idx(struct widget_data *sc_data, struct item_list_entry *ilist)
268 while (ilist != sc_data->item_list) {
270 ilist = LIST_PREV(ilist);
276 static inline void init_evtq(struct evt_queue *evtq)
281 evtq->old_timestamp = 0;
284 static inline void dq_evt(struct evt_queue *evtq)
289 if (evtq->front >= SAMPLE_MAX)
290 evtq->front -= SAMPLE_MAX;
294 static inline void enq_evt(struct evt_queue *evtq, Evas_Coord x, unsigned int timestamp)
300 t_diff = timestamp - evtq->old_timestamp;
303 evtq->old_timestamp = timestamp;
304 else if (t_diff > EVT_SAMPLE_PERIOD)
305 evtq->old_timestamp += EVT_SAMPLE_PERIOD * (t_diff / EVT_SAMPLE_PERIOD);
310 if (evtq->cnt >= SAMPLE_MAX)
313 if (evtq->rear >= SAMPLE_MAX)
314 evtq->rear -= SAMPLE_MAX;
318 evtq->ei[evtq->rear].x = x;
319 evtq->ei[evtq->rear].timestamp = evtq->old_timestamp;
322 static inline Evas_Coord get_evt_avg(struct evt_queue *evtq)
330 t = (int)(ecore_time_get() * 1000);
334 for (i = 0; i < evtq->cnt; i += weight) {
335 weight = (t - evtq->ei[rear].timestamp) / EVT_SAMPLE_PERIOD;
336 if (weight > (evtq->cnt - i))
337 weight = evtq->cnt - i;
341 x += evtq->ei[rear].x * weight;
342 t = evtq->ei[rear].timestamp;
352 /* Move the item to given direction to fit its coordinates to border */
353 static inline int calc_anim_dx_with_dir(struct widget_data *sc_data, int *dir)
357 LIST_ITEM_GEO_GET(sc_data->curlist, &x, NULL, &w, NULL);
358 sc_data->sc_anim_dx = 0;
361 DbgPrint("MOVE to LEFT\n");
362 if (x < sc_data->clip_bx) {
365 if (sc_data->tolist == sc_data->item_list) {
366 if (!sc_data->is_loop) {
368 DbgPrint("Looping is disabled\n");
373 sc_data->tolist = LIST_PREV(sc_data->tolist);
374 sc_data->sc_anim_dx = sc_data->clip_bx - x /*- w*/;
376 sc_data->sc_anim_dx = sc_data->clip_bx - x;
378 } else if (*dir > 0) {
379 DbgPrint("MOVE to RIGHT\n");
380 if (x < sc_data->clip_bx) {
381 sc_data->sc_anim_dx = sc_data->clip_bx - x;
382 } else if (x > sc_data->clip_bx) {
383 struct item_list_entry *newlist;
386 newlist = LIST_NEXT(sc_data->tolist);
387 if (newlist == sc_data->item_list) {
388 if (!sc_data->is_loop) {
390 DbgPrint("Looping is disabled\n");
394 sc_data->tolist = newlist;
395 sc_data->sc_anim_dx = sc_data->clip_bx - x; /*(sc_data->clip_bx + sc_data->clip_bw) - x;*/
402 static inline void move_item(struct widget_data *sc_data, struct item_list_entry *ilist, int x, int y, int w, int h)
404 struct live_sc_move_info info;
406 info.item = LIST_DATA(ilist);
408 info.relx = ((double)x - (double)sc_data->clip_bx) / (double)sc_data->clip_bw;
410 LIST_ITEM_GEO_SET(ilist, x, y, w, h);
416 evas_object_smart_callback_call(sc_data->scroller, "item,moved", &info);
419 static struct item_list_entry *update_items_geo(struct widget_data *sc_data, int dx)
423 struct item_list_entry *ilist;
424 struct item_list_entry *newlist;
425 struct item_list_entry *boundary;
429 LIST_ITEM_GEO_GET(sc_data->curlist, &sx, &y, &sw, &h);
431 bx_bw = sc_data->clip_bx + sc_data->clip_bw;
434 move_item(sc_data, sc_data->curlist, sx, y, sw, h);
438 if (sc_data->item_cnt < 3) {
439 ilist = LIST_NEXT(sc_data->curlist);
440 LIST_ITEM_GEO_GET(ilist, NULL, &y, &w, &h);
442 if (sx + sw < bx_bw) {
444 move_item(sc_data, ilist, x, y, w, h);
445 if (x == sc_data->clip_bx || (x < sc_data->clip_bx && (x + w) > sc_data->clip_bx))
449 move_item(sc_data, ilist, x, y, w, h);
450 if (x == sc_data->clip_bx || (x > sc_data->clip_bx && x < bx_bw)) {
460 ilist = sc_data->curlist;
462 if (!sc_data->is_loop && ilist == sc_data->item_list)
465 ilist = LIST_PREV(ilist);
469 LIST_ITEM_GEO_GET(ilist, NULL, &y, &w, &h);
471 move_item(sc_data, ilist, x, y, w, h);
473 if (dx > 0 && !newlist) {
474 if ((x == sc_data->clip_bx) || (x > sc_data->clip_bx && x < bx_bw))
479 } while (x > sc_data->clip_bx);
483 ilist = sc_data->curlist;
485 ilist = LIST_NEXT(ilist);
486 if (!ilist || (!sc_data->is_loop && ilist == sc_data->item_list) || ilist == boundary)
490 LIST_ITEM_GEO_GET(ilist, NULL, &y, &w, &h);
491 move_item(sc_data, ilist, x, y, w, h);
493 if (dx < 0 && !newlist) {
494 if ((x == sc_data->clip_bx) || (x < sc_data->clip_bx && (x + w) > sc_data->clip_bx))
501 sc_data->curlist = newlist;
506 static Eina_Bool emulate_evt(void *data)
509 struct widget_data *sc_data;
512 struct item_list_entry *newlist;
516 x = get_evt_avg(&sc_data->evtq);
517 if (x == sc_data->old_x) {
519 return ECORE_CALLBACK_RENEW;
522 dx = x - sc_data->old_x;
525 newlist = update_items_geo(sc_data, dx);
529 idx = list_item_idx(sc_data, newlist);
530 evas_object_smart_callback_call(sc_data->scroller, "page,changed", (void *)idx);
533 return ECORE_CALLBACK_RENEW;
536 static void evt_mouse_down_cb(void *data, Evas *e, Evas_Object *evt_layer, void *event_info)
538 Evas_Event_Mouse_Down *down;
539 struct widget_data *sc_data;
544 sc_data->is_pressed = EINA_TRUE;
545 sc_data->press_x = down->canvas.x;
546 sc_data->press_y = down->canvas.y;
547 sc_data->old_x = down->canvas.x;
549 if (!sc_data->is_freezed) {
550 init_evtq(&sc_data->evtq);
551 enq_evt(&sc_data->evtq, down->canvas.x, down->timestamp);
555 static void evt_mouse_up_cb(void *data, Evas *e, Evas_Object *evt_layer, void *event_info)
557 Evas_Event_Mouse_Up *up;
558 struct widget_data *sc_data;
559 struct live_sc_drag_info info;
563 if (!sc_data->is_pressed)
566 sc_data->is_pressed = EINA_FALSE;
568 if (sc_data->evt_emulator) {
569 ecore_timer_del(sc_data->evt_emulator);
570 sc_data->evt_emulator = NULL;
573 if (sc_data->drag_started == EINA_FALSE) {
574 DbgPrint("drag is not started\n");
580 info.dx = up->canvas.x - sc_data->press_x;
581 info.dy = up->canvas.y - sc_data->press_y;
583 sc_data->drag_started = EINA_FALSE;
585 evas_object_smart_callback_call(sc_data->scroller, "drag,stop", &info);
588 static void evt_mouse_move_cb(void *data, Evas *e, Evas_Object *evt_layer, void *event_info)
590 struct widget_data *sc_data;
591 Evas_Event_Mouse_Move *move;
595 if (sc_data->is_pressed == EINA_FALSE)
598 if (sc_data->item_cnt <= 1)
601 if (sc_data->is_freezed)
606 if (sc_data->drag_started == EINA_FALSE) {
607 if (abs(move->cur.canvas.x - sc_data->press_x) < DRAG_SENS)
610 if (sc_data->sc_anim_timer) {
611 ecore_timer_del(sc_data->sc_anim_timer);
612 sc_data->sc_anim_timer = NULL;
615 evas_object_smart_callback_call(sc_data->scroller, "drag,start", NULL);
616 sc_data->drag_started = EINA_TRUE;
619 sc_data->prev_timestamp = move->timestamp;
620 enq_evt(&sc_data->evtq, move->cur.canvas.x, move->timestamp);
621 if (!sc_data->evt_emulator) {
622 if (!sc_data->curlist)
623 sc_data->curlist = sc_data->item_list;
625 sc_data->evt_emulator = ecore_timer_add(EVT_PERIOD, emulate_evt, sc_data);
629 static inline int prepare_evt_layer(struct widget_data *sc_data)
633 e = evas_object_evas_get(sc_data->scroller);
637 sc_data->evt_layer = evas_object_rectangle_add(e);
638 if (!sc_data->evt_layer)
641 evas_object_smart_member_add(sc_data->evt_layer, sc_data->scroller);
643 evas_object_color_set(sc_data->evt_layer, 255, 255, 255, 0);
644 evas_object_show(sc_data->evt_layer);
645 evas_object_repeat_events_set(sc_data->evt_layer, EINA_TRUE);
647 evas_object_event_callback_add(sc_data->evt_layer,
648 EVAS_CALLBACK_MOUSE_DOWN, evt_mouse_down_cb, sc_data);
650 evas_object_event_callback_add(sc_data->evt_layer,
651 EVAS_CALLBACK_MOUSE_UP, evt_mouse_up_cb, sc_data);
653 evas_object_event_callback_add(sc_data->evt_layer,
654 EVAS_CALLBACK_MOUSE_MOVE, evt_mouse_move_cb, sc_data);
656 evas_object_clip_set(sc_data->evt_layer, sc_data->clip);
660 static void live_add(Evas_Object *scroller)
662 struct widget_data *sc_data;
666 sc_data = calloc(1, sizeof(*sc_data));
670 e = evas_object_evas_get(scroller);
676 evas_object_smart_data_set(scroller, sc_data);
678 sc_data->clip = evas_object_rectangle_add(e);
679 if (!sc_data->clip) {
684 sc_data->is_pressed = EINA_FALSE;
685 sc_data->drag_started = EINA_FALSE;
686 sc_data->tolist = NULL;
687 sc_data->curlist = NULL;
688 sc_data->item_list = NULL;
689 sc_data->scroller = scroller;
691 evas_object_smart_member_add(sc_data->clip, sc_data->scroller);
693 ret = prepare_evt_layer(sc_data);
695 evas_object_del(sc_data->clip);
702 static void live_del(Evas_Object *scroller)
704 struct widget_data *sc_data;
706 struct item_list_entry *ilist;
707 struct item_list_entry *next;
709 sc_data = evas_object_smart_data_get(scroller);
711 ErrPrint("sc_data is not valid\n");
715 ilist = sc_data->item_list;
718 next = LIST_NEXT(ilist);
719 item = LIST_DATA(ilist);
720 evas_object_clip_unset(item);
721 evas_object_smart_member_del(item);
724 } while (ilist != sc_data->item_list);
727 evas_object_del(sc_data->evt_layer);
728 evas_object_del(sc_data->clip);
732 static void live_move(Evas_Object *scroller, Evas_Coord bx, Evas_Coord by)
734 struct widget_data *sc_data;
735 Evas_Coord x, y, w, h;
741 struct item_list_entry *n;
743 sc_data = evas_object_smart_data_get(scroller);
745 ErrPrint("sc_data is not valid\n");
749 evas_object_geometry_get(sc_data->clip, &x, &y, &bw, NULL);
751 evas_object_move(sc_data->evt_layer, bx, by);
752 evas_object_move(sc_data->clip, bx, by);
753 sc_data->clip_bx = bx;
754 sc_data->clip_bw = bw;
759 if (sc_data->item_list) {
760 n = sc_data->item_list;
762 evas_object_move(LIST_DATA(n), bx, by);
764 LIST_ITEM_GEO_GET(n, &x, &y, &w, &h);
767 move_item(sc_data, n, x, y, w, h);
769 } while (n != sc_data->item_list);
773 static void live_resize(Evas_Object *scroller, Evas_Coord w, Evas_Coord h)
775 struct widget_data *sc_data;
777 sc_data = evas_object_smart_data_get(scroller);
779 ErrPrint("sc_data is not valid\n");
783 evas_object_resize(sc_data->clip, w, h);
784 evas_object_resize(sc_data->evt_layer, w, h);
786 sc_data->clip_bw = w;
789 static void live_show(Evas_Object *scroller)
791 struct widget_data *sc_data;
793 sc_data = evas_object_smart_data_get(scroller);
795 ErrPrint("sc_data is not valid\n");
799 evas_object_show(sc_data->clip);
802 static void live_hide(Evas_Object *scroller)
804 struct widget_data *sc_data;
806 sc_data = evas_object_smart_data_get(scroller);
808 ErrPrint("sc_data is not valid\n");
812 evas_object_hide(sc_data->clip);
815 static void live_set_color(Evas_Object *scroller, int r, int g, int b, int a)
817 struct widget_data *sc_data;
819 sc_data = evas_object_smart_data_get(scroller);
821 ErrPrint("sc_data is not valid\n");
825 evas_object_color_set(sc_data->clip, r, g, b, a);
828 static void live_set_clip(Evas_Object *scroller, Evas_Object *clip)
830 struct widget_data *sc_data;
832 sc_data = evas_object_smart_data_get(scroller);
834 ErrPrint("sc_data is not valid\n");
838 evas_object_clip_set(sc_data->clip, clip);
841 static void live_unset_clip(Evas_Object *scroller)
843 struct widget_data *sc_data;
845 sc_data = evas_object_smart_data_get(scroller);
847 ErrPrint("sc_data is not valid\n");
851 evas_object_clip_unset(sc_data->clip);
854 static inline void rearrange_items(struct widget_data *sc_data)
856 struct item_list_entry *ilist;
857 Evas_Coord x, y, w, h;
860 LIST_ITEM_GEO_GET(sc_data->curlist, NULL, &y, &sw, &h);
861 move_item(sc_data, sc_data->curlist, sc_data->clip_bx, y, sw, h);
863 x = sc_data->clip_bx;
864 ilist = sc_data->curlist;
865 while (ilist != sc_data->item_list) {
866 ilist = LIST_PREV(ilist);
867 LIST_ITEM_GEO_GET(ilist, NULL, &y, &w, &h);
869 move_item(sc_data, ilist, x, y, w, h);
873 x = sc_data->clip_bx;
874 ilist = LIST_NEXT(sc_data->curlist);
875 while (ilist != sc_data->item_list) {
877 LIST_ITEM_GEO_GET(ilist, NULL, &y, &w, &h);
878 move_item(sc_data, ilist, x, y, w, h);
879 ilist = LIST_NEXT(ilist);
883 static Eina_Bool sc_anim_cb(void *data)
886 struct widget_data *sc_data;
890 struct item_list_entry *ilist;
894 if (!sc_data->curlist || !sc_data->tolist) {
895 DbgPrint("cur_list: %p, tolist: %p\n", sc_data->curlist, sc_data->tolist);
899 ilist = sc_data->curlist;
900 if (sc_data->curlist != sc_data->tolist) {
901 if (sc_data->sc_anim_dx > 0)
902 ilist = LIST_PREV(ilist);
904 ilist = LIST_NEXT(ilist);
907 LIST_ITEM_GEO_GET(ilist, &sx, &y, &sw, NULL);
908 if (ilist == sc_data->tolist) {
909 DbgPrint("next list == tolist\n");
910 dx = abs(sx - sc_data->clip_bx);
911 DbgPrint("sx: %d, clip_bx: %d --> %d\n", sx, sc_data->clip_bx, dx);
912 if (dx < abs(sc_data->sc_anim_dx)) {
913 if (sc_data->sc_anim_dx < 0)
916 dx = sc_data->sc_anim_dx;
919 dx = sc_data->sc_anim_dx;
920 DbgPrint("dx: %d\n", dx);
924 DbgPrint("dx is 0\n");
928 ilist = update_items_geo(sc_data, dx);
932 idx = list_item_idx(sc_data, ilist);
933 evas_object_smart_callback_call(sc_data->scroller,"page,changed", (void *)idx);
936 return ECORE_CALLBACK_RENEW;
940 evas_object_smart_callback_call(sc_data->scroller, "anim,stop", NULL);
941 sc_data->sc_anim_timer = NULL;
942 return ECORE_CALLBACK_CANCEL;
945 Evas_Object *live_scroller_add(Evas_Object *parent)
947 static Evas_Smart_Class sc = EVAS_SMART_CLASS_INIT_NAME_VERSION("live,scroller");
948 static Evas_Smart *smart = NULL;
949 Evas_Object *scroller;
955 e = evas_object_evas_get(parent);
963 sc.resize = live_resize;
966 sc.color_set = live_set_color;
967 sc.clip_set = live_set_clip;
968 sc.clip_unset = live_unset_clip;
970 smart = evas_smart_class_new(&sc);
973 scroller = evas_object_smart_add(e, smart);
978 int live_scroller_append(Evas_Object *scroller, Evas_Object *item)
980 Evas_Coord x, y, w, h;
981 Evas_Coord bx, by, bw, bh;
982 struct widget_data *sc_data;
983 struct item_list_entry *tmplist;
984 Evas_Coord start_x = 0;
985 Evas_Coord start_w = 0;
987 sc_data = evas_object_smart_data_get(scroller);
989 ErrPrint("sc_data is not valid\n");
993 evas_object_geometry_get(sc_data->clip, &bx, &by, &bw, &bh);
995 if (sc_data->item_list)
996 LIST_ITEM_GEO_GET(sc_data->item_list, &start_x, NULL, &start_w, NULL);
998 tmplist = list_item_last_list(sc_data->item_list);
1000 LIST_ITEM_GEO_GET(tmplist, &x, NULL, &w, NULL);
1001 if (x + w == start_x) {
1010 evas_object_geometry_get(item, NULL, NULL, &w, &h);
1011 evas_object_smart_member_add(item, sc_data->scroller);
1013 y = by + ((bh - h) >> 1);
1015 tmplist = list_item_append(sc_data->item_list, item);
1016 if (sc_data->item_list == sc_data->curlist)
1017 sc_data->curlist = tmplist;
1018 if (sc_data->item_list == sc_data->tolist)
1019 sc_data->tolist = tmplist;
1020 sc_data->item_list = tmplist;
1022 sc_data->item_cnt++;
1023 evas_object_clip_set(item, sc_data->clip);
1024 evas_object_stack_below(item, sc_data->clip);
1026 evas_object_move(item, bx, by);
1027 move_item(sc_data, list_item_find(sc_data->item_list, item), x, y, w, h);
1032 int live_scroller_remove_by_obj(Evas_Object *scroller, Evas_Object *obj)
1034 struct widget_data *sc_data;
1035 struct item_list_entry *tmplist;
1038 sc_data = evas_object_smart_data_get(scroller);
1040 ErrPrint("sc_data is not valid\n");
1044 if (sc_data->curlist) {
1045 if (LIST_DATA(sc_data->curlist) == obj) {
1046 sc_data->curlist = sc_data->item_list;
1047 DbgPrint("Reset curlist\n");
1051 if (sc_data->tolist) {
1052 if (LIST_DATA(sc_data->tolist) == obj) {
1053 sc_data->tolist = sc_data->item_list;
1054 DbgPrint("Reset tolist\n");
1058 tmplist = list_item_remove(sc_data->item_list, obj);
1059 if (sc_data->item_list == sc_data->curlist) {
1060 sc_data->curlist = tmplist;
1061 DbgPrint("Update curlist\n");
1063 if (sc_data->item_list == sc_data->tolist) {
1064 sc_data->tolist = tmplist;
1065 DbgPrint("Update tolist\n");
1067 sc_data->item_list = tmplist;
1069 sc_data->item_cnt--;
1070 evas_object_clip_unset(obj);
1071 evas_object_smart_member_del(obj);
1072 DbgPrint("Count of items: %d\n", sc_data->item_cnt);
1074 item = LIST_DATA(sc_data->curlist);
1079 LIST_ITEM_GEO_GET(sc_data->curlist, NULL, &y, &w, &h);
1080 DbgPrint("Current GEO: %d, %dx%d\n", y, w, h);
1081 LIST_ITEM_GEO_SET(sc_data->curlist, sc_data->clip_bx, y, w, h);
1082 DbgPrint("sc_data->curlist : %p\n", sc_data->curlist);
1083 update_items_geo(sc_data, 0);
1084 DbgPrint("sc_data->curlist : %p\n", sc_data->curlist);
1086 idx = list_item_idx(sc_data, sc_data->curlist);
1087 evas_object_smart_callback_call(sc_data->scroller, "page,changed", (void *)idx);
1093 Evas_Object *live_scroller_remove(Evas_Object *scroller, int idx)
1095 struct widget_data *sc_data;
1096 struct item_list_entry *tmplist;
1100 sc_data = evas_object_smart_data_get(scroller);
1102 ErrPrint("sc_data is not valid\n");
1106 if (idx < 0 || idx >= sc_data->item_cnt)
1109 ret = list_item_nth(sc_data->item_list, idx);
1113 if (list_item_nth_list(sc_data->item_list, idx) == sc_data->curlist) {
1114 DbgPrint("Reset curlist\n");
1115 sc_data->curlist = sc_data->item_list;
1118 if (list_item_nth_list(sc_data->item_list, idx) == sc_data->tolist) {
1119 DbgPrint("Reset tolist\n");
1120 sc_data->tolist = sc_data->item_list;
1123 tmplist = list_item_remove(sc_data->item_list, ret);
1124 if (sc_data->item_list == sc_data->curlist)
1125 sc_data->curlist = tmplist;
1126 if (sc_data->item_list == sc_data->tolist)
1127 sc_data->tolist = tmplist;
1128 sc_data->item_list = tmplist;
1130 sc_data->item_cnt--;
1131 evas_object_clip_unset(ret);
1132 evas_object_smart_member_del(ret);
1134 item = LIST_DATA(sc_data->curlist);
1138 LIST_ITEM_GEO_GET(sc_data->curlist, NULL, &y, &w, &h);
1139 LIST_ITEM_GEO_SET(sc_data->curlist, sc_data->clip_bx, y, w, h);
1140 update_items_geo(sc_data, 0);
1141 idx = list_item_idx(sc_data, sc_data->curlist);
1142 evas_object_smart_callback_call(sc_data->scroller, "page,changed", (void *)idx);
1147 Evas_Object *live_scroller_get_item(Evas_Object *scroller, int idx)
1149 struct widget_data *sc_data;
1151 sc_data = evas_object_smart_data_get(scroller);
1153 ErrPrint("sc_data is not valid\n");
1157 if (idx < 0 || idx >= sc_data->item_cnt)
1160 return list_item_nth(sc_data->item_list, idx);
1163 int live_scroller_get_current(Evas_Object *scroller)
1165 struct widget_data *sc_data;
1166 struct item_list_entry *ilist;
1169 sc_data = evas_object_smart_data_get(scroller);
1171 ErrPrint("sc_data is not valid\n");
1175 ilist = sc_data->curlist;
1178 while (ilist != sc_data->item_list) {
1180 ilist = LIST_PREV(ilist);
1187 int live_scroller_loop_set(Evas_Object *scroller, int is_loop)
1189 struct widget_data *sc_data;
1191 sc_data = evas_object_smart_data_get(scroller);
1193 ErrPrint("sc_data is not valid\n");
1197 if (is_loop == EINA_FALSE && sc_data->is_loop == EINA_TRUE)
1198 rearrange_items(sc_data);
1200 sc_data->is_loop = is_loop;
1204 int live_scroller_freeze(Evas_Object *scroller)
1206 struct widget_data *sc_data;
1208 sc_data = evas_object_smart_data_get(scroller);
1210 ErrPrint("sc_data is not valid\n");
1214 sc_data->is_freezed = EINA_TRUE;
1218 int live_scroller_thaw(Evas_Object *scroller)
1220 struct widget_data *sc_data;
1222 sc_data = evas_object_smart_data_get(scroller);
1224 ErrPrint("sc_data is not valid\n");
1228 sc_data->is_freezed = EINA_FALSE;
1232 int live_scroller_anim_to(Evas_Object *scroller, double sec, int offset)
1235 struct widget_data *sc_data;
1238 struct live_sc_event_info info;
1239 struct item_list_entry *ilist;
1243 sc_data = evas_object_smart_data_get(scroller);
1245 ErrPrint("sc_data is not valid\n");
1250 if (sc_data->is_freezed) {
1251 ErrPrint("Scroller is freezed\n");
1256 if (!sc_data->curlist)
1257 sc_data->curlist = sc_data->item_list;
1259 if (!sc_data->curlist) {
1260 ErrPrint("List is empty\n");
1265 if (sc_data->sc_anim_timer) {
1266 ecore_timer_del(sc_data->sc_anim_timer);
1267 sc_data->sc_anim_timer = NULL;
1268 evas_object_smart_callback_call(sc_data->scroller, "anim,stop", NULL);
1270 sc_data->tolist = sc_data->curlist;
1273 LIST_ITEM_GEO_GET(sc_data->curlist, &sx, &y, &sw, NULL);
1276 sc_data->sc_anim_dx = sc_data->clip_bx - sx;
1277 DbgPrint("offset==0, dx: %d\n", sc_data->sc_anim_dx);
1280 struct item_list_entry *tmplist;
1282 calc_anim_dx_with_dir(sc_data, &offset);
1283 DbgPrint("Offset: %d\n", offset);
1285 ilist = sc_data->curlist;
1286 while (offset < 0) {
1287 if (!sc_data->is_loop && ilist == sc_data->item_list) {
1288 DbgPrint("Loop is disabled\n");
1292 LIST_ITEM_GEO_GET(ilist, NULL, NULL, &tw, NULL);
1293 ilist = LIST_PREV(ilist);
1295 sc_data->sc_anim_dx += tw;
1296 DbgPrint("tw: %d (%d)\n", tw, sc_data->sc_anim_dx);
1299 if (sc_data->tolist == sc_data->item_list) {
1300 if (!sc_data->is_loop) {
1301 DbgPrint("Looping disabled\n");
1305 sc_data->tolist = LIST_PREV(sc_data->tolist);
1308 while (offset > 0) {
1309 LIST_ITEM_GEO_GET(ilist, NULL, NULL, &tw, NULL);
1310 ilist = LIST_NEXT(ilist);
1312 sc_data->sc_anim_dx -= tw;
1313 DbgPrint("tw: %d (%d)\n", tw, sc_data->sc_anim_dx);
1316 tmplist = LIST_NEXT(sc_data->tolist);
1317 if (tmplist == sc_data->item_list) {
1318 if (!sc_data->is_loop) {
1319 DbgPrint("Looping disabled\n");
1323 sc_data->tolist = tmplist;
1325 if (!sc_data->is_loop && ilist == sc_data->item_list) {
1326 DbgPrint("Destination arrived or loop is disabled");
1332 if (abs(sc_data->sc_anim_dx) > ANIM_MIN) {
1333 ftmp = (double)sc_data->sc_anim_dx / ANIM_UNIT;
1334 DbgPrint("ftmp: %lf\n", ftmp);
1335 if (fabs(ftmp) < ANIM_MIN || fabs(ftmp) > abs(sc_data->sc_anim_dx))
1336 sc_data->sc_anim_dx = ftmp < 0 ? -ANIM_MIN : ANIM_MIN;
1338 sc_data->sc_anim_dx = (int)ftmp;
1339 DbgPrint("Result: %d\n", sc_data->sc_anim_dx);
1342 sc_data->sc_anim_timer = ecore_timer_add(sec, sc_anim_cb, sc_data);
1343 if (!sc_data->sc_anim_timer) {
1344 ErrPrint("Failed to add a animator\n");
1349 info.curidx = list_item_idx(sc_data, sc_data->curlist);
1350 info.toidx = list_item_idx(sc_data, sc_data->tolist);
1351 DbgPrint("Current index: %d, To index: %d\n", info.curidx, info.toidx);
1353 evas_object_smart_callback_call(sc_data->scroller, "anim,start", &info);
1361 int live_scroller_go_to(Evas_Object *scroller, int idx)
1363 struct widget_data *sc_data;
1365 sc_data = evas_object_smart_data_get(scroller);
1367 ErrPrint("sc_data is not valid\n");
1371 if (sc_data->is_freezed)
1374 if (idx < 0 || idx >= sc_data->item_cnt)
1377 sc_data->curlist = list_item_nth_list(sc_data->item_list, idx);
1378 if (!sc_data->curlist)
1381 rearrange_items(sc_data);
1382 evas_object_smart_callback_call(sc_data->scroller, "page,changed", (void *)idx);
1387 int live_scroller_update(Evas_Object *scroller)
1389 struct widget_data *sc_data;
1390 struct item_list_entry *n;
1392 Evas_Coord x, y, w, h;
1394 sc_data = evas_object_smart_data_get(scroller);
1396 ErrPrint("sc_data is not valid\n");
1400 if (sc_data->item_list) {
1401 n = sc_data->item_list;
1403 item = LIST_DATA(n);
1404 LIST_ITEM_GEO_GET(n, &x, &y, &w, &h);
1405 move_item(sc_data, n, x, y, w, h);
1407 } while (n != sc_data->item_list);
1413 int live_scroller_get_item_count(Evas_Object *scroller)
1415 struct widget_data *sc_data;
1417 sc_data = evas_object_smart_data_get(scroller);
1419 ErrPrint("sc_data is not valid\n");
1423 return list_item_count(sc_data->item_list);
1426 int live_scroller_get_item_index(Evas_Object *scroller, Evas_Object *item)
1428 struct widget_data *sc_data;
1429 struct item_list_entry *n;
1433 sc_data = evas_object_smart_data_get(scroller);
1435 ErrPrint("sc_data is not valid\n");
1439 if (!sc_data->item_list)
1443 n = sc_data->item_list;
1452 } while (n != sc_data->item_list);