1 #include <Elementary.h>
6 #define MAX_ITEM_NUM (9)
7 #define MAX_MOVE_INTERVAL (0.2)
8 #define ELM_MAX(v1, v2) (((v1) > (v2)) ? (v1) : (v2))
11 #define MAX_SHOWN_ITEM (3)
13 struct _Stackedicon_Item
21 Evas_Coord x, y, w, h;
26 typedef struct _Widget_Data Widget_Data;
30 int interval_x, interval_y;
32 Ecore_Animator *animator;
34 Evas_Coord x, y, w, h;
38 Evas_Object *fake_img;
40 int mdx, mdy, mmx, mmy;
41 Eina_Bool move_start: 1;
45 static const char *widtype = NULL;
46 static void _del_hook(Evas_Object *obj);
47 static void _theme_hook(Evas_Object *obj);
48 static void _sizing_eval(Evas_Object *obj);
49 static void _del_image(void *data);
50 static void _del_all_image(void *data);
51 static unsigned int _current_time_get(void);
52 static void _icon_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
53 static void _icon_move_to_zero(Evas_Object *obj);
54 static Eina_Bool _icon_move_to_zero_cb(void *data);
55 static void _icon_move_map(void *data, int interval_x, int interval_y);
56 static void _icon_map_pos(Evas_Object *obj, int index, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h);
57 static void _calc_item_size(int w, int h, int iw, int ih, int *res_w, int *res_h);
58 static void _add_image(Evas_Object *obj, void *data);
59 static void _fake_img_mouse_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
60 static void _fake_img_mouse_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
61 static void _fake_img_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
62 static void _add_image_to_buffer(Evas_Object *obj, Evas* e, void *data);
63 static Evas_Object * _create_fake_image(Evas_Object *obj);
64 static void _show_all_image(Evas_Object *obj);
65 static void _hide_all_image(Evas_Object *obj);
66 static void _hide_hidden_image(Evas_Object *obj);
67 static void _update_stackedicon(Evas_Object *obj);
68 static void _resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
69 static void _move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
70 static void _show_cb(void *data, Evas * e, Evas_Object * obj, void *event_info);
71 static void _hide_cb(void *data, Evas * e, Evas_Object * obj, void *event_info);
72 static void _event_init(Evas_Object *obj);
75 _del_hook(Evas_Object *obj)
77 Widget_Data *wd = elm_widget_data_get(obj);
79 Elm_Stackedicon_Item *it;
84 ecore_animator_del(wd->animator);
92 EINA_LIST_FOREACH(wd->list, l, it)
94 eina_list_free(wd->list);
100 _theme_hook(Evas_Object *obj)
102 Widget_Data *wd = elm_widget_data_get(obj);
104 Elm_Stackedicon_Item *it;
107 _elm_theme_object_set(obj, wd->base, "stackedicon", "base", elm_widget_style_get(obj));
108 if (wd->fake_img) edje_object_part_swallow(wd->base, "elm.bg.swallow", wd->fake_img);
109 edje_object_scale_set(wd->base, elm_widget_scale_get(obj) * _elm_config->scale);
111 EINA_LIST_FOREACH(wd->list, l, it)
113 if (it->ly) _elm_theme_object_set(obj, it->ly, "stackedicon", "icon", elm_widget_style_get(obj));
114 if (it->ic) edje_object_part_swallow(it->ly, "contents", it->ic);
115 if (it->pad) edje_object_part_swallow(it->ly, "shadow", it->pad);
116 edje_object_scale_set(it->ly, elm_widget_scale_get(obj) * _elm_config->scale);
118 _update_stackedicon(obj);
123 _sizing_eval(Evas_Object *obj)
125 Widget_Data *wd = elm_widget_data_get(obj);
126 Evas_Coord minw = -1, minh = -1;
130 edje_object_size_min_restricted_calc(wd->base, &minw, &minh, minw, minh);
131 evas_object_size_hint_min_get(obj, &w, &h);
132 if (w > minw) minw = w;
133 if (h > minh) minh = h;
134 evas_object_size_hint_min_set(obj, minw, minh);
138 _del_image(void *data)
140 Elm_Stackedicon_Item *it = (Elm_Stackedicon_Item *)data;
144 evas_object_del(it->ly);
145 evas_object_del(it->ic);
146 evas_object_del(it->pad);
150 it->exist = EINA_FALSE;
155 _del_all_image(void *data)
157 Widget_Data *wd = (Widget_Data *)data;
159 Elm_Stackedicon_Item *it = NULL;
162 EINA_LIST_FOREACH(wd->list, l, it)
163 if (it && it->exist) _del_image(it);
167 _icon_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
169 Elm_Stackedicon_Item *it = data;
171 Widget_Data *wd = elm_widget_data_get(it->parent);
176 if (it->exist && it->ly)
178 evas_object_geometry_get(obj, &x, &y, NULL, NULL);
179 _icon_map_pos(it->ly, it->index, x, y, it->w, it->h);
184 _fake_img_mouse_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
186 Widget_Data *wd = elm_widget_data_get(data);
187 Evas_Event_Mouse_Down *ev = event_info;
189 Elm_Stackedicon_Item *it = NULL;
192 wd->mdx = ev->output.x;
193 wd->mdy = ev->output.y;
196 EINA_LIST_REVERSE_FOREACH(wd->list, l, it)
200 if (!it->exist) _add_image(data, it);
201 evas_object_move(it->ly, wd->x + wd->w/2 - it->mw/2, wd->y + wd->h/2 - it->mh/2);
202 if (wd->visible) evas_object_show(it->ly);
206 EINA_LIST_REVERSE_FOREACH(wd->list, l, it)
207 if (it && it->exist) evas_object_raise(it->ly);
209 evas_object_color_set(wd->fake_img, 0, 0, 0, 0);
210 wd->move_start = TRUE;
214 _fake_img_mouse_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
216 Widget_Data *wd = elm_widget_data_get(data);
217 Evas_Event_Mouse_Move *ev = event_info;
218 if (!wd || !ev->buttons) return;
220 if (wd->move_start == TRUE)
222 evas_object_smart_callback_call(data, "drag,start", NULL);
223 _show_all_image(data);
224 wd->move_start = FALSE;
227 wd->mmx = ev->cur.output.x;
228 wd->mmy = ev->cur.output.y;
230 wd->interval_x = wd->mmx - wd->mdx;
231 wd->interval_y = wd->mmy - wd->mdy;
233 _icon_move_map(wd, wd->x + wd->interval_x, wd->y + wd->interval_y);
237 _fake_img_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
239 Widget_Data *wd = elm_widget_data_get(data);
240 double interval = 0.0;
243 interval = sqrt(wd->interval_x*wd->interval_x + wd->interval_y*wd->interval_y);
245 if (((double)(interval/wd->h) > MAX_MOVE_INTERVAL))
250 _icon_move_map(wd, wd->x, wd->y);
251 _hide_hidden_image(data);
252 evas_object_smart_callback_call(data, "expanded", NULL);
253 evas_object_smart_callback_call(data, "drag,stop", NULL);
264 ecore_animator_del(wd->animator);
267 wd->time = _current_time_get();
268 wd->animator= ecore_animator_add(_icon_move_to_zero_cb, data);
273 _current_time_get(void)
275 struct timeval timev;
276 gettimeofday(&timev, NULL);
277 return ((timev.tv_sec * 1000) + ((timev.tv_usec) / 1000));
281 _icon_move_to_zero(Evas_Object *obj)
283 Widget_Data *wd = elm_widget_data_get(obj);
288 t = ELM_MAX(0.0, _current_time_get() - wd->time) / 100;
292 x = (1 * sin((t / 2.0) * (M_PI / 2)) * wd->interval_x);
293 y = (1 * sin((t / 2.0) * (M_PI / 2)) * wd->interval_y);
301 if ( y == wd->interval_y)
303 ecore_animator_del(wd->animator);
307 _icon_move_map(wd, wd->x, wd->y);
308 _hide_hidden_image(obj);
309 evas_object_smart_callback_call(obj, "clicked", NULL);
310 evas_object_smart_callback_call(obj, "drag,stop", NULL);
314 _icon_move_map(wd, wd->x + wd->interval_x - x, wd->y + wd->interval_y - y);
319 _icon_move_to_zero_cb(void *data)
321 Evas_Object *obj = (Evas_Object *)data;
322 _icon_move_to_zero(obj);
328 _icon_move_map(void *data, int interval_x, int interval_y)
330 Widget_Data *wd = (Widget_Data *)data;
335 num = eina_list_count(wd->list);
337 for (i =0; i < num; i++)
339 Elm_Stackedicon_Item *it = NULL;
340 it = (Elm_Stackedicon_Item *)eina_list_nth(wd->list, i);
344 x = wd->x + wd->w/2 - it->mw/2 + ((interval_x - wd->x)/num)*(num -i);
345 y = wd->y + wd->h/2 - it->mh/2 + ((interval_y - wd->y)/num)*(num -i);
346 evas_object_move(it->ly, x, y);
352 _icon_map_pos(Evas_Object *obj, int index, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
357 if ((index % 3) == 1)
359 else if ((index % 3) == 2)
363 evas_map_util_points_populate_from_geometry(m, x, y, w, h, 0);
364 evas_map_util_3d_rotate(m, 0, 0, degree, x + w/2, y + h/2, 0);
365 evas_map_util_3d_perspective(m, x + w/2, y + h/2, 0, 10000);
366 evas_map_smooth_set(m, 1);
367 evas_map_alpha_set(m, 1);
368 evas_object_map_set(obj, m);
369 evas_object_map_enable_set(obj, 1);
374 _calc_item_size(int w, int h, int iw, int ih, int *res_w, int *res_h)
394 *res_h = w*h/(h*iw/ih);
405 _add_image(Evas_Object *obj, void *data)
407 Widget_Data *wd = elm_widget_data_get(obj);
408 Elm_Stackedicon_Item *it = (Elm_Stackedicon_Item *)data;
409 Evas_Object *ly = NULL;
410 Evas_Object *ic = NULL;
411 Evas_Object *pad = NULL;
413 if (!wd || !it) return;
415 ly = edje_object_add(evas_object_evas_get(obj));
417 _elm_theme_object_set(obj, ly, "stackedicon", "icon", elm_widget_style_get(obj));
418 evas_object_size_hint_weight_set(ly, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
419 elm_widget_sub_object_add(obj, ly);
421 ic = evas_object_image_add(evas_object_evas_get(obj));
423 evas_object_image_load_size_set(ic, wd->w/2, wd->h/2);
424 evas_object_image_file_set(ic, it->path, NULL);
425 evas_object_image_size_get(ic, &iw, &ih);
426 if (!iw || !ih) return;
428 _calc_item_size(wd->w - 2, wd->h - 2, iw, ih, &it->w, &it->h);
430 evas_object_image_fill_set(ic, 0, 0, it->w, it->h);
431 evas_object_size_hint_min_set(ly, it->w, it->h);
432 evas_object_resize(ly, it->w, it->h);
434 evas_object_image_filled_set(ic, 1);
435 edje_object_part_swallow(ly, "contents", ic);
437 pad = evas_object_rectangle_add(evas_object_evas_get(obj));
439 evas_object_size_hint_align_set(pad, EVAS_HINT_FILL, EVAS_HINT_FILL);
440 evas_object_color_set(pad, 0, 0, 0, it->index*25);
441 edje_object_part_swallow(ly, "shadow", pad);
443 evas_object_event_callback_add(ly, EVAS_CALLBACK_MOVE, _icon_move_cb, it);
450 it->exist = EINA_TRUE;
454 _add_image_to_buffer(Evas_Object *obj, Evas* e, void *data)
456 Widget_Data *wd = elm_widget_data_get(obj);
457 Elm_Stackedicon_Item *it = (Elm_Stackedicon_Item *)data;
458 Evas_Object *ly = NULL;
459 Evas_Object *ic = NULL;
460 int iw, ih, res_w, res_h;
461 if (!wd || !it) return;
463 // FIXME: add an opaque rectangle because of alpha bug of evas_map.
464 Evas_Object* rect = evas_object_rectangle_add( e );
466 evas_object_resize( rect, 1, 1);
467 evas_object_move(rect, wd->w/2, wd->h/2);
468 evas_object_color_set( rect, 0, 0, 0, 255 );
469 evas_object_show( rect );
471 ly = edje_object_add(e);
473 _elm_theme_object_set(obj, ly, "stackedicon", "icon", elm_widget_style_get(obj));
474 evas_object_size_hint_weight_set(ly, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
476 ic = evas_object_image_add(e);
478 evas_object_image_alpha_set(ic, EINA_TRUE);
479 evas_object_image_load_size_set(ic, wd->w/2, wd->h/2);
480 evas_object_image_file_set(ic, it->path, NULL);
481 evas_object_image_size_get(ic, &iw, &ih);
482 if (!iw || !ih) return;
484 _calc_item_size(wd->w - 2, wd->h - 2, iw, ih, &res_w, &res_h);
486 evas_object_image_fill_set(ic, 0, 0, res_w, res_h);
487 evas_object_image_filled_set(ic, 1);
488 edje_object_part_swallow(ly, "contents", ic);
490 evas_object_resize(ly, res_w, res_h);
491 evas_object_move(ly, (wd->w - res_w)/2, (wd->h - res_h)/2);
492 evas_object_show(ly);
494 _icon_map_pos(ly, it->index, (wd->w - res_w)/2, (wd->h - res_h)/2, res_w, res_h);
498 _create_fake_image(Evas_Object *obj)
500 Widget_Data *wd = elm_widget_data_get(obj);
501 Evas_Object *eo = NULL;
503 Elm_Stackedicon_Item *it = NULL;
504 if (!wd) return NULL;
507 eo = evas_object_image_add(evas_object_evas_get(obj));
508 if (!eo) return NULL;
509 elm_widget_sub_object_add(obj, eo);
510 evas_object_image_alpha_set(eo,EINA_TRUE);
511 evas_object_image_data_set(eo, NULL);
512 evas_object_image_size_set(eo, wd->w, wd->h);
513 evas_object_image_fill_set(eo, 0, 0, wd->w, wd->h);
514 edje_object_part_swallow(wd->base, "elm.bg.swallow", eo);
516 // create ecore_evas (buffer)
517 Ecore_Evas* ee = ecore_evas_buffer_new( wd->w, wd->h );
518 Evas* e = ecore_evas_get( ee );
521 EINA_LIST_REVERSE_FOREACH(wd->list, l, it)
525 if (it->index >= MAX_SHOWN_ITEM) continue;
526 _add_image_to_buffer(obj, e, it);
529 ecore_evas_show( ee );
532 // copy buffer to data(mem)
533 unsigned char* data = (unsigned char*) calloc( 1, sizeof( unsigned char ) * 4 * wd->w * wd->h );
534 memcpy( data, (unsigned char*) ecore_evas_buffer_pixels_get( ee ), sizeof( unsigned char ) * 4 * wd->w * wd->h );
535 ecore_evas_free( ee );
537 // copy data to fake_img
538 evas_object_image_data_copy_set(eo, data);
539 evas_object_image_data_update_add(eo, 0, 0, wd->w, wd->h);
540 evas_object_resize(eo, wd->w, wd->h);
542 evas_object_color_get(eo, &wd->r, &wd->g, &wd->b, &wd->a);
544 // add mouse events callback
545 evas_object_event_callback_add(eo, EVAS_CALLBACK_MOUSE_DOWN, _fake_img_mouse_down_cb, obj);
546 evas_object_event_callback_add(eo, EVAS_CALLBACK_MOUSE_MOVE, _fake_img_mouse_move_cb, obj);
547 evas_object_event_callback_add(eo, EVAS_CALLBACK_MOUSE_UP, _fake_img_mouse_up_cb, obj);
553 _update_stackedicon(Evas_Object *obj)
555 Widget_Data *wd = elm_widget_data_get(obj);
556 if (!wd || ((wd->w == 1) && (wd->h == 1))) return;
560 wd->fake_img = _create_fake_image(obj);
562 else if (wd->on_update)
564 wd->on_update = FALSE;
565 elm_widget_sub_object_del(obj, wd->fake_img);
566 edje_object_part_unswallow(wd->base, wd->fake_img);
567 evas_object_del(wd->fake_img);
569 wd->fake_img = _create_fake_image(obj);
573 static void _show_all_image(Evas_Object *obj)
575 Widget_Data *wd = elm_widget_data_get(obj);
579 for (i =0; i < eina_list_count (wd->list); i++)
581 Elm_Stackedicon_Item *it = NULL;
582 it = (Elm_Stackedicon_Item *)eina_list_nth(wd->list, i);
586 if (it->exist == EINA_TRUE)
588 evas_object_show(it->ly);
594 static void _hide_all_image(Evas_Object *obj)
596 Widget_Data *wd = elm_widget_data_get(obj);
600 for (i =0; i < eina_list_count (wd->list); i++)
602 Elm_Stackedicon_Item *it = NULL;
603 it = (Elm_Stackedicon_Item *)eina_list_nth(wd->list, i);
607 if (it->exist == EINA_TRUE)
609 evas_object_hide(it->ly);
615 static void _hide_hidden_image(Evas_Object *obj)
617 Widget_Data *wd = elm_widget_data_get(obj);
619 Elm_Stackedicon_Item *it = NULL;
622 EINA_LIST_REVERSE_FOREACH(wd->list, l, it)
624 if (it->ly) evas_object_hide(it->ly);
626 evas_object_color_set(wd->fake_img, wd->r, wd->g, wd->b, wd->a);
630 _resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
632 Widget_Data *wd = elm_widget_data_get(data);
636 evas_object_geometry_get(obj, NULL, NULL, &w, &h);
640 _update_stackedicon(data);
644 _move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
646 Widget_Data *wd = elm_widget_data_get(data);
650 evas_object_geometry_get(obj, &x, &y, NULL, NULL);
654 _update_stackedicon(data);
658 _show_cb(void *data, Evas * e, Evas_Object * obj, void *event_info)
660 Widget_Data *wd = elm_widget_data_get(data);
663 wd->visible = EINA_TRUE;
664 _update_stackedicon(data);
668 _hide_cb(void *data, Evas * e, Evas_Object * obj, void *event_info)
670 Widget_Data *wd = elm_widget_data_get(data);
673 wd->visible = EINA_FALSE;
674 _hide_all_image(data);
678 _event_init(Evas_Object *obj)
680 Widget_Data *wd = elm_widget_data_get(obj);
683 evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize_cb, obj);
684 evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _move_cb, obj);
685 evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _show_cb, obj);
686 evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _hide_cb, obj);
690 elm_stackedicon_add(Evas_Object *parent)
696 wd = ELM_NEW(Widget_Data);
697 e = evas_object_evas_get(parent);
698 obj = elm_widget_add(e);
699 ELM_SET_WIDTYPE(widtype, "stackedicon");
700 elm_widget_type_set(obj, "stackedicon");
701 elm_widget_sub_object_add(parent, obj);
702 elm_widget_data_set(obj, wd);
704 elm_widget_del_hook_set(obj, _del_hook);
705 elm_widget_theme_hook_set(obj, _theme_hook);
707 wd->base = edje_object_add(e);
708 _elm_theme_object_set(obj, wd->base, "stackedicon", "base", "default");
709 elm_widget_resize_object_set(obj, wd->base);
720 EAPI Elm_Stackedicon_Item *elm_stackedicon_item_append(Evas_Object *obj, const char *path)
722 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
723 Widget_Data *wd = elm_widget_data_get(obj);
724 Elm_Stackedicon_Item *it;
725 if (!wd) return NULL;
726 if (eina_list_count(wd->list) >= MAX_ITEM_NUM) return NULL;
728 it = (Elm_Stackedicon_Item *)calloc(1, sizeof(Elm_Stackedicon_Item));
729 it->path = eina_stringshare_add(path);
734 it->index = eina_list_count(wd->list);
735 it->exist = EINA_FALSE;
736 wd->list = eina_list_append(wd->list, it);
738 if (it->index < MAX_SHOWN_ITEM)
740 wd->on_update = TRUE;
741 _update_stackedicon(obj);
747 EAPI Elm_Stackedicon_Item *elm_stackedicon_item_prepend(Evas_Object *obj, const char *path)
749 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
750 Widget_Data *wd = elm_widget_data_get(obj);
751 Elm_Stackedicon_Item *it;
752 if (!wd) return NULL;
753 if (eina_list_count(wd->list) >= MAX_ITEM_NUM) return NULL;
755 it = (Elm_Stackedicon_Item *)calloc(1, sizeof(Elm_Stackedicon_Item));
756 it->path = eina_stringshare_add(path);
761 it->index = eina_list_count(wd->list);
762 it->exist = EINA_FALSE;
763 wd->list = eina_list_prepend(wd->list, it);
765 if (it->index < MAX_SHOWN_ITEM)
767 wd->on_update = TRUE;
768 _update_stackedicon(obj);
774 EAPI void elm_stackedicon_item_del(Elm_Stackedicon_Item *it)
777 ELM_CHECK_WIDTYPE(it->parent, widtype);
778 Evas_Object *obj = it->parent;
779 Widget_Data *wd = elm_widget_data_get(obj);
781 Elm_Stackedicon_Item *_it = NULL;
785 if (it->index < MAX_SHOWN_ITEM) wd->on_update = TRUE;
787 if (it->exist == EINA_TRUE) _del_image(it);
788 wd->list = eina_list_remove(wd->list, it);
791 EINA_LIST_FOREACH(wd->list, l, _it)
792 if (_it->ly) _it->index = i++;
794 _update_stackedicon(obj);
797 EAPI Eina_List *elm_stackedicon_item_list_get(Evas_Object *obj)
799 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
800 Widget_Data *wd = elm_widget_data_get(obj);
801 if (!wd) return NULL;