[elm_cabinet] merged.
authorInho Oh <inho48.oh@samsung.com>
Wed, 9 Jun 2010 09:00:22 +0000 (18:00 +0900)
committerInho Oh <inho48.oh@samsung.com>
Wed, 9 Jun 2010 09:00:22 +0000 (18:00 +0900)
src/lib/Elementary.h.in
src/lib/Makefile.am
src/lib/elm_cabinet.c [new file with mode: 0755]

index 12ee226..127de4d 100755 (executable)
@@ -2310,6 +2310,34 @@ extern "C" {
    EAPI Elm_Coverflow_Item* elm_coverflow_item_append( Evas_Object* obj, Elm_Coverflow_Item_Class* cic, void* data, void (*func)(void* data, Evas_Object* obj, void* event_info ), void* func_data );
    EAPI void elm_coverflow_clear( Evas_Object* obj );                  
 
+   /* Cabinet */
+   typedef struct _Cabinet_Item Elm_Cabinet_Item;
+   EAPI Evas_Object        *elm_cabinet_add(Evas_Object *parent);
+   EAPI void                elm_cabinet_next(Evas_Object *obj);
+   EAPI void                elm_cabinet_prev(Evas_Object *obj);
+   EAPI Eina_Bool           elm_cabinet_bounce_get(Evas_Object *obj);
+   EAPI void                elm_cabinet_bounce_set(Evas_Object *obj, Eina_Bool bounce);
+   EAPI Elm_Cabinet_Item   *elm_cabinet_item_append(Evas_Object *obj, const char *label, void (*func)(void *data, Evas_Object *obj, void *event_info), void *data);
+   EAPI Elm_Cabinet_Item   *elm_cabinet_item_prepend(Evas_Object *obj, const char *label, void (*func)(void *data, Evas_Object *obj, void *event_info), void *data);
+   EAPI const Eina_List    *elm_cabinet_items_get(Evas_Object *obj);
+   EAPI Elm_Cabinet_Item   *elm_cabinet_first_item_get(Evas_Object *obj);
+   EAPI Elm_Cabinet_Item   *elm_cabinet_last_item_get(Evas_Object *obj);
+   EAPI Elm_Cabinet_Item   *elm_cabinet_selected_item_get(Evas_Object *obj);
+   EAPI void                elm_cabinet_item_selected_set(Elm_Cabinet_Item *item);
+   EAPI void                elm_cabinet_item_del(Elm_Cabinet_Item *item);
+   EAPI const char         *elm_cabinet_item_label_get(Elm_Cabinet_Item *item);
+   EAPI void                elm_cabinet_item_label_set(Elm_Cabinet_Item *item, const char *label);
+   EAPI const char         *elm_cabinet_item_sub_info_get(Elm_Cabinet_Item *item);
+   EAPI void                elm_cabinet_item_sub_info_set(Elm_Cabinet_Item *item, const char *sub_info);
+   EAPI Elm_Cabinet_Item   *elm_cabinet_item_prev(Elm_Cabinet_Item *item);
+   EAPI Elm_Cabinet_Item   *elm_cabinet_item_next(Elm_Cabinet_Item *item);
+   EAPI void               *elm_cabinet_item_data_get(Elm_Cabinet_Item *item);
+   EAPI void                elm_cabinet_item_data_set(Elm_Cabinet_Item *item, void *data);
+   EAPI Eina_Bool           elm_cabinet_item_del_btn_disabled_get(Elm_Cabinet_Item *item);
+   EAPI void                elm_cabinet_item_del_btn_disabled_set(Elm_Cabinet_Item *item, Eina_Bool disabled);
+   EAPI Eina_Bool           elm_cabinet_item_sub_info_disabled_get(Elm_Cabinet_Item *item);
+   EAPI void                elm_cabinet_item_sub_info_disabled_set(Elm_Cabinet_Item *item, Eina_Bool disabled);
+
 #ifdef __cplusplus
 }
 #endif
index 51825a6..b3a3920 100755 (executable)
@@ -116,6 +116,7 @@ elm_chronometer.c \
 elm_dialoguegroup.c \
 elm_animatedicon.c \
 elm_coverflow.c \
+elm_cabinet.c \
 \
 elc_anchorblock.c \
 elc_anchorview.c \
diff --git a/src/lib/elm_cabinet.c b/src/lib/elm_cabinet.c
new file mode 100755 (executable)
index 0000000..79c9291
--- /dev/null
@@ -0,0 +1,1095 @@
+#include <Elementary.h>
+#include <math.h>
+#include "elm_priv.h"
+
+#define CELL_ITEM_NUMS (9)
+#define PI (3.141592)
+#define RADIAN_STEP (PI/14)
+#define MOUSE_MOVE_SAMPLE (5)
+#define SCALE_DOWN_FACTOR (0.25)
+#define VISIBLE_CONTENT_NUMS (2)
+#define DEF_ITEM_HEIGHT (74)
+#define FRAME_RATE (0.03)
+#define V_MIN (50)
+#define ITEM_DEL_MOVE_DISTANCE (30)
+
+//#define SCALE_DOWN_FACTOR (0.125)
+
+/**
+ * @addtogroup Cabinet Cabinet
+ *
+ * This is a cabinet.
+ */
+struct _Cabinet_Item {
+       Evas_Object *cabinet;
+       const char *label;
+       const char *sub_info;
+       void (*func)(void *data, Evas_Object *obj, void *event_info);
+       void *data;
+       void *priv_data;
+       int btn_disabled : 1;
+       int info_disabled : 1;
+};
+
+typedef struct _Widget_Data Widget_Data;
+struct _Widget_Data {
+       Evas_Object *base;
+       Evas_Object *clip;
+       Evas_Object *cover;
+
+       Eina_List *its;
+       Eina_List *cur;
+       Eina_List *cells;
+       Evas_Coord x, y, w, h;
+       double rad_step, rad_gap, rad_tmp;
+       double v;
+       Evas_Coord d, item_d, item_h;
+       int item_cnt;
+
+       unsigned int prev_evt_t;
+       Evas_Coord prev_evt_y;
+       Evas_Coord_Point down_point;
+       Elm_Animator *ani;
+       Ecore_Timer *scroll_ani;
+
+       int bounce_enable : 1;
+       int bounce_flag : 1;
+       int item_del_flag : 1;
+       int dragged : 1;
+};
+
+static void _del_hook(Evas_Object *obj);
+static void _theme_hook(Evas_Object *obj);
+static void _sizing_eval(Evas_Object *obj);
+static void _mouse_init(Evas_Object *obj);
+
+static void _mouse_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
+static void _mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
+static void _mouse_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
+static void _resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
+static void _move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
+
+static Eina_List *_cells_add(Evas_Object *obj);
+static void _cells_del(Evas_Object *obj);
+static void _cells_update(Evas_Object *obj);
+static double _rad_next_get(Widget_Data *wd, double rad, Evas_Coord_Rectangle *pos);
+static void _items_reorder(Evas_Object *obj);
+
+static void _ani_stop_all(Evas_Object *obj);
+static void _ani_bounce_cb(void *data, Elm_Animator *animator, double frame);
+static void _ani_bounce_done_cb(void *data);
+static void _bounce(Evas_Object *obj);
+static int _ani_scroll_cb(void *data);
+static void _scroll(Evas_Object *obj);
+static void _ani_item_del_cb(void *data, Elm_Animator *animator, double frame);
+static void _ani_item_del_done_cb(void *data);
+static void _item_del(Evas_Object *obj, Evas_Object *item);
+
+static void
+_del_hook(Evas_Object *obj)
+{
+       Widget_Data *wd = elm_widget_data_get(obj);
+       Elm_Cabinet_Item *it;
+
+       if (!wd) return;
+
+       _ani_stop_all(obj);
+       if (wd->its) {
+               EINA_LIST_FREE(wd->its, it) {
+                       if (it->label) eina_stringshare_del(it->label);
+                       free(it);
+               }
+       }
+       free(wd);
+}
+
+static void
+_theme_hook(Evas_Object *obj)
+{
+       Widget_Data *wd = elm_widget_data_get(obj);
+       if (!wd) return;
+       _elm_theme_object_set(obj, wd->base, "cabinet", "base", elm_widget_style_get(obj));
+       _sizing_eval(obj);
+}
+
+static void
+_sizing_eval(Evas_Object *obj)
+{
+       int it_cnt;
+       Widget_Data *wd = elm_widget_data_get(obj);
+       Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
+
+       if (!wd) return;
+       elm_coords_finger_size_adjust(1, &minw, 1, &minh);
+       edje_object_size_min_restricted_calc(wd->base, &minw, &minh, minw, minh);
+       elm_coords_finger_size_adjust(1, &minw, 1, &minh);
+       evas_object_size_hint_min_set(obj, minw, minh);
+       evas_object_size_hint_max_set(obj, maxw, maxh);
+
+       evas_object_geometry_get(obj, &wd->x, &wd->y, &wd->w, &wd->h);
+       wd->item_h = DEF_ITEM_HEIGHT * elm_scale_get();
+       if (!wd->h) return;
+
+       wd->rad_step = asin((double)wd->item_h / wd->h);
+       if (!wd->rad_step) return;
+       it_cnt = (PI / 2) / wd->rad_step;
+       if (wd->item_cnt != it_cnt) {
+               _cells_del(obj);
+               wd->item_cnt = it_cnt;
+               wd->cells = _cells_add(obj);
+               _cells_update(obj);
+       }
+       
+       wd->item_d = (Evas_Coord) (2 * wd->h * (sin(wd->rad_step / 2)));
+       _cells_update(obj);
+}
+
+static void
+_mouse_init(Evas_Object *obj)
+{
+       Widget_Data *wd = elm_widget_data_get(obj);
+       if (!wd) return;
+       evas_object_event_callback_add(wd->base, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, obj);
+       evas_object_event_callback_add(wd->base, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, obj);
+       evas_object_event_callback_add(wd->base, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, obj);
+}
+
+static void
+_mouse_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+       Widget_Data *wd = elm_widget_data_get(data);
+       Evas_Event_Mouse_Down *ev = event_info;
+
+       if (!wd || wd->item_del_flag) return;
+
+       if (wd->ani) {
+               elm_animator_del(wd->ani);
+               wd->ani = NULL;
+       }
+
+       if (wd->scroll_ani) {
+               ecore_timer_del(wd->scroll_ani);
+               wd->scroll_ani = NULL;
+       }
+
+       wd->d = 0;
+       wd->prev_evt_t = ev->timestamp;
+       wd->prev_evt_y = ev->canvas.y;
+
+       wd->dragged = 0;
+       wd->down_point.x = ev->canvas.x;
+       wd->down_point.y = ev->canvas.y;
+}
+
+static void
+_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+       unsigned int t;
+       Evas_Coord d;
+       Widget_Data *wd = elm_widget_data_get(data);
+       Evas_Event_Mouse_Up *ev = event_info;
+
+       if (!wd || wd->item_del_flag) return;
+
+       t = ev->timestamp - wd->prev_evt_t;
+       d = ev->canvas.y - wd->prev_evt_y;
+
+       if (wd->bounce_flag || t <= 0) {
+               _bounce(data);
+       } else {
+               wd->d = -d;
+               wd->v = (double)(wd->d) / (double)t * 1000;
+               if (wd->v < V_MIN && wd->v > -V_MIN)
+                       wd->v = wd->v < 0 ? V_MIN : -V_MIN;
+               _scroll(data);
+       }
+       wd->prev_evt_t = 0;
+       wd->prev_evt_y = 0;
+}
+
+static void
+_mouse_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+       Widget_Data *wd = elm_widget_data_get(data);
+       Evas_Event_Mouse_Move *ev = event_info;
+       unsigned int t;
+       Evas_Coord d;
+       Evas_Coord x, y, distance;
+       static int sample = MOUSE_MOVE_SAMPLE;
+
+       if (!wd) return;
+       
+       if (!wd->dragged) {
+               x = ev->cur.canvas.x - wd->down_point.x;
+               y = ev->cur.canvas.y - wd->down_point.y;
+               distance = (x * x) + (y * y);
+               if (distance >= (elm_finger_size_get() >> 1)) wd->dragged = 1;
+       }
+
+       if (sample) {
+               sample--;
+               return;
+       }
+       sample = MOUSE_MOVE_SAMPLE;
+
+       if (wd->item_del_flag || !ev->timestamp) return;
+
+       if (wd->prev_evt_t) {
+               t = ev->timestamp - wd->prev_evt_t;
+               d = ev->cur.canvas.y - wd->prev_evt_y;
+               wd->d -= d;
+               _items_reorder(data);
+               wd->rad_gap = wd->rad_step * ((double)wd->d / (double)wd->item_d);
+               _cells_update(data);
+       }
+       wd->prev_evt_t = ev->timestamp;
+       wd->prev_evt_y = ev->cur.canvas.y;
+}
+
+static void
+_resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+       _sizing_eval(data);
+}
+
+static void
+_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+       _sizing_eval(data);
+}
+
+static void
+_item_del_cb(void *data, Evas_Object *obj, const char *emission, const char *source)
+{
+       Widget_Data *wd = elm_widget_data_get(data);
+       if (!wd || wd->item_del_flag || wd->dragged) return;
+       _ani_stop_all(data);
+       _item_del(data, obj);
+
+}
+
+static void
+_item_sel_cb(void *data, Evas_Object *obj, const char *emission, const char *source)
+{
+       Widget_Data *wd = elm_widget_data_get(data);
+       Elm_Cabinet_Item *it;
+
+       if (!wd) return;
+       if (wd->dragged) return;
+
+       it = evas_object_data_get(obj, "item");
+       if (it && it->func) {
+               it->func(it->data, it->cabinet, it);
+       }
+}
+
+static Eina_List *
+_cells_add(Evas_Object *obj)
+{
+       int i;
+       Evas *e;
+       Eina_List *cells = NULL;
+       Evas_Object *eo;
+       Widget_Data *wd = elm_widget_data_get(obj);
+       if (!wd) return NULL;
+
+       e = evas_object_evas_get(obj);
+       for (i = 0; i < wd->item_cnt; i++) {
+               eo = edje_object_add(e);
+               _elm_theme_object_set(obj, eo, "cabinet/item", "base", elm_widget_style_get(obj));
+               edje_object_signal_callback_add(eo, "elm,action,del", "*", _item_del_cb, obj);
+               edje_object_signal_callback_add(eo, "elm,action,clicked", "*", _item_sel_cb, obj);
+               cells = eina_list_append(cells, eo);
+               elm_widget_sub_object_add(obj, eo);
+               evas_object_smart_member_add(eo, obj);
+               evas_object_clip_set(eo, wd->clip);
+               evas_object_stack_below(eo, wd->base);
+       }
+       return cells;
+}
+
+static void
+_cells_del(Evas_Object *obj)
+{
+       Evas_Object *eo;
+       Widget_Data *wd = elm_widget_data_get(obj);
+
+       if (!wd || !wd->cells) return;
+       EINA_LIST_FREE(wd->cells, eo) evas_object_del(eo);
+}
+
+static void
+_cells_update(Evas_Object *obj)
+{
+       int color;
+       double rad;
+       Eina_List *l, *data;
+       Evas_Object *eo;
+       Elm_Cabinet_Item *it;
+       Widget_Data *wd = elm_widget_data_get(obj);
+       Evas_Coord_Rectangle pos = {0, };
+
+       if (!wd || !wd->cells) return;
+       data = wd->cur;
+       rad = wd->rad_gap;
+
+       EINA_LIST_REVERSE_FOREACH(wd->cells, l, eo) {
+               rad = _rad_next_get(wd, rad, &pos);
+               evas_object_move(eo, pos.x, pos.y);
+               evas_object_resize(eo, pos.w, wd->item_h);
+               
+               if (wd->h - wd->item_h) color = 255 * ((double)pos.y / (wd->h - wd->item_h));
+               else color = 255;
+               evas_object_color_set(eo, color, color, color, 255);
+
+               if (data) {
+                       it = eina_list_data_get(data);
+                       edje_object_part_text_set(eo, "elm.label", it->label);
+                       edje_object_part_text_set(eo, "elm.info_label", it->info_disabled ? NULL : it->sub_info);
+                       edje_object_signal_emit(eo, it->btn_disabled ? "info_disable" : "info_enable", "elm");
+                       data = eina_list_next(data);
+                       evas_object_show(eo);
+                       evas_object_data_set(eo, "item", it);
+               } else {
+                       evas_object_hide(eo);
+                       evas_object_data_set(eo, "item", NULL);
+               }
+       }
+}
+
+static double
+_rad_next_get(Widget_Data *wd, double rad, Evas_Coord_Rectangle *pos)
+{
+       if (rad >= 0) pos->w = wd->w * (cos(rad / 2));
+       else pos->w = wd->w;
+       rad += wd->rad_step;
+       pos->y = (wd->h * (1 - sin(rad))) + wd->y;
+       pos->x = wd->x + ((wd->w - pos->w) >> 1);
+       return rad;
+}
+
+static void
+_items_reorder(Evas_Object *obj)
+{
+       Eina_List *l;
+       Widget_Data *wd = elm_widget_data_get(obj);
+
+       if ((wd->d > 0 && wd->cur == wd->its)
+                       || (wd->d < 0 && wd->cur == eina_list_last(wd->its))) {
+               if (wd->bounce_enable)
+                       wd->bounce_flag = 1;
+               else
+                       wd->d = 0;
+               return;
+       }
+       wd->bounce_flag = 0;
+
+       l = wd->cur;
+       if (wd->d > 0) {
+               do {
+                       if (l) l = eina_list_prev(l);
+                       wd->d -= wd->item_d;
+               } while (wd->d > 0);
+       } else if (wd->d <= -wd->item_d) {
+               do {
+                       l = eina_list_next(l);
+                       if (!l) break;
+                       wd->d += wd->item_d;
+               } while (wd->d <= -wd->item_d);
+               wd->d = 0;
+       }
+
+       if (l) wd->cur = l;
+       return;
+}
+
+
+static void
+_ani_stop_all(Evas_Object *obj)
+{
+       Widget_Data *wd;
+       wd = elm_widget_data_get(obj);
+       if (!wd) return;
+
+       if (wd->ani) {
+               elm_animator_del(wd->ani);
+               wd->ani = NULL;
+       }
+
+       if (wd->scroll_ani) {
+               ecore_timer_del(wd->scroll_ani);
+               wd->scroll_ani = NULL;
+       }
+}
+
+static void
+_ani_bounce_cb(void *data, Elm_Animator *animator, double frame)
+{
+       Widget_Data *wd;
+       wd = elm_widget_data_get(data);
+       if (!wd) return;
+
+       wd->rad_gap = wd->rad_tmp * (1 - frame);
+       _cells_update(data);
+}
+
+static void
+_ani_bounce_done_cb(void *data)
+{
+       Widget_Data *wd = elm_widget_data_get(data);
+       wd->item_del_flag = 0;
+       wd->rad_gap = 0;
+       if (wd->ani) {
+               elm_animator_del(wd->ani);
+               wd->ani = NULL;
+       }
+
+       if (wd->cur)
+               evas_object_smart_callback_call(data, "changed", wd->cur ? eina_list_data_get(wd->cur) : NULL);
+}
+
+static void
+_bounce(Evas_Object *obj)
+{
+       double dur;
+       Widget_Data *wd;
+       wd = elm_widget_data_get(obj);
+       if (!wd || !wd->d) {
+               wd->item_del_flag = 0;
+               return;
+       }
+
+       if (wd->item_del_flag) dur = 0.2;
+       else dur = 0.5;
+
+       wd->d = 0;
+       wd->rad_tmp = wd->rad_gap;
+       if (wd->ani) elm_animator_del(wd->ani);
+       wd->ani = elm_animator_add(obj);
+       elm_animator_curve_style_set(wd->ani, ELM_ANIMATOR_CURVE_OUT);
+       elm_animator_duration_set(wd->ani, dur);
+       elm_animator_operation_callback_set(wd->ani, _ani_bounce_cb, obj);
+       elm_animator_completion_callback_set(wd->ani, _ani_bounce_done_cb, obj);
+       elm_animator_animate(wd->ani);
+}
+
+static int
+_ani_scroll_cb(void *data)
+{
+       Widget_Data *wd;
+       Evas_Coord d;
+       wd = elm_widget_data_get(data);
+       if (!wd) return 0;
+
+       d = wd->v * FRAME_RATE;
+       wd->d += d;
+
+       if (wd->v > (V_MIN >> 1) || wd->v < (-V_MIN >> 1)) {
+               if (wd->cur == eina_list_last(wd->its) || wd->cur == wd->its)
+                       wd->v *= 0.5;
+               else
+                       wd->v *= 0.9;
+       } else {
+               wd->scroll_ani = NULL;
+               _bounce(data);
+               return 0;
+       }
+
+       _items_reorder(data);
+       wd->rad_gap = wd->rad_step * ((double)wd->d / (double)wd->item_d);
+       _cells_update(data);
+
+       return 1;
+}
+
+static void
+_scroll(Evas_Object *obj)
+{
+       Widget_Data *wd;
+       wd = elm_widget_data_get(obj);
+       if (!wd) return;
+
+
+       if (wd->ani) {
+               elm_animator_del(wd->ani);
+               wd->ani = NULL;
+       }
+
+       if (wd->scroll_ani) ecore_timer_del(wd->scroll_ani);
+       wd->scroll_ani = ecore_timer_add(FRAME_RATE, _ani_scroll_cb, obj);
+}
+
+static void
+_ani_item_del_cb(void *data, Elm_Animator *animator, double frame)
+{
+       Evas_Object *it = data;
+       int color;
+       Evas_Coord x, y;
+       x = (Evas_Coord)evas_object_data_get(it, "X");
+       y = (Evas_Coord)evas_object_data_get(it, "Y");
+
+       if (frame == 1) {
+               evas_object_color_set(it, 255, 255, 255, 255);
+       } else {
+               y -= ITEM_DEL_MOVE_DISTANCE * elm_scale_get() * frame;
+               evas_object_move(it, x, y);
+               color = 255 * (1 - frame);
+               evas_object_color_set(it, color, color, color, color);
+       }
+}
+
+static void
+_ani_item_del_done_cb(void *data)
+{
+       Evas_Object *obj;
+       Widget_Data *wd;
+       Eina_List *l;
+       Elm_Cabinet_Item *it, *_it;
+       it = data;
+       if (!it) return;
+       obj = it->cabinet;
+       wd = elm_widget_data_get(obj);
+       if (!wd) return;
+       if (wd->ani) {
+               elm_animator_del(wd->ani);
+               wd->ani = NULL;
+       }
+
+       EINA_LIST_FOREACH(wd->its, l, _it) {
+               if (_it == it) {
+                       wd->its = eina_list_remove_list(wd->its, l);
+                       if (wd->cur == l) {
+                               wd->cur = eina_list_prev(l);
+                               if (!wd->cur) wd->cur = wd->its;
+                       }
+                       evas_object_smart_callback_call(obj, "item,deleted", _it);
+                       free(_it);
+                       break;
+               }
+       }
+
+       _cells_update(obj);
+       if (wd->cur == NULL) {
+               evas_object_smart_callback_call(obj, "item,deleted,all", NULL);
+       }
+       _bounce(obj);
+}
+
+static void
+_item_del(Evas_Object *obj, Evas_Object *item)
+{
+       Evas_Coord x, y;
+       Widget_Data *wd;
+       Elm_Cabinet_Item *it;
+       wd = elm_widget_data_get(obj);
+       if (!wd) return;
+
+       it = evas_object_data_get(item, "item");
+       if (!it) return;
+       wd->item_del_flag = 1;
+
+       evas_object_geometry_get(item, &x, &y, NULL, NULL);
+       evas_object_data_set(item, "X", (void *)x);
+       evas_object_data_set(item, "Y", (void *)y);
+
+       wd->ani = elm_animator_add(obj);
+       elm_animator_curve_style_set(wd->ani, ELM_ANIMATOR_CURVE_OUT);
+       elm_animator_duration_set(wd->ani, 0.5);
+
+       elm_animator_operation_callback_set(wd->ani, _ani_item_del_cb, item);
+       elm_animator_completion_callback_set(wd->ani, _ani_item_del_done_cb, it);
+       elm_animator_animate(wd->ani);
+}
+
+/**
+ * Add a new cabinet to the parent
+ *
+ * @param parent The parent object
+ * @return The new object or NULL if it cannot be created
+ *
+ * @ingroup Cabinet
+ */
+EAPI Evas_Object *
+elm_cabinet_add(Evas_Object *parent)
+{
+       Evas_Object *obj;
+       Evas *e;
+       Widget_Data *wd;
+
+       wd = ELM_NEW(Widget_Data);
+       e = evas_object_evas_get(parent);
+       obj = elm_widget_add(e);
+       elm_widget_type_set(obj, "cabinet");
+       elm_widget_sub_object_add(parent, obj);
+       elm_widget_data_set(obj, wd);
+
+       elm_widget_del_hook_set(obj, _del_hook);
+       elm_widget_theme_hook_set(obj, _theme_hook);
+
+       wd->clip = evas_object_rectangle_add(e);
+       elm_widget_resize_object_set(obj, wd->clip);
+       evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize_cb, obj);
+       evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _move_cb, obj);
+
+       wd->base = edje_object_add(e);
+       _elm_theme_object_set(obj, wd->base, "cabinet", "base", "default");
+       elm_widget_hover_object_set(obj, wd->base);
+       evas_object_clip_set(wd->base, wd->clip);
+       evas_object_smart_member_add(wd->base, obj);
+       evas_object_show(wd->base);
+
+       _mouse_init(obj);
+       _sizing_eval(obj);
+       return obj;
+}
+
+EAPI Eina_Bool
+elm_cabinet_bounce_get(Evas_Object *obj)
+{
+       Widget_Data *wd = elm_widget_data_get(obj);
+       if (!wd) return EINA_FALSE;
+       return wd->bounce_enable ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+elm_cabinet_bounce_set(Evas_Object *obj, Eina_Bool bounce)
+{
+       Widget_Data *wd = elm_widget_data_get(obj);
+       if (!wd) return;
+       wd->bounce_enable = bounce ? 1 : 0;
+}
+
+/**
+ * Select next item of cabinet
+ *
+ * @param obj The cabinet object
+ *
+ * @ingroup Cabinet
+ */
+EAPI void
+elm_cabinet_next(Evas_Object *obj)
+{
+}
+
+/**
+ * Select previous item of cabinet
+ *
+ * @param obj The cabinet object
+ *
+ * @ingroup Cabinet
+ */
+EAPI void
+elm_cabinet_prev(Evas_Object *obj)
+{
+}
+
+/**
+ * Append item to the end of cabinet
+ *
+ * @param obj The cabinet object
+ * @param label The label of new item
+ * @param func Convenience function called when item selected
+ * @param data Data passed to @p func above
+ * @return A handle to the item added or NULL if not possible
+ *
+ * @ingroup Cabinet
+ */
+EAPI Elm_Cabinet_Item *
+elm_cabinet_item_append(Evas_Object *obj, const char *label, void (*func)(void *data, Evas_Object *obj, void *event_info), void *data)
+{
+       Elm_Cabinet_Item *item;
+       Widget_Data *wd = elm_widget_data_get(obj);
+       if (!wd) return NULL;
+
+       item = ELM_NEW(Elm_Cabinet_Item);
+       if (item) {
+               if (label) item->label = eina_stringshare_add(label);
+               item->func = func;
+               item->data = data;
+               item->cabinet = obj;
+               wd->its = eina_list_append(wd->its, item);
+               if (!wd->cur) {
+                       wd->cur = wd->its;
+               }
+               _sizing_eval(obj);
+       }
+       return item;
+}
+
+/**
+ * Prepend item at start of cabinet
+ *
+ * @param obj The cabinet object
+ * @param label The label of new item
+ * @param func Convenience function called when item selected
+ * @param data Data passed to @p func above
+ * @return A handle to the item added or NULL if not possible
+ *
+ * @ingroup Cabinet
+ */
+EAPI Elm_Cabinet_Item *
+elm_cabinet_item_prepend(Evas_Object *obj, const char *label, void (*func)(void *data, Evas_Object *obj, void *event_info), void *data)
+{
+       Elm_Cabinet_Item *item;
+       Widget_Data *wd = elm_widget_data_get(obj);
+       if (!wd) return NULL;
+
+       item = ELM_NEW(Elm_Cabinet_Item);
+       if (item) {
+               if (label) item->label = eina_stringshare_add(label);
+               item->func = func;
+               item->data = data;
+               item->cabinet = obj;
+               wd->its = eina_list_prepend(wd->its, item);
+               if (!wd->cur) wd->cur = wd->its;
+               _sizing_eval(obj);
+       }
+       return item;
+}
+
+/**
+ * Get a list of items in the cabinet
+ *
+ * @param obj The cabinet object
+ * @return The list of items, or NULL if none
+ *
+ * @ingroup Cabinet
+ */
+EAPI const Eina_List *
+elm_cabinet_items_get(Evas_Object *obj)
+{
+       Widget_Data *wd = elm_widget_data_get(obj);
+       if (!wd) return NULL;
+       return wd->its;
+}
+
+/**
+ * Get the first item in the cabinet
+ *
+ * @param obj The cabinet object
+ * @return The first item, or NULL if none
+ *
+ * @ingroup Cabinet
+ */
+EAPI Elm_Cabinet_Item *
+elm_cabinet_first_item_get(Evas_Object *obj)
+{
+       Widget_Data *wd;
+       if (!obj) return NULL;
+       wd = elm_widget_data_get(obj);
+       if (!wd || !wd->its) return NULL;
+       return eina_list_data_get(wd->its);
+}
+
+/**
+ * Get the last item in the cabinet
+ *
+ * @param obj The cabinet object
+ * @return The last item, or NULL if none
+ *
+ * @ingroup Cabinet
+ */
+EAPI Elm_Cabinet_Item *
+elm_cabinet_last_item_get(Evas_Object *obj)
+{
+       Widget_Data *wd;
+       if (!obj) return NULL;
+       wd = elm_widget_data_get(obj);
+       if (!wd || !wd->its) return NULL;
+       return eina_list_data_get(eina_list_last(wd->its));
+}
+
+/**
+ * Get the selected item in the cabinet
+ *
+ * @param obj The cabinet object
+ * @return The selected item, or NULL if none
+ *
+ * @ingroup Cabinet
+ */
+EAPI Elm_Cabinet_Item *
+elm_cabinet_selected_item_get(Evas_Object *obj)
+{
+       Widget_Data *wd = elm_widget_data_get(obj);
+       if (!wd || !wd->cur) return NULL;
+       return eina_list_data_get(wd->cur);
+}
+
+/**
+ * Set the selected state of an item
+ *
+ * @param item The item
+ *
+ * @ingroup Cabinet
+ */
+EAPI void
+elm_cabinet_item_selected_set(Elm_Cabinet_Item *item)
+{
+       Widget_Data *wd;
+       Eina_List *l;
+       Elm_Cabinet_Item *_item;
+
+       if (!item) return;
+       wd = elm_widget_data_get(item->cabinet);
+       if (!wd) return;
+
+       EINA_LIST_FOREACH(wd->its, l, _item) {
+               if (_item == item) {
+                       ;
+                       //TODO: NOT YET
+               }
+       }
+}
+
+/**
+ * Delete a given item
+ *
+ * @param item The item
+ *
+ * @ingroup Cabinet
+ */
+EAPI void
+elm_cabinet_item_del(Elm_Cabinet_Item *item)
+{
+       Widget_Data *wd;
+       Eina_List *l;
+       Elm_Cabinet_Item *_item;
+
+       if (!item) return;
+       wd = elm_widget_data_get(item->cabinet);
+       if (!wd) return;
+
+       EINA_LIST_FOREACH(wd->its, l, _item) {
+               if (_item == item) {
+                       wd->its = eina_list_remove_list(wd->its, l);
+                       if (wd->cur == l)
+                               wd->cur = wd->its;
+                       free(_item);
+                       break;
+               }
+       }
+}
+
+/**
+ * Get the label of a given item
+ *
+ * @param item The item
+ * @return The label of a given item, or NULL if none
+ *
+ * @ingroup Cabinet
+ */
+EAPI const char *
+elm_cabinet_item_label_get(Elm_Cabinet_Item *item)
+{
+       Widget_Data *wd;
+       Eina_List *l;
+       Elm_Cabinet_Item *_item;
+
+       if (!item) return NULL;
+       wd = elm_widget_data_get(item->cabinet);
+       if (!wd || !wd->its) return NULL;
+
+       EINA_LIST_FOREACH(wd->its, l, _item)
+               if (_item == item)
+                       return item->label;
+
+       return NULL;
+}
+
+/**
+ * Set the label of a given item
+ *
+ * @param item The item
+ * @param label The text label string in UTF-8
+ *
+ * @ingroup Cabinet
+ */
+EAPI void
+elm_cabinet_item_label_set(Elm_Cabinet_Item *item, const char *label)
+{
+       Widget_Data *wd;
+       Eina_List *l;
+       Elm_Cabinet_Item *_item;
+
+       if (!item || !label) return;
+       wd = elm_widget_data_get(item->cabinet);
+       if (!wd || !wd->its) return;
+
+       EINA_LIST_FOREACH(wd->its, l, _item)
+               if (_item == item) {
+                       eina_stringshare_del(item->label);
+                       item->label = eina_stringshare_add(label);
+               }
+}
+
+/**
+ * Get the sub info of a given item
+ *
+ * @param item The item
+ * @return The label of a given item, or NULL if none
+ *
+ * @ingroup Cabinet
+ */
+EAPI const char *
+elm_cabinet_item_sub_info_get(Elm_Cabinet_Item *item)
+{
+       Widget_Data *wd;
+       Eina_List *l;
+       Elm_Cabinet_Item *_item;
+
+       if (!item) return NULL;
+       wd = elm_widget_data_get(item->cabinet);
+       if (!wd || !wd->its) return NULL;
+
+       EINA_LIST_FOREACH(wd->its, l, _item)
+               if (_item == item)
+                       return item->sub_info;
+
+       return NULL;
+}
+
+/**
+ * Set the sub info of a given item
+ *
+ * @param item The item
+ * @param label The text label string in UTF-8
+ *
+ * @ingroup Cabinet
+ */
+EAPI void
+elm_cabinet_item_sub_info_set(Elm_Cabinet_Item *item, const char *sub_info)
+{
+       Widget_Data *wd;
+       Eina_List *l;
+       Elm_Cabinet_Item *_item;
+
+       if (!item || !sub_info) return;
+       wd = elm_widget_data_get(item->cabinet);
+       if (!wd || !wd->its) return;
+
+       EINA_LIST_FOREACH(wd->its, l, _item)
+               if (_item == item) {
+                       eina_stringshare_del(item->sub_info);
+                       item->sub_info = eina_stringshare_add(sub_info);
+               }
+}
+
+/**
+ * Get the previous item in the cabinet
+ *
+ * @param item The item
+ * @return The item before the item @p item
+ *
+ * @ingroup Cabinet
+ */
+EAPI Elm_Cabinet_Item *
+elm_cabinet_item_prev(Elm_Cabinet_Item *item)
+{
+       Widget_Data *wd;
+       Eina_List *l;
+       Elm_Cabinet_Item *_item;
+
+       if (!item) return NULL;
+       wd = elm_widget_data_get(item->cabinet);
+       if (!wd || !wd->its) return NULL;
+
+       EINA_LIST_FOREACH(wd->its, l, _item)
+               if (_item == item) {
+                       l = eina_list_prev(l);
+                       if (!l) return NULL;
+                       return eina_list_data_get(l);
+               }
+       return NULL;
+}
+
+/**
+ * Get the next item in the cabinet
+ *
+ * @param item The item
+ * @return The item after the item @p item
+ *
+ * @ingroup Cabinet
+ */
+EAPI Elm_Cabinet_Item *
+elm_cabinet_item_next(Elm_Cabinet_Item *item)
+{
+       Widget_Data *wd;
+       Eina_List *l;
+       Elm_Cabinet_Item *_item;
+
+       if (!item) return NULL;
+       wd = elm_widget_data_get(item->cabinet);
+       if (!wd || !wd->its) return NULL;
+
+       EINA_LIST_FOREACH(wd->its, l, _item)
+               if (_item == item) {
+                       l = eina_list_next(l);
+                       if (!l) return NULL;
+                       return eina_list_data_get(l);
+               }
+       return NULL;
+}
+
+/**
+ * Get private data of item
+ *
+ * @param item The item
+ * @return Private data of the item @p item
+ *
+ * @ingroup Cabinet
+ */
+EAPI void *
+elm_cabinet_item_data_get(Elm_Cabinet_Item *item)
+{
+       if (!item) return NULL;
+       return item->priv_data;
+}
+
+/**
+ * Set private data of item
+ *
+ * @param item The item
+ * @param data data
+ *
+ * @ingroup Cabinet
+ */
+EAPI void
+elm_cabinet_item_data_set(Elm_Cabinet_Item *item, void *data)
+{
+       if (!item) return;
+       item->priv_data = data;
+}
+
+EAPI Eina_Bool
+elm_cabinet_item_del_btn_disabled_get(Elm_Cabinet_Item *item)
+{
+       if (!item) return EINA_FALSE;
+       return item->btn_disabled ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+elm_cabinet_item_del_btn_disabled_set(Elm_Cabinet_Item *item, Eina_Bool disabled)
+{
+       if (!item) return;
+
+       if (item->btn_disabled == !!disabled) return;
+       item->btn_disabled = !!disabled;
+       _cells_update(item->cabinet);
+}
+
+EAPI Eina_Bool
+elm_cabinet_item_sub_info_disabled_get(Elm_Cabinet_Item *item)
+{
+       if (!item) return EINA_FALSE;
+       return item->info_disabled ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+elm_cabinet_item_sub_info_disabled_set(Elm_Cabinet_Item *item, Eina_Bool disabled)
+{
+       if (!item) return;
+       
+       if (item->info_disabled == !!disabled) return;
+       item->info_disabled = !!disabled;
+       _cells_update(item->cabinet);
+}