1 #include <Elementary.h>
7 * This holds 2 content objects: one on the front and one on the back. It
8 * allows you to flip from front to back and vice-versa using various effects.
10 * Supported flip types:
11 * ELM_FLIP_ROTATE_Y_CENTER_AXIS
12 * ELM_FLIP_ROTATE_X_CENTER_AXIS
13 * ELM_FLIP_ROTATE_XZ_CENTER_AXIS
14 * ELM_FLIP_ROTATE_YZ_CENTER_AXIS
20 * Signals that you can add callbacks for are:
22 * "animate,done" - when a flip animation is finished
25 typedef struct _Widget_Data Widget_Data;
29 Ecore_Animator *animator;
34 Evas_Object *content, *clip;
39 static const char *widtype = NULL;
40 static void _del_hook(Evas_Object *obj);
41 static void _theme_hook(Evas_Object *obj);
42 static void _sizing_eval(Evas_Object *obj);
43 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
44 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
46 static void _configure(Evas_Object *obj);
48 static const char SIG_ANIMATE_DONE[] = "animate,done";
50 static const Evas_Smart_Cb_Description _signals[] = {
51 {SIG_ANIMATE_DONE, ""},
56 _del_hook(Evas_Object *obj)
58 Widget_Data *wd = elm_widget_data_get(obj);
60 if (wd->animator) ecore_animator_del(wd->animator);
65 _theme_hook(Evas_Object *obj)
67 Widget_Data *wd = elm_widget_data_get(obj);
73 _elm_flip_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
75 Widget_Data *wd = elm_widget_data_get(obj);
80 /* Try Focus cycle in subitem */
82 return elm_widget_focus_next_get(wd->front.content, dir, next);
84 return elm_widget_focus_next_get(wd->back.content, dir, next);
89 _sizing_eval(Evas_Object *obj)
91 Widget_Data *wd = elm_widget_data_get(obj);
92 Evas_Coord minw = -1, minh = -1, minw2 = -1, minh2 = -1;
93 Evas_Coord maxw = -1, maxh = -1, maxw2 = -1, maxh2 = -1;
95 if (wd->front.content)
96 evas_object_size_hint_min_get(wd->front.content, &minw, &minh);
98 evas_object_size_hint_min_get(wd->back.content, &minw2, &minh2);
99 if (wd->front.content)
100 evas_object_size_hint_max_get(wd->front.content, &maxw, &maxh);
101 if (wd->back.content)
102 evas_object_size_hint_max_get(wd->back.content, &maxw2, &maxh2);
104 if (minw2 > minw) minw = minw2;
105 if (minh2 > minh) minh = minh2;
106 if ((maxw2 >= 0) && (maxw2 < maxw)) maxw = maxw2;
107 if ((maxh2 >= 0) && (maxh2 < maxh)) maxh = maxh2;
109 evas_object_size_hint_min_set(obj, minw, minh);
110 evas_object_size_hint_max_set(obj, maxw, maxh);
114 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
116 Widget_Data *wd = elm_widget_data_get(data);
122 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
124 Widget_Data *wd = elm_widget_data_get(obj);
125 Evas_Object *sub = event_info;
127 if (sub == wd->front.content)
129 evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
130 _changed_size_hints, obj);
131 wd->front.content = NULL;
132 evas_object_hide(wd->front.clip);
135 else if (sub == wd->back.content)
137 evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
138 _changed_size_hints, obj);
139 wd->back.content = NULL;
140 evas_object_hide(wd->back.clip);
146 flip_show_hide(Evas_Object *obj)
148 Widget_Data *wd = elm_widget_data_get(obj);
149 if (elm_flip_front_get(obj))
151 if (wd->front.content)
152 evas_object_show(wd->front.clip);
154 evas_object_hide(wd->front.clip);
155 if (wd->back.content)
156 evas_object_hide(wd->back.clip);
158 evas_object_hide(wd->back.clip);
162 if (wd->front.content)
163 evas_object_hide(wd->front.clip);
165 evas_object_hide(wd->front.clip);
166 if (wd->back.content)
167 evas_object_show(wd->back.clip);
169 evas_object_hide(wd->back.clip);
174 _flip(Evas_Object *obj)
176 Widget_Data *wd = elm_widget_data_get(obj);
177 double t = ecore_loop_time_get() - wd->start;
178 Evas_Coord x, y, w, h;
181 Evas_Coord cx, cy, px, py, foc;
182 int lx, ly, lz, lr, lg, lb, lar, lag, lab;
183 if (!wd->animator) return ECORE_CALLBACK_CANCEL;
185 if (t > 1.0) t = 1.0;
187 if (!wd) return ECORE_CALLBACK_CANCEL;
189 mf = evas_map_new(4);
190 evas_map_smooth_set(mf, 0);
191 mb = evas_map_new(4);
192 evas_map_smooth_set(mb, 0);
194 if (wd->front.content)
196 evas_object_geometry_get(wd->front.content, &x, &y, &w, &h);
197 evas_map_util_points_populate_from_geometry(mf, x, y, w, h, 0);
199 if (wd->back.content)
201 evas_object_geometry_get(wd->back.content, &x, &y, &w, &h);
202 evas_map_util_points_populate_from_geometry(mb, x, y, w, h, 0);
205 evas_object_geometry_get(obj, &x, &y, &w, &h);
226 case ELM_FLIP_ROTATE_Y_CENTER_AXIS:
229 if (wd->state) deg = 180.0 * p;
230 else deg = 180 + (180.0 * p);
231 evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, 0);
232 evas_map_util_3d_rotate(mb, 0.0, deg + 180.0, 0.0, cx, cy, 0);
234 case ELM_FLIP_ROTATE_X_CENTER_AXIS:
237 if (wd->state) deg = 180.0 * p;
238 else deg = 180 + (180.0 * p);
239 evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, 0);
240 evas_map_util_3d_rotate(mb, deg + 180.0, 0.0, 0.0, cx, cy, 0);
242 case ELM_FLIP_ROTATE_XZ_CENTER_AXIS:
245 if (wd->state) deg = 180.0 * p;
246 else deg = 180 + (180.0 * p);
247 evas_map_util_3d_rotate(mf, deg, 0.0, deg, cx, cy, 0);
248 evas_map_util_3d_rotate(mb, deg + 180.0, 0.0, deg + 180.0, cx, cy, 0);
250 case ELM_FLIP_ROTATE_YZ_CENTER_AXIS:
253 if (wd->state) deg = 180.0 * p;
254 else deg = 180 + (180.0 * p);
255 evas_map_util_3d_rotate(mf, 0.0, deg, deg, cx, cy, 0);
256 evas_map_util_3d_rotate(mb, 0.0, deg + 180.0, deg + 180.0, cx, cy, 0);
258 case ELM_FLIP_CUBE_LEFT:
264 evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, w / 2);
265 evas_map_util_3d_rotate(mb, 0.0, deg + 90, 0.0, cx, cy, w / 2);
269 evas_map_util_3d_rotate(mf, 0.0, deg + 90, 0.0, cx, cy, w / 2);
270 evas_map_util_3d_rotate(mb, 0.0, deg, 0.0, cx, cy, w / 2);
273 case ELM_FLIP_CUBE_RIGHT:
279 evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, w / 2);
280 evas_map_util_3d_rotate(mb, 0.0, deg - 90, 0.0, cx, cy, w / 2);
284 evas_map_util_3d_rotate(mf, 0.0, deg - 90, 0.0, cx, cy, w / 2);
285 evas_map_util_3d_rotate(mb, 0.0, deg, 0.0, cx, cy, w / 2);
288 case ELM_FLIP_CUBE_UP:
294 evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, h / 2);
295 evas_map_util_3d_rotate(mb, deg + 90, 0.0, 0.0, cx, cy, h / 2);
299 evas_map_util_3d_rotate(mf, deg + 90, 0.0, 0.0, cx, cy, h / 2);
300 evas_map_util_3d_rotate(mb, deg, 0.0, 0.0, cx, cy, h / 2);
303 case ELM_FLIP_CUBE_DOWN:
309 evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, h / 2);
310 evas_map_util_3d_rotate(mb, deg - 90, 0.0, 0.0, cx, cy, h / 2);
314 evas_map_util_3d_rotate(mf, deg - 90, 0.0, 0.0, cx, cy, h / 2);
315 evas_map_util_3d_rotate(mb, deg, 0.0, 0.0, cx, cy, h / 2);
323 if (wd->front.content)
325 evas_map_util_3d_lighting(mf, lx, ly, lz, lr, lg, lb, lar, lag, lab);
326 evas_map_util_3d_perspective(mf, px, py, 0, foc);
327 evas_object_map_set(wd->front.content, mf);
328 evas_object_map_enable_set(wd->front.content, 1);
329 if (evas_map_util_clockwise_get(mf)) evas_object_show(wd->front.clip);
330 else evas_object_hide(wd->front.clip);
333 if (wd->back.content)
335 evas_map_util_3d_lighting(mb, lx, ly, lz, lr, lg, lb, lar, lag, lab);
336 evas_map_util_3d_perspective(mb, px, py, 0, foc);
337 evas_object_map_set(wd->back.content, mb);
338 evas_object_map_enable_set(wd->back.content, 1);
339 if (evas_map_util_clockwise_get(mb)) evas_object_show(wd->back.clip);
340 else evas_object_hide(wd->back.clip);
348 evas_object_map_enable_set(wd->front.content, 0);
349 evas_object_map_enable_set(wd->back.content, 0);
350 // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow
351 evas_object_resize(wd->front.content, 0, 0);
352 evas_object_resize(wd->back.content, 0, 0);
353 evas_smart_objects_calculate(evas_object_evas_get(obj));
356 wd->state = !wd->state;
358 evas_object_smart_callback_call(obj, SIG_ANIMATE_DONE, NULL);
359 return ECORE_CALLBACK_CANCEL;
361 return ECORE_CALLBACK_RENEW;
365 _configure(Evas_Object *obj)
367 Widget_Data *wd = elm_widget_data_get(obj);
368 Evas_Coord x, y, w, h;
370 evas_object_geometry_get(obj, &x, &y, &w, &h);
371 if (wd->front.content)
374 evas_object_move(wd->front.content, x, y);
375 evas_object_resize(wd->front.content, w, h);
377 if (wd->back.content)
380 evas_object_move(wd->back.content, x, y);
381 evas_object_resize(wd->back.content, w, h);
387 _move(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
393 _resize(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
405 * Add a new flip to the parent
407 * @param parent The parent object
408 * @return The new object or NULL if it cannot be created
413 elm_flip_add(Evas_Object *parent)
419 ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
421 ELM_SET_WIDTYPE(widtype, "flip");
422 elm_widget_type_set(obj, "flip");
423 elm_widget_sub_object_add(parent, obj);
424 elm_widget_data_set(obj, wd);
425 elm_widget_del_hook_set(obj, _del_hook);
426 elm_widget_theme_hook_set(obj, _theme_hook);
427 elm_widget_focus_next_hook_set(obj, _elm_flip_focus_next_hook);
428 elm_widget_can_focus_set(obj, EINA_FALSE);
430 wd->clip = evas_object_rectangle_add(e);
431 evas_object_static_clip_set(wd->clip, 1);
432 evas_object_color_set(wd->clip, 255, 255, 255, 255);
433 evas_object_move(wd->clip, -49999, -49999);
434 evas_object_resize(wd->clip, 99999, 99999);
435 elm_widget_sub_object_add(obj, wd->clip);
436 evas_object_clip_set(wd->clip, evas_object_clip_get(obj));
437 evas_object_smart_member_add(wd->clip, obj);
439 wd->front.clip = evas_object_rectangle_add(e);
440 evas_object_static_clip_set(wd->front.clip, 1);
441 evas_object_data_set(wd->front.clip, "_elm_leaveme", obj);
442 evas_object_color_set(wd->front.clip, 255, 255, 255, 255);
443 evas_object_move(wd->front.clip, -49999, -49999);
444 evas_object_resize(wd->front.clip, 99999, 99999);
445 elm_widget_sub_object_add(obj, wd->front.clip);
446 evas_object_smart_member_add(wd->front.clip, obj);
447 evas_object_clip_set(wd->front.clip, wd->clip);
449 wd->back.clip = evas_object_rectangle_add(e);
450 evas_object_static_clip_set(wd->back.clip, 1);
451 evas_object_data_set(wd->back.clip, "_elm_leaveme", obj);
452 evas_object_color_set(wd->back.clip, 255, 255, 255, 255);
453 evas_object_move(wd->back.clip, -49999, -49999);
454 evas_object_resize(wd->back.clip, 99999, 99999);
455 elm_widget_sub_object_add(wd->back.clip, obj);
456 evas_object_smart_member_add(obj, wd->back.clip);
457 evas_object_clip_set(wd->back.clip, wd->clip);
459 evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
460 evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _move, NULL);
461 evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize, NULL);
463 evas_object_smart_callbacks_descriptions_set(obj, _signals);
473 * Set the front content of the flip widget.
475 * Once the content object is set, a previously set one will be deleted.
476 * If you want to keep that old content object, use the
477 * elm_flip_content_front_unset() function.
479 * @param obj The flip object
480 * @param content The new front content object
485 elm_flip_content_front_set(Evas_Object *obj, Evas_Object *content)
487 ELM_CHECK_WIDTYPE(obj, widtype);
488 Widget_Data *wd = elm_widget_data_get(obj);
490 if (wd->front.content == content) return;
491 if (wd->front.content) evas_object_del(wd->back.content);
492 wd->front.content = content;
495 elm_widget_sub_object_add(obj, content);
496 evas_object_smart_member_add(content, obj);
497 evas_object_clip_set(content, wd->front.clip);
498 evas_object_event_callback_add(content,
499 EVAS_CALLBACK_CHANGED_SIZE_HINTS,
500 _changed_size_hints, obj);
503 // force calc to contents are the right size before transition
504 evas_smart_objects_calculate(evas_object_evas_get(obj));
510 * Set the back content of the flip widget.
512 * Once the content object is set, a previously set one will be deleted.
513 * If you want to keep that old content object, use the
514 * elm_flip_content_back_unset() function.
516 * @param obj The flip object
517 * @param content The new back content object
522 elm_flip_content_back_set(Evas_Object *obj, Evas_Object *content)
524 ELM_CHECK_WIDTYPE(obj, widtype);
525 Widget_Data *wd = elm_widget_data_get(obj);
527 if (wd->back.content == content) return;
528 if (wd->back.content) evas_object_del(wd->back.content);
529 wd->back.content = content;
532 elm_widget_sub_object_add(obj, content);
533 evas_object_smart_member_add(content, obj);
534 evas_object_clip_set(content, wd->back.clip);
535 evas_object_event_callback_add(content,
536 EVAS_CALLBACK_CHANGED_SIZE_HINTS,
537 _changed_size_hints, obj);
540 // force calc to contents are the right size before transition
541 evas_smart_objects_calculate(evas_object_evas_get(obj));
547 * Get the front content used for the flip
549 * Return the front content object which is set for this widget.
551 * @param obj The flip object
552 * @return The front content object that is being used
557 elm_flip_content_front_get(const Evas_Object *obj)
559 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
560 Widget_Data *wd = elm_widget_data_get(obj);
561 return wd->front.content;
566 * Get the back content used for the flip
568 * Return the back content object which is set for this widget.
570 * @param obj The flip object
571 * @return The back content object that is being used
576 elm_flip_content_back_get(const Evas_Object *obj)
578 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
579 Widget_Data *wd = elm_widget_data_get(obj);
580 return wd->back.content;
584 * Unset the front content used for the flip
586 * Unparent and return the front content object which was set for this widget.
588 * @param obj The flip object
589 * @return The front content object that was being used
594 elm_flip_content_front_unset(Evas_Object *obj)
596 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
597 Widget_Data *wd = elm_widget_data_get(obj);
598 if (!wd) return NULL;
599 if (!wd->front.content) return NULL;
600 Evas_Object *content = wd->front.content;
601 evas_object_clip_unset(content);
602 elm_widget_sub_object_del(obj, content);
603 evas_object_smart_member_del(content);
604 wd->front.content = NULL;
609 * Unset the back content used for the flip
611 * Unparent and return the back content object which was set for this widget.
613 * @param obj The flip object
614 * @return The back content object that was being used
619 elm_flip_content_back_unset(Evas_Object *obj)
621 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
622 Widget_Data *wd = elm_widget_data_get(obj);
623 if (!wd) return NULL;
624 if (!wd->back.content) return NULL;
625 Evas_Object *content = wd->back.content;
626 evas_object_clip_unset(content);
627 elm_widget_sub_object_del(obj, content);
628 evas_object_smart_member_del(content);
629 wd->back.content = NULL;
634 * Get flip front visibility state
636 * @param obj The flip object
637 * @return If front front is showing or not currently
642 elm_flip_front_get(const Evas_Object *obj)
644 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
645 Widget_Data *wd = elm_widget_data_get(obj);
646 if (!wd) return EINA_FALSE;
651 * Set flip perspective
653 * @param obj The flip object
654 * @param foc The coordinate to set the focus on
655 * @param x The X coordinate
656 * @param y The Y coordinate
658 * NOTE: This function currently does nothing.
663 elm_flip_perspective_set(Evas_Object *obj, Evas_Coord foc __UNUSED__, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
665 ELM_CHECK_WIDTYPE(obj, widtype);
666 Widget_Data *wd = elm_widget_data_get(obj);
671 * Runs the flip animation
673 * @param obj The flip object
674 * @param mode The mode type. Currently accepted modes are:
676 * ELM_FLIP_ROTATE_Y_CENTER_AXIS
677 * ELM_FLIP_ROTATE_X_CENTER_AXIS
678 * ELM_FLIP_ROTATE_XZ_CENTER_AXIS
679 * ELM_FLIP_ROTATE_YZ_CENTER_AXIS
681 * ELM_FLIP_CUBE_RIGHT
685 * FIXME: add - ELM_FLIP_CUBE_UP
686 * FIXME: add - ELM_FLIP_CUBE_DOWN
691 elm_flip_go(Evas_Object *obj, Elm_Flip_Mode mode)
693 ELM_CHECK_WIDTYPE(obj, widtype);
694 Widget_Data *wd = elm_widget_data_get(obj);
696 if (!wd->animator) wd->animator = ecore_animator_add(_animate, obj);
699 wd->start = ecore_loop_time_get();
701 // force calc to contents are the right size before transition
702 evas_smart_objects_calculate(evas_object_evas_get(obj));
704 // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow)
705 evas_object_map_enable_set(wd->front.content, 0);
706 evas_object_map_enable_set(wd->back.content, 0);
707 evas_object_resize(wd->front.content, 0, 0);
708 evas_object_resize(wd->back.content, 0, 0);
709 evas_smart_objects_calculate(evas_object_evas_get(obj));