1 #include <Elementary.h>
8 * This holds 2 content objects: one on the front and one on the back. It
9 * allows you to flip from front to back and vice-versa using various effects.
11 * Supported flip types:
12 * ELM_FLIP_ROTATE_Y_CENTER_AXIS
13 * ELM_FLIP_ROTATE_X_CENTER_AXIS
14 * ELM_FLIP_ROTATE_XZ_CENTER_AXIS
15 * ELM_FLIP_ROTATE_YZ_CENTER_AXIS
17 * Signals that you can add callbacks for are:
19 * "animate,done" - when a flip animation is finished
22 typedef struct _Widget_Data Widget_Data;
26 Ecore_Animator *animator;
31 Evas_Object *content, *clip;
36 static const char *widtype = NULL;
37 static void _del_hook(Evas_Object *obj);
38 static void _theme_hook(Evas_Object *obj);
39 static void _sizing_eval(Evas_Object *obj);
40 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
41 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
43 static void _configure(Evas_Object *obj);
46 _del_hook(Evas_Object *obj)
48 Widget_Data *wd = elm_widget_data_get(obj);
50 if (wd->animator) ecore_animator_del(wd->animator);
55 _theme_hook(Evas_Object *obj)
57 Widget_Data *wd = elm_widget_data_get(obj);
63 _elm_flip_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
65 Widget_Data *wd = elm_widget_data_get(obj);
70 /* Try Focus cycle in subitem */
72 return elm_widget_focus_next_get(wd->front.content, dir, next);
74 return elm_widget_focus_next_get(wd->back.content, dir, next);
79 _sizing_eval(Evas_Object *obj)
81 Widget_Data *wd = elm_widget_data_get(obj);
82 Evas_Coord minw = -1, minh = -1, minw2 = -1, minh2 = -1;
83 Evas_Coord maxw = -1, maxh = -1, maxw2 = -1, maxh2 = -1;
85 if (wd->front.content)
86 evas_object_size_hint_min_get(wd->front.content, &minw, &minh);
88 evas_object_size_hint_min_get(wd->back.content, &minw2, &minh2);
89 if (wd->front.content)
90 evas_object_size_hint_max_get(wd->front.content, &maxw, &maxh);
92 evas_object_size_hint_max_get(wd->back.content, &maxw2, &maxh2);
94 if (minw2 > minw) minw = minw2;
95 if (minh2 > minh) minh = minh2;
96 if ((maxw2 >= 0) && (maxw2 < maxw)) maxw = maxw2;
97 if ((maxh2 >= 0) && (maxh2 < maxh)) maxh = maxh2;
99 evas_object_size_hint_min_set(obj, minw, minh);
100 evas_object_size_hint_max_set(obj, maxw, maxh);
104 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
106 Widget_Data *wd = elm_widget_data_get(data);
112 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
114 Widget_Data *wd = elm_widget_data_get(obj);
115 Evas_Object *sub = event_info;
117 if (sub == wd->front.content)
119 evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
120 _changed_size_hints, obj);
121 wd->front.content = NULL;
122 evas_object_hide(wd->front.clip);
125 else if (sub == wd->back.content)
127 evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
128 _changed_size_hints, obj);
129 wd->back.content = NULL;
130 evas_object_hide(wd->back.clip);
136 flip_show_hide(Evas_Object *obj)
138 Widget_Data *wd = elm_widget_data_get(obj);
139 if (elm_flip_front_get(obj))
141 if (wd->front.content)
142 evas_object_show(wd->front.clip);
144 evas_object_hide(wd->front.clip);
145 if (wd->back.content)
146 evas_object_hide(wd->back.clip);
148 evas_object_hide(wd->back.clip);
152 if (wd->front.content)
153 evas_object_hide(wd->front.clip);
155 evas_object_hide(wd->front.clip);
156 if (wd->back.content)
157 evas_object_show(wd->back.clip);
159 evas_object_hide(wd->back.clip);
164 _flip(Evas_Object *obj)
166 Widget_Data *wd = elm_widget_data_get(obj);
167 double t = ecore_loop_time_get() - wd->start;
168 Evas_Coord x, y, w, h;
171 Evas_Coord cx, cy, px, py, foc;
172 int lx, ly, lz, lr, lg, lb, lar, lag, lab;
173 if (!wd->animator) return ECORE_CALLBACK_CANCEL;
175 if (t > 1.0) t = 1.0;
177 if (!wd) return ECORE_CALLBACK_CANCEL;
179 mf = evas_map_new(4);
180 evas_map_smooth_set(mf, 0);
181 mb = evas_map_new(4);
182 evas_map_smooth_set(mb, 0);
184 if (wd->front.content)
186 evas_object_geometry_get(wd->front.content, &x, &y, &w, &h);
187 evas_map_util_points_populate_from_geometry(mf, x, y, w, h, 0);
189 if (wd->back.content)
191 evas_object_geometry_get(wd->back.content, &x, &y, &w, &h);
192 evas_map_util_points_populate_from_geometry(mb, x, y, w, h, 0);
195 evas_object_geometry_get(obj, &x, &y, &w, &h);
216 case ELM_FLIP_ROTATE_Y_CENTER_AXIS:
219 if (wd->state) deg = 180.0 * p;
220 else deg = 180 + (180.0 * p);
221 evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, 0);
222 evas_map_util_3d_rotate(mb, 0.0, deg + 180.0, 0.0, cx, cy, 0);
224 case ELM_FLIP_ROTATE_X_CENTER_AXIS:
227 if (wd->state) deg = 180.0 * p;
228 else deg = 180 + (180.0 * p);
229 evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, 0);
230 evas_map_util_3d_rotate(mb, deg + 180.0, 0.0, 0.0, cx, cy, 0);
232 case ELM_FLIP_ROTATE_XZ_CENTER_AXIS:
235 if (wd->state) deg = 180.0 * p;
236 else deg = 180 + (180.0 * p);
237 evas_map_util_3d_rotate(mf, deg, 0.0, deg, cx, cy, 0);
238 evas_map_util_3d_rotate(mb, deg + 180.0, 0.0, deg + 180.0, cx, cy, 0);
240 case ELM_FLIP_ROTATE_YZ_CENTER_AXIS:
243 if (wd->state) deg = 180.0 * p;
244 else deg = 180 + (180.0 * p);
245 evas_map_util_3d_rotate(mf, 0.0, deg, deg, cx, cy, 0);
246 evas_map_util_3d_rotate(mb, 0.0, deg + 180.0, deg + 180.0, cx, cy, 0);
248 case ELM_FLIP_CUBE_LEFT:
254 evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, w / 2);
255 evas_map_util_3d_rotate(mb, 0.0, deg + 90, 0.0, cx, cy, w / 2);
259 evas_map_util_3d_rotate(mf, 0.0, deg + 90, 0.0, cx, cy, w / 2);
260 evas_map_util_3d_rotate(mb, 0.0, deg, 0.0, cx, cy, w / 2);
263 case ELM_FLIP_CUBE_RIGHT:
269 evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, w / 2);
270 evas_map_util_3d_rotate(mb, 0.0, deg - 90, 0.0, cx, cy, w / 2);
274 evas_map_util_3d_rotate(mf, 0.0, deg - 90, 0.0, cx, cy, w / 2);
275 evas_map_util_3d_rotate(mb, 0.0, deg, 0.0, cx, cy, w / 2);
278 case ELM_FLIP_CUBE_UP:
284 evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, h / 2);
285 evas_map_util_3d_rotate(mb, deg + 90, 0.0, 0.0, cx, cy, h / 2);
289 evas_map_util_3d_rotate(mf, deg + 90, 0.0, 0.0, cx, cy, h / 2);
290 evas_map_util_3d_rotate(mb, deg, 0.0, 0.0, cx, cy, h / 2);
293 case ELM_FLIP_CUBE_DOWN:
299 evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, h / 2);
300 evas_map_util_3d_rotate(mb, deg - 90, 0.0, 0.0, cx, cy, h / 2);
304 evas_map_util_3d_rotate(mf, deg - 90, 0.0, 0.0, cx, cy, h / 2);
305 evas_map_util_3d_rotate(mb, deg, 0.0, 0.0, cx, cy, h / 2);
313 if (wd->front.content)
315 evas_map_util_3d_lighting(mf, lx, ly, lz, lr, lg, lb, lar, lag, lab);
316 evas_map_util_3d_perspective(mf, px, py, 0, foc);
317 evas_object_map_set(wd->front.content, mf);
318 evas_object_map_enable_set(wd->front.content, 1);
319 if (evas_map_util_clockwise_get(mf)) evas_object_show(wd->front.clip);
320 else evas_object_hide(wd->front.clip);
323 if (wd->back.content)
325 evas_map_util_3d_lighting(mb, lx, ly, lz, lr, lg, lb, lar, lag, lab);
326 evas_map_util_3d_perspective(mb, px, py, 0, foc);
327 evas_object_map_set(wd->back.content, mb);
328 evas_object_map_enable_set(wd->back.content, 1);
329 if (evas_map_util_clockwise_get(mb)) evas_object_show(wd->back.clip);
330 else evas_object_hide(wd->back.clip);
338 evas_object_map_enable_set(wd->front.content, 0);
339 evas_object_map_enable_set(wd->back.content, 0);
340 // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow
341 evas_object_resize(wd->front.content, 0, 0);
342 evas_object_resize(wd->back.content, 0, 0);
343 evas_smart_objects_calculate(evas_object_evas_get(obj));
346 wd->state = !wd->state;
348 evas_object_smart_callback_call(obj, "animate,done", NULL);
349 return ECORE_CALLBACK_CANCEL;
351 return ECORE_CALLBACK_RENEW;
355 _configure(Evas_Object *obj)
357 Widget_Data *wd = elm_widget_data_get(obj);
358 Evas_Coord x, y, w, h;
360 evas_object_geometry_get(obj, &x, &y, &w, &h);
361 if (wd->front.content)
364 evas_object_move(wd->front.content, x, y);
365 evas_object_resize(wd->front.content, w, h);
367 if (wd->back.content)
370 evas_object_move(wd->back.content, x, y);
371 evas_object_resize(wd->back.content, w, h);
377 _move(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
383 _resize(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
395 * Add a new flip to the parent
397 * @param parent The parent object
398 * @return The new object or NULL if it cannot be created
403 elm_flip_add(Evas_Object *parent)
409 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
411 wd = ELM_NEW(Widget_Data);
412 e = evas_object_evas_get(parent);
414 obj = elm_widget_add(e);
415 ELM_SET_WIDTYPE(widtype, "flip");
416 elm_widget_type_set(obj, "flip");
417 elm_widget_sub_object_add(parent, obj);
418 elm_widget_data_set(obj, wd);
419 elm_widget_del_hook_set(obj, _del_hook);
420 elm_widget_theme_hook_set(obj, _theme_hook);
421 elm_widget_focus_next_hook_set(obj, _elm_flip_focus_next_hook);
422 elm_widget_can_focus_set(obj, EINA_FALSE);
424 wd->clip = evas_object_rectangle_add(e);
425 evas_object_static_clip_set(wd->clip, 1);
426 evas_object_color_set(wd->clip, 255, 255, 255, 255);
427 evas_object_move(wd->clip, -49999, -49999);
428 evas_object_resize(wd->clip, 99999, 99999);
429 elm_widget_sub_object_add(obj, wd->clip);
430 evas_object_clip_set(wd->clip, evas_object_clip_get(obj));
431 evas_object_smart_member_add(wd->clip, obj);
433 wd->front.clip = evas_object_rectangle_add(e);
434 evas_object_static_clip_set(wd->front.clip, 1);
435 evas_object_data_set(wd->front.clip, "_elm_leaveme", obj);
436 evas_object_color_set(wd->front.clip, 255, 255, 255, 255);
437 evas_object_move(wd->front.clip, -49999, -49999);
438 evas_object_resize(wd->front.clip, 99999, 99999);
439 elm_widget_sub_object_add(obj, wd->front.clip);
440 evas_object_smart_member_add(wd->front.clip, obj);
441 evas_object_clip_set(wd->front.clip, wd->clip);
443 wd->back.clip = evas_object_rectangle_add(e);
444 evas_object_static_clip_set(wd->back.clip, 1);
445 evas_object_data_set(wd->back.clip, "_elm_leaveme", obj);
446 evas_object_color_set(wd->back.clip, 255, 255, 255, 255);
447 evas_object_move(wd->back.clip, -49999, -49999);
448 evas_object_resize(wd->back.clip, 99999, 99999);
449 elm_widget_sub_object_add(wd->back.clip, obj);
450 evas_object_smart_member_add(obj, wd->back.clip);
451 evas_object_clip_set(wd->back.clip, wd->clip);
453 evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
454 evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _move, NULL);
455 evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize, NULL);
464 * Set the front content of the flip widget.
466 * Once the content object is set, a previously set one will be deleted.
467 * If you want to keep that old content object, use the
468 * elm_flip_content_front_unset() function.
470 * @param obj The flip object
471 * @param content The new front content object
476 elm_flip_content_front_set(Evas_Object *obj, Evas_Object *content)
478 ELM_CHECK_WIDTYPE(obj, widtype);
479 Widget_Data *wd = elm_widget_data_get(obj);
481 if (wd->front.content == content) return;
482 if (wd->front.content) evas_object_del(wd->back.content);
483 wd->front.content = content;
486 elm_widget_sub_object_add(obj, content);
487 evas_object_smart_member_add(content, obj);
488 evas_object_clip_set(content, wd->front.clip);
489 evas_object_event_callback_add(content,
490 EVAS_CALLBACK_CHANGED_SIZE_HINTS,
491 _changed_size_hints, obj);
494 // force calc to contents are the right size before transition
495 evas_smart_objects_calculate(evas_object_evas_get(obj));
501 * Set the back content of the flip widget.
503 * Once the content object is set, a previously set one will be deleted.
504 * If you want to keep that old content object, use the
505 * elm_flip_content_back_unset() function.
507 * @param obj The flip object
508 * @param content The new back content object
513 elm_flip_content_back_set(Evas_Object *obj, Evas_Object *content)
515 ELM_CHECK_WIDTYPE(obj, widtype);
516 Widget_Data *wd = elm_widget_data_get(obj);
518 if (wd->back.content == content) return;
519 if (wd->back.content) evas_object_del(wd->back.content);
520 wd->back.content = content;
523 elm_widget_sub_object_add(obj, content);
524 evas_object_smart_member_add(content, obj);
525 evas_object_clip_set(content, wd->back.clip);
526 evas_object_event_callback_add(content,
527 EVAS_CALLBACK_CHANGED_SIZE_HINTS,
528 _changed_size_hints, obj);
531 // force calc to contents are the right size before transition
532 evas_smart_objects_calculate(evas_object_evas_get(obj));
538 * Get the front content used for the flip
540 * Return the front content object which is set for this widget.
542 * @param obj The flip object
543 * @return The front content object that is being used
548 elm_flip_content_front_get(const Evas_Object *obj)
550 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
551 Widget_Data *wd = elm_widget_data_get(obj);
552 return wd->front.content;
557 * Get the back content used for the flip
559 * Return the back content object which is set for this widget.
561 * @param obj The flip object
562 * @return The back content object that is being used
567 elm_flip_content_back_get(const Evas_Object *obj)
569 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
570 Widget_Data *wd = elm_widget_data_get(obj);
571 return wd->back.content;
575 * Unset the front content used for the flip
577 * Unparent and return the front content object which was set for this widget.
579 * @param obj The flip object
580 * @return The front content object that was being used
585 elm_flip_content_front_unset(Evas_Object *obj)
587 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
588 Widget_Data *wd = elm_widget_data_get(obj);
589 if (!wd) return NULL;
590 if (!wd->front.content) return NULL;
591 Evas_Object *content = wd->front.content;
592 evas_object_clip_unset(content);
593 elm_widget_sub_object_del(obj, content);
594 evas_object_smart_member_del(content);
595 wd->front.content = NULL;
600 * Unset the back content used for the flip
602 * Unparent and return the back content object which was set for this widget.
604 * @param obj The flip object
605 * @return The back content object that was being used
610 elm_flip_content_back_unset(Evas_Object *obj)
612 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
613 Widget_Data *wd = elm_widget_data_get(obj);
614 if (!wd) return NULL;
615 if (!wd->back.content) return NULL;
616 Evas_Object *content = wd->back.content;
617 evas_object_clip_unset(content);
618 elm_widget_sub_object_del(obj, content);
619 evas_object_smart_member_del(content);
620 wd->back.content = NULL;
625 * Get flip front visibility state
627 * @param obj The flip object
628 * @return If front front is showing or not currently
633 elm_flip_front_get(const Evas_Object *obj)
635 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
636 Widget_Data *wd = elm_widget_data_get(obj);
637 if (!wd) return EINA_FALSE;
642 * Set flip perspective
644 * @param obj The flip object
645 * @param foc The coordinate to set the focus on
646 * @param x The X coordinate
647 * @param y The Y coordinate
649 * NOTE: This function currently does nothing.
654 elm_flip_perspective_set(Evas_Object *obj, Evas_Coord foc __UNUSED__, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
656 ELM_CHECK_WIDTYPE(obj, widtype);
657 Widget_Data *wd = elm_widget_data_get(obj);
662 * Runs the flip animation
664 * @param obj The flip object
665 * @param mode The mode type. Currently accepted modes are:
667 * ELM_FLIP_ROTATE_Y_CENTER_AXIS
668 * ELM_FLIP_ROTATE_X_CENTER_AXIS
669 * ELM_FLIP_ROTATE_XZ_CENTER_AXIS
670 * ELM_FLIP_ROTATE_YZ_CENTER_AXIS
672 * ELM_FLIP_CUBE_RIGHT
674 * FIXME: add - ELM_FLIP_CUBE_UP
675 * FIXMEL add - ELM_FLIP_CUBE_DOWN
680 elm_flip_go(Evas_Object *obj, Elm_Flip_Mode mode)
682 ELM_CHECK_WIDTYPE(obj, widtype);
683 Widget_Data *wd = elm_widget_data_get(obj);
685 if (!wd->animator) wd->animator = ecore_animator_add(_animate, obj);
688 wd->start = ecore_loop_time_get();
690 // force calc to contents are the right size before transition
691 evas_smart_objects_calculate(evas_object_evas_get(obj));
693 // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow
694 evas_object_map_enable_set(wd->front.content, 0);
695 evas_object_map_enable_set(wd->back.content, 0);
696 evas_object_resize(wd->front.content, 0, 0);
697 evas_object_resize(wd->back.content, 0, 0);
698 evas_smart_objects_calculate(evas_object_evas_get(obj));