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
16 * Signals that you can add callbacks for are:
18 * "animate,done" - when a flip animation is finished
21 typedef struct _Widget_Data Widget_Data;
25 Ecore_Animator *animator;
30 Evas_Object *content, *clip;
35 static const char *widtype = NULL;
36 static void _del_hook(Evas_Object *obj);
37 static void _theme_hook(Evas_Object *obj);
38 static void _sizing_eval(Evas_Object *obj);
39 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
40 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
42 static void _configure(Evas_Object *obj);
45 _del_hook(Evas_Object *obj)
47 Widget_Data *wd = elm_widget_data_get(obj);
49 if (wd->animator) ecore_animator_del(wd->animator);
54 _theme_hook(Evas_Object *obj)
56 Widget_Data *wd = elm_widget_data_get(obj);
62 _elm_flip_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
64 Widget_Data *wd = elm_widget_data_get(obj);
69 /* Try Focus cycle in subitem */
71 return elm_widget_focus_next_get(wd->front.content, dir, next);
73 return elm_widget_focus_next_get(wd->back.content, dir, next);
78 _sizing_eval(Evas_Object *obj)
80 Widget_Data *wd = elm_widget_data_get(obj);
81 Evas_Coord minw = -1, minh = -1, minw2 = -1, minh2 = -1;
82 Evas_Coord maxw = -1, maxh = -1, maxw2 = -1, maxh2 = -1;
84 if (wd->front.content)
85 evas_object_size_hint_min_get(wd->front.content, &minw, &minh);
87 evas_object_size_hint_min_get(wd->back.content, &minw2, &minh2);
88 if (wd->front.content)
89 evas_object_size_hint_max_get(wd->front.content, &maxw, &maxh);
91 evas_object_size_hint_max_get(wd->back.content, &maxw2, &maxh2);
93 if (minw2 > minw) minw = minw2;
94 if (minh2 > minh) minh = minh2;
95 if ((maxw2 >= 0) && (maxw2 < maxw)) maxw = maxw2;
96 if ((maxh2 >= 0) && (maxh2 < maxh)) maxh = maxh2;
98 evas_object_size_hint_min_set(obj, minw, minh);
99 evas_object_size_hint_max_set(obj, maxw, maxh);
103 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
105 Widget_Data *wd = elm_widget_data_get(data);
111 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
113 Widget_Data *wd = elm_widget_data_get(obj);
114 Evas_Object *sub = event_info;
116 if (sub == wd->front.content)
118 evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
119 _changed_size_hints, obj);
120 wd->front.content = NULL;
121 evas_object_hide(wd->front.clip);
124 else if (sub == wd->back.content)
126 evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
127 _changed_size_hints, obj);
128 wd->back.content = NULL;
129 evas_object_hide(wd->back.clip);
135 flip_show_hide(Evas_Object *obj)
137 Widget_Data *wd = elm_widget_data_get(obj);
138 if (elm_flip_front_get(obj))
140 if (wd->front.content)
141 evas_object_show(wd->front.clip);
143 evas_object_hide(wd->front.clip);
144 if (wd->back.content)
145 evas_object_hide(wd->back.clip);
147 evas_object_hide(wd->back.clip);
151 if (wd->front.content)
152 evas_object_hide(wd->front.clip);
154 evas_object_hide(wd->front.clip);
155 if (wd->back.content)
156 evas_object_show(wd->back.clip);
158 evas_object_hide(wd->back.clip);
163 _flip(Evas_Object *obj)
165 Widget_Data *wd = elm_widget_data_get(obj);
166 double t = ecore_loop_time_get() - wd->start;
167 Evas_Coord x, y, w, h;
170 Evas_Coord cx, cy, px, py, foc;
171 int lx, ly, lz, lr, lg, lb, lar, lag, lab;
172 if (!wd->animator) return ECORE_CALLBACK_CANCEL;
174 if (t > 1.0) t = 1.0;
176 if (!wd) return ECORE_CALLBACK_CANCEL;
178 mf = evas_map_new(4);
179 evas_map_smooth_set(mf, 0);
180 mb = evas_map_new(4);
181 evas_map_smooth_set(mb, 0);
183 if (wd->front.content)
185 evas_object_geometry_get(wd->front.content, &x, &y, &w, &h);
186 evas_map_util_points_populate_from_geometry(mf, x, y, w, h, 0);
188 if (wd->back.content)
190 evas_object_geometry_get(wd->back.content, &x, &y, &w, &h);
191 evas_map_util_points_populate_from_geometry(mb, x, y, w, h, 0);
194 evas_object_geometry_get(obj, &x, &y, &w, &h);
215 case ELM_FLIP_ROTATE_Y_CENTER_AXIS:
218 if (wd->state) deg = 180.0 * p;
219 else deg = 180 + (180.0 * p);
220 evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, 0);
221 evas_map_util_3d_rotate(mb, 0.0, deg + 180.0, 0.0, cx, cy, 0);
223 case ELM_FLIP_ROTATE_X_CENTER_AXIS:
226 if (wd->state) deg = 180.0 * p;
227 else deg = 180 + (180.0 * p);
228 evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, 0);
229 evas_map_util_3d_rotate(mb, deg + 180.0, 0.0, 0.0, cx, cy, 0);
231 case ELM_FLIP_ROTATE_XZ_CENTER_AXIS:
234 if (wd->state) deg = 180.0 * p;
235 else deg = 180 + (180.0 * p);
236 evas_map_util_3d_rotate(mf, deg, 0.0, deg, cx, cy, 0);
237 evas_map_util_3d_rotate(mb, deg + 180.0, 0.0, deg + 180.0, cx, cy, 0);
239 case ELM_FLIP_ROTATE_YZ_CENTER_AXIS:
242 if (wd->state) deg = 180.0 * p;
243 else deg = 180 + (180.0 * p);
244 evas_map_util_3d_rotate(mf, 0.0, deg, deg, cx, cy, 0);
245 evas_map_util_3d_rotate(mb, 0.0, deg + 180.0, deg + 180.0, cx, cy, 0);
247 case ELM_FLIP_CUBE_LEFT:
253 evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, w / 2);
254 evas_map_util_3d_rotate(mb, 0.0, deg + 90, 0.0, cx, cy, w / 2);
258 evas_map_util_3d_rotate(mf, 0.0, deg + 90, 0.0, cx, cy, w / 2);
259 evas_map_util_3d_rotate(mb, 0.0, deg, 0.0, cx, cy, w / 2);
262 case ELM_FLIP_CUBE_RIGHT:
268 evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, w / 2);
269 evas_map_util_3d_rotate(mb, 0.0, deg - 90, 0.0, cx, cy, w / 2);
273 evas_map_util_3d_rotate(mf, 0.0, deg - 90, 0.0, cx, cy, w / 2);
274 evas_map_util_3d_rotate(mb, 0.0, deg, 0.0, cx, cy, w / 2);
277 case ELM_FLIP_CUBE_UP:
283 evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, h / 2);
284 evas_map_util_3d_rotate(mb, deg + 90, 0.0, 0.0, cx, cy, h / 2);
288 evas_map_util_3d_rotate(mf, deg + 90, 0.0, 0.0, cx, cy, h / 2);
289 evas_map_util_3d_rotate(mb, deg, 0.0, 0.0, cx, cy, h / 2);
292 case ELM_FLIP_CUBE_DOWN:
298 evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, h / 2);
299 evas_map_util_3d_rotate(mb, deg - 90, 0.0, 0.0, cx, cy, h / 2);
303 evas_map_util_3d_rotate(mf, deg - 90, 0.0, 0.0, cx, cy, h / 2);
304 evas_map_util_3d_rotate(mb, deg, 0.0, 0.0, cx, cy, h / 2);
312 if (wd->front.content)
314 evas_map_util_3d_lighting(mf, lx, ly, lz, lr, lg, lb, lar, lag, lab);
315 evas_map_util_3d_perspective(mf, px, py, 0, foc);
316 evas_object_map_set(wd->front.content, mf);
317 evas_object_map_enable_set(wd->front.content, 1);
318 if (evas_map_util_clockwise_get(mf)) evas_object_show(wd->front.clip);
319 else evas_object_hide(wd->front.clip);
322 if (wd->back.content)
324 evas_map_util_3d_lighting(mb, lx, ly, lz, lr, lg, lb, lar, lag, lab);
325 evas_map_util_3d_perspective(mb, px, py, 0, foc);
326 evas_object_map_set(wd->back.content, mb);
327 evas_object_map_enable_set(wd->back.content, 1);
328 if (evas_map_util_clockwise_get(mb)) evas_object_show(wd->back.clip);
329 else evas_object_hide(wd->back.clip);
337 evas_object_map_enable_set(wd->front.content, 0);
338 evas_object_map_enable_set(wd->back.content, 0);
339 // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow
340 evas_object_resize(wd->front.content, 0, 0);
341 evas_object_resize(wd->back.content, 0, 0);
342 evas_smart_objects_calculate(evas_object_evas_get(obj));
345 wd->state = !wd->state;
347 evas_object_smart_callback_call(obj, "animate,done", NULL);
348 return ECORE_CALLBACK_CANCEL;
350 return ECORE_CALLBACK_RENEW;
354 _configure(Evas_Object *obj)
356 Widget_Data *wd = elm_widget_data_get(obj);
357 Evas_Coord x, y, w, h;
359 evas_object_geometry_get(obj, &x, &y, &w, &h);
360 if (wd->front.content)
363 evas_object_move(wd->front.content, x, y);
364 evas_object_resize(wd->front.content, w, h);
366 if (wd->back.content)
369 evas_object_move(wd->back.content, x, y);
370 evas_object_resize(wd->back.content, w, h);
376 _move(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
382 _resize(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
394 * Add a new flip to the parent
396 * @param parent The parent object
397 * @return The new object or NULL if it cannot be created
402 elm_flip_add(Evas_Object *parent)
408 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
410 wd = ELM_NEW(Widget_Data);
411 e = evas_object_evas_get(parent);
413 obj = elm_widget_add(e);
414 ELM_SET_WIDTYPE(widtype, "flip");
415 elm_widget_type_set(obj, "flip");
416 elm_widget_sub_object_add(parent, obj);
417 elm_widget_data_set(obj, wd);
418 elm_widget_del_hook_set(obj, _del_hook);
419 elm_widget_theme_hook_set(obj, _theme_hook);
420 elm_widget_focus_next_hook_set(obj, _elm_flip_focus_next_hook);
421 elm_widget_can_focus_set(obj, EINA_FALSE);
423 wd->clip = evas_object_rectangle_add(e);
424 evas_object_static_clip_set(wd->clip, 1);
425 evas_object_color_set(wd->clip, 255, 255, 255, 255);
426 evas_object_move(wd->clip, -49999, -49999);
427 evas_object_resize(wd->clip, 99999, 99999);
428 elm_widget_sub_object_add(obj, wd->clip);
429 evas_object_clip_set(wd->clip, evas_object_clip_get(obj));
430 evas_object_smart_member_add(wd->clip, obj);
432 wd->front.clip = evas_object_rectangle_add(e);
433 evas_object_static_clip_set(wd->front.clip, 1);
434 evas_object_data_set(wd->front.clip, "_elm_leaveme", obj);
435 evas_object_color_set(wd->front.clip, 255, 255, 255, 255);
436 evas_object_move(wd->front.clip, -49999, -49999);
437 evas_object_resize(wd->front.clip, 99999, 99999);
438 elm_widget_sub_object_add(obj, wd->front.clip);
439 evas_object_smart_member_add(wd->front.clip, obj);
440 evas_object_clip_set(wd->front.clip, wd->clip);
442 wd->back.clip = evas_object_rectangle_add(e);
443 evas_object_static_clip_set(wd->back.clip, 1);
444 evas_object_data_set(wd->back.clip, "_elm_leaveme", obj);
445 evas_object_color_set(wd->back.clip, 255, 255, 255, 255);
446 evas_object_move(wd->back.clip, -49999, -49999);
447 evas_object_resize(wd->back.clip, 99999, 99999);
448 elm_widget_sub_object_add(wd->back.clip, obj);
449 evas_object_smart_member_add(obj, wd->back.clip);
450 evas_object_clip_set(wd->back.clip, wd->clip);
452 evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
453 evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _move, NULL);
454 evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize, NULL);
463 * Set the front content of the flip widget.
465 * Once the content object is set, a previously set one will be deleted.
466 * If you want to keep that old content object, use the
467 * elm_flip_content_front_unset() function.
469 * @param obj The flip object
470 * @param content The new front content object
475 elm_flip_content_front_set(Evas_Object *obj, Evas_Object *content)
477 ELM_CHECK_WIDTYPE(obj, widtype);
478 Widget_Data *wd = elm_widget_data_get(obj);
480 if (wd->front.content == content) return;
481 if (wd->front.content) evas_object_del(wd->back.content);
482 wd->front.content = content;
485 elm_widget_sub_object_add(obj, content);
486 evas_object_smart_member_add(content, obj);
487 evas_object_clip_set(content, wd->front.clip);
488 evas_object_event_callback_add(content,
489 EVAS_CALLBACK_CHANGED_SIZE_HINTS,
490 _changed_size_hints, obj);
493 // force calc to contents are the right size before transition
494 evas_smart_objects_calculate(evas_object_evas_get(obj));
500 * Set the back content of the flip widget.
502 * Once the content object is set, a previously set one will be deleted.
503 * If you want to keep that old content object, use the
504 * elm_flip_content_back_unset() function.
506 * @param obj The flip object
507 * @param content The new back content object
512 elm_flip_content_back_set(Evas_Object *obj, Evas_Object *content)
514 ELM_CHECK_WIDTYPE(obj, widtype);
515 Widget_Data *wd = elm_widget_data_get(obj);
517 if (wd->back.content == content) return;
518 if (wd->back.content) evas_object_del(wd->back.content);
519 wd->back.content = content;
522 elm_widget_sub_object_add(obj, content);
523 evas_object_smart_member_add(content, obj);
524 evas_object_clip_set(content, wd->back.clip);
525 evas_object_event_callback_add(content,
526 EVAS_CALLBACK_CHANGED_SIZE_HINTS,
527 _changed_size_hints, obj);
530 // force calc to contents are the right size before transition
531 evas_smart_objects_calculate(evas_object_evas_get(obj));
537 * Get the front content used for the flip
539 * Return the front content object which is set for this widget.
541 * @param obj The flip object
542 * @return The front content object that is being used
547 elm_flip_content_front_get(const Evas_Object *obj)
549 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
550 Widget_Data *wd = elm_widget_data_get(obj);
551 return wd->front.content;
556 * Get the back content used for the flip
558 * Return the back content object which is set for this widget.
560 * @param obj The flip object
561 * @return The back content object that is being used
566 elm_flip_content_back_get(const Evas_Object *obj)
568 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
569 Widget_Data *wd = elm_widget_data_get(obj);
570 return wd->back.content;
574 * Unset the front content used for the flip
576 * Unparent and return the front content object which was set for this widget.
578 * @param obj The flip object
579 * @return The front content object that was being used
584 elm_flip_content_front_unset(Evas_Object *obj)
586 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
587 Widget_Data *wd = elm_widget_data_get(obj);
588 if (!wd) return NULL;
589 if (!wd->front.content) return NULL;
590 Evas_Object *content = wd->front.content;
591 evas_object_clip_unset(content);
592 elm_widget_sub_object_del(obj, content);
593 evas_object_smart_member_del(content);
594 wd->front.content = NULL;
599 * Unset the back content used for the flip
601 * Unparent and return the back content object which was set for this widget.
603 * @param obj The flip object
604 * @return The back content object that was being used
609 elm_flip_content_back_unset(Evas_Object *obj)
611 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
612 Widget_Data *wd = elm_widget_data_get(obj);
613 if (!wd) return NULL;
614 if (!wd->back.content) return NULL;
615 Evas_Object *content = wd->back.content;
616 evas_object_clip_unset(content);
617 elm_widget_sub_object_del(obj, content);
618 evas_object_smart_member_del(content);
619 wd->back.content = NULL;
624 * Get flip front visibility state
626 * @param obj The flip object
627 * @return If front front is showing or not currently
632 elm_flip_front_get(const Evas_Object *obj)
634 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
635 Widget_Data *wd = elm_widget_data_get(obj);
636 if (!wd) return EINA_FALSE;
641 * Set flip perspective
643 * @param obj The flip object
644 * @param foc The coordinate to set the focus on
645 * @param x The X coordinate
646 * @param y The Y coordinate
648 * NOTE: This function currently does nothing.
653 elm_flip_perspective_set(Evas_Object *obj, Evas_Coord foc __UNUSED__, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
655 ELM_CHECK_WIDTYPE(obj, widtype);
656 Widget_Data *wd = elm_widget_data_get(obj);
661 * Runs the flip animation
663 * @param obj The flip object
664 * @param mode The mode type. Currently accepted modes are:
666 * ELM_FLIP_ROTATE_Y_CENTER_AXIS
667 * ELM_FLIP_ROTATE_X_CENTER_AXIS
668 * ELM_FLIP_ROTATE_XZ_CENTER_AXIS
669 * ELM_FLIP_ROTATE_YZ_CENTER_AXIS
671 * ELM_FLIP_CUBE_RIGHT
673 * FIXME: add - ELM_FLIP_CUBE_UP
674 * FIXMEL add - ELM_FLIP_CUBE_DOWN
679 elm_flip_go(Evas_Object *obj, Elm_Flip_Mode mode)
681 ELM_CHECK_WIDTYPE(obj, widtype);
682 Widget_Data *wd = elm_widget_data_get(obj);
684 if (!wd->animator) wd->animator = ecore_animator_add(_animate, obj);
687 wd->start = ecore_loop_time_get();
689 // force calc to contents are the right size before transition
690 evas_smart_objects_calculate(evas_object_evas_get(obj));
692 // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow
693 evas_object_map_enable_set(wd->front.content, 0);
694 evas_object_map_enable_set(wd->back.content, 0);
695 evas_object_resize(wd->front.content, 0, 0);
696 evas_object_resize(wd->back.content, 0, 0);
697 evas_smart_objects_calculate(evas_object_evas_get(obj));