1 #include <Elementary.h>
6 * @defgroup Stackedicon Stackedicon
9 * This is a Stackedicon.
13 #define MAX_ITEM_NUM (9)
14 #define MAX_MOVE_INTERVAL (0.2)
15 #define ELM_MAX(v1, v2) (((v1) > (v2)) ? (v1) : (v2))
18 #define MAX_SHOWN_ITEM (3)
20 struct _Stackedicon_Item
28 Evas_Coord x, y, w, h;
33 typedef struct _Widget_Data Widget_Data;
37 int interval_x, interval_y;
39 Ecore_Animator *animator;
41 Evas_Coord x, y, w, h;
45 Evas_Object *fake_img;
47 int mdx, mdy, mmx, mmy;
48 Eina_Bool move_start: 1;
52 static const char *widtype = NULL;
53 static void _del_hook(Evas_Object *obj);
54 static void _theme_hook(Evas_Object *obj);
55 static void _sizing_eval(Evas_Object *obj);
56 static void _del_image(void *data);
57 static void _del_all_image(void *data);
58 static unsigned int _current_time_get(void);
59 static void _icon_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
60 static void _icon_move_to_zero(Evas_Object *obj);
61 static Eina_Bool _icon_move_to_zero_cb(void *data);
62 static void _icon_move_map(void *data, int interval_x, int interval_y);
63 static void _icon_map_pos(Evas_Object *obj, int index, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h);
64 static void _calc_item_size(int w, int h, int iw, int ih, int *res_w, int *res_h);
65 static void _add_image(Evas_Object *obj, void *data);
66 static void _fake_img_mouse_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
67 static void _fake_img_mouse_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
68 static void _fake_img_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
69 static void _add_image_to_buffer(Evas_Object *obj, Evas* e, void *data);
70 static Evas_Object * _create_fake_image(Evas_Object *obj);
71 static void _show_all_image(Evas_Object *obj);
72 static void _hide_all_image(Evas_Object *obj);
73 static void _hide_hidden_image(Evas_Object *obj);
74 static void _update_stackedicon(Evas_Object *obj);
75 static void _resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
76 static void _move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
77 static void _show_cb(void *data, Evas * e, Evas_Object * obj, void *event_info);
78 static void _hide_cb(void *data, Evas * e, Evas_Object * obj, void *event_info);
79 static void _event_init(Evas_Object *obj);
82 _del_hook(Evas_Object *obj)
84 Widget_Data *wd = elm_widget_data_get(obj);
86 Elm_Stackedicon_Item *it;
91 ecore_animator_del(wd->animator);
99 EINA_LIST_FOREACH(wd->list, l, it)
101 eina_list_free(wd->list);
107 _theme_hook(Evas_Object *obj)
109 Widget_Data *wd = elm_widget_data_get(obj);
111 Elm_Stackedicon_Item *it;
114 _elm_theme_object_set(obj, wd->base, "stackedicon", "base", elm_widget_style_get(obj));
115 if (wd->fake_img) edje_object_part_swallow(wd->base, "elm.bg.swallow", wd->fake_img);
116 edje_object_scale_set(wd->base, elm_widget_scale_get(obj) * _elm_config->scale);
118 EINA_LIST_FOREACH(wd->list, l, it)
120 if (it->ly) _elm_theme_object_set(obj, it->ly, "stackedicon", "icon", elm_widget_style_get(obj));
121 if (it->ic) edje_object_part_swallow(it->ly, "contents", it->ic);
122 if (it->pad) edje_object_part_swallow(it->ly, "shadow", it->pad);
123 edje_object_scale_set(it->ly, elm_widget_scale_get(obj) * _elm_config->scale);
125 _update_stackedicon(obj);
130 _sizing_eval(Evas_Object *obj)
132 Widget_Data *wd = elm_widget_data_get(obj);
133 Evas_Coord minw = -1, minh = -1;
137 edje_object_size_min_restricted_calc(wd->base, &minw, &minh, minw, minh);
138 evas_object_size_hint_min_get(obj, &w, &h);
139 if (w > minw) minw = w;
140 if (h > minh) minh = h;
141 evas_object_size_hint_min_set(obj, minw, minh);
145 _del_image(void *data)
147 Elm_Stackedicon_Item *it = (Elm_Stackedicon_Item *)data;
151 evas_object_del(it->ly);
152 evas_object_del(it->ic);
153 evas_object_del(it->pad);
157 it->exist = EINA_FALSE;
162 _del_all_image(void *data)
164 Widget_Data *wd = (Widget_Data *)data;
166 Elm_Stackedicon_Item *it = NULL;
169 EINA_LIST_FOREACH(wd->list, l, it)
170 if (it && it->exist) _del_image(it);
174 _icon_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
176 Elm_Stackedicon_Item *it = data;
178 Widget_Data *wd = elm_widget_data_get(it->parent);
183 if (it->exist && it->ly)
185 evas_object_geometry_get(obj, &x, &y, NULL, NULL);
186 _icon_map_pos(it->ly, it->index, x, y, it->w, it->h);
191 _fake_img_mouse_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
193 Widget_Data *wd = elm_widget_data_get(data);
194 Evas_Event_Mouse_Down *ev = event_info;
196 Elm_Stackedicon_Item *it = NULL;
199 wd->mdx = ev->output.x;
200 wd->mdy = ev->output.y;
203 EINA_LIST_REVERSE_FOREACH(wd->list, l, it)
207 if (!it->exist) _add_image(data, it);
208 evas_object_move(it->ly, wd->x + wd->w/2 - it->mw/2, wd->y + wd->h/2 - it->mh/2);
209 if (wd->visible) evas_object_show(it->ly);
213 EINA_LIST_REVERSE_FOREACH(wd->list, l, it)
214 if (it && it->exist) evas_object_raise(it->ly);
216 evas_object_color_set(wd->fake_img, 0, 0, 0, 0);
217 wd->move_start = TRUE;
221 _fake_img_mouse_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
223 Widget_Data *wd = elm_widget_data_get(data);
224 Evas_Event_Mouse_Move *ev = event_info;
225 if (!wd || !ev->buttons) return;
227 if (wd->move_start == TRUE)
229 evas_object_smart_callback_call(data, "drag,start", NULL);
230 _show_all_image(data);
231 wd->move_start = FALSE;
234 wd->mmx = ev->cur.output.x;
235 wd->mmy = ev->cur.output.y;
237 wd->interval_x = wd->mmx - wd->mdx;
238 wd->interval_y = wd->mmy - wd->mdy;
240 _icon_move_map(wd, wd->x + wd->interval_x, wd->y + wd->interval_y);
244 _fake_img_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
246 Widget_Data *wd = elm_widget_data_get(data);
247 double interval = 0.0;
250 interval = sqrt(wd->interval_x*wd->interval_x + wd->interval_y*wd->interval_y);
252 if (((double)(interval/wd->h) > MAX_MOVE_INTERVAL))
257 _icon_move_map(wd, wd->x, wd->y);
258 _hide_hidden_image(data);
259 evas_object_smart_callback_call(data, "expanded", NULL);
260 evas_object_smart_callback_call(data, "drag,stop", NULL);
271 ecore_animator_del(wd->animator);
274 wd->time = _current_time_get();
275 wd->animator= ecore_animator_add(_icon_move_to_zero_cb, data);
280 _current_time_get(void)
282 struct timeval timev;
283 gettimeofday(&timev, NULL);
284 return ((timev.tv_sec * 1000) + ((timev.tv_usec) / 1000));
288 _icon_move_to_zero(Evas_Object *obj)
290 Widget_Data *wd = elm_widget_data_get(obj);
295 t = ELM_MAX(0.0, _current_time_get() - wd->time) / 100;
299 x = (1 * sin((t / 2.0) * (M_PI / 2)) * wd->interval_x);
300 y = (1 * sin((t / 2.0) * (M_PI / 2)) * wd->interval_y);
308 if ( y == wd->interval_y)
310 ecore_animator_del(wd->animator);
314 _icon_move_map(wd, wd->x, wd->y);
315 _hide_hidden_image(obj);
316 evas_object_smart_callback_call(obj, "clicked", NULL);
317 evas_object_smart_callback_call(obj, "drag,stop", NULL);
321 _icon_move_map(wd, wd->x + wd->interval_x - x, wd->y + wd->interval_y - y);
326 _icon_move_to_zero_cb(void *data)
328 Evas_Object *obj = (Evas_Object *)data;
329 _icon_move_to_zero(obj);
335 _icon_move_map(void *data, int interval_x, int interval_y)
337 Widget_Data *wd = (Widget_Data *)data;
342 num = eina_list_count(wd->list);
344 for (i =0; i < num; i++)
346 Elm_Stackedicon_Item *it = NULL;
347 it = (Elm_Stackedicon_Item *)eina_list_nth(wd->list, i);
351 x = wd->x + wd->w/2 - it->mw/2 + ((interval_x - wd->x)/num)*(num -i);
352 y = wd->y + wd->h/2 - it->mh/2 + ((interval_y - wd->y)/num)*(num -i);
353 evas_object_move(it->ly, x, y);
359 _icon_map_pos(Evas_Object *obj, int index, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
364 if ((index % 3) == 1)
366 else if ((index % 3) == 2)
370 evas_map_util_points_populate_from_geometry(m, x, y, w, h, 0);
371 evas_map_util_3d_rotate(m, 0, 0, degree, x + w/2, y + h/2, 0);
372 evas_map_util_3d_perspective(m, x + w/2, y + h/2, 0, 10000);
373 evas_map_smooth_set(m, 1);
374 evas_map_alpha_set(m, 1);
375 evas_object_map_set(obj, m);
376 evas_object_map_enable_set(obj, 1);
381 _calc_item_size(int w, int h, int iw, int ih, int *res_w, int *res_h)
401 *res_h = w*h/(h*iw/ih);
412 _add_image(Evas_Object *obj, void *data)
414 Widget_Data *wd = elm_widget_data_get(obj);
415 Elm_Stackedicon_Item *it = (Elm_Stackedicon_Item *)data;
416 Evas_Object *ly = NULL;
417 Evas_Object *ic = NULL;
418 Evas_Object *pad = NULL;
420 if (!wd || !it) return;
422 ly = edje_object_add(evas_object_evas_get(obj));
424 _elm_theme_object_set(obj, ly, "stackedicon", "icon", elm_widget_style_get(obj));
425 evas_object_size_hint_weight_set(ly, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
426 elm_widget_sub_object_add(obj, ly);
428 ic = evas_object_image_add(evas_object_evas_get(obj));
430 evas_object_image_load_size_set(ic, wd->w/2, wd->h/2);
431 evas_object_image_file_set(ic, it->path, NULL);
432 evas_object_image_size_get(ic, &iw, &ih);
433 if (!iw || !ih) return;
435 _calc_item_size(wd->w - 2, wd->h - 2, iw, ih, &it->w, &it->h);
437 evas_object_image_fill_set(ic, 0, 0, it->w, it->h);
438 evas_object_size_hint_min_set(ly, it->w, it->h);
439 evas_object_resize(ly, it->w, it->h);
441 evas_object_image_filled_set(ic, 1);
442 edje_object_part_swallow(ly, "contents", ic);
444 pad = evas_object_rectangle_add(evas_object_evas_get(obj));
446 evas_object_size_hint_align_set(pad, EVAS_HINT_FILL, EVAS_HINT_FILL);
447 evas_object_color_set(pad, 0, 0, 0, it->index*25);
448 edje_object_part_swallow(ly, "shadow", pad);
450 evas_object_event_callback_add(ly, EVAS_CALLBACK_MOVE, _icon_move_cb, it);
457 it->exist = EINA_TRUE;
461 _add_image_to_buffer(Evas_Object *obj, Evas* e, void *data)
463 Widget_Data *wd = elm_widget_data_get(obj);
464 Elm_Stackedicon_Item *it = (Elm_Stackedicon_Item *)data;
465 Evas_Object *ly = NULL;
466 Evas_Object *ic = NULL;
467 int iw, ih, res_w, res_h;
468 if (!wd || !it) return;
470 // FIXME: add an opaque rectangle because of alpha bug of evas_map.
471 Evas_Object* rect = evas_object_rectangle_add( e );
473 evas_object_resize( rect, 1, 1);
474 evas_object_move(rect, wd->w/2, wd->h/2);
475 evas_object_color_set( rect, 0, 0, 0, 255 );
476 evas_object_show( rect );
478 ly = edje_object_add(e);
480 _elm_theme_object_set(obj, ly, "stackedicon", "icon", elm_widget_style_get(obj));
481 evas_object_size_hint_weight_set(ly, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
483 ic = evas_object_image_add(e);
485 evas_object_image_alpha_set(ic, EINA_TRUE);
486 evas_object_image_load_size_set(ic, wd->w/2, wd->h/2);
487 evas_object_image_file_set(ic, it->path, NULL);
488 evas_object_image_size_get(ic, &iw, &ih);
489 if (!iw || !ih) return;
491 _calc_item_size(wd->w - 2, wd->h - 2, iw, ih, &res_w, &res_h);
493 evas_object_image_fill_set(ic, 0, 0, res_w, res_h);
494 evas_object_image_filled_set(ic, 1);
495 edje_object_part_swallow(ly, "contents", ic);
497 evas_object_resize(ly, res_w, res_h);
498 evas_object_move(ly, (wd->w - res_w)/2, (wd->h - res_h)/2);
499 evas_object_show(ly);
501 _icon_map_pos(ly, it->index, (wd->w - res_w)/2, (wd->h - res_h)/2, res_w, res_h);
505 _create_fake_image(Evas_Object *obj)
507 Widget_Data *wd = elm_widget_data_get(obj);
508 Evas_Object *eo = NULL;
510 Elm_Stackedicon_Item *it = NULL;
511 if (!wd) return NULL;
514 eo = evas_object_image_add(evas_object_evas_get(obj));
515 if (!eo) return NULL;
516 elm_widget_sub_object_add(obj, eo);
517 evas_object_image_alpha_set(eo,EINA_TRUE);
518 evas_object_image_data_set(eo, NULL);
519 evas_object_image_size_set(eo, wd->w, wd->h);
520 evas_object_image_fill_set(eo, 0, 0, wd->w, wd->h);
521 edje_object_part_swallow(wd->base, "elm.bg.swallow", eo);
523 // create ecore_evas (buffer)
524 Ecore_Evas* ee = ecore_evas_buffer_new( wd->w, wd->h );
525 Evas* e = ecore_evas_get( ee );
528 EINA_LIST_REVERSE_FOREACH(wd->list, l, it)
532 if (it->index >= MAX_SHOWN_ITEM) continue;
533 _add_image_to_buffer(obj, e, it);
536 ecore_evas_show( ee );
539 // copy buffer to data(mem)
540 unsigned char* data = (unsigned char*) calloc( 1, sizeof( unsigned char ) * 4 * wd->w * wd->h );
541 memcpy( data, (unsigned char*) ecore_evas_buffer_pixels_get( ee ), sizeof( unsigned char ) * 4 * wd->w * wd->h );
542 ecore_evas_free( ee );
544 // copy data to fake_img
545 evas_object_image_data_copy_set(eo, data);
546 evas_object_image_data_update_add(eo, 0, 0, wd->w, wd->h);
547 evas_object_resize(eo, wd->w, wd->h);
549 evas_object_color_get(eo, &wd->r, &wd->g, &wd->b, &wd->a);
551 // add mouse events callback
552 evas_object_event_callback_add(eo, EVAS_CALLBACK_MOUSE_DOWN, _fake_img_mouse_down_cb, obj);
553 evas_object_event_callback_add(eo, EVAS_CALLBACK_MOUSE_MOVE, _fake_img_mouse_move_cb, obj);
554 evas_object_event_callback_add(eo, EVAS_CALLBACK_MOUSE_UP, _fake_img_mouse_up_cb, obj);
560 _update_stackedicon(Evas_Object *obj)
562 Widget_Data *wd = elm_widget_data_get(obj);
563 if (!wd || ((wd->w == 1) && (wd->h == 1))) return;
567 wd->fake_img = _create_fake_image(obj);
569 else if (wd->on_update)
571 wd->on_update = FALSE;
572 elm_widget_sub_object_del(obj, wd->fake_img);
573 edje_object_part_unswallow(wd->base, wd->fake_img);
574 evas_object_del(wd->fake_img);
576 wd->fake_img = _create_fake_image(obj);
580 static void _show_all_image(Evas_Object *obj)
582 Widget_Data *wd = elm_widget_data_get(obj);
586 for (i =0; i < eina_list_count (wd->list); i++)
588 Elm_Stackedicon_Item *it = NULL;
589 it = (Elm_Stackedicon_Item *)eina_list_nth(wd->list, i);
593 if (it->exist == EINA_TRUE)
595 evas_object_show(it->ly);
601 static void _hide_all_image(Evas_Object *obj)
603 Widget_Data *wd = elm_widget_data_get(obj);
607 for (i =0; i < eina_list_count (wd->list); i++)
609 Elm_Stackedicon_Item *it = NULL;
610 it = (Elm_Stackedicon_Item *)eina_list_nth(wd->list, i);
614 if (it->exist == EINA_TRUE)
616 evas_object_hide(it->ly);
622 static void _hide_hidden_image(Evas_Object *obj)
624 Widget_Data *wd = elm_widget_data_get(obj);
626 Elm_Stackedicon_Item *it = NULL;
629 EINA_LIST_REVERSE_FOREACH(wd->list, l, it)
631 if (it->ly) evas_object_hide(it->ly);
633 evas_object_color_set(wd->fake_img, wd->r, wd->g, wd->b, wd->a);
637 _resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
639 Widget_Data *wd = elm_widget_data_get(data);
643 evas_object_geometry_get(obj, NULL, NULL, &w, &h);
647 _update_stackedicon(data);
651 _move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
653 Widget_Data *wd = elm_widget_data_get(data);
657 evas_object_geometry_get(obj, &x, &y, NULL, NULL);
661 _update_stackedicon(data);
665 _show_cb(void *data, Evas * e, Evas_Object * obj, void *event_info)
667 Widget_Data *wd = elm_widget_data_get(data);
670 wd->visible = EINA_TRUE;
671 _update_stackedicon(data);
675 _hide_cb(void *data, Evas * e, Evas_Object * obj, void *event_info)
677 Widget_Data *wd = elm_widget_data_get(data);
680 wd->visible = EINA_FALSE;
681 _hide_all_image(data);
685 _event_init(Evas_Object *obj)
687 Widget_Data *wd = elm_widget_data_get(obj);
690 evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize_cb, obj);
691 evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _move_cb, obj);
692 evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _show_cb, obj);
693 evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _hide_cb, obj);
697 * Add a new stackedicon to the parent
699 * @param parent The parent object
700 * @return The new object or NULL if it cannot be created
702 * @ingroup Stackedicon
705 elm_stackedicon_add(Evas_Object *parent)
711 wd = ELM_NEW(Widget_Data);
712 e = evas_object_evas_get(parent);
713 obj = elm_widget_add(e);
714 ELM_SET_WIDTYPE(widtype, "stackedicon");
715 elm_widget_type_set(obj, "stackedicon");
716 elm_widget_sub_object_add(parent, obj);
717 elm_widget_data_set(obj, wd);
719 elm_widget_del_hook_set(obj, _del_hook);
720 elm_widget_theme_hook_set(obj, _theme_hook);
722 wd->base = edje_object_add(e);
723 _elm_theme_object_set(obj, wd->base, "stackedicon", "base", "default");
724 elm_widget_resize_object_set(obj, wd->base);
736 * This appends a path to the stackedicon
738 * @param obj The stackedicon object
739 * @param path The image full path
740 * @return The new item or NULL if it cannot be created
742 * @ingroup Stackedicon
744 EAPI Elm_Stackedicon_Item *elm_stackedicon_item_append(Evas_Object *obj, const char *path)
746 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
747 Widget_Data *wd = elm_widget_data_get(obj);
748 Elm_Stackedicon_Item *it;
749 if (!wd) return NULL;
750 if (eina_list_count(wd->list) >= MAX_ITEM_NUM) return NULL;
752 it = (Elm_Stackedicon_Item *)calloc(1, sizeof(Elm_Stackedicon_Item));
753 it->path = eina_stringshare_add(path);
758 it->index = eina_list_count(wd->list);
759 it->exist = EINA_FALSE;
760 wd->list = eina_list_append(wd->list, it);
762 if (it->index < MAX_SHOWN_ITEM)
764 wd->on_update = TRUE;
765 _update_stackedicon(obj);
772 * This prepends a path to the stackedicon
774 * @param obj The stackedicon object
775 * @param path The image full path
776 * @return The new item or NULL if it cannot be created
778 * @ingroup Stackedicon
780 EAPI Elm_Stackedicon_Item *elm_stackedicon_item_prepend(Evas_Object *obj, const char *path)
782 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
783 Widget_Data *wd = elm_widget_data_get(obj);
784 Elm_Stackedicon_Item *it;
785 if (!wd) return NULL;
786 if (eina_list_count(wd->list) >= MAX_ITEM_NUM) return NULL;
788 it = (Elm_Stackedicon_Item *)calloc(1, sizeof(Elm_Stackedicon_Item));
789 it->path = eina_stringshare_add(path);
794 it->index = eina_list_count(wd->list);
795 it->exist = EINA_FALSE;
796 wd->list = eina_list_prepend(wd->list, it);
798 if (it->index < MAX_SHOWN_ITEM)
800 wd->on_update = TRUE;
801 _update_stackedicon(obj);
808 * This delete a path at the stackedicon
810 * @param Elm_Stackedicon_Item The delete item
812 * @ingroup Stackedicon
814 EAPI void elm_stackedicon_item_del(Elm_Stackedicon_Item *it)
817 ELM_CHECK_WIDTYPE(it->parent, widtype);
818 Evas_Object *obj = it->parent;
819 Widget_Data *wd = elm_widget_data_get(obj);
821 Elm_Stackedicon_Item *_it = NULL;
825 if (it->index < MAX_SHOWN_ITEM) wd->on_update = TRUE;
827 if (it->exist == EINA_TRUE) _del_image(it);
828 wd->list = eina_list_remove(wd->list, it);
831 EINA_LIST_FOREACH(wd->list, l, _it)
832 if (_it->ly) _it->index = i++;
834 _update_stackedicon(obj);
838 * Get item list from the stackedicon
840 * @param obj The stackedicon object
841 * @return The item list or NULL if it cannot be created
843 * @ingroup Stackedicon
845 EAPI Eina_List *elm_stackedicon_item_list_get(Evas_Object *obj)
847 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
848 Widget_Data *wd = elm_widget_data_get(obj);
849 if (!wd) return NULL;