-PROJECT(live-viewer CXX)
+PROJECT(live-viewer C)
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
INCLUDE(FindPkgConfig)
ADD_DEFINITIONS("-DNDEBUG")
ADD_DEFINITIONS("-DPKGROOT=\"${PKGROOT}\"")
#ADD_DEFINITIONS("-DFLOG")
+ADD_DEFINITIONS("-DLOG_TAG=\"${PROJECT_NAME}\"")
ADD_DEFINITIONS(${pkgs_CFLAGS})
ADD_DEFINITIONS(${pkgs_LDFLAGS})
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
ADD_EXECUTABLE(${PROJECT_NAME}
- src/CLiveBox.cpp
- src/CLiveBoxMgr.cpp
- src/CMain.cpp
- src/CResourceMgr.cpp
- src/CUtil.cpp
- src/dlist.cpp
+ src/main.c
+ src/dlist.c
+ src/live_scroller.c
+ src/util.c
+ src/scroller.c
+ src/lb.c
)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS})
evas_object_image_colorspace_set(pCanvasImage, EVAS_COLORSPACE_ARGB8888);
evas_object_image_alpha_set(pCanvasImage, EINA_TRUE);
-
evas_object_move(pCanvasImage, 0, 0);
- evas_object_resize(pCanvasImage, w, h);
return pCanvasImage;
}
--- /dev/null
+#define dlist_remove_data(list, data) do { \
+ struct dlist *l; \
+ l = dlist_find_data(list, data); \
+ list = dlist_remove(list, l); \
+} while (0)
+
+#define dlist_foreach(list, l, data) \
+ for ((l) = (list); (l) && ((data) = dlist_data(l)); (l) = dlist_next(l))
+
+#define dlist_foreach_safe(list, l, n, data) \
+ for ((l) = (list), (n) = dlist_next(l); \
+ (l) && ((data) = dlist_data(l)); \
+ (l) = (n), (n) = dlist_next(l))
+
+struct dlist;
+
+extern struct dlist *dlist_append(struct dlist *list, void *data);
+extern struct dlist *dlist_prepend(struct dlist *list, void *data);
+extern struct dlist *dlist_remove(struct dlist *list, struct dlist *l);
+extern struct dlist *dlist_find_data(struct dlist *list, void *data);
+extern void *dlist_data(struct dlist *l);
+extern struct dlist *dlist_next(struct dlist *l);
+extern struct dlist *dlist_prev(struct dlist *l);
+extern int dlist_count(struct dlist *l);
+extern struct dlist *dlist_nth(struct dlist *l, int nth);
+
+/* End of a file */
--- /dev/null
+#if !defined(FLOG)
+#define DbgPrint(format, arg...) LOGD("[\e[32m%s/%s\e[0m:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg)
+#define ErrPrint(format, arg...) LOGE("[\e[32m%s/%s\e[0m:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg)
+#else
+extern FILE *__file_log_fp;
+#define DbgPrint(format, arg...) do { fprintf(__file_log_fp, "[LOG] [\e[32m%s/%s\e[0m:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0)
+
+#define ErrPrint(format, arg...) do { fprintf(__file_log_fp, "[ERR] [\e[32m%s/%s\e[0m:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0)
+#endif
+
+/* End of a file */
--- /dev/null
+extern int lb_init(void);
+extern int lb_fini(void);
+extern int lb_add(Evas_Object *sc, const char *pkgname);
+
+/* End of a file */
--- /dev/null
+struct live_sc_event_info {
+ int curidx;
+ int toidx;
+};
+
+struct live_sc_drag_info {
+ int dx;
+ int dy;
+};
+
+struct live_sc_move_info {
+ Evas_Object *item;
+ Evas_Coord x;
+ Evas_Coord y;
+ Evas_Coord w;
+ Evas_Coord h;
+
+ double relx;
+ double rely;
+};
+
+extern Evas_Object *live_scroller_add(Evas_Object *parent);
+extern int live_scroller_append(Evas_Object *scroller, Evas_Object *item);
+extern Evas_Object *live_scroller_remove(Evas_Object *scroller, int idx);
+extern Evas_Object *live_scroller_get_item(Evas_Object *scroller, int idx);
+extern int live_scroller_get_current(Evas_Object *scroller);
+extern int live_scroller_loop_set(Evas_Object *scroller, int is_loop);
+
+extern int live_scroller_freeze(Evas_Object *scroller);
+extern int live_scroller_thaw(Evas_Object *scroller);
+
+extern int live_scroller_anim_to(Evas_Object *scroller, double fps, int offset);
+extern int live_scroller_go_to(Evas_Object *scroller, int idx);
+
+extern int live_scroller_update(Evas_Object *scroller);
+
+extern int live_scroller_remove_by_obj(Evas_Object *scroller, Evas_Object *obj);
+extern int live_scroller_get_item_index(Evas_Object *scroller, Evas_Object *item);
+extern int live_scroller_get_item_count(Evas_Object *scroller);
+
+/* End of a file */
--- /dev/null
+extern Evas_Object *main_get_window(void);
--- /dev/null
+/*
+ * com.samsung.live-magazine
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Sung-jae Park <nicesj.park@samsung.com>, Youngjoo Park <yjoo93.park@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+extern Evas_Object *scroller_create(Evas_Object *parent);
+extern Evas_Object *scroller_peek_by_idx(Evas_Object *sc, int idx);
+extern int scroller_peek_by_obj(Evas_Object *sc, Evas_Object *obj);
+extern int scroller_append(Evas_Object *sc, Evas_Object *child);
+extern int scroller_get_current_idx(Evas_Object *sc);
+extern int scroller_peek_by_obj(Evas_Object *sc, Evas_Object *obj);
+extern Evas_Object *scroller_get_page(Evas_Object *sc, int idx);
+extern int scroller_is_scrolling(Evas_Object *sc);
+
+extern int scroller_add_stop_cb(Evas_Object *scroller, int (*cb)(Evas_Object *sc, void *data), void *data);
+extern void scroller_del_stop_cb(Evas_Object *scroller, int (*cb)(Evas_Object *sc, void *data), void *data);
+
+extern int scroller_get_page_index(Evas_Object *sc, Evas_Object *page);
+
+extern void scroller_unlock(Evas_Object *sc);
+extern void scroller_lock(Evas_Object *sc);
+
+extern int scroller_get_page_count(Evas_Object *sc);
+extern int scroller_scroll_to(Evas_Object *sc, int idx);
+extern int scroller_jump_to(Evas_Object *sc, int idx);
+
+extern int scroller_destroy(Evas_Object *sc);
+extern int scroller_update(Evas_Object *sc, void *data);
+extern int scroller_fast_scroll(Evas_Object *sc, int idx);
+extern void scroller_loop_set(Evas_Object *sc, Eina_Bool val);
+extern void scroller_quick_navi(Evas_Object *sc, Eina_Bool val);
+
+/* End of a file */
--- /dev/null
+/*
+ * com.samsung.live-magazine
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Sung-jae Park <nicesj.park@samsung.com>, Youngjoo Park <yjoo93.park@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+extern const char *util_basename(const char *name);
+
+/* End of a file */
<author email="nicesj.park@samsung.com" href="www.samsung.com">Sung-jae Park</author>
<description>Live box simple viewer (native)</description>
- <ui-application appid="live.viewer" exec="/opt/usr/apps/live.viewer/bin/live-viewer" nodisplay="true" multiple="false" type="capp" taskmanage="false">
- <icon>live.viewer.png</icon>
+ <ui-application appid="live.viewer" exec="/opt/usr/apps/live.viewer/bin/live-viewer" nodisplay="false" multiple="false" type="capp" taskmanage="true">
+ <icon>live-viewer.png</icon>
<label>Live box simple viewer (native)</label>
<label xml:lang="en-us">Live box simple viewer (native)</label>
</ui-application>
}
part {
- name: "viewer";
+ name: "delete,btn";
type: SWALLOW;
mouse_events: 1;
description {
state: "default" 0.0;
- rel1 { relative: 10/720 1.0; to, "indicator"; }
- rel2 { relative: 710/720 800/1280; }
+ rel1 { relative: 4/720 1.0; to_y, "viewer"; }
+ rel2 { relative: 716/720 850/1280; }
}
}
part {
- name: "controller";
+ name: "controller"; /* size list */
type: SWALLOW;
mouse_events: 1;
description {
state: "default" 0.0;
- rel1 { relative: 0.0 1.0; to_y, "viewer"; }
- rel2 { relative: 0.3 1230/1280; }
+ rel1 { relative: 0.0 1.0; to_y, "delete,btn"; }
+ rel2 { relative: 0.3 1.0; }
}
}
part {
- name: "pd"; /* button ctrl */
+ name: "logger";
type: SWALLOW;
mouse_events: 1;
description {
state: "default" 0.0;
- rel1 { relative: 0.0 1.0; to_y, "controller"; }
- rel2 { relative: 1.0 1.0; to_x, "controller"; }
+ rel1 { relative: 1.0 1.0; to_x: "controller"; to_y: "delete,btn"; }
+ rel2 { relative: 1.0 1.0; }
}
}
part {
- name: "logger";
- type: SWALLOW;
+ name: "viewer";
+ type: RECT;
mouse_events: 1;
description {
state: "default" 0.0;
- rel1 { relative: 1.0 1.0; to_x: "controller"; to_y: "viewer"; }
- rel2 { relative: 1.0 1.0; }
+ rel1 { relative: 4/720 1.0; to, "indicator"; }
+ rel2 { relative: 716/720 800/1280; }
+ color: 255 255 255 255;
}
}
- }
- }
- group {
- name: "icon,slot";
- parts {
part {
- name: "bg";
+ name: "event,blocker";
type: RECT;
mouse_events: 1;
description {
state: "default" 0.0;
rel1 { relative: 0.0 0.0; }
rel2 { relative: 1.0 1.0; }
- color: 0 0 0 255;
+ color: 0 0 0 0;
+ visible: 0;
+ }
+ description {
+ state: "show" 0.0;
+ inherit: "default" 0.0;
+ color: 50 50 50 50;
+ visible: 1;
}
}
mouse_events: 1;
description {
state: "default" 0.0;
- rel1 { relative: 0.0 0.0; }
- rel2 { relative: 1.0 1.0; }
- align: 0.5 1.0;
- }
-
- description {
- state: "size_172x172" 0.0;
- inherit: "default" 0.0;
- rel1 { relative: ((700-172)/2.0)/700 ((700-172)/2.0)/700; }
- rel2 { relative: ((700+172)/2.0)/700 ((700+172)/2.0)/700; }
- }
-
- description {
- state: "size_348x172" 0.0;
- inherit: "default" 0.0;
- rel1 { relative: ((700-348)/2.0)/700 ((700-172)/2.0)/700; }
- rel2 { relative: ((700+348)/2.0)/700 ((700+172)/2.0)/700; }
- }
-
- description {
- state: "size_348x348" 0.0;
- inherit: "default" 0.0;
- rel1 { relative: ((700-348)/2.0)/700 ((700-348)/2.0)/700; }
- rel2 { relative: ((700+348)/2.0)/700 ((700+348)/2.0)/700; }
- }
-
- description {
- state: "size_700x172" 0.0;
- inherit: "default" 0.0;
- rel1 { relative: 0.0 ((700-172)/2.0)/700; }
- rel2 { relative: 1.0 ((700+172)/2.0)/700; }
- }
-
- description {
- state: "size_700x348" 0.0;
- inherit: "default" 0.0;
- rel1 { relative: 0.0 ((700-348)/2.0)/700; }
- rel2 { relative: 1.0 ((700+348)/2.0)/700; }
- }
-
- description {
- state: "size_700x700" 0.0;
- inherit: "default" 0.0;
- rel1 { relative: 0.0 0.0; }
- rel2 { relative: 1.0 1.0; }
+ rel1 { relative: 0.4 0.4; to, "viewer"; }
+ rel2 { relative: 0.6 0.6; to, "viewer"; }
}
}
mouse_events: 1;
description {
state: "default" 0.0;
- rel1 { relative: 0.0 -1.0; }
- rel2 { relative: 1.0 0.0; }
- align: 0.5 1.0;
+ rel1 { relative: 0.0 0.95; to_y, "livebox"; }
+ rel2 { relative: 1.0 1.0; to_y, "livebox"; }
+ visible: 0;
+ align: 0.0 0.0;
}
description {
- state: "open" 0.0;
- rel1 { relative: 0.0 0.0; }
+ state: "show" 0.0;
+ rel1 { relative: 0.0 1.0; to_y, "livebox"; }
rel2 { relative: 1.0 1.0; }
- align: 0.5 0.0;
+ visible: 1;
+ align: 0.0 0.0;
}
}
-
}
programs {
program {
- name: "pd,open";
- signal: "open";
+ name: "open,pd";
source: "pd";
- action: STATE_SET "open" 0.0;
+ signal: "open";
+ action: STATE_SET "show" 0.0;
target: "pd";
- transition: LINEAR 0.3;
+ target: "event,blocker";
+ transition: LINEAR 0.2;
}
program {
- name: "pd,close";
- signal: "close";
+ name: "hide,pd";
source: "pd";
+ signal: "close";
action: STATE_SET "default" 0.0;
target: "pd";
- transition: LINEAR 0.3;
- after: "pd,closed";
- }
- program {
- name: "pd,closed";
- action: SIGNAL_EMIT "closed" "pd";
+ target: "event,blocker";
+ transition: LINEAR 0.1;
+ after: "hide,pd,done";
}
program {
- name: "lb,172x172";
- signal: "resize,to,172x172";
- source: "livebox";
- action: STATE_SET "size_172x172" 0.0;
- target: "livebox";
- transition: LINEAR 0.5;
- }
- program {
- name: "lb,348x172";
- signal: "resize,to,348x172";
- source: "livebox";
- action: STATE_SET "size_348x172" 0.0;
- target: "livebox";
- transition: LINEAR 0.5;
- }
- program {
- name: "lb,348x348";
- signal: "resize,to,348x348";
- source: "livebox";
- action: STATE_SET "size_348x348" 0.0;
- target: "livebox";
- transition: LINEAR 0.5;
- }
- program {
- name: "lb,700x172";
- signal: "resize,to,700x172";
- source: "livebox";
- action: STATE_SET "size_700x172" 0.0;
- target: "livebox";
- transition: LINEAR 0.5;
+ name: "hide,pd,done";
+ action: SIGNAL_EMIT "hide,done" "pd";
}
+
program {
- name: "lb,700x348";
- signal: "resize,to,700x348";
- source: "livebox";
- action: STATE_SET "size_700x348" 0.0;
- target: "livebox";
- transition: LINEAR 0.5;
+ name: "event,blocker";
+ source: "event,blocker";
+ signal: "mouse,clicked,1";
+ action: SIGNAL_EMIT "close" "pd";
}
+
program {
- name: "lb,700x700";
- signal: "resize,to,700x700";
- source: "livebox";
- action: STATE_SET "size_700x700" 0.0;
- target: "livebox";
- transition: LINEAR 0.5;
+ name: "pd,close,pd";
+ source: "viewer";
+ signal: "mouse,clicked,1";
+ action: SIGNAL_EMIT "close" "pd";
}
}
}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "dlist.h"
+
+/*!
+ * \brief
+ * This dlist is called Modified Doubly Linked List.
+ *
+ * Noramlly, The dobule linked list contains address of previous and next element.
+ * This dlist also contains them, but the tail element only contains prev address.
+ *
+ * The head element's prev pointer indicates the last element.
+ * But the last element's next pointer indicates NIL.
+ *
+ * So we can find the last element while crawling this DList
+ * But we have to remember the address of the head element.
+ */
+
+struct dlist {
+ struct dlist *next;
+ struct dlist *prev;
+ void *data;
+};
+
+struct dlist *dlist_append(struct dlist *list, void *data)
+{
+ struct dlist *item;
+
+ item = malloc(sizeof(*item));
+ if (!item)
+ return NULL;
+
+ item->next = NULL;
+ item->data = data;
+
+ if (!list) {
+ item->prev = item;
+
+ list = item;
+ } else {
+ item->prev = list->prev;
+ item->prev->next = item;
+ list->prev = item;
+ }
+
+ assert(!list->prev->next && "item NEXT");
+
+ return list;
+}
+
+struct dlist *dlist_prepend(struct dlist *list, void *data)
+{
+ struct dlist *item;
+
+ item = malloc(sizeof(*item));
+ if (!item)
+ return NULL;
+
+ item->data = data;
+
+ if (!list) {
+ item->prev = item;
+ item->next = NULL;
+ } else {
+ if (list->prev->next)
+ list->prev->next = item;
+
+ item->prev = list->prev;
+ item->next = list;
+
+ list->prev = item;
+
+ }
+
+ return item;
+}
+
+struct dlist *dlist_remove(struct dlist *list, struct dlist *l)
+{
+ if (!list || !l)
+ return NULL;
+
+ if (l == list)
+ list = l->next;
+ else
+ l->prev->next = l->next;
+
+ if (l->next)
+ l->next->prev = l->prev;
+ /*!
+ * \note
+ * If the removed entry 'l' has no next element, it is the last element.
+ * In this case, check the existence of the list first,
+ * and if the list is not empty, update the 'prev' of the list (which is a head element of the list)
+ *
+ * If we didn't care about this, the head element(list) can indicates the invalid element.
+ */
+ else if (list)
+ list->prev = l->prev;
+
+ free(l);
+ return list;
+}
+
+struct dlist *dlist_find_data(struct dlist *list, void *data)
+{
+ struct dlist *l;
+ void *_data;
+
+ dlist_foreach(list, l, _data) {
+ if (data == _data)
+ return l;
+ }
+
+ return NULL;
+}
+
+void *dlist_data(struct dlist *l)
+{
+ return l ? l->data : NULL;
+}
+
+struct dlist *dlist_next(struct dlist *l)
+{
+ return l ? l->next : NULL;
+}
+
+struct dlist *dlist_prev(struct dlist *l)
+{
+ return l ? l->prev : NULL;
+}
+
+int dlist_count(struct dlist *l)
+{
+ register int i;
+ struct dlist *n;
+ void *data;
+
+ i = 0;
+ dlist_foreach(l, n, data) {
+ i++;
+ }
+
+ return i;
+}
+
+struct dlist *dlist_nth(struct dlist *l, int nth)
+{
+ register int i;
+ struct dlist *n;
+
+ i = 0;
+ for (n = l; n; n = n->next) {
+ if (i == nth)
+ return n;
+ i++;
+ }
+
+ return NULL;
+}
+
+/* End of a file */
--- /dev/null
+#include <Elementary.h>
+#include <Ecore_X.h>
+
+#include <dlog.h>
+
+#include <livebox.h>
+#include <livebox-service.h>
+
+#include "main.h"
+#include "util.h"
+#include "debug.h"
+#include "lb.h"
+#include "scroller.h"
+
+#define FLICK_COND 100
+
+static Evas_Object *create_canvas(Evas_Object *parent)
+{
+ Evas_Object *canvas;
+
+ canvas = evas_object_image_filled_add(evas_object_evas_get(parent));
+ if (!canvas)
+ return NULL;
+
+ evas_object_image_colorspace_set(canvas, EVAS_COLORSPACE_ARGB8888);
+ evas_object_image_alpha_set(canvas, EINA_TRUE);
+ evas_object_move(canvas, 0, 0);
+ return canvas;
+}
+
+static int update_pd_canvas(struct livebox *handle, Evas_Object *image)
+{
+ int w;
+ int h;
+
+ switch (livebox_pd_type(handle)) {
+ case PD_TYPE_BUFFER:
+ case PD_TYPE_PIXMAP:
+ evas_object_image_colorspace_set(image, EVAS_COLORSPACE_ARGB8888);
+ evas_object_image_alpha_set(image, EINA_TRUE);
+
+ livebox_get_pdsize(handle, &w, &h);
+ if (w > 0 && h > 0) {
+ void *data;
+ data = livebox_acquire_pdfb(handle);
+ if (data) {
+ evas_object_image_size_set(image, w, h);
+ evas_object_image_data_copy_set(image, data);
+ livebox_release_pdfb(data);
+ }
+ evas_object_resize(image, w, h);
+ //evas_object_size_hint_min_set(image, w, h);
+ evas_object_size_hint_max_set(image, w, h);
+ }
+ break;
+ case PD_TYPE_TEXT:
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int update_canvas(struct livebox *handle, Evas_Object *image)
+{
+ const char *filename;
+ int w;
+ int h;
+ int type;
+
+ switch (livebox_lb_type(handle)) {
+ case LB_TYPE_BUFFER:
+ case LB_TYPE_PIXMAP:
+ evas_object_image_colorspace_set(image, EVAS_COLORSPACE_ARGB8888);
+ evas_object_image_alpha_set(image, EINA_TRUE);
+
+ w = h = 0;
+ type = livebox_size(handle);
+ livebox_service_get_size(type, &w, &h);
+ if (w > 0 && h > 0) {
+ void *data;
+ data = livebox_acquire_fb(handle);
+ if (data) {
+ evas_object_image_size_set(image, w, h);
+ evas_object_image_data_copy_set(image, data);
+ livebox_release_fb(data);
+ }
+ evas_object_resize(image, w, h);
+ evas_object_size_hint_min_set(image, w, h);
+ evas_object_size_hint_max_set(image, w, h);
+ }
+ break;
+ case LB_TYPE_IMAGE:
+ filename = livebox_filename(handle);
+ if (filename) {
+ const char *old;
+ evas_object_image_file_get(image, &old, NULL);
+ if (old && !strcmp(filename, old)) {
+ evas_object_image_reload(image);
+ } else {
+ evas_object_image_file_set(image, filename, NULL);
+ }
+
+ w = h = 0;
+ type = livebox_size(handle);
+ livebox_service_get_size(type, &w, &h);
+ if (w > 0 && h > 0) {
+ evas_object_resize(image, w, h);
+ evas_object_size_hint_min_set(image, w, h);
+ evas_object_size_hint_max_set(image, w, h);
+ }
+ }
+ break;
+ case LB_TYPE_TEXT:
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static inline void prepend_log(struct livebox *handle, const char *buffer)
+{
+ Evas_Object *layout;
+ Evas_Object *logger;
+
+ layout = livebox_get_data(handle);
+ if (!layout) {
+ ErrPrint("Failed to get layout\n");
+ return;
+ }
+
+ logger = elm_object_part_content_get(layout, "logger");
+ if (logger)
+ elm_list_item_prepend(logger, buffer, NULL, NULL, NULL, NULL);
+}
+
+static int lb_event_cb(struct livebox *handle, enum livebox_event_type event, void *data)
+{
+ Evas_Object *layout;
+ Evas_Object *sc;
+ Evas_Object *pd;
+ Evas_Object *image;
+
+ layout = (Evas_Object *)livebox_get_data(handle);
+ if (!layout)
+ return -EFAULT;
+
+ switch (event) {
+ case LB_EVENT_LB_UPDATED:
+ DbgPrint("Contents: [%s]\n", livebox_content(handle));
+ image = elm_object_part_content_get(layout, "livebox");
+ if (image)
+ update_canvas(handle, image);
+ break;
+ case LB_EVENT_PD_UPDATED:
+ image = elm_object_part_content_get(layout, "pd");
+ if (image)
+ update_pd_canvas(handle, image);
+ break;
+ case LB_EVENT_DELETED:
+ sc = evas_object_data_del(layout, "sc");
+ if (sc)
+ scroller_peek_by_obj(sc, layout);
+
+ evas_object_del(layout);
+ break;
+ case LB_EVENT_PD_DESTROYED:
+ pd = elm_object_part_content_unset(layout, "pd");
+ if (pd)
+ evas_object_del(pd);
+
+ sc = evas_object_data_del(layout, "sc");
+ if (sc)
+ scroller_unlock(sc);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int lb_fault_cb(enum livebox_fault_type event,
+ const char *pkgname, const char *filename,
+ const char *funcname, void *data)
+{
+ DbgPrint("pkgname: %s\nfilename: %s\n:funcname: %s\n", pkgname, filename, funcname);
+ return 0;
+}
+
+static void del_cb(struct livebox *handle, int ret, void *data)
+{
+ Evas_Object *layout;
+ Evas_Object *sc;
+
+ layout = livebox_get_data(handle);
+ if (!layout) {
+ ErrPrint("Failed to get layout\n");
+ return;
+ }
+
+ sc = evas_object_data_del(layout, "sc");
+ if (sc) {
+ DbgPrint("Scroller: %p\n", sc);
+ scroller_peek_by_obj(sc, layout);
+ }
+
+ DbgPrint("Delete a layout object\n");
+ evas_object_del(layout);
+}
+
+static void delete_btn_cb(void *handle, Evas_Object *obj, void *event_info)
+{
+ int ret;
+ ret = livebox_del(handle, del_cb, NULL);
+ if (ret < 0) {
+ char buffer[256];
+ snprintf(buffer, sizeof(buffer), "Delete returns: %d\n", ret);
+ prepend_log(handle, buffer);
+ }
+}
+
+static void exit_cb(void *data, Evas_Object *obj, void *event_info)
+{
+ evas_object_del(obj);
+}
+
+static void error_popup(Evas_Object *parent, struct livebox *handle, int ret)
+{
+ Evas_Object *popup;
+ Evas_Object *button;
+ char buffer[256];
+
+ popup = elm_popup_add(parent);
+ if (!popup)
+ return;
+
+ button = elm_button_add(parent);
+ if (!button) {
+ evas_object_del(popup);
+ return;
+ }
+
+ elm_popup_orient_set(popup, ELM_POPUP_ORIENT_CENTER);
+ elm_object_part_text_set(popup, "title,text", "Unable to load a livebox");
+
+ elm_object_text_set(button, "Okay");
+ elm_object_part_content_set(popup, "button2", button);
+ evas_object_smart_callback_add(button, "clicked", exit_cb, popup);
+
+ snprintf(buffer, sizeof(buffer) - 1,
+ "%s(%s): %d", livebox_pkgname(handle), livebox_content(handle), ret);
+ elm_object_part_text_set(popup, "default", buffer);
+ evas_object_show(popup);
+
+ return;
+}
+
+static void resize_cb(struct livebox *handle, int ret, void *data)
+{
+ Evas_Object *layout;
+ Evas_Object *log_list;
+ char buffer[256];
+
+ layout = livebox_get_data(handle);
+ if (!layout)
+ return;
+
+ log_list = elm_object_part_content_get(layout, "logger");
+ if (!log_list)
+ return;
+
+ snprintf(buffer, sizeof(buffer) - 1, "Resize: %d", ret);
+ elm_list_item_prepend(log_list, buffer, NULL, NULL, NULL, NULL);
+}
+
+static void resize_click_cb(void *handle, Evas_Object *obj, void *event_info)
+{
+ Elm_Object_Item *item;
+ const char *label;
+ int w;
+ int h;
+ int size_type;
+
+ item = elm_list_selected_item_get(obj);
+ if (!item)
+ return;
+
+ label = elm_object_item_part_text_get(item, NULL);
+ if (!label)
+ return;
+
+ sscanf(label, "%dx%d", &w, &h);
+ size_type = livebox_service_size_type(w, h);
+
+ livebox_resize(handle, size_type, resize_cb, NULL);
+}
+
+static void create_resize_controller(struct livebox *handle, Evas_Object *layout)
+{
+ Evas_Object *size_list;
+ char buffer[256];
+ int sizes[7];
+ int cnt;
+ int i;
+ int w;
+ int h;
+
+ size_list = elm_list_add(layout);
+ cnt = 7;
+ livebox_get_supported_sizes(handle, &cnt, sizes);
+ for (i = 0; i < cnt; i++) {
+ livebox_service_get_size(sizes[i], &w, &h);
+ snprintf(buffer, sizeof(buffer) - 1, "%dx%d", w, h);
+
+ elm_list_item_append(size_list, buffer, NULL, NULL, resize_click_cb, handle);
+ }
+ evas_object_show(size_list);
+ elm_list_go(size_list);
+ evas_object_size_hint_weight_set(size_list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(size_list, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_object_part_content_set(layout, "controller", size_list);
+}
+
+static void create_logger(struct livebox *handle, Evas_Object *layout)
+{
+ Evas_Object *log_list;
+
+ log_list = elm_list_add(layout);
+ if (!log_list)
+ return;
+
+ elm_list_item_prepend(log_list, "Created", NULL, NULL, NULL, NULL);
+ evas_object_show(log_list);
+ elm_list_go(log_list);
+
+ evas_object_size_hint_weight_set(log_list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(log_list, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_object_part_content_set(layout, "logger", log_list);
+}
+
+struct event_data {
+ Evas_Coord x;
+ Evas_Coord y;
+
+ enum flick {
+ FLICK_UNKNOWN = 0x00,
+ FLICK_DOWN = 0x01,
+ FLICK_UP = 0x02,
+ } flick;
+};
+
+static void pd_closed_cb(struct livebox *handle, int ret, void *data)
+{
+ evas_object_del(data);
+}
+
+static void pd_hide_done_cb(void *data, Evas_Object *obj, const char *emission, const char *source)
+{
+ Evas_Object *pd;
+ Evas_Object *sc;
+
+ sc = evas_object_data_get(obj, "sc");
+ scroller_unlock(sc);
+
+ elm_object_signal_callback_del(obj, emission, source, pd_hide_done_cb);
+ pd = elm_object_part_content_unset(obj, "pd");
+ livebox_destroy_pd(data, pd_closed_cb, pd);
+}
+
+static void pd_mouse_up_cb(void *handle, Evas *e, Evas_Object *obj, void *event_info)
+{
+ Evas_Event_Mouse_Up *up = event_info;
+ Evas_Coord x, y, w, h;
+ double rx, ry;
+
+ evas_object_geometry_get(obj, &x, &y, &w, &h);
+
+ rx = (double)(up->canvas.x - x) / (double)w;
+ ry = (double)(up->canvas.y - y) / (double)h;
+ livebox_content_event(handle, PD_MOUSE_UP, rx, ry);
+}
+
+static void pd_mouse_down_cb(void *handle, Evas *e, Evas_Object *obj, void *event_info)
+{
+ Evas_Event_Mouse_Down *down = event_info;
+ Evas_Coord x, y, w, h;
+ double rx, ry;
+
+ evas_object_geometry_get(obj, &x, &y, &w, &h);
+ rx = (double)(down->canvas.x - x) / (double)w;
+ ry = (double)(down->canvas.y - y) / (double)h;
+ livebox_content_event(handle, PD_MOUSE_DOWN, rx, ry);
+}
+
+static void pd_mouse_move_cb(void *handle, Evas *e, Evas_Object *obj, void *event_info)
+{
+ Evas_Event_Mouse_Move *move = event_info;
+ Evas_Coord x, y, w, h;
+ double rx, ry;
+
+ evas_object_geometry_get(obj, &x, &y, &w, &h);
+ rx = (double)(move->cur.canvas.x - x) / (double)w;
+ ry = (double)(move->cur.canvas.y - y) / (double)h;
+ livebox_content_event(handle, PD_MOUSE_MOVE, rx, ry);
+}
+
+static void pd_created_cb(struct livebox *handle, int ret, void *data)
+{
+ Evas_Object *layout;
+ Evas_Object *pd_image;
+ Evas_Object *sc;
+
+ layout = (Evas_Object *)livebox_get_data(handle);
+ if (!layout)
+ return;
+
+ sc = evas_object_data_get(layout, "sc");
+
+ pd_image = create_canvas(layout);
+ if (!pd_image)
+ return;
+
+ evas_object_event_callback_add(pd_image, EVAS_CALLBACK_MOUSE_UP, pd_mouse_up_cb, handle);
+ evas_object_event_callback_add(pd_image, EVAS_CALLBACK_MOUSE_DOWN, pd_mouse_down_cb, handle);
+ evas_object_event_callback_add(pd_image, EVAS_CALLBACK_MOUSE_MOVE, pd_mouse_move_cb, handle);
+
+ update_pd_canvas(handle, pd_image);
+
+ elm_object_signal_callback_add(layout, "hide,done", "pd", pd_hide_done_cb, handle);
+ elm_object_part_content_set(layout, "pd", pd_image);
+ elm_object_signal_emit(layout, "open", "pd");
+ scroller_lock(sc);
+}
+
+static void lb_mouse_up_cb(void *handle, Evas *e, Evas_Object *obj, void *event_info)
+{
+ Evas_Event_Mouse_Up *up = event_info;
+ struct event_data *evt;
+
+ evt = evas_object_data_del(obj, "evt");
+ if (!evt)
+ return;
+
+ if (livebox_lb_type(handle) == LB_TYPE_PIXMAP || livebox_lb_type(handle) == LB_TYPE_BUFFER) {
+ Evas_Coord x, y, w, h;
+ double rx, ry;
+
+ evas_object_geometry_get(obj, &x, &y, &w, &h);
+ rx = (double)(up->canvas.x - x) / (double)w;
+ ry = (double)(up->canvas.y - y) / (double)h;
+ livebox_content_event(handle, LB_MOUSE_UP, rx, ry);
+ } else {
+ Evas_Coord x, y, w, h;
+ evas_object_geometry_get(obj, &x, &y, &w, &h);
+
+ if (x < up->canvas.x && up->canvas.x < x + w) {
+ if (y < up->canvas.y && up->canvas.y < y + h) {
+ livebox_click(handle, (double)x / (double)w, (double)y / (double)h);
+ }
+ }
+ }
+
+ if (evt->flick == FLICK_DOWN && (up->canvas.y - evt->y) > (FLICK_COND>>1)) {
+ int ret;
+ /* Open PD */
+ ret = livebox_create_pd_with_position(handle, 0.5, 0.0, pd_created_cb, NULL);
+ }
+
+ free(evt);
+}
+
+static void lb_mouse_down_cb(void *handle, Evas *e, Evas_Object *obj, void *event_info)
+{
+ struct event_data *evt;
+ Evas_Event_Mouse_Down *down = event_info;
+ Evas_Object *layout;
+ Evas_Object *sc;
+
+ layout = livebox_get_data(handle);
+ if (!layout)
+ return;
+
+ sc = evas_object_data_get(layout, "sc");
+ if (!sc)
+ return;
+
+ if (scroller_is_scrolling(sc))
+ return;
+
+ if (livebox_lb_type(handle) == LB_TYPE_PIXMAP || livebox_lb_type(handle) == LB_TYPE_BUFFER) {
+ Evas_Coord x, y, w, h;
+ double rx, ry;
+
+ evas_object_geometry_get(obj, &x, &y, &w, &h);
+ rx = (double)(down->canvas.x - x) / (double)w;
+ ry = (double)(down->canvas.y - y) / (double)h;
+ livebox_content_event(handle, LB_MOUSE_DOWN, rx, ry);
+ }
+
+ evt = evas_object_data_get(obj, "evt");
+ if (evt) {
+ ErrPrint("Huh?");
+ } else {
+ evt = malloc(sizeof(*evt));
+ if (!evt) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return;
+ }
+ }
+
+ evas_object_data_set(obj, "evt", evt);
+
+ evt->x = down->canvas.x;
+ evt->y = down->canvas.y;
+ evt->flick = FLICK_UNKNOWN;
+}
+
+static void lb_mouse_move_cb(void *handle, Evas *e, Evas_Object *obj, void *event_info)
+{
+ Evas_Event_Mouse_Move *move = event_info;
+ struct event_data *evt;
+
+ evt = evas_object_data_get(obj, "evt");
+ if (!evt)
+ return;
+
+ if (livebox_lb_type(handle) == LB_TYPE_PIXMAP || livebox_lb_type(handle) == LB_TYPE_BUFFER) {
+ Evas_Coord x, y, w, h;
+ double rx, ry;
+
+ evas_object_geometry_get(obj, &x, &y, &w, &h);
+ rx = (double)(move->cur.canvas.x - x) / (double)w;
+ ry = (double)(move->cur.canvas.y - y) / (double)h;
+ livebox_content_event(handle, LB_MOUSE_MOVE, rx, ry);
+ }
+
+ if ((move->cur.canvas.x - move->prev.canvas.x) > FLICK_COND) {
+ evt->flick = FLICK_UNKNOWN;
+ return;
+ } else if ((move->cur.canvas.x - move->prev.canvas.x) < -FLICK_COND) {
+ evt->flick = FLICK_UNKNOWN;
+ return;
+ }
+
+ if ((move->cur.canvas.y - move->prev.canvas.y) > 0) {
+ if (evt->flick != FLICK_DOWN)
+ evt->flick = FLICK_DOWN;
+ } else if ((move->cur.canvas.y - move->prev.canvas.y) < 0) {
+ if (evt->flick != FLICK_UP)
+ evt->flick = FLICK_UP;
+ }
+}
+
+static void livebox_added_cb(struct livebox *handle, int ret, void *data)
+{
+ Evas_Object *layout;
+ Evas_Object *lb_image;
+ Evas_Object *btn;
+ int w;
+ int h;
+ int type;
+ int idx;
+
+ DbgPrint("%s - %d\n", livebox_pkgname(handle), ret);
+
+ if (ret != 0) {
+ error_popup(data, handle, ret);
+ return;
+ }
+
+ layout = elm_layout_add(main_get_window());
+ if (!layout) {
+ ErrPrint("Failed to add a layout\n");
+ return;
+ }
+
+ if (elm_layout_file_set(layout, PKGROOT "/res/edje/live-viewer.edj", "layout") == EINA_FALSE) {
+ DbgPrint("Failed to add a layout\n");
+ evas_object_del(layout);
+ return;
+ }
+
+ lb_image = create_canvas(layout);
+ if (!lb_image) {
+ ErrPrint("Failed to create a canvas\n");
+ evas_object_del(layout);
+ return;
+ }
+
+ evas_object_event_callback_add(lb_image, EVAS_CALLBACK_MOUSE_UP, lb_mouse_up_cb, handle);
+ evas_object_event_callback_add(lb_image, EVAS_CALLBACK_MOUSE_DOWN, lb_mouse_down_cb, handle);
+ evas_object_event_callback_add(lb_image, EVAS_CALLBACK_MOUSE_MOVE, lb_mouse_move_cb, handle);
+
+ w = 0;
+ h = 0;
+ type = livebox_size(handle);
+ if (type != LB_SIZE_TYPE_UNKNOWN) {
+ livebox_service_get_size(type, &w, &h);
+ DbgPrint("%dx%d\n", w, h);
+ }
+ evas_object_resize(lb_image, w, h);
+ evas_object_show(lb_image);
+
+ update_canvas(handle, lb_image);
+
+ btn = elm_button_add(main_get_window());
+ if (btn) {
+ elm_object_text_set(btn, "Delete");
+ evas_object_smart_callback_add(btn, "clicked", delete_btn_cb, handle);
+ elm_object_part_content_set(layout, "delete,btn", btn);
+ }
+
+ elm_object_part_content_set(layout, "livebox", lb_image);
+ evas_object_resize(layout, 720, 1280);
+ evas_object_show(layout);
+
+ create_resize_controller(handle, layout);
+ create_logger(handle, layout);
+
+ livebox_set_data(handle, layout);
+ evas_object_data_set(layout, "sc", data);
+
+ scroller_append(data, layout);
+
+ idx = scroller_get_page_index(data, layout);
+ DbgPrint("Scroll to %d\n", idx);
+ scroller_scroll_to(data, idx);
+}
+
+int lb_add(Evas_Object *sc, const char *pkgname)
+{
+ int w, h;
+ struct livebox *handle;
+
+ evas_object_geometry_get(sc, NULL, NULL, &w, &h);
+
+ DbgPrint("sc: %dx%d, package: %s\n", w, h, pkgname);
+ livebox_activate(pkgname, NULL, NULL);
+
+ handle = livebox_add(pkgname, "default", "user,created", "default",
+ DEFAULT_PERIOD, livebox_added_cb, sc);
+ if (!handle) {
+ ErrPrint("Failed to add a new livebox\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int lb_init(void)
+{
+ livebox_init(ecore_x_display_get());
+ livebox_set_event_handler(lb_event_cb, NULL);
+ livebox_set_fault_handler(lb_fault_cb, NULL);
+ return 0;
+}
+
+int lb_fini(void)
+{
+ livebox_fini();
+ return 0;
+}
+
+/* End of a file */
--- /dev/null
+#include <Elementary.h>
+
+#include <dlog.h>
+
+#include "live_scroller.h"
+#include "util.h"
+#include "debug.h"
+
+#define SAMPLE_MAX 10
+#define EVT_PERIOD 0.016 /* 60 fps */
+#define EVT_SAMPLE_PERIOD 9
+#define DRAG_SENS 100
+#define ANIM_MIN 40
+#define ANIM_UNIT 15
+
+struct item_list_entry {
+ struct item_list_entry *prev;
+ struct item_list_entry *next;
+
+ Evas_Object *data;
+ Evas_Coord x;
+ Evas_Coord y;
+ Evas_Coord w;
+ Evas_Coord h;
+};
+
+struct evt_info {
+ Evas_Coord x;
+ unsigned int timestamp;
+};
+
+struct evt_queue {
+ struct evt_info ei[SAMPLE_MAX];
+ int front;
+ int rear;
+ int cnt;
+ unsigned int old_timestamp;
+};
+
+struct widget_data {
+ Eina_Bool is_loop;
+ Eina_Bool is_freezed;
+
+ struct item_list_entry *item_list;
+
+ int item_cnt;
+ struct item_list_entry *curlist;
+ struct item_list_entry *tolist;
+
+ Eina_Bool drag_started;
+ Eina_Bool is_pressed;
+ Evas_Coord press_x;
+ Evas_Coord press_y;
+
+ Ecore_Timer *sc_anim_timer;
+ int sc_anim_dx;
+
+ Evas_Object *clip;
+ Evas_Object *evt_layer;
+ Evas_Object *scroller;
+
+ Evas_Coord clip_bx;
+ Evas_Coord clip_bw;
+
+ struct evt_queue evtq;
+ Ecore_Timer *evt_emulator;
+ Evas_Coord old_x;
+ unsigned int prev_timestamp;
+};
+
+#ifdef PROFILE
+#define PROFILE_START() \
+static int _exec_cnt = 0; \
+struct timeval _stv, _etv; \
+long _elapsed; \
+gettimeofday(&_stv, NULL);
+
+#define PROFILE_END() \
+do { \
+ _exec_cnt++; \
+ gettimeofday(&_etv, NULL); \
+ _elapsed = (_etv.tv_sec - _stv.tv_sec) * 1000000l + (_etv.tv_usec - _stv.tv_usec); \
+ DbgPrint("[%d] Elapsed time: %lu\n", _exec_cnt, _elapsed); \
+} while (0)
+#else
+#define PROFILE_START()
+#define PROFILE_END()
+#endif
+
+#define LIST_NEXT(list) ((list)->next)
+#define LIST_PREV(list) ((list)->prev)
+#define LIST_DATA(list) ((list) ? (list)->data : NULL)
+
+static inline void LIST_ITEM_GEO_SET(struct item_list_entry *list, int x, int y, int w, int h)
+{
+ list->x = x;
+ list->y = y;
+ list->w = w;
+ list->h = h;
+}
+
+static inline void LIST_ITEM_GEO_GET(struct item_list_entry *list, int *x, int *y, int *w, int *h)
+{
+ if (x)
+ *x = list->x;
+ if (y)
+ *y = list->y;
+ if (w)
+ *w = list->w;
+ if (h)
+ *h = list->h;
+}
+
+static inline struct item_list_entry *list_item_append(struct item_list_entry *list, void *obj)
+{
+ struct item_list_entry *item;
+
+ item = malloc(sizeof(*item));
+ if (!item)
+ return NULL;
+
+ item->data = obj;
+
+ if (list) {
+ list->prev->next = item;
+ item->prev = list->prev;
+
+ item->next = list;
+ list->prev = item;
+ } else{
+ item->prev = item;
+ item->next = item;
+ list = item;
+ }
+
+ return list;
+}
+
+static inline void *list_item_nth(struct item_list_entry *list, int idx)
+{
+ if (!list)
+ return NULL;
+
+ while (--idx >= 0)
+ list = list->next;
+
+ return list->data;
+}
+
+static inline struct item_list_entry *list_item_nth_list(struct item_list_entry *list, int idx)
+{
+ if (!list)
+ return NULL;
+
+ while (--idx >= 0)
+ list = list->next;
+
+ return list;
+}
+
+static inline struct item_list_entry *list_item_find(struct item_list_entry *list, void *data)
+{
+ struct item_list_entry *item;
+
+ if (!list)
+ return NULL;
+
+ item = list;
+ do {
+ if (LIST_DATA(item) == data)
+ return item;
+
+ item = LIST_NEXT(item);
+ } while (item != list);
+
+ return NULL;
+}
+
+static inline struct item_list_entry *list_item_remove(struct item_list_entry *list, void *data)
+{
+ struct item_list_entry *item;
+
+ if (!list)
+ return NULL;
+
+ item = list;
+ do {
+ if (LIST_DATA(item) == data) {
+ if (item == list) {
+ if (list == list->next)
+ list = NULL;
+ else
+ list = list->next;
+ }
+
+ item->prev->next = item->next;
+ item->next->prev = item->prev;
+ free(item);
+ break;
+ }
+ } while (item != list);
+
+ return list;
+}
+
+static inline void *list_item_last(struct item_list_entry *list)
+{
+ if (!list)
+ return NULL;
+
+ return list->prev->data;
+}
+
+static inline struct item_list_entry *list_item_last_list(struct item_list_entry *list)
+{
+ if (!list)
+ return NULL;
+
+ return list->prev;
+}
+
+static inline int list_item_count(struct item_list_entry *list)
+{
+ struct item_list_entry *n;
+ int cnt;
+
+ if (!list)
+ return 0;
+
+ cnt = 0;
+ n = list;
+ do {
+ cnt++;
+ n = LIST_NEXT(n);
+ } while (n != list);
+
+ return cnt;
+}
+
+static inline int list_item_idx(struct widget_data *sc_data, struct item_list_entry *ilist)
+{
+ int idx;
+ idx = 0;
+ while (ilist != sc_data->item_list) {
+ idx++;
+ ilist = LIST_PREV(ilist);
+ }
+
+ return idx;
+}
+
+static inline void init_evtq(struct evt_queue *evtq)
+{
+ evtq->front = 0;
+ evtq->rear = 0;
+ evtq->cnt = 0;
+ evtq->old_timestamp = 0;
+}
+
+static inline void dq_evt(struct evt_queue *evtq)
+{
+ if (evtq->cnt <= 0)
+ return;
+ evtq->front++;
+ if (evtq->front >= SAMPLE_MAX)
+ evtq->front -= SAMPLE_MAX;
+ evtq->cnt--;
+}
+
+static inline void enq_evt(struct evt_queue *evtq, Evas_Coord x, unsigned int timestamp)
+{
+ unsigned int t_diff;
+ int replace;
+
+ replace = 0;
+ t_diff = timestamp - evtq->old_timestamp;
+
+ if (evtq->cnt <= 0)
+ evtq->old_timestamp = timestamp;
+ else if (t_diff > EVT_SAMPLE_PERIOD)
+ evtq->old_timestamp += EVT_SAMPLE_PERIOD * (t_diff / EVT_SAMPLE_PERIOD);
+ else
+ replace = 1;
+
+ if (!replace) {
+ if (evtq->cnt >= SAMPLE_MAX)
+ dq_evt(evtq);
+ evtq->rear++;
+ if (evtq->rear >= SAMPLE_MAX)
+ evtq->rear -= SAMPLE_MAX;
+ evtq->cnt++;
+ }
+
+ evtq->ei[evtq->rear].x = x;
+ evtq->ei[evtq->rear].timestamp = evtq->old_timestamp;
+}
+
+static inline Evas_Coord get_evt_avg(struct evt_queue *evtq)
+{
+ int i;
+ int rear;
+ Evas_Coord x;
+ int weight;
+ int t;
+
+ t = (int)(ecore_time_get() * 1000);
+ rear = evtq->rear;
+
+ x = 0;
+ for (i = 0; i < evtq->cnt; i += weight) {
+ weight = (t - evtq->ei[rear].timestamp) / EVT_SAMPLE_PERIOD;
+ if (weight > (evtq->cnt - i))
+ weight = evtq->cnt - i;
+ else
+ weight = 1;
+
+ x += evtq->ei[rear].x * weight;
+ t = evtq->ei[rear].timestamp;
+ rear--;
+ if (rear < 0)
+ rear += SAMPLE_MAX;
+ }
+
+ x /= evtq->cnt;
+ return x;
+}
+
+/* Move the item to given direction to fit its coordinates to border */
+static inline int calc_anim_dx_with_dir(struct widget_data *sc_data, int *dir)
+{
+ Evas_Coord x, w;
+
+ LIST_ITEM_GEO_GET(sc_data->curlist, &x, NULL, &w, NULL);
+ sc_data->sc_anim_dx = 0;
+
+ if (*dir < 0) {
+ /* MOVE to LEFT */
+ if (x < sc_data->clip_bx) {
+ (*dir)++;
+
+ if (sc_data->tolist == sc_data->item_list) {
+ if (!sc_data->is_loop) {
+ *dir = 0;
+ return -EINVAL;
+ }
+ }
+
+ sc_data->tolist = LIST_PREV(sc_data->tolist);
+ sc_data->sc_anim_dx = sc_data->clip_bx - x /*- w*/;
+ } else {
+ sc_data->sc_anim_dx = sc_data->clip_bx - x;
+ }
+ } else if (*dir > 0) {
+ /* MOVE to RIGHT */
+ if (x < sc_data->clip_bx) {
+ sc_data->sc_anim_dx = sc_data->clip_bx - x;
+ } else if (x > sc_data->clip_bx) {
+ struct item_list_entry *newlist;
+
+ (*dir)--;
+ newlist = LIST_NEXT(sc_data->tolist);
+ if (newlist == sc_data->item_list) {
+ if (!sc_data->is_loop) {
+ *dir = 0;
+ return -EINVAL;
+ }
+ }
+ sc_data->tolist = newlist;
+ sc_data->sc_anim_dx = sc_data->clip_bx - x; /*(sc_data->clip_bx + sc_data->clip_bw) - x;*/
+ }
+ }
+
+ return 0;
+}
+
+static inline void move_item(struct widget_data *sc_data, struct item_list_entry *ilist, int x, int y, int w, int h)
+{
+ struct live_sc_move_info info;
+
+ info.item = LIST_DATA(ilist);
+
+ info.relx = ((double)x - (double)sc_data->clip_bx) / (double)sc_data->clip_bw;
+
+ LIST_ITEM_GEO_SET(ilist, x, y, w, h);
+ info.x = x;
+ info.y = y;
+ info.w = w;
+ info.h = h;
+
+ evas_object_smart_callback_call(sc_data->scroller, "item,moved", &info);
+}
+
+static struct item_list_entry *update_items_geo(struct widget_data *sc_data, int dx)
+{
+ Evas_Coord sx, sw;
+ Evas_Coord y, w, h;
+ struct item_list_entry *ilist;
+ struct item_list_entry *newlist;
+ struct item_list_entry *boundary;
+ int bx_bw;
+ register int x;
+
+ LIST_ITEM_GEO_GET(sc_data->curlist, &sx, &y, &sw, &h);
+
+ bx_bw = sc_data->clip_bx + sc_data->clip_bw;
+
+ sx += dx;
+ move_item(sc_data, sc_data->curlist, sx, y, sw, h);
+
+ newlist = NULL;
+
+ if (sc_data->item_cnt < 3) {
+ ilist = LIST_NEXT(sc_data->curlist);
+ LIST_ITEM_GEO_GET(ilist, NULL, &y, &w, &h);
+
+ if (sx + sw < bx_bw) {
+ x = sx + sw;
+ move_item(sc_data, ilist, x, y, w, h);
+ if (x == sc_data->clip_bx || (x < sc_data->clip_bx && (x + w) > sc_data->clip_bx))
+ newlist = ilist;
+ } else if (sx > 0) {
+ x = sx - w;
+ move_item(sc_data, ilist, x, y, w, h);
+ if (x == sc_data->clip_bx || (x > sc_data->clip_bx && x < bx_bw)) {
+ newlist = ilist;
+ }
+ }
+
+ goto out;
+ }
+
+ x = sx;
+ boundary = NULL;
+ ilist = sc_data->curlist;
+ do {
+ if (!sc_data->is_loop && ilist == sc_data->item_list)
+ break;
+
+ ilist = LIST_PREV(ilist);
+ if (!ilist)
+ break;
+
+ LIST_ITEM_GEO_GET(ilist, NULL, &y, &w, &h);
+ x -= w;
+ move_item(sc_data, ilist, x, y, w, h);
+
+ if (dx > 0 && !newlist) {
+ if ((x == sc_data->clip_bx) || (x > sc_data->clip_bx && x < bx_bw))
+ newlist = ilist;
+ }
+
+ boundary = ilist;
+ } while (x > sc_data->clip_bx);
+
+ x = sx;
+ w = sw;
+ ilist = sc_data->curlist;
+ do {
+ ilist = LIST_NEXT(ilist);
+ if (!ilist || (!sc_data->is_loop && ilist == sc_data->item_list) || ilist == boundary)
+ break;
+
+ x += w;
+ LIST_ITEM_GEO_GET(ilist, NULL, &y, &w, &h);
+ move_item(sc_data, ilist, x, y, w, h);
+
+ if (dx < 0 && !newlist) {
+ if ((x == sc_data->clip_bx) || (x < sc_data->clip_bx && (x + w) > sc_data->clip_bx))
+ newlist = ilist;
+ }
+ } while (x < bx_bw);
+
+out:
+ if (newlist)
+ sc_data->curlist = newlist;
+
+ return newlist;
+}
+
+static Eina_Bool emulate_evt(void *data)
+{
+ PROFILE_START();
+ struct widget_data *sc_data;
+ Evas_Coord x;
+ Evas_Coord dx;
+ struct item_list_entry *newlist;
+
+ sc_data = data;
+
+ x = get_evt_avg(&sc_data->evtq);
+ if (x == sc_data->old_x) {
+ PROFILE_END();
+ return ECORE_CALLBACK_RENEW;
+ }
+
+ dx = x - sc_data->old_x;
+ sc_data->old_x = x;
+
+ newlist = update_items_geo(sc_data, dx);
+ if (newlist) {
+ int idx;
+
+ idx = list_item_idx(sc_data, newlist);
+ evas_object_smart_callback_call(
+ sc_data->scroller, "page,changed", (void *)idx);
+ }
+ PROFILE_END();
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void evt_mouse_down_cb(void *data, Evas *e, Evas_Object *evt_layer, void *event_info)
+{
+ Evas_Event_Mouse_Down *down;
+ struct widget_data *sc_data;
+
+ sc_data = data;
+ down = event_info;
+
+ sc_data->is_pressed = EINA_TRUE;
+ sc_data->press_x = down->canvas.x;
+ sc_data->press_y = down->canvas.y;
+ sc_data->old_x = down->canvas.x;
+
+ if (!sc_data->is_freezed) {
+ init_evtq(&sc_data->evtq);
+ enq_evt(&sc_data->evtq, down->canvas.x, down->timestamp);
+ }
+}
+
+static void evt_mouse_up_cb(void *data, Evas *e, Evas_Object *evt_layer, void *event_info)
+{
+ Evas_Event_Mouse_Up *up;
+ struct widget_data *sc_data;
+ struct live_sc_drag_info info;
+
+ sc_data = data;
+
+ if (!sc_data->is_pressed)
+ return;
+
+ sc_data->is_pressed = EINA_FALSE;
+
+ if (sc_data->evt_emulator) {
+ ecore_timer_del(sc_data->evt_emulator);
+ sc_data->evt_emulator = NULL;
+ }
+
+ if (sc_data->drag_started == EINA_FALSE) {
+ DbgPrint("drag is not started\n");
+ return;
+ }
+
+ up = event_info;
+
+ info.dx = up->canvas.x - sc_data->press_x;
+ info.dy = up->canvas.y - sc_data->press_y;
+
+ sc_data->drag_started = EINA_FALSE;
+
+ evas_object_smart_callback_call(sc_data->scroller, "drag,stop", &info);
+}
+
+static void evt_mouse_move_cb(void *data, Evas *e, Evas_Object *evt_layer, void *event_info)
+{
+ struct widget_data *sc_data;
+ Evas_Event_Mouse_Move *move;
+
+ sc_data = data;
+
+ if (sc_data->is_pressed == EINA_FALSE)
+ return;
+
+ if (sc_data->item_cnt <= 1)
+ return;
+
+ if (sc_data->is_freezed)
+ return;
+
+ move = event_info;
+
+ if (sc_data->drag_started == EINA_FALSE) {
+ if (abs(move->cur.canvas.x - sc_data->press_x) < DRAG_SENS)
+ return;
+
+ if (sc_data->sc_anim_timer) {
+ ecore_timer_del(sc_data->sc_anim_timer);
+ sc_data->sc_anim_timer = NULL;
+ }
+
+ evas_object_smart_callback_call(sc_data->scroller, "drag,start", NULL);
+ sc_data->drag_started = EINA_TRUE;
+ }
+
+ sc_data->prev_timestamp = move->timestamp;
+ enq_evt(&sc_data->evtq, move->cur.canvas.x, move->timestamp);
+ if (!sc_data->evt_emulator) {
+ if (!sc_data->curlist)
+ sc_data->curlist = sc_data->item_list;
+
+ sc_data->evt_emulator = ecore_timer_add(EVT_PERIOD, emulate_evt, sc_data);
+ }
+}
+
+static inline int prepare_evt_layer(struct widget_data *sc_data)
+{
+ Evas *e;
+
+ e = evas_object_evas_get(sc_data->scroller);
+ if (!e)
+ return -EFAULT;
+
+ sc_data->evt_layer = evas_object_rectangle_add(e);
+ if (!sc_data->evt_layer)
+ return -EFAULT;
+
+ evas_object_smart_member_add(sc_data->evt_layer, sc_data->scroller);
+
+ evas_object_color_set(sc_data->evt_layer, 255, 255, 255, 0);
+ evas_object_show(sc_data->evt_layer);
+ evas_object_repeat_events_set(sc_data->evt_layer, EINA_TRUE);
+
+ evas_object_event_callback_add(sc_data->evt_layer,
+ EVAS_CALLBACK_MOUSE_DOWN, evt_mouse_down_cb, sc_data);
+
+ evas_object_event_callback_add(sc_data->evt_layer,
+ EVAS_CALLBACK_MOUSE_UP, evt_mouse_up_cb, sc_data);
+
+ evas_object_event_callback_add(sc_data->evt_layer,
+ EVAS_CALLBACK_MOUSE_MOVE, evt_mouse_move_cb, sc_data);
+
+ evas_object_clip_set(sc_data->evt_layer, sc_data->clip);
+ return 0;
+}
+
+static void live_add(Evas_Object *scroller)
+{
+ struct widget_data *sc_data;
+ Evas *e;
+ int ret;
+
+ sc_data = calloc(1, sizeof(*sc_data));
+ if (!sc_data)
+ return;
+
+ e = evas_object_evas_get(scroller);
+ if (!e) {
+ free(sc_data);
+ return;
+ }
+
+ evas_object_smart_data_set(scroller, sc_data);
+
+ sc_data->clip = evas_object_rectangle_add(e);
+ if (!sc_data->clip) {
+ free(sc_data);
+ return;
+ }
+
+ sc_data->is_pressed = EINA_FALSE;
+ sc_data->drag_started = EINA_FALSE;
+ sc_data->tolist = NULL;
+ sc_data->curlist = NULL;
+ sc_data->item_list = NULL;
+ sc_data->scroller = scroller;
+
+ evas_object_smart_member_add(sc_data->clip, sc_data->scroller);
+
+ ret = prepare_evt_layer(sc_data);
+ if (ret < 0) {
+ evas_object_del(sc_data->clip);
+ free(sc_data);
+ }
+
+ return;
+}
+
+static void live_del(Evas_Object *scroller)
+{
+ struct widget_data *sc_data;
+ Evas_Object *item;
+ struct item_list_entry *ilist;
+ struct item_list_entry *next;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return;
+
+ ilist = sc_data->item_list;
+ if (ilist) {
+ do {
+ next = LIST_NEXT(ilist);
+ item = LIST_DATA(ilist);
+ evas_object_clip_unset(item);
+ evas_object_smart_member_del(item);
+ free(ilist);
+ ilist = next;
+ } while (ilist != sc_data->item_list);
+ }
+
+ evas_object_del(sc_data->evt_layer);
+ evas_object_del(sc_data->clip);
+ free(sc_data);
+}
+
+static void live_move(Evas_Object *scroller, Evas_Coord bx, Evas_Coord by)
+{
+ struct widget_data *sc_data;
+ Evas_Coord x, y, w, h;
+ Evas_Coord bw;
+
+ Evas_Coord dx;
+ Evas_Coord dy;
+
+ struct item_list_entry *n;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return;
+
+ evas_object_geometry_get(sc_data->clip, &x, &y, &bw, NULL);
+
+ evas_object_move(sc_data->evt_layer, bx, by);
+ evas_object_move(sc_data->clip, bx, by);
+ sc_data->clip_bx = bx;
+ sc_data->clip_bw = bw;
+
+ dx = bx - x;
+ dy = by - y;
+
+ if (sc_data->item_list) {
+ n = sc_data->item_list;
+ do {
+ evas_object_move(LIST_DATA(n), bx, by);
+
+ LIST_ITEM_GEO_GET(n, &x, &y, &w, &h);
+ x += dx;
+ y += dy;
+ move_item(sc_data, n, x, y, w, h);
+ n = LIST_NEXT(n);
+ } while (n != sc_data->item_list);
+ }
+}
+
+static void live_resize(Evas_Object *scroller, Evas_Coord w, Evas_Coord h)
+{
+ struct widget_data *sc_data;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return;
+
+ evas_object_resize(sc_data->clip, w, h);
+ evas_object_resize(sc_data->evt_layer, w, h);
+
+ sc_data->clip_bw = w;
+}
+
+static void live_show(Evas_Object *scroller)
+{
+ struct widget_data *sc_data;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return;
+
+ evas_object_show(sc_data->clip);
+}
+
+static void live_hide(Evas_Object *scroller)
+{
+ struct widget_data *sc_data;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return;
+
+ evas_object_hide(sc_data->clip);
+}
+
+static void live_set_color(Evas_Object *scroller, int r, int g, int b, int a)
+{
+ struct widget_data *sc_data;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return;
+
+ evas_object_color_set(sc_data->clip, r, g, b, a);
+}
+
+static void live_set_clip(Evas_Object *scroller, Evas_Object *clip)
+{
+ struct widget_data *sc_data;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return;
+
+ evas_object_clip_set(sc_data->clip, clip);
+}
+
+static void live_unset_clip(Evas_Object *scroller)
+{
+ struct widget_data *sc_data;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return;
+
+ evas_object_clip_unset(sc_data->clip);
+}
+
+static inline void rearrange_items(struct widget_data *sc_data)
+{
+ struct item_list_entry *ilist;
+ Evas_Coord x, y, w, h;
+ Evas_Coord sw;
+
+ LIST_ITEM_GEO_GET(sc_data->curlist, NULL, &y, &sw, &h);
+ move_item(sc_data, sc_data->curlist, sc_data->clip_bx, y, sw, h);
+
+ x = sc_data->clip_bx;
+ ilist = sc_data->curlist;
+ while (ilist != sc_data->item_list) {
+ ilist = LIST_PREV(ilist);
+ LIST_ITEM_GEO_GET(ilist, NULL, &y, &w, &h);
+ x -= w;
+ move_item(sc_data, ilist, x, y, w, h);
+ }
+
+ w = sw;
+ x = sc_data->clip_bx;
+ ilist = LIST_NEXT(sc_data->curlist);
+ while (ilist != sc_data->item_list) {
+ x += w;
+ LIST_ITEM_GEO_GET(ilist, NULL, &y, &w, &h);
+ move_item(sc_data, ilist, x, y, w, h);
+ ilist = LIST_NEXT(ilist);
+ }
+}
+
+static Eina_Bool sc_anim_cb(void *data)
+{
+ PROFILE_START();
+ struct widget_data *sc_data;
+ Evas_Coord sx, sw;
+ Evas_Coord y;
+ Evas_Coord dx;
+ struct item_list_entry *ilist;
+
+ sc_data = data;
+
+ if (!sc_data->curlist || !sc_data->tolist) {
+ DbgPrint("cur_list: %p, tolist: %p\n", sc_data->curlist, sc_data->tolist);
+ goto clean_out;
+ }
+
+ ilist = sc_data->curlist;
+ if (sc_data->curlist != sc_data->tolist) {
+ if (sc_data->sc_anim_dx > 0)
+ ilist = LIST_PREV(ilist);
+ else
+ ilist = LIST_NEXT(ilist);
+ }
+
+ LIST_ITEM_GEO_GET(ilist, &sx, &y, &sw, NULL);
+ if (ilist == sc_data->tolist) {
+ dx = abs(sx - sc_data->clip_bx);
+ if (dx < abs(sc_data->sc_anim_dx)) {
+ if (sc_data->sc_anim_dx < 0)
+ dx = -dx;
+ } else {
+ dx = sc_data->sc_anim_dx;
+ }
+ } else {
+ dx = sc_data->sc_anim_dx;
+ }
+
+ if (!dx) {
+ DbgPrint("dx is 0\n");
+ goto clean_out;
+ }
+
+ ilist = update_items_geo(sc_data, dx);
+ if (ilist) {
+ int idx;
+
+ idx = list_item_idx(sc_data, ilist);
+ evas_object_smart_callback_call(sc_data->scroller,
+ "page,changed", (void *)idx);
+ }
+ PROFILE_END();
+ return ECORE_CALLBACK_RENEW;
+
+clean_out:
+ PROFILE_END();
+ evas_object_smart_callback_call(sc_data->scroller, "anim,stop", NULL);
+ sc_data->sc_anim_timer = NULL;
+ return ECORE_CALLBACK_CANCEL;
+}
+
+Evas_Object *live_scroller_add(Evas_Object *parent)
+{
+ static Evas_Smart_Class sc = EVAS_SMART_CLASS_INIT_NAME_VERSION("live,scroller");
+ static Evas_Smart *smart = NULL;
+ Evas_Object *scroller;
+ Evas *e;
+
+ if (!parent)
+ return NULL;
+
+ e = evas_object_evas_get(parent);
+ if (!e)
+ return NULL;
+
+ if (!smart) {
+ sc.add = live_add;
+ sc.del = live_del;
+ sc.move = live_move;
+ sc.resize = live_resize;
+ sc.show = live_show;
+ sc.hide = live_hide;
+ sc.color_set = live_set_color;
+ sc.clip_set = live_set_clip;
+ sc.clip_unset = live_unset_clip;
+
+ smart = evas_smart_class_new(&sc);
+ }
+
+ scroller = evas_object_smart_add(e, smart);
+
+ return scroller;
+}
+
+int live_scroller_append(Evas_Object *scroller, Evas_Object *item)
+{
+ Evas_Coord x, y, w, h;
+ Evas_Coord bx, by, bw, bh;
+ struct widget_data *sc_data;
+ struct item_list_entry *tmplist;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return -EINVAL;
+
+ evas_object_geometry_get(sc_data->clip, &bx, &by, &bw, &bh);
+
+ tmplist = list_item_last_list(sc_data->item_list);
+ if (tmplist) {
+ LIST_ITEM_GEO_GET(tmplist, &x, NULL, &w, NULL);
+ x += w;
+ } else {
+ x = bx;
+ }
+
+ evas_object_geometry_get(item, NULL, NULL, &w, &h);
+ evas_object_smart_member_add(item, sc_data->scroller);
+
+ y = by + ((bh - h) >> 1);
+
+ tmplist = list_item_append(sc_data->item_list, item);
+ if (sc_data->item_list == sc_data->curlist)
+ sc_data->curlist = tmplist;
+ if (sc_data->item_list == sc_data->tolist)
+ sc_data->tolist = tmplist;
+ sc_data->item_list = tmplist;
+
+ sc_data->item_cnt++;
+ evas_object_clip_set(item, sc_data->clip);
+ evas_object_stack_below(item, sc_data->clip);
+
+ evas_object_move(item, bx, by);
+ move_item(sc_data, list_item_find(sc_data->item_list, item), x, y, w, h);
+
+ return 0;
+}
+
+int live_scroller_remove_by_obj(Evas_Object *scroller, Evas_Object *obj)
+{
+ struct widget_data *sc_data;
+ struct item_list_entry *tmplist;
+ Evas_Object *item;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return -EINVAL;
+
+ tmplist = list_item_remove(sc_data->item_list, obj);
+ if (sc_data->item_list == sc_data->curlist)
+ sc_data->curlist = tmplist;
+ if (sc_data->item_list == sc_data->tolist)
+ sc_data->tolist = tmplist;
+ sc_data->item_list = tmplist;
+
+ sc_data->item_cnt--;
+ evas_object_clip_unset(obj);
+ evas_object_smart_member_del(obj);
+
+ item = LIST_DATA(sc_data->curlist);
+ if (item) {
+ Evas_Coord y, w, h;
+ int idx;
+
+ LIST_ITEM_GEO_GET(sc_data->curlist, NULL, &y, &w, &h);
+ LIST_ITEM_GEO_SET(sc_data->curlist, sc_data->clip_bx, y, w, h);
+ update_items_geo(sc_data, 0);
+
+ idx = list_item_idx(sc_data, sc_data->curlist);
+ evas_object_smart_callback_call(sc_data->scroller,
+ "page,changed", (void *)idx);
+ }
+
+ return 0;
+}
+
+Evas_Object *live_scroller_remove(Evas_Object *scroller, int idx)
+{
+ struct widget_data *sc_data;
+ struct item_list_entry *tmplist;
+ Evas_Object *ret;
+ Evas_Object *item;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return NULL;
+
+ if (idx < 0 || idx >= sc_data->item_cnt)
+ return NULL;
+
+ ret = list_item_nth(sc_data->item_list, idx);
+ if (!ret)
+ return NULL;
+
+ tmplist = list_item_remove(sc_data->item_list, ret);
+ if (sc_data->item_list == sc_data->curlist)
+ sc_data->curlist = tmplist;
+ if (sc_data->item_list == sc_data->tolist)
+ sc_data->tolist = tmplist;
+ sc_data->item_list = tmplist;
+
+ sc_data->item_cnt--;
+ evas_object_clip_unset(ret);
+ evas_object_smart_member_del(ret);
+
+ item = LIST_DATA(sc_data->curlist);
+ if (item) {
+ Evas_Coord y, w, h;
+ int idx;
+ LIST_ITEM_GEO_GET(sc_data->curlist, NULL, &y, &w, &h);
+ LIST_ITEM_GEO_SET(sc_data->curlist, sc_data->clip_bx, y, w, h);
+ update_items_geo(sc_data, 0);
+ idx = list_item_idx(sc_data, sc_data->curlist);
+ evas_object_smart_callback_call(
+ sc_data->scroller, "page,changed", (void *)idx);
+ }
+ return ret;
+}
+
+Evas_Object *live_scroller_get_item(Evas_Object *scroller, int idx)
+{
+ struct widget_data *sc_data;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return NULL;
+
+ if (idx < 0 || idx >= sc_data->item_cnt)
+ return NULL;
+
+ return list_item_nth(sc_data->item_list, idx);
+}
+
+int live_scroller_get_current(Evas_Object *scroller)
+{
+ struct widget_data *sc_data;
+ struct item_list_entry *ilist;
+ int idx;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return -EINVAL;
+
+ ilist = sc_data->curlist;
+ idx = 0;
+ if (ilist) {
+ while (ilist != sc_data->item_list) {
+ idx++;
+ ilist = LIST_PREV(ilist);
+ }
+ }
+
+ return idx;
+}
+
+int live_scroller_loop_set(Evas_Object *scroller, int is_loop)
+{
+ struct widget_data *sc_data;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return -EINVAL;
+
+ if (is_loop == EINA_FALSE && sc_data->is_loop == EINA_TRUE)
+ rearrange_items(sc_data);
+
+ sc_data->is_loop = is_loop;
+ return 0;
+}
+
+int live_scroller_freeze(Evas_Object *scroller)
+{
+ struct widget_data *sc_data;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return -EINVAL;
+
+ sc_data->is_freezed = EINA_TRUE;
+ return 0;
+}
+
+int live_scroller_thaw(Evas_Object *scroller)
+{
+ struct widget_data *sc_data;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return -EINVAL;
+
+ sc_data->is_freezed = EINA_FALSE;
+ return 0;
+}
+
+int live_scroller_anim_to(Evas_Object *scroller, double sec, int offset)
+{
+ PROFILE_START();
+ struct widget_data *sc_data;
+ Evas_Coord sx, sw;
+ Evas_Coord y;
+ struct live_sc_event_info info;
+ struct item_list_entry *ilist;
+ double ftmp;
+ int ret;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (sc_data->is_freezed) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (!sc_data->curlist)
+ sc_data->curlist = sc_data->item_list;
+
+ if (!sc_data->curlist) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ if (sc_data->sc_anim_timer) {
+ ecore_timer_del(sc_data->sc_anim_timer);
+ sc_data->sc_anim_timer = NULL;
+ evas_object_smart_callback_call(sc_data->scroller, "anim,stop", NULL);
+ } else {
+ sc_data->tolist = sc_data->curlist;
+ }
+
+ LIST_ITEM_GEO_GET(sc_data->curlist, &sx, &y, &sw, NULL);
+
+ if (!offset) {
+ sc_data->sc_anim_dx = sc_data->clip_bx - sx;
+ } else {
+ Evas_Coord tw;
+ struct item_list_entry *tmplist;
+
+ calc_anim_dx_with_dir(sc_data, &offset);
+
+ ilist = sc_data->curlist;
+ while (offset < 0) {
+ if (!sc_data->is_loop && ilist == sc_data->item_list)
+ break;
+
+ LIST_ITEM_GEO_GET(ilist, NULL, NULL, &tw, NULL);
+ ilist = LIST_PREV(ilist);
+
+ sc_data->sc_anim_dx += tw;
+
+ offset++;
+ if (sc_data->tolist == sc_data->item_list) {
+ if (!sc_data->is_loop)
+ break;
+ }
+ sc_data->tolist = LIST_PREV(sc_data->tolist);
+ }
+
+ while (offset > 0) {
+ LIST_ITEM_GEO_GET(ilist, NULL, NULL, &tw, NULL);
+ ilist = LIST_NEXT(ilist);
+
+ sc_data->sc_anim_dx -= tw;
+
+ offset--;
+ tmplist = LIST_NEXT(sc_data->tolist);
+ if (tmplist == sc_data->item_list) {
+ if (!sc_data->is_loop)
+ break;
+ }
+ sc_data->tolist = tmplist;
+
+ if (!sc_data->is_loop && ilist == sc_data->item_list)
+ break;
+ }
+ }
+
+ if (abs(sc_data->sc_anim_dx) > ANIM_MIN) {
+ ftmp = (double)sc_data->sc_anim_dx / ANIM_UNIT;
+ if (fabs(ftmp) < ANIM_MIN || fabs(ftmp) > abs(sc_data->sc_anim_dx))
+ sc_data->sc_anim_dx = ftmp < 0 ? -ANIM_MIN : ANIM_MIN;
+ else
+ sc_data->sc_anim_dx = ftmp;
+ }
+
+ sc_data->sc_anim_timer = ecore_timer_add(sec, sc_anim_cb, sc_data);
+ if (!sc_data->sc_anim_timer) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ info.curidx = list_item_idx(sc_data, sc_data->curlist);
+ info.toidx = list_item_idx(sc_data, sc_data->tolist);
+
+ evas_object_smart_callback_call(sc_data->scroller, "anim,start", &info);
+ ret = 0;
+
+out:
+ PROFILE_END();
+ return ret;
+}
+
+int live_scroller_go_to(Evas_Object *scroller, int idx)
+{
+ struct widget_data *sc_data;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return -EINVAL;
+
+ if (sc_data->is_freezed)
+ return -EBUSY;
+
+ if (idx < 0 || idx >= sc_data->item_cnt)
+ return -EINVAL;
+
+ sc_data->curlist = list_item_nth_list(sc_data->item_list, idx);
+ if (!sc_data->curlist)
+ return -EFAULT;
+
+ rearrange_items(sc_data);
+ evas_object_smart_callback_call(sc_data->scroller,
+ "page,changed", (void *)idx);
+
+ return 0;
+}
+
+int live_scroller_update(Evas_Object *scroller)
+{
+ struct widget_data *sc_data;
+ struct item_list_entry *n;
+ Evas_Object *item;
+ Evas_Coord x, y, w, h;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return -EINVAL;
+
+ if (sc_data->item_list) {
+ n = sc_data->item_list;
+ do {
+ item = LIST_DATA(n);
+ LIST_ITEM_GEO_GET(n, &x, &y, &w, &h);
+ move_item(sc_data, n, x, y, w, h);
+ n = LIST_NEXT(n);
+ } while (n != sc_data->item_list);
+ }
+
+ return 0;
+}
+
+int live_scroller_get_item_count(Evas_Object *scroller)
+{
+ struct widget_data *sc_data;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return 0;
+
+ return list_item_count(sc_data->item_list);
+}
+
+int live_scroller_get_item_index(Evas_Object *scroller, Evas_Object *item)
+{
+ struct widget_data *sc_data;
+ struct item_list_entry *n;
+ Evas_Object *tmp;
+ int idx;
+
+ sc_data = evas_object_smart_data_get(scroller);
+ if (!sc_data)
+ return -EINVAL;
+
+ if (!sc_data->item_list)
+ return -ENOENT;
+
+ idx = 0;
+ n = sc_data->item_list;
+ do {
+ tmp = LIST_DATA(n);
+ n = LIST_NEXT(n);
+
+ if (tmp == item)
+ return idx;
+
+ idx++;
+ } while (n != sc_data->item_list);
+
+ return -ENOENT;
+}
+
+/* End of a file */
--- /dev/null
+#include <Elementary.h>
+
+#include <dlog.h>
+#include <ail.h>
+#include <app.h>
+#include <bundle.h>
+
+#include <livebox.h>
+#include <livebox-service.h>
+
+#include "main.h"
+#include "util.h"
+#include "debug.h"
+#include "scroller.h"
+#include "lb.h"
+
+static struct info {
+ Evas_Object *window;
+ Evas_Object *scroller;
+} s_info = {
+ .window = NULL,
+ .scroller = NULL,
+};
+
+Evas_Object *main_get_window(void)
+{
+ return s_info.window;
+}
+
+static void click_cb(void *data, Evas_Object *obj, void *event_info)
+{
+ Elm_Object_Item *item;
+ const char *label;
+
+ item = elm_list_selected_item_get(obj);
+ if (!item)
+ return;
+
+ label = elm_object_item_part_text_get(item, NULL);
+ if (!label)
+ return;
+
+ DbgPrint("Label: %s (%s)\n", label, data);
+ if (lb_add(s_info.scroller, data) < 0)
+ ErrPrint("Failed to add a new livebox\n");
+}
+
+static int append_livebox_cb(const char *appid, const char *lbid, int is_prime, void *data)
+{
+ char *name;
+
+ DbgPrint("%s - %s\n", appid, lbid);
+
+ name = livebox_service_i18n_name(lbid, NULL);
+ if (!name) {
+ name = strdup(lbid);
+ if (!name) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return 0;
+ }
+ }
+
+ DbgPrint("Name: %s\n", name);
+ elm_list_item_append(data, name, NULL, NULL, click_cb, strdup(lbid));
+ free(name);
+ return 0;
+}
+
+static inline void livebox_list_create(void)
+{
+ Evas_Object *list;
+
+ list = elm_list_add(s_info.window);
+ evas_object_resize(list, 720, 1280);
+ evas_object_show(list);
+
+ DbgPrint("Get Package list\n");
+ livebox_service_get_pkglist(append_livebox_cb, list);
+ scroller_append(s_info.scroller, list);
+ elm_list_go(list);
+}
+
+static bool app_create(void *data)
+{
+ DbgPrint("create");
+ lb_init();
+
+ s_info.window = elm_win_add(NULL, "Box viewer", ELM_WIN_BASIC);
+ if (!s_info.window) {
+ ErrPrint("Failed to create a window\n");
+ return false;
+ }
+
+ evas_object_resize(s_info.window, 720, 1280);
+ evas_object_show(s_info.window);
+
+ s_info.scroller = scroller_create(s_info.window);
+ if (!s_info.scroller) {
+ evas_object_del(s_info.window);
+ s_info.window = NULL;
+ ErrPrint("Failed to create a scroller\n");
+ return false;
+ }
+
+ evas_object_resize(s_info.scroller, 720, 1280);
+ evas_object_show(s_info.scroller);
+
+ livebox_list_create();
+
+ return true;
+}
+
+static void app_terminate(void *data)
+{
+ DbgPrint("terminate");
+ lb_fini();
+ /*!
+ * \TODO
+ * Delete all objects from the scroller.
+ */
+
+ scroller_destroy(s_info.scroller);
+ evas_object_del(s_info.window);
+ s_info.window = NULL;
+}
+
+static void app_pause(void *data)
+{
+ DbgPrint("pause");
+}
+
+static void app_resume(void *data)
+{
+ DbgPrint("resume");
+}
+
+static void app_reset(service_h service, void *data)
+{
+ DbgPrint("reset");
+}
+
+int main(int argc, char *argv[])
+{
+ app_event_callback_s event_callback;
+
+ setenv("ELM_ENGINE", "gl", 0);
+ event_callback.create = app_create;
+ event_callback.terminate = app_terminate;
+ event_callback.pause = app_pause;
+ event_callback.resume = app_resume;
+ event_callback.service = app_reset;
+ event_callback.low_memory = NULL;
+ event_callback.low_battery = NULL;
+ event_callback.device_orientation = NULL;
+ event_callback.language_changed = NULL;
+
+ return app_efl_main(&argc, &argv, &event_callback, NULL);
+}
+
+/* End of a file */
--- /dev/null
+#include <Elementary.h>
+
+#include <dlog.h>
+
+#include "util.h"
+#include "live_scroller.h"
+#include "scroller.h"
+#include "debug.h"
+
+#define FOCAL_DIST 800
+#define FLICK_COND 100
+
+struct cb_item {
+ int (*cb)(Evas_Object *sc, void *data);
+ void *data;
+};
+
+struct scroll_info {
+ int locked;
+ Eina_Bool scrolling;
+ int focal;
+ Eina_Bool quick;
+
+ Evas_Map *map;
+
+ Ecore_Idler *bg_changer;
+ Eina_List *cb_list;
+};
+
+void scroller_lock(Evas_Object *sc)
+{
+ struct scroll_info *scinfo;
+
+ scinfo = evas_object_data_get(sc, "scinfo");
+ if (!scinfo)
+ return;
+
+ if (!scinfo->locked)
+ live_scroller_freeze(sc);
+
+ scinfo->locked++;
+}
+
+void scroller_unlock(Evas_Object *sc)
+{
+ struct scroll_info *scinfo;
+
+ scinfo = evas_object_data_get(sc, "scinfo");
+ if (!scinfo)
+ return;
+
+ if (scinfo->locked == 0)
+ return;
+
+ scinfo->locked--;
+
+ if (scinfo->locked == 0)
+ live_scroller_thaw(sc);
+}
+
+static void sc_anim_stop(void *data, Evas_Object *obj, void *event_info)
+{
+ Eina_List *l;
+ Eina_List *tmp;
+ struct cb_item *item;
+ struct scroll_info *scinfo;
+
+ scinfo = evas_object_data_get(obj, "scinfo");
+ if (!scinfo)
+ return;
+ /*!
+ * \TODO
+ * Do what you want at here when the scroller is stopped
+ */
+
+ scinfo->scrolling = EINA_FALSE;
+ EINA_LIST_FOREACH_SAFE(scinfo->cb_list, l, tmp, item) {
+ if (item->cb(obj, item->data) == ECORE_CALLBACK_CANCEL) {
+ if (eina_list_data_find(scinfo->cb_list, item)) {
+ scinfo->cb_list = eina_list_remove(scinfo->cb_list, item);
+ free(item);
+ }
+ }
+ }
+}
+
+static inline void sc_drag_start(void *data, Evas_Object *obj, void *event_info)
+{
+ struct scroll_info *scinfo;
+
+ scinfo = evas_object_data_get(obj, "scinfo");
+ if (!scinfo)
+ return;
+
+ scinfo->scrolling = EINA_TRUE;
+}
+
+static inline void sc_drag_stop(void *data, Evas_Object *scroller, void *event_info)
+{
+ struct live_sc_drag_info *info;
+ int offset = 0;
+ int ret;
+
+ info = event_info;
+
+ if (info->dx > FLICK_COND)
+ offset = -1;
+ else if (info->dx < -FLICK_COND)
+ offset = 1;
+
+ ret = live_scroller_anim_to(scroller, 0.016f, offset);
+ if (ret < 0) {
+ struct scroll_info *scinfo;
+ scinfo = evas_object_data_get(scroller, "scinfo");
+ if (scinfo)
+ scinfo->scrolling = EINA_FALSE;
+ }
+}
+
+static Eina_Bool bg_change_cb(void *data)
+{
+ Evas_Object *sc = data;
+ struct scroll_info *scinfo;
+
+ scinfo = evas_object_data_get(sc, "scinfo");
+ if (scinfo)
+ scinfo->bg_changer = NULL;
+
+ /*
+ * NOTE:
+ * Here,
+ * Filename of background image handling code is only
+ * used to demonstrates UX concept and estimates its perfomance.
+ * So, I'll change this if it should be appled to
+ * main branch.
+ */
+ DbgPrint("Change the background image (%p)\n", sc);
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static void sc_anim_start(void *data, Evas_Object *obj, void *event_info)
+{
+ struct scroll_info *scinfo;
+
+ scinfo = evas_object_data_get(obj, "scinfo");
+ if (!scinfo)
+ return;
+
+ /* \note
+ * without drag,start
+ * anim start can be invoked by the scroller_anim_to
+ */
+ scinfo->scrolling = EINA_TRUE;
+
+ if (scinfo->bg_changer)
+ ecore_idler_del(scinfo->bg_changer);
+
+ scinfo->bg_changer = ecore_idler_add(bg_change_cb, obj);
+ if (!scinfo->bg_changer)
+ DbgPrint("Failed to add an idler\n");
+}
+
+static void sc_item_moved(void *data, Evas_Object *obj, void *event_info)
+{
+ struct live_sc_move_info *evt = event_info;
+ int color;
+ int focal;
+ Evas_Coord y, sx, sw;
+ double ftmp;
+ struct scroll_info *scinfo;
+
+ scinfo = evas_object_data_get(obj, "scinfo");
+ if (!scinfo) {
+ ErrPrint("Has no scinfo\n");
+ return;
+ }
+
+ ftmp = fabsl(evt->relx);
+ if (ftmp >= 1.0f) {
+ evas_object_map_enable_set(evt->item, EINA_FALSE);
+ evas_object_hide(evt->item);
+ return;
+ }
+
+ color = 255 * (1.0f - ftmp);
+ if (scinfo->quick) {
+ if (color < 100)
+ color = 100;
+
+ focal = scinfo->focal;
+ } else {
+ if (color == 0) {
+ evas_object_map_enable_set(evt->item, EINA_FALSE);
+ evas_object_hide(evt->item);
+ return;
+ }
+
+ focal = -ftmp * 200.0f + scinfo->focal;
+ }
+
+ evas_object_geometry_get(data, &sx, NULL, &sw, NULL);
+
+ /* LEFT */
+ evas_map_point_coord_set(scinfo->map, 0, evt->x, evt->y, 0);
+ evas_map_point_image_uv_set(scinfo->map, 0, 0, 0);
+ evas_map_point_color_set(scinfo->map, 0, color, color, color, color);
+
+ /* RIGHT */
+ evas_map_point_coord_set(scinfo->map, 1, evt->x + evt->w, evt->y, 0);
+ evas_map_point_image_uv_set(scinfo->map, 1, evt->w, 0);
+ evas_map_point_color_set(scinfo->map, 1, color, color, color, color);
+
+ /* BOTTOM-RIGHT */
+ evas_map_point_coord_set(scinfo->map, 2, evt->x + evt->w, evt->y + evt->h, 0);
+ evas_map_point_image_uv_set(scinfo->map, 2, evt->w, evt->h);
+ evas_map_point_color_set(scinfo->map, 2, color, color, color, color);
+
+ /* BOTTOM-LEFT */
+ evas_map_point_coord_set(scinfo->map, 3, evt->x, evt->y + evt->h, 0);
+ evas_map_point_image_uv_set(scinfo->map, 3, 0, evt->h);
+ evas_map_point_color_set(scinfo->map, 3, color, color, color, color);
+
+ y = evt->y + (evt->h >> 1);
+ evas_map_util_3d_rotate(scinfo->map, 0.0f, -30.0f * evt->relx, 0.0f, evt->x + (evt->w >> 1), y, 0);
+ evas_map_util_3d_perspective(scinfo->map, sx + (sw >> 1), y, focal, FOCAL_DIST);
+ evas_object_map_set(evt->item, scinfo->map);
+ evas_object_map_enable_set(evt->item, EINA_TRUE);
+ evas_object_show(evt->item);
+ return;
+}
+
+static void sc_page_changed(void *data, Evas_Object *obj, void *event_info)
+{
+ DbgPrint("Page is changed %d\n", (int)event_info);
+}
+
+int scroller_add_stop_cb(Evas_Object *scroller,
+ int (*cb)(Evas_Object *sc, void *data), void *data)
+{
+ struct cb_item *item;
+ struct scroll_info *scinfo;
+
+ scinfo = evas_object_data_get(scroller, "scinfo");
+ if (!scinfo)
+ return -EINVAL;
+
+ item = calloc(1, sizeof(*item));
+ if (!item) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ item->cb = cb;
+ item->data = data;
+
+ scinfo->cb_list = eina_list_append(scinfo->cb_list, item);
+ return EXIT_SUCCESS;
+}
+
+void scroller_del_stop_cb(Evas_Object *scroller,
+ int (*cb)(Evas_Object *sc, void *data), void *data)
+{
+ struct cb_item *item;
+ Eina_List *l;
+ Eina_List *tmp;
+ struct scroll_info *scinfo;
+
+ scinfo = evas_object_data_get(scroller, "scinfo");
+ if (!scinfo) {
+ ErrPrint("Failed to get scinfo\n");
+ return;
+ }
+
+ EINA_LIST_FOREACH_SAFE(scinfo->cb_list, l, tmp, item) {
+ if (item->cb == cb && item->data == data) {
+ scinfo->cb_list = eina_list_remove(scinfo->cb_list, item);
+ free(item);
+ break;
+ }
+ }
+}
+
+Evas_Object *scroller_create(Evas_Object *ctrl)
+{
+ Evas_Object *sc;
+ struct scroll_info *scinfo;
+
+ scinfo = calloc(1, sizeof(*scinfo));
+ if (!scinfo) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ sc = live_scroller_add(ctrl);
+ if (!sc) {
+ DbgPrint("Failed to create flip object\n");
+ free(scinfo);
+ return NULL;
+ }
+
+ evas_object_data_set(sc, "scinfo", scinfo);
+
+ scinfo->map = evas_map_new(4);
+ if (!scinfo->map) {
+ evas_object_del(sc);
+ free(scinfo);
+ return NULL;
+ }
+
+ evas_map_smooth_set(scinfo->map, EINA_TRUE);
+ evas_map_alpha_set(scinfo->map, EINA_TRUE);
+
+ evas_object_size_hint_weight_set(sc,
+ EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_smart_callback_add(sc, "drag,start", sc_drag_start, NULL);
+ evas_object_smart_callback_add(sc, "drag,stop", sc_drag_stop, NULL);
+ evas_object_smart_callback_add(sc, "anim,stop", sc_anim_stop, NULL);
+ evas_object_smart_callback_add(sc, "anim,start", sc_anim_start, NULL);
+ evas_object_smart_callback_add(sc, "page,changed", sc_page_changed, NULL);
+ evas_object_smart_callback_add(sc, "item,moved", sc_item_moved, NULL);
+ live_scroller_loop_set(sc, EINA_TRUE);
+ evas_object_show(sc);
+
+ return sc;
+}
+
+int scroller_append(Evas_Object *sc, Evas_Object *child)
+{
+ return live_scroller_append(sc, child);
+}
+
+int scroller_get_page_index(Evas_Object *sc, Evas_Object *page)
+{
+ return live_scroller_get_item_index(sc, page);
+}
+
+Evas_Object *scroller_get_page(Evas_Object *sc, int idx)
+{
+ return live_scroller_get_item(sc, idx);
+}
+
+Evas_Object *scroller_peek_by_idx(Evas_Object *sc, int idx)
+{
+ return live_scroller_remove(sc, idx);
+}
+
+int scroller_peek_by_obj(Evas_Object *sc, Evas_Object *page)
+{
+ return live_scroller_remove_by_obj(sc, page);
+}
+
+int scroller_get_current_idx(Evas_Object *sc)
+{
+ return live_scroller_get_current(sc);
+}
+
+int scroller_is_scrolling(Evas_Object *sc)
+{
+ struct scroll_info *scinfo;
+
+ scinfo = evas_object_data_get(sc, "scinfo");
+ if (!scinfo)
+ return -EINVAL;
+
+ return scinfo->scrolling;
+}
+
+int scroller_get_page_count(Evas_Object *sc)
+{
+ return live_scroller_get_item_count(sc);
+}
+
+int scroller_scroll_to(Evas_Object *sc, int idx)
+{
+ int curidx;
+ int cnt;
+ register int i;
+ int next_offset;
+ int prev_offset;
+ struct scroll_info *scinfo;
+
+ scinfo = evas_object_data_get(sc, "scinfo");
+ if (!scinfo)
+ return -EINVAL;
+
+ if (scinfo->scrolling) {
+ DbgPrint("Scroller is scrolling\n");
+ return -EINVAL;
+ }
+
+ curidx = live_scroller_get_current(sc);
+ cnt = live_scroller_get_item_count(sc);
+
+ i = curidx;
+ next_offset = 0;
+ while (i != idx/* && i >= 0 && i < cnt*/) {
+ i++;
+ if (i >= cnt)
+ i = 0;
+
+ next_offset++;
+ }
+
+ i = curidx;
+ prev_offset = 0;
+ while (i != idx/* && i >= 0 && i < cnt*/) {
+ i--;
+ if (i < 0)
+ i = cnt - 1;
+
+ prev_offset--;
+ }
+
+ idx = next_offset < -prev_offset ? next_offset : prev_offset;
+ live_scroller_anim_to(sc, 0.016f, idx);
+ return 0;
+}
+
+int scroller_jump_to(Evas_Object *sc, int idx)
+{
+ live_scroller_go_to(sc, idx);
+ return 0;
+}
+
+int scroller_destroy(Evas_Object *sc)
+{
+ int cnt;
+ struct scroll_info *scinfo;
+ struct cb_item *item;
+
+ scinfo = evas_object_data_del(sc, "scinfo");
+ if (!scinfo)
+ return -EFAULT;
+
+ if (scinfo->bg_changer)
+ ecore_idler_del(scinfo->bg_changer);
+
+ EINA_LIST_FREE(scinfo->cb_list, item) {
+ free(item);
+ }
+
+ cnt = live_scroller_get_item_count(sc);
+ if (cnt)
+ DbgPrint("Children is not cleared (%d)\n", cnt);
+
+ evas_object_del(sc);
+ evas_map_free(scinfo->map);
+ free(scinfo);
+ return 0;
+}
+
+int scroller_update(Evas_Object *sc, void *data)
+{
+ struct scroll_info *scinfo;
+
+ scinfo = evas_object_data_get(sc, "scinfo");
+ if (!scinfo)
+ return -EFAULT;
+
+ scinfo->focal = (int)data;
+ live_scroller_update(sc);
+ return EXIT_SUCCESS;
+}
+
+int scroller_fast_scroll(Evas_Object *sc, int idx)
+{
+ idx -= scroller_get_current_idx(sc);
+ live_scroller_anim_to(sc, 0.016f, idx);
+ return 0;
+}
+
+void scroller_loop_set(Evas_Object *sc, Eina_Bool val)
+{
+ live_scroller_loop_set(sc, val);
+}
+
+void scroller_quick_navi(Evas_Object *sc, Eina_Bool val)
+{
+ struct scroll_info *scinfo;
+ scinfo = evas_object_data_get(sc, "scinfo");
+ if (!scinfo)
+ return;
+
+ scinfo->quick = val;
+}
+
+/* End of a file */
--- /dev/null
+/*
+ * com.samsung.live-magazine
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Sung-jae Park <nicesj.park@samsung.com>, Youngjoo Park <yjoo93.park@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <dlog.h>
+
+#include "debug.h"
+#include "util.h"
+
+int errno;
+
+const char *util_basename(const char *name)
+{
+ int length;
+ length = name ? strlen(name) : 0;
+ if (!length)
+ return ".";
+
+ while (--length > 0 && name[length] != '/');
+
+ return length <= 0 ? name : name + length + (name[length] == '/');
+}
+
+/* End of a file */