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);
45 static const char SIG_ANIMATE_DONE[] = "animate,done";
47 static const Evas_Smart_Cb_Description _signals[] = {
48 {SIG_ANIMATE_DONE, ""},
53 _del_hook(Evas_Object *obj)
55 Widget_Data *wd = elm_widget_data_get(obj);
57 if (wd->animator) ecore_animator_del(wd->animator);
62 _theme_hook(Evas_Object *obj)
64 Widget_Data *wd = elm_widget_data_get(obj);
70 _elm_flip_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
72 Widget_Data *wd = elm_widget_data_get(obj);
77 /* Try Focus cycle in subitem */
79 return elm_widget_focus_next_get(wd->front.content, dir, next);
81 return elm_widget_focus_next_get(wd->back.content, dir, next);
86 _sizing_eval(Evas_Object *obj)
88 Widget_Data *wd = elm_widget_data_get(obj);
89 Evas_Coord minw = -1, minh = -1, minw2 = -1, minh2 = -1;
90 Evas_Coord maxw = -1, maxh = -1, maxw2 = -1, maxh2 = -1;
92 if (wd->front.content)
93 evas_object_size_hint_min_get(wd->front.content, &minw, &minh);
95 evas_object_size_hint_min_get(wd->back.content, &minw2, &minh2);
96 if (wd->front.content)
97 evas_object_size_hint_max_get(wd->front.content, &maxw, &maxh);
99 evas_object_size_hint_max_get(wd->back.content, &maxw2, &maxh2);
101 if (minw2 > minw) minw = minw2;
102 if (minh2 > minh) minh = minh2;
103 if ((maxw2 >= 0) && (maxw2 < maxw)) maxw = maxw2;
104 if ((maxh2 >= 0) && (maxh2 < maxh)) maxh = maxh2;
106 evas_object_size_hint_min_set(obj, minw, minh);
107 evas_object_size_hint_max_set(obj, maxw, maxh);
111 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
113 Widget_Data *wd = elm_widget_data_get(data);
119 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
121 Widget_Data *wd = elm_widget_data_get(obj);
122 Evas_Object *sub = event_info;
124 if (sub == wd->front.content)
126 evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
127 _changed_size_hints, obj);
128 wd->front.content = NULL;
129 evas_object_hide(wd->front.clip);
132 else if (sub == wd->back.content)
134 evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
135 _changed_size_hints, obj);
136 wd->back.content = NULL;
137 evas_object_hide(wd->back.clip);
143 flip_show_hide(Evas_Object *obj)
145 Widget_Data *wd = elm_widget_data_get(obj);
146 if (elm_flip_front_get(obj))
148 if (wd->front.content)
149 evas_object_show(wd->front.clip);
151 evas_object_hide(wd->front.clip);
152 if (wd->back.content)
153 evas_object_hide(wd->back.clip);
155 evas_object_hide(wd->back.clip);
159 if (wd->front.content)
160 evas_object_hide(wd->front.clip);
162 evas_object_hide(wd->front.clip);
163 if (wd->back.content)
164 evas_object_show(wd->back.clip);
166 evas_object_hide(wd->back.clip);
171 _flip(Evas_Object *obj)
173 Widget_Data *wd = elm_widget_data_get(obj);
174 double t = ecore_loop_time_get() - wd->start;
175 Evas_Coord x, y, w, h;
178 Evas_Coord cx, cy, px, py, foc;
179 int lx, ly, lz, lr, lg, lb, lar, lag, lab;
180 if (!wd->animator) return ECORE_CALLBACK_CANCEL;
182 if (t > 1.0) t = 1.0;
184 if (!wd) return ECORE_CALLBACK_CANCEL;
186 mf = evas_map_new(4);
187 evas_map_smooth_set(mf, 0);
188 mb = evas_map_new(4);
189 evas_map_smooth_set(mb, 0);
191 if (wd->front.content)
193 evas_object_geometry_get(wd->front.content, &x, &y, &w, &h);
194 evas_map_util_points_populate_from_geometry(mf, x, y, w, h, 0);
196 if (wd->back.content)
198 evas_object_geometry_get(wd->back.content, &x, &y, &w, &h);
199 evas_map_util_points_populate_from_geometry(mb, x, y, w, h, 0);
202 evas_object_geometry_get(obj, &x, &y, &w, &h);
223 case ELM_FLIP_ROTATE_Y_CENTER_AXIS:
226 if (wd->state) deg = 180.0 * p;
227 else deg = 180 + (180.0 * p);
228 evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, 0);
229 evas_map_util_3d_rotate(mb, 0.0, deg + 180.0, 0.0, cx, cy, 0);
231 case ELM_FLIP_ROTATE_X_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, 0.0, cx, cy, 0);
237 evas_map_util_3d_rotate(mb, deg + 180.0, 0.0, 0.0, cx, cy, 0);
239 case ELM_FLIP_ROTATE_XZ_CENTER_AXIS:
242 if (wd->state) deg = 180.0 * p;
243 else deg = 180 + (180.0 * p);
244 evas_map_util_3d_rotate(mf, deg, 0.0, deg, cx, cy, 0);
245 evas_map_util_3d_rotate(mb, deg + 180.0, 0.0, deg + 180.0, cx, cy, 0);
247 case ELM_FLIP_ROTATE_YZ_CENTER_AXIS:
250 if (wd->state) deg = 180.0 * p;
251 else deg = 180 + (180.0 * p);
252 evas_map_util_3d_rotate(mf, 0.0, deg, deg, cx, cy, 0);
253 evas_map_util_3d_rotate(mb, 0.0, deg + 180.0, deg + 180.0, cx, cy, 0);
255 case ELM_FLIP_CUBE_LEFT:
261 evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, w / 2);
262 evas_map_util_3d_rotate(mb, 0.0, deg + 90, 0.0, cx, cy, w / 2);
266 evas_map_util_3d_rotate(mf, 0.0, deg + 90, 0.0, cx, cy, w / 2);
267 evas_map_util_3d_rotate(mb, 0.0, deg, 0.0, cx, cy, w / 2);
270 case ELM_FLIP_CUBE_RIGHT:
276 evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, w / 2);
277 evas_map_util_3d_rotate(mb, 0.0, deg - 90, 0.0, cx, cy, w / 2);
281 evas_map_util_3d_rotate(mf, 0.0, deg - 90, 0.0, cx, cy, w / 2);
282 evas_map_util_3d_rotate(mb, 0.0, deg, 0.0, cx, cy, w / 2);
285 case ELM_FLIP_CUBE_UP:
291 evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, h / 2);
292 evas_map_util_3d_rotate(mb, deg + 90, 0.0, 0.0, cx, cy, h / 2);
296 evas_map_util_3d_rotate(mf, deg + 90, 0.0, 0.0, cx, cy, h / 2);
297 evas_map_util_3d_rotate(mb, deg, 0.0, 0.0, cx, cy, h / 2);
300 case ELM_FLIP_CUBE_DOWN:
306 evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, h / 2);
307 evas_map_util_3d_rotate(mb, deg - 90, 0.0, 0.0, cx, cy, h / 2);
311 evas_map_util_3d_rotate(mf, deg - 90, 0.0, 0.0, cx, cy, h / 2);
312 evas_map_util_3d_rotate(mb, deg, 0.0, 0.0, cx, cy, h / 2);
320 if (wd->front.content)
322 evas_map_util_3d_lighting(mf, lx, ly, lz, lr, lg, lb, lar, lag, lab);
323 evas_map_util_3d_perspective(mf, px, py, 0, foc);
324 evas_object_map_set(wd->front.content, mf);
325 evas_object_map_enable_set(wd->front.content, 1);
326 if (evas_map_util_clockwise_get(mf)) evas_object_show(wd->front.clip);
327 else evas_object_hide(wd->front.clip);
330 if (wd->back.content)
332 evas_map_util_3d_lighting(mb, lx, ly, lz, lr, lg, lb, lar, lag, lab);
333 evas_map_util_3d_perspective(mb, px, py, 0, foc);
334 evas_object_map_set(wd->back.content, mb);
335 evas_object_map_enable_set(wd->back.content, 1);
336 if (evas_map_util_clockwise_get(mb)) evas_object_show(wd->back.clip);
337 else evas_object_hide(wd->back.clip);
345 evas_object_map_enable_set(wd->front.content, 0);
346 evas_object_map_enable_set(wd->back.content, 0);
347 // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow
348 evas_object_resize(wd->front.content, 0, 0);
349 evas_object_resize(wd->back.content, 0, 0);
350 evas_smart_objects_calculate(evas_object_evas_get(obj));
353 wd->state = !wd->state;
355 evas_object_smart_callback_call(obj, SIG_ANIMATE_DONE, NULL);
356 return ECORE_CALLBACK_CANCEL;
358 return ECORE_CALLBACK_RENEW;
362 _configure(Evas_Object *obj)
364 Widget_Data *wd = elm_widget_data_get(obj);
365 Evas_Coord x, y, w, h;
367 evas_object_geometry_get(obj, &x, &y, &w, &h);
368 if (wd->front.content)
371 evas_object_move(wd->front.content, x, y);
372 evas_object_resize(wd->front.content, w, h);
374 if (wd->back.content)
377 evas_object_move(wd->back.content, x, y);
378 evas_object_resize(wd->back.content, w, h);
384 _move(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
390 _resize(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
402 * Add a new flip to the parent
404 * @param parent The parent object
405 * @return The new object or NULL if it cannot be created
410 elm_flip_add(Evas_Object *parent)
416 ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
418 ELM_SET_WIDTYPE(widtype, "flip");
419 elm_widget_type_set(obj, "flip");
420 elm_widget_sub_object_add(parent, obj);
421 elm_widget_data_set(obj, wd);
422 elm_widget_del_hook_set(obj, _del_hook);
423 elm_widget_theme_hook_set(obj, _theme_hook);
424 elm_widget_focus_next_hook_set(obj, _elm_flip_focus_next_hook);
425 elm_widget_can_focus_set(obj, EINA_FALSE);
427 wd->clip = evas_object_rectangle_add(e);
428 evas_object_static_clip_set(wd->clip, 1);
429 evas_object_color_set(wd->clip, 255, 255, 255, 255);
430 evas_object_move(wd->clip, -49999, -49999);
431 evas_object_resize(wd->clip, 99999, 99999);
432 elm_widget_sub_object_add(obj, wd->clip);
433 evas_object_clip_set(wd->clip, evas_object_clip_get(obj));
434 evas_object_smart_member_add(wd->clip, obj);
436 wd->front.clip = evas_object_rectangle_add(e);
437 evas_object_static_clip_set(wd->front.clip, 1);
438 evas_object_data_set(wd->front.clip, "_elm_leaveme", obj);
439 evas_object_color_set(wd->front.clip, 255, 255, 255, 255);
440 evas_object_move(wd->front.clip, -49999, -49999);
441 evas_object_resize(wd->front.clip, 99999, 99999);
442 elm_widget_sub_object_add(obj, wd->front.clip);
443 evas_object_smart_member_add(wd->front.clip, obj);
444 evas_object_clip_set(wd->front.clip, wd->clip);
446 wd->back.clip = evas_object_rectangle_add(e);
447 evas_object_static_clip_set(wd->back.clip, 1);
448 evas_object_data_set(wd->back.clip, "_elm_leaveme", obj);
449 evas_object_color_set(wd->back.clip, 255, 255, 255, 255);
450 evas_object_move(wd->back.clip, -49999, -49999);
451 evas_object_resize(wd->back.clip, 99999, 99999);
452 elm_widget_sub_object_add(wd->back.clip, obj);
453 evas_object_smart_member_add(obj, wd->back.clip);
454 evas_object_clip_set(wd->back.clip, wd->clip);
456 evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
457 evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _move, NULL);
458 evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize, NULL);
460 evas_object_smart_callbacks_descriptions_set(obj, _signals);
470 * Set the front content of the flip widget.
472 * Once the content object is set, a previously set one will be deleted.
473 * If you want to keep that old content object, use the
474 * elm_flip_content_front_unset() function.
476 * @param obj The flip object
477 * @param content The new front content object
482 elm_flip_content_front_set(Evas_Object *obj, Evas_Object *content)
484 ELM_CHECK_WIDTYPE(obj, widtype);
485 Widget_Data *wd = elm_widget_data_get(obj);
487 if (wd->front.content == content) return;
488 if (wd->front.content) evas_object_del(wd->back.content);
489 wd->front.content = content;
492 elm_widget_sub_object_add(obj, content);
493 evas_object_smart_member_add(content, obj);
494 evas_object_clip_set(content, wd->front.clip);
495 evas_object_event_callback_add(content,
496 EVAS_CALLBACK_CHANGED_SIZE_HINTS,
497 _changed_size_hints, obj);
500 // force calc to contents are the right size before transition
501 evas_smart_objects_calculate(evas_object_evas_get(obj));
507 * Set the back content of the flip widget.
509 * Once the content object is set, a previously set one will be deleted.
510 * If you want to keep that old content object, use the
511 * elm_flip_content_back_unset() function.
513 * @param obj The flip object
514 * @param content The new back content object
519 elm_flip_content_back_set(Evas_Object *obj, Evas_Object *content)
521 ELM_CHECK_WIDTYPE(obj, widtype);
522 Widget_Data *wd = elm_widget_data_get(obj);
524 if (wd->back.content == content) return;
525 if (wd->back.content) evas_object_del(wd->back.content);
526 wd->back.content = content;
529 elm_widget_sub_object_add(obj, content);
530 evas_object_smart_member_add(content, obj);
531 evas_object_clip_set(content, wd->back.clip);
532 evas_object_event_callback_add(content,
533 EVAS_CALLBACK_CHANGED_SIZE_HINTS,
534 _changed_size_hints, obj);
537 // force calc to contents are the right size before transition
538 evas_smart_objects_calculate(evas_object_evas_get(obj));
544 * Get the front content used for the flip
546 * Return the front content object which is set for this widget.
548 * @param obj The flip object
549 * @return The front content object that is being used
554 elm_flip_content_front_get(const Evas_Object *obj)
556 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
557 Widget_Data *wd = elm_widget_data_get(obj);
558 return wd->front.content;
563 * Get the back content used for the flip
565 * Return the back content object which is set for this widget.
567 * @param obj The flip object
568 * @return The back content object that is being used
573 elm_flip_content_back_get(const Evas_Object *obj)
575 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
576 Widget_Data *wd = elm_widget_data_get(obj);
577 return wd->back.content;
581 * Unset the front content used for the flip
583 * Unparent and return the front content object which was set for this widget.
585 * @param obj The flip object
586 * @return The front content object that was being used
591 elm_flip_content_front_unset(Evas_Object *obj)
593 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
594 Widget_Data *wd = elm_widget_data_get(obj);
595 if (!wd) return NULL;
596 if (!wd->front.content) return NULL;
597 Evas_Object *content = wd->front.content;
598 evas_object_clip_unset(content);
599 elm_widget_sub_object_del(obj, content);
600 evas_object_smart_member_del(content);
601 wd->front.content = NULL;
606 * Unset the back content used for the flip
608 * Unparent and return the back content object which was set for this widget.
610 * @param obj The flip object
611 * @return The back content object that was being used
616 elm_flip_content_back_unset(Evas_Object *obj)
618 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
619 Widget_Data *wd = elm_widget_data_get(obj);
620 if (!wd) return NULL;
621 if (!wd->back.content) return NULL;
622 Evas_Object *content = wd->back.content;
623 evas_object_clip_unset(content);
624 elm_widget_sub_object_del(obj, content);
625 evas_object_smart_member_del(content);
626 wd->back.content = NULL;
631 * Get flip front visibility state
633 * @param obj The flip object
634 * @return If front front is showing or not currently
639 elm_flip_front_get(const Evas_Object *obj)
641 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
642 Widget_Data *wd = elm_widget_data_get(obj);
643 if (!wd) return EINA_FALSE;
648 * Set flip perspective
650 * @param obj The flip object
651 * @param foc The coordinate to set the focus on
652 * @param x The X coordinate
653 * @param y The Y coordinate
655 * NOTE: This function currently does nothing.
660 elm_flip_perspective_set(Evas_Object *obj, Evas_Coord foc __UNUSED__, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
662 ELM_CHECK_WIDTYPE(obj, widtype);
663 Widget_Data *wd = elm_widget_data_get(obj);
668 * Runs the flip animation
670 * @param obj The flip object
671 * @param mode The mode type. Currently accepted modes are:
673 * ELM_FLIP_ROTATE_Y_CENTER_AXIS
674 * ELM_FLIP_ROTATE_X_CENTER_AXIS
675 * ELM_FLIP_ROTATE_XZ_CENTER_AXIS
676 * ELM_FLIP_ROTATE_YZ_CENTER_AXIS
678 * ELM_FLIP_CUBE_RIGHT
680 * FIXME: add - ELM_FLIP_CUBE_UP
681 * FIXMEL add - ELM_FLIP_CUBE_DOWN
686 elm_flip_go(Evas_Object *obj, Elm_Flip_Mode mode)
688 ELM_CHECK_WIDTYPE(obj, widtype);
689 Widget_Data *wd = elm_widget_data_get(obj);
691 if (!wd->animator) wd->animator = ecore_animator_add(_animate, obj);
694 wd->start = ecore_loop_time_get();
696 // force calc to contents are the right size before transition
697 evas_smart_objects_calculate(evas_object_evas_get(obj));
699 // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow
700 evas_object_map_enable_set(wd->front.content, 0);
701 evas_object_map_enable_set(wd->back.content, 0);
702 evas_object_resize(wd->front.content, 0, 0);
703 evas_object_resize(wd->back.content, 0, 0);
704 evas_smart_objects_calculate(evas_object_evas_get(obj));