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 _sizing_eval(Evas_Object *obj)
65 Widget_Data *wd = elm_widget_data_get(obj);
66 Evas_Coord minw = -1, minh = -1, minw2 = -1, minh2 = -1;
67 Evas_Coord maxw = -1, maxh = -1, maxw2 = -1, maxh2 = -1;
69 if (wd->front.content)
70 evas_object_size_hint_min_get(wd->front.content, &minw, &minh);
72 evas_object_size_hint_min_get(wd->back.content, &minw2, &minh2);
73 if (wd->front.content)
74 evas_object_size_hint_max_get(wd->front.content, &maxw, &maxh);
76 evas_object_size_hint_max_get(wd->back.content, &maxw2, &maxh2);
78 if (minw2 > minw) minw = minw2;
79 if (minh2 > minh) minh = minh2;
80 if ((maxw2 >= 0) && (maxw2 < maxw)) maxw = maxw2;
81 if ((maxh2 >= 0) && (maxh2 < maxh)) maxh = maxh2;
83 evas_object_size_hint_min_set(obj, minw, minh);
84 evas_object_size_hint_max_set(obj, maxw, maxh);
88 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
90 Widget_Data *wd = elm_widget_data_get(data);
96 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
98 Widget_Data *wd = elm_widget_data_get(obj);
99 Evas_Object *sub = event_info;
101 if (sub == wd->front.content)
103 evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
104 _changed_size_hints, obj);
105 wd->front.content = NULL;
106 evas_object_hide(wd->front.clip);
109 else if (sub == wd->back.content)
111 evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
112 _changed_size_hints, obj);
113 wd->back.content = NULL;
114 evas_object_hide(wd->back.clip);
120 flip_show_hide(Evas_Object *obj)
122 Widget_Data *wd = elm_widget_data_get(obj);
123 if (elm_flip_front_get(obj))
125 if (wd->front.content)
126 evas_object_show(wd->front.clip);
128 evas_object_hide(wd->front.clip);
129 if (wd->back.content)
130 evas_object_hide(wd->back.clip);
132 evas_object_hide(wd->back.clip);
136 if (wd->front.content)
137 evas_object_hide(wd->front.clip);
139 evas_object_hide(wd->front.clip);
140 if (wd->back.content)
141 evas_object_show(wd->back.clip);
143 evas_object_hide(wd->back.clip);
147 _flip(Evas_Object *obj)
149 Widget_Data *wd = elm_widget_data_get(obj);
150 double t = ecore_loop_time_get() - wd->start;
151 Evas_Coord x, y, w, h;
154 Evas_Coord cx, cy, px, py, foc;
155 int lx, ly, lz, lr, lg, lb, lar, lag, lab;
156 if (!wd->animator) return ECORE_CALLBACK_CANCEL;
158 if (t > 1.0) t = 1.0;
160 if (!wd) return ECORE_CALLBACK_CANCEL;
161 evas_object_geometry_get(obj, &x, &y, &w, &h);
163 mf = evas_map_new(4);
164 evas_map_smooth_set(mf, 0);
165 mb = evas_map_new(4);
166 evas_map_smooth_set(mb, 0);
168 if (wd->front.content)
169 evas_map_util_points_populate_from_object_full(mf, wd->front.content, 0);
170 if (wd->back.content)
171 evas_map_util_points_populate_from_object_full(mb, wd->back.content, 0);
192 case ELM_FLIP_ROTATE_Y_CENTER_AXIS:
195 if (wd->state) deg = 180.0 * p;
196 else deg = 180 + (180.0 * p);
197 evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, 0);
198 evas_map_util_3d_rotate(mb, 0.0, deg + 180.0, 0.0, cx, cy, 0);
200 case ELM_FLIP_ROTATE_X_CENTER_AXIS:
203 if (wd->state) deg = 180.0 * p;
204 else deg = 180 + (180.0 * p);
205 evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, 0);
206 evas_map_util_3d_rotate(mb, deg + 180.0, 0.0, 0.0, cx, cy, 0);
208 case ELM_FLIP_ROTATE_XZ_CENTER_AXIS:
211 if (wd->state) deg = 180.0 * p;
212 else deg = 180 + (180.0 * p);
213 evas_map_util_3d_rotate(mf, deg, 0.0, deg, cx, cy, 0);
214 evas_map_util_3d_rotate(mb, deg + 180.0, 0.0, deg + 180.0, cx, cy, 0);
216 case ELM_FLIP_ROTATE_YZ_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, deg, cx, cy, 0);
222 evas_map_util_3d_rotate(mb, 0.0, deg + 180.0, deg + 180.0, cx, cy, 0);
224 case ELM_FLIP_CUBE_LEFT:
230 evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, w / 2);
231 evas_map_util_3d_rotate(mb, 0.0, deg + 90, 0.0, cx, cy, w / 2);
235 evas_map_util_3d_rotate(mf, 0.0, deg + 90, 0.0, cx, cy, w / 2);
236 evas_map_util_3d_rotate(mb, 0.0, deg, 0.0, cx, cy, w / 2);
239 case ELM_FLIP_CUBE_RIGHT:
245 evas_map_util_3d_rotate(mf, 0.0, deg, 0.0, cx, cy, w / 2);
246 evas_map_util_3d_rotate(mb, 0.0, deg - 90, 0.0, cx, cy, w / 2);
250 evas_map_util_3d_rotate(mf, 0.0, deg - 90, 0.0, cx, cy, w / 2);
251 evas_map_util_3d_rotate(mb, 0.0, deg, 0.0, cx, cy, w / 2);
254 case ELM_FLIP_CUBE_UP:
260 evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, h / 2);
261 evas_map_util_3d_rotate(mb, deg + 90, 0.0, 0.0, cx, cy, h / 2);
265 evas_map_util_3d_rotate(mf, deg + 90, 0.0, 0.0, cx, cy, h / 2);
266 evas_map_util_3d_rotate(mb, deg, 0.0, 0.0, cx, cy, h / 2);
269 case ELM_FLIP_CUBE_DOWN:
275 evas_map_util_3d_rotate(mf, deg, 0.0, 0.0, cx, cy, h / 2);
276 evas_map_util_3d_rotate(mb, deg - 90, 0.0, 0.0, cx, cy, h / 2);
280 evas_map_util_3d_rotate(mf, deg - 90, 0.0, 0.0, cx, cy, h / 2);
281 evas_map_util_3d_rotate(mb, deg, 0.0, 0.0, cx, cy, h / 2);
289 if (wd->front.content)
291 evas_map_util_3d_lighting(mf, lx, ly, lz, lr, lg, lb, lar, lag, lab);
292 evas_map_util_3d_perspective(mf, px, py, 0, foc);
293 evas_object_map_set(wd->front.content, mf);
294 evas_object_map_enable_set(wd->front.content, 1);
295 if (evas_map_util_clockwise_get(mf)) evas_object_show(wd->front.clip);
296 else evas_object_hide(wd->front.clip);
299 if (wd->back.content)
301 evas_map_util_3d_lighting(mb, lx, ly, lz, lr, lg, lb, lar, lag, lab);
302 evas_map_util_3d_perspective(mb, px, py, 0, foc);
303 evas_object_map_set(wd->back.content, mb);
304 evas_object_map_enable_set(wd->back.content, 1);
305 if (evas_map_util_clockwise_get(mb)) evas_object_show(wd->back.clip);
306 else evas_object_hide(wd->back.clip);
314 evas_object_map_enable_set(wd->front.content, 0);
315 evas_object_map_enable_set(wd->back.content, 0);
316 // FIXME: hack around evas rendering bug (only fix makes evas bitch-slow
317 evas_object_resize(wd->front.content, 0, 0);
318 evas_object_resize(wd->back.content, 0, 0);
319 evas_smart_objects_calculate(evas_object_evas_get(obj));
322 wd->state = !wd->state;
324 evas_object_smart_callback_call(obj, "animate,done", NULL);
325 return ECORE_CALLBACK_CANCEL;
327 return ECORE_CALLBACK_RENEW;
331 _configure(Evas_Object *obj)
333 Widget_Data *wd = elm_widget_data_get(obj);
334 Evas_Coord x, y, w, h;
336 evas_object_geometry_get(obj, &x, &y, &w, &h);
337 if (wd->front.content)
340 evas_object_move(wd->front.content, x, y);
341 evas_object_resize(wd->front.content, w, h);
343 if (wd->back.content)
346 evas_object_move(wd->back.content, x, y);
347 evas_object_resize(wd->back.content, w, h);
353 _move(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
359 _resize(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
371 * Add a new flip to the parent
373 * @param parent The parent object
374 * @return The new object or NULL if it cannot be created
379 elm_flip_add(Evas_Object *parent)
385 wd = ELM_NEW(Widget_Data);
386 e = evas_object_evas_get(parent);
387 obj = elm_widget_add(e);
388 ELM_SET_WIDTYPE(widtype, "flip");
389 elm_widget_type_set(obj, "flip");
390 elm_widget_sub_object_add(parent, obj);
391 elm_widget_data_set(obj, wd);
392 elm_widget_del_hook_set(obj, _del_hook);
393 elm_widget_theme_hook_set(obj, _theme_hook);
395 wd->clip = evas_object_rectangle_add(e);
396 evas_object_color_set(wd->clip, 255, 255, 255, 255);
397 evas_object_move(wd->clip, -49999, -49999);
398 evas_object_resize(wd->clip, 99999, 99999);
399 elm_widget_sub_object_add(obj, wd->clip);
400 evas_object_clip_set(wd->clip, evas_object_clip_get(obj));
401 evas_object_smart_member_add(wd->clip, obj);
402 wd->front.clip = evas_object_rectangle_add(e);
403 evas_object_static_clip_set(wd->front.clip, 1);
404 evas_object_data_set(wd->front.clip, "_elm_leaveme", obj);
405 evas_object_color_set(wd->front.clip, 255, 255, 255, 255);
406 evas_object_move(wd->front.clip, -49999, -49999);
407 evas_object_resize(wd->front.clip, 99999, 99999);
408 elm_widget_sub_object_add(obj, wd->front.clip);
409 evas_object_smart_member_add(wd->front.clip, obj);
410 evas_object_clip_set(wd->front.clip, wd->clip);
412 wd->back.clip = evas_object_rectangle_add(e);
413 evas_object_static_clip_set(wd->back.clip, 1);
414 evas_object_data_set(wd->back.clip, "_elm_leaveme", obj);
415 evas_object_color_set(wd->back.clip, 255, 255, 255, 255);
416 evas_object_move(wd->back.clip, -49999, -49999);
417 evas_object_resize(wd->back.clip, 99999, 99999);
418 elm_widget_sub_object_add(wd->back.clip, obj);
419 evas_object_smart_member_add(obj, wd->back.clip);
420 evas_object_clip_set(wd->back.clip, wd->clip);
422 evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
423 evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _move, NULL);
424 evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize, NULL);
433 * Set the flip front content
435 * @param obj The flip object
436 * @param content The content to be used in this flip object
441 elm_flip_content_front_set(Evas_Object *obj, Evas_Object *content)
443 ELM_CHECK_WIDTYPE(obj, widtype);
444 Widget_Data *wd = elm_widget_data_get(obj);
446 if (wd->front.content == content) return;
447 if ((wd->front.content != content) && (wd->front.content))
449 evas_object_clip_set(wd->front.content, NULL);
450 elm_widget_sub_object_del(obj, wd->front.content);
451 evas_object_smart_member_del(wd->front.content);
453 wd->front.content = content;
456 elm_widget_sub_object_add(obj, content);
457 evas_object_smart_member_add(content, obj);
458 evas_object_clip_set(content, wd->front.clip);
459 evas_object_event_callback_add(content,
460 EVAS_CALLBACK_CHANGED_SIZE_HINTS,
461 _changed_size_hints, obj);
469 * Set the flip back content
471 * @param obj The flip object
472 * @param content The content to be used in this flip object
477 elm_flip_content_back_set(Evas_Object *obj, Evas_Object *content)
479 ELM_CHECK_WIDTYPE(obj, widtype);
480 Widget_Data *wd = elm_widget_data_get(obj);
482 if (wd->back.content == content) return;
483 if ((wd->back.content != content) && (wd->back.content))
485 evas_object_clip_set(wd->back.content, NULL);
486 elm_widget_sub_object_del(obj, wd->back.content);
487 evas_object_smart_member_del(wd->back.content);
489 wd->back.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->back.clip);
495 evas_object_event_callback_add(content,
496 EVAS_CALLBACK_CHANGED_SIZE_HINTS,
497 _changed_size_hints, obj);
505 * Get the flip front content
507 * @param obj The flip object
508 * @return The content to be used in this flip object front
513 elm_flip_content_front_get(const Evas_Object *obj)
515 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
516 Widget_Data *wd = elm_widget_data_get(obj);
517 return wd->front.content;
521 * Get the flip back content
523 * @param obj The flip object
524 * @return The content to be used in this flip object back
529 elm_flip_content_back_get(const Evas_Object *obj)
531 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
532 Widget_Data *wd = elm_widget_data_get(obj);
533 return wd->back.content;
537 * Get flip front visibility state
539 * @param obj The flip object
540 * @return If front front is showing or not currently
545 elm_flip_front_get(const Evas_Object *obj)
547 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
548 Widget_Data *wd = elm_widget_data_get(obj);
549 if (!wd) return EINA_FALSE;
554 * Set flip perspective
556 * @param obj The flip object
557 * @param foc The coordinate to set the focus on
558 * @param x The X coordinate
559 * @param y The Y coordinate
561 * NOTE: This function currently does nothing.
566 elm_flip_perspective_set(Evas_Object *obj, Evas_Coord foc __UNUSED__, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
568 ELM_CHECK_WIDTYPE(obj, widtype);
569 Widget_Data *wd = elm_widget_data_get(obj);
574 * Runs the flip animation
576 * @param obj The flip object
577 * @param mode The mode type. Currently accepted modes are:
579 * ELM_FLIP_ROTATE_Y_CENTER_AXIS
580 * ELM_FLIP_ROTATE_X_CENTER_AXIS
581 * ELM_FLIP_ROTATE_XZ_CENTER_AXIS
582 * ELM_FLIP_ROTATE_YZ_CENTER_AXIS
584 * ELM_FLIP_CUBE_RIGHT
589 elm_flip_go(Evas_Object *obj, Elm_Flip_Mode mode)
591 ELM_CHECK_WIDTYPE(obj, widtype);
592 Widget_Data *wd = elm_widget_data_get(obj);
594 if (!wd->animator) wd->animator = ecore_animator_add(_animate, obj);
597 wd->start = ecore_loop_time_get();