792071ecbeb0720013bcd6a360250b3bfed36fed
[framework/uifw/evas.git] / src / examples / evas-smart-object.c
1 /**
2  * Simple Evas example illustrating a custom Evas smart object
3  *
4  * You'll need at least one engine built for it (excluding the buffer
5  * one). See stdout/stderr for output.
6  *
7  * @verbatim
8  * gcc -o evas-smart-object evas-smart-object.c `pkg-config --libs --cflags evas ecore ecore-evas`
9  * @endverbatim
10  */
11
12 #ifdef HAVE_CONFIG_H
13
14 #include "config.h"
15 #else
16
17 #define PACKAGE_EXAMPLES_DIR "."
18 #define __UNUSED__
19
20 #endif
21
22 #include <Ecore.h>
23 #include <Ecore_Evas.h>
24 #include <stdio.h>
25 #include <errno.h>
26
27 #define WIDTH  (320)
28 #define HEIGHT (240)
29
30 static const char *commands = \
31   "commands are:\n"
32   "\tl - insert child rectangle on the left\n"
33   "\tr - insert child rectangle on the right\n"
34   "\tright arrow - move smart object to the right\n"
35   "\tleft arrow - move smart object to the left\n"
36   "\tup arrow - move smart object up\n"
37   "\tdown arrow - move smart object down\n"
38   "\td - decrease smart object's size\n"
39   "\ti - increase smart object's size\n"
40   "\tc - change smart object's clipper color\n"
41   "\th - print help\n";
42
43 #define WHITE {255, 255, 255, 255}
44 #define RED   {255, 0, 0, 255}
45 #define GREEN {0, 255, 0, 255}
46 #define BLUE  {0, 0, 255, 255}
47
48 struct test_data
49 {
50    Ecore_Evas  *ee;
51    Evas        *evas;
52    Evas_Object *smt, *bg, *clipper;
53 };
54
55 struct color_tuple
56 {
57    int r, g, b, a;
58 } clipper_colors[4] = {WHITE, RED, GREEN, BLUE};
59 int cur_color = 0;
60
61 static const char *
62 _index_to_color(int i)
63 {
64    switch (i)
65      {
66       case 0:
67         return "WHITE (default)";
68
69       case 1:
70         return "RED";
71
72       case 2:
73         return "GREEN";
74
75       case 3:
76         return "BLUE";
77
78       default:
79         return "other";
80      }
81 }
82
83 static struct test_data d = {0};
84 static const char *border_img_path = PACKAGE_EXAMPLES_DIR "/red.png";
85
86 #define _evas_smart_example_type "Evas_Smart_Example"
87 #define SIG_CHILD_ADDED          "child,added"
88 #define SIG_CHILD_REMOVED        "child,removed"
89
90 static const Evas_Smart_Cb_Description _signals[] =
91 {
92    {SIG_CHILD_ADDED, ""},
93    {SIG_CHILD_REMOVED, ""},
94    {NULL, NULL}
95 };
96
97 typedef struct _Evas_Smart_Example_Data Evas_Smart_Example_Data;
98 /*
99  * This structure augments clipped smart object's instance data,
100  * providing extra members required by our example smart object's
101  * implementation.
102  */
103 struct _Evas_Smart_Example_Data
104 {
105    Evas_Object_Smart_Clipped_Data base;
106    Evas_Object                   *children[2], *border;
107 };
108
109 #define EVAS_SMART_EXAMPLE_DATA_GET(o, ptr) \
110   Evas_Smart_Example_Data * ptr = evas_object_smart_data_get(o)
111
112 #define EVAS_SMART_EXAMPLE_DATA_GET_OR_RETURN(o, ptr)        \
113   EVAS_SMART_EXAMPLE_DATA_GET(o, ptr);                       \
114   if (!ptr)                                                  \
115     {                                                        \
116        fprintf(stderr, "No widget data for object %p (%s)!", \
117                o, evas_object_type_get(o));                  \
118        fflush(stderr);                                       \
119        abort();                                              \
120        return;                                               \
121     }
122
123 #define EVAS_SMART_EXAMPLE_DATA_GET_OR_RETURN_VAL(o, ptr, val) \
124   EVAS_SMART_EXAMPLE_DATA_GET(o, ptr);                         \
125   if (!ptr)                                                    \
126     {                                                          \
127        fprintf(stderr, "No widget data for object %p (%s)!",   \
128                o, evas_object_type_get(o));                    \
129        fflush(stderr);                                         \
130        abort();                                                \
131        return val;                                             \
132     }
133
134 EVAS_SMART_SUBCLASS_NEW(_evas_smart_example_type, _evas_smart_example,
135                         Evas_Smart_Class, Evas_Smart_Class,
136                         evas_object_smart_clipped_class_get, _signals);
137
138 static void
139 _on_destroy(Ecore_Evas *ee __UNUSED__)
140 {
141    ecore_main_loop_quit();
142 }
143
144 /* here just to keep our example's window size and background image's
145  * size in synchrony */
146 static void
147 _canvas_resize_cb(Ecore_Evas *ee)
148 {
149    int w, h;
150
151    ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
152    evas_object_resize(d.bg, w, h);
153 }
154
155 static void
156 _on_child_del(void        *data,
157               Evas        *evas __UNUSED__,
158               Evas_Object *o,
159               void        *einfo __UNUSED__)
160 {
161    Evas_Object *example_smart = data;
162    int index;
163
164    EVAS_SMART_EXAMPLE_DATA_GET(example_smart, priv);
165
166    index = (int)evas_object_data_get(o, "index");
167    index--;
168
169    priv->children[index] = NULL;
170
171    evas_object_smart_member_del(o);
172    evas_object_smart_changed(example_smart);
173 }
174
175 static void
176 _evas_smart_example_child_callbacks_unregister(Evas_Object *obj)
177 {
178    evas_object_data_set(obj, "index", NULL);
179    evas_object_event_callback_del(obj, EVAS_CALLBACK_FREE, _on_child_del);
180 }
181
182 static void
183 _evas_smart_example_child_callbacks_register(Evas_Object *o,
184                                              Evas_Object *child,
185                                              int          index)
186 {
187    evas_object_event_callback_add(child, EVAS_CALLBACK_FREE, _on_child_del, o);
188    evas_object_data_set(child, "index", (void *)(++index));
189 }
190
191 /* create and setup a new example smart object's internals */
192 static void
193 _evas_smart_example_smart_add(Evas_Object *o)
194 {
195    EVAS_SMART_DATA_ALLOC(o, Evas_Smart_Example_Data);
196
197    /* this is a border around the smart object's area, delimiting it */
198    priv->border = evas_object_image_filled_add(evas_object_evas_get(o));
199    evas_object_image_file_set(priv->border, border_img_path, NULL);
200    evas_object_image_border_set(priv->border, 3, 3, 3, 3);
201    evas_object_image_border_center_fill_set(
202      priv->border, EVAS_BORDER_FILL_NONE);
203    evas_object_smart_member_add(priv->border, o);
204
205    _evas_smart_example_parent_sc->add(o);
206 }
207
208 static void
209 _evas_smart_example_smart_del(Evas_Object *o)
210 {
211    EVAS_SMART_EXAMPLE_DATA_GET(o, priv);
212
213    if (priv->children[0])
214      {
215         _evas_smart_example_child_callbacks_unregister(priv->children[0]);
216         priv->children[0] = NULL;
217      }
218
219    if (priv->children[1])
220      {
221         _evas_smart_example_child_callbacks_unregister(priv->children[1]);
222         priv->children[1] = NULL;
223      }
224
225    _evas_smart_example_parent_sc->del(o);
226 }
227
228 static void
229 _evas_smart_example_smart_show(Evas_Object *o)
230 {
231    EVAS_SMART_EXAMPLE_DATA_GET(o, priv);
232
233    if (priv->children[0]) evas_object_show(priv->children[0]);
234    if (priv->children[1]) evas_object_show(priv->children[1]);
235    evas_object_show(priv->border);
236
237    _evas_smart_example_parent_sc->show(o);
238 }
239
240 static void
241 _evas_smart_example_smart_hide(Evas_Object *o)
242 {
243    EVAS_SMART_EXAMPLE_DATA_GET(o, priv);
244
245    if (priv->children[0]) evas_object_hide(priv->children[0]);
246    if (priv->children[1]) evas_object_hide(priv->children[1]);
247    evas_object_hide(priv->border);
248
249    _evas_smart_example_parent_sc->hide(o);
250 }
251
252 static void
253 _evas_smart_example_smart_resize(Evas_Object *o,
254                                  Evas_Coord   w,
255                                  Evas_Coord   h)
256 {
257    Evas_Coord ow, oh;
258    evas_object_geometry_get(o, NULL, NULL, &ow, &oh);
259    if ((ow == w) && (oh == h)) return;
260
261    /* this will trigger recalculation */
262    evas_object_smart_changed(o);
263 }
264
265 /* act on child objects' properties, before rendering */
266 static void
267 _evas_smart_example_smart_calculate(Evas_Object *o)
268 {
269    Evas_Coord x, y, w, h;
270
271    EVAS_SMART_EXAMPLE_DATA_GET_OR_RETURN(o, priv);
272    evas_object_geometry_get(o, &x, &y, &w, &h);
273
274    evas_object_resize(priv->border, w, h);
275    evas_object_move(priv->border, x, y);
276
277    if (priv->children[0])
278      {
279         evas_object_move(priv->children[0], x + 3, y + 3);
280         evas_object_resize(priv->children[0], (w / 2) - 3, (h / 2) - 3);
281      }
282
283    if (priv->children[1])
284      {
285         evas_object_move(priv->children[1], x + (w / 2), y + (h / 2));
286         evas_object_resize(priv->children[1], (w / 2) - 3, (h / 2) - 3);
287      }
288 }
289
290 /* setting our smart interface */
291 static void
292 _evas_smart_example_smart_set_user(Evas_Smart_Class *sc)
293 {
294    /* specializing these two */
295     sc->add = _evas_smart_example_smart_add;
296     sc->del = _evas_smart_example_smart_del;
297     sc->show = _evas_smart_example_smart_show;
298     sc->hide = _evas_smart_example_smart_hide;
299
300     /* clipped smart object has no hook on resizes or calculations */
301     sc->resize = _evas_smart_example_smart_resize;
302     sc->calculate = _evas_smart_example_smart_calculate;
303 }
304
305 /* BEGINS example smart object's own interface */
306
307 /* add a new example smart object to a canvas */
308 Evas_Object *
309 evas_smart_example_add(Evas *evas)
310 {
311    return evas_object_smart_add(evas, _evas_smart_example_smart_class_new());
312 }
313
314 /* remove a child element, return its pointer (or NULL on errors) */
315 Evas_Object *
316 evas_smart_example_remove(Evas_Object *o,
317                           Evas_Object *child)
318 {
319    int index;
320
321    EVAS_SMART_EXAMPLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
322
323    if (priv->children[0] != child && priv->children[1] != child)
324      {
325         fprintf(stderr, "You are trying to remove something not belonging to"
326                         " the example smart object!\n");
327         return NULL;
328      }
329
330    index = (int)evas_object_data_get(child, "index");
331    index--;
332
333    priv->children[index] = NULL;
334
335    evas_object_smart_callback_call(o, SIG_CHILD_REMOVED, child);
336    _evas_smart_example_child_callbacks_unregister(child);
337    evas_object_smart_member_del(child);
338    evas_object_smart_changed(o);
339
340    return child;
341 }
342
343 /* set to return any previous object set to the left position of the
344  * smart object or NULL, if any (or on errors) */
345 Evas_Object *
346 evas_smart_example_set_left(Evas_Object *o,
347                             Evas_Object *child)
348 {
349    Evas_Object *ret = NULL;
350
351    EVAS_SMART_EXAMPLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
352    if (!child)
353      return NULL;
354
355    if (priv->children[1] == child)
356      {
357         fprintf(stderr, "You mustn't place a child on both slots of"
358                         " the example smart object!\n");
359         return NULL;
360      }
361
362    if (priv->children[0])
363      {
364         if (priv->children[0] != child)
365           ret = evas_smart_example_remove(o, priv->children[0]);
366         else return child;
367      }
368
369    priv->children[0] = child;
370    evas_object_smart_callback_call(o, SIG_CHILD_ADDED, child);
371
372    _evas_smart_example_child_callbacks_register(o, child, 0);
373    evas_object_smart_member_add(child, o);
374    evas_object_smart_changed(o);
375
376    return ret;
377 }
378
379 /* set to return any previous object set to the right position of the
380  * smart object or NULL, if any (or on errors) */
381 Evas_Object *
382 evas_smart_example_set_right(Evas_Object *o,
383                              Evas_Object *child)
384 {
385    Evas_Object *ret = NULL;
386
387    EVAS_SMART_EXAMPLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
388    if (!child)
389      return NULL;
390
391    if (priv->children[0] == child)
392      {
393         fprintf(stderr, "You mustn't place a child on both slots of"
394                         " the example smart object!\n");
395         return NULL;
396      }
397
398    if (priv->children[1])
399      {
400         if (priv->children[1] != child)
401           ret = evas_smart_example_remove(o, priv->children[1]);
402         else return child;
403      }
404
405    priv->children[1] = child;
406    evas_object_smart_callback_call(o, SIG_CHILD_ADDED, child);
407
408    _evas_smart_example_child_callbacks_register(o, child, 1);
409    evas_object_smart_member_add(child, o);
410    evas_object_smart_changed(o);
411
412    return ret;
413 }
414
415 /* END OF example smart object's own interface */
416
417 static void
418 _on_keydown(void        *data __UNUSED__,
419             Evas        *evas __UNUSED__,
420             Evas_Object *o __UNUSED__,
421             void        *einfo)
422 {
423    Evas_Event_Key_Down *ev = einfo;
424
425    if (strcmp(ev->keyname, "h") == 0) /* print help */
426      {
427         fprintf(stdout, commands);
428         return;
429      }
430
431    if (strcmp(ev->keyname, "l") == 0) /* insert random colored
432                                        * rectangle on the left */
433      {
434         Evas_Object *rect = evas_object_rectangle_add(d.evas), *prev;
435         evas_object_color_set(
436           rect, rand() % 255, rand() % 255, rand() % 255, 255);
437         evas_object_show(rect);
438
439         prev = evas_smart_example_set_left(d.smt, rect);
440         fprintf(stdout, "Setting smart object's left spot with a new"
441                         " rectangle.\n");
442         fprintf(stdout, "Checking its new smart object parent: %s\n",
443                 evas_object_smart_parent_get(rect) == d.smt ? "OK!" :
444                 "Failure!");
445         if (prev)
446           {
447              int r, g, b;
448
449              evas_object_color_get(prev, &r, &g, &b, NULL);
450              fprintf(stdout, "Deleting previous left child,"
451                              " which had colors (%d, %d, %d)\n", r, g, b);
452              evas_object_del(prev);
453           }
454
455         return;
456      }
457
458    if (strcmp(ev->keyname, "r") == 0) /* insert random colored
459                                        * rectangle on the right */
460      {
461         Evas_Object *rect = evas_object_rectangle_add(d.evas), *prev;
462         evas_object_color_set(
463           rect, rand() % 255, rand() % 255, rand() % 255, 255);
464         evas_object_show(rect);
465
466         prev = evas_smart_example_set_right(d.smt, rect);
467         fprintf(stdout, "Setting smart object's right spot with a new"
468                         " rectangle.\n");
469         fprintf(stdout, "Checking its new smart object parent: %s\n",
470                 evas_object_smart_parent_get(rect) == d.smt ? "OK!" :
471                 "Failure!");
472         if (prev)
473           {
474              int r, g, b;
475
476              evas_object_color_get(prev, &r, &g, &b, NULL);
477              fprintf(stdout, "Deleting previous right child,"
478                              " which had colors (%d, %d, %d)\n", r, g, b);
479              evas_object_del(prev);
480           }
481
482         return;
483      }
484
485    /* move smart object along the canvas */
486    if (strcmp(ev->keyname, "Right") == 0 || strcmp(ev->keyname, "Left") == 0 ||
487        strcmp(ev->keyname, "Up") == 0 || strcmp(ev->keyname, "Down") == 0)
488      {
489         Evas_Coord x, y;
490
491         evas_object_geometry_get(d.smt, &x, &y, NULL, NULL);
492
493         switch (ev->keyname[0])
494           {
495            case 'R':
496              x += 20;
497              break;
498
499            case 'L':
500              x -= 20;
501              break;
502
503            case 'U':
504              y -= 20;
505              break;
506
507            case 'D':
508              y += 20;
509              break;
510           }
511
512         evas_object_move(d.smt, x, y);
513
514         return;
515      }
516
517    /* increase smart object's size */
518    if (strcmp(ev->keyname, "i") == 0)
519      {
520         Evas_Coord w, h;
521
522         evas_object_geometry_get(d.smt, NULL, NULL, &w, &h);
523
524         w *= 1.1;
525         h *= 1.1;
526
527         evas_object_resize(d.smt, w, h);
528
529         return;
530      }
531
532    /* decrease smart object's size */
533    if (strcmp(ev->keyname, "d") == 0)
534      {
535         Evas_Coord w, h;
536
537         evas_object_geometry_get(d.smt, NULL, NULL, &w, &h);
538
539         w *= 0.9;
540         h *= 0.9;
541
542         evas_object_resize(d.smt, w, h);
543
544         return;
545      }
546
547    /* change smart object's clipper color */
548    if (strcmp(ev->keyname, "c") == 0)
549      {
550         cur_color = (cur_color + 1) % 4;
551
552         evas_object_color_set(
553           d.clipper, clipper_colors[cur_color].r, clipper_colors[cur_color].g,
554           clipper_colors[cur_color].b, clipper_colors[cur_color].a);
555
556         fprintf (stderr, "Changing clipper's color to %s\n",
557                  _index_to_color(cur_color));
558
559         return;
560      }
561 }
562
563 int
564 main(void)
565 {
566    Eina_Bool ret;
567
568    srand(time(NULL));
569
570    if (!ecore_evas_init())
571      return EXIT_FAILURE;
572
573    /* this will give you a window with an Evas canvas under the first
574     * engine available */
575    d.ee = ecore_evas_new(NULL, 10, 10, WIDTH, HEIGHT, NULL);
576    if (!d.ee)
577      goto error;
578
579    ecore_evas_callback_destroy_set(d.ee, _on_destroy);
580    ecore_evas_callback_resize_set(d.ee, _canvas_resize_cb);
581    ecore_evas_show(d.ee);
582
583    /* the canvas pointer, de facto */
584    d.evas = ecore_evas_get(d.ee);
585
586    d.bg = evas_object_rectangle_add(d.evas);
587    evas_object_color_set(d.bg, 255, 255, 255, 255);
588    evas_object_move(d.bg, 0, 0);
589    evas_object_resize(d.bg, WIDTH, HEIGHT);
590    evas_object_show(d.bg);
591
592    d.smt = evas_smart_example_add(d.evas);
593    evas_object_move(d.smt, WIDTH / 4, HEIGHT / 4);
594    evas_object_resize(d.smt, WIDTH / 2, HEIGHT / 2);
595    evas_object_show(d.smt);
596
597    ret = evas_object_smart_type_check(d.smt, _evas_smart_example_type);
598    fprintf(stdout, "Adding smart object of type \"%s\" to the canvas: %s.\n",
599            _evas_smart_example_type, ret ? "success" : "failure");
600
601    d.clipper = evas_object_smart_clipped_clipper_get(d.smt);
602    fprintf(stdout, "Checking if clipped smart object's clipper is a "
603            "\"static\" one: %s\n", evas_object_static_clip_get(d.clipper) ?
604            "yes" : "no");
605
606    evas_object_color_set(
607      d.clipper, clipper_colors[cur_color].r, clipper_colors[cur_color].g,
608      clipper_colors[cur_color].b, clipper_colors[cur_color].a);
609
610    evas_object_focus_set(d.bg, EINA_TRUE);
611    evas_object_event_callback_add(
612      d.bg, EVAS_CALLBACK_KEY_DOWN, _on_keydown, NULL);
613
614    fprintf(stdout, commands);
615    ecore_main_loop_begin();
616
617    ecore_evas_free(d.ee);
618    ecore_evas_shutdown();
619    return 0;
620
621 error:
622    fprintf(stderr, "you got to have at least one evas engine built and linked"
623                    " up to ecore-evas for this example to run properly.\n");
624    ecore_evas_shutdown();
625    return -1;
626 }