From f61c62bb742217f9c7e216ca2cfa7dbae8664934 Mon Sep 17 00:00:00 2001 From: glima Date: Fri, 10 Jun 2011 21:32:02 +0000 Subject: [PATCH] [evas] Examples on the last block of documented functions. git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/evas@60209 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- doc/examples.dox | 7 ++ src/examples/Makefile.am | 4 + src/examples/evas-events.c | 262 +++++++++++++++++++++++++++++++++++++++++++++ src/lib/Evas.h | 124 ++++++++++++++------- 4 files changed, 359 insertions(+), 38 deletions(-) create mode 100644 src/examples/evas-events.c diff --git a/doc/examples.dox b/doc/examples.dox index ccc7720..c537822 100644 --- a/doc/examples.dox +++ b/doc/examples.dox @@ -33,3 +33,10 @@ * @include evas-load-error-str.c * @example evas-load-error-str.c */ + +/** + * @page Example_Evas_Events Evas' canvas events example + * + * @include evas-events.c + * @example evas-events.c + */ diff --git a/src/examples/Makefile.am b/src/examples/Makefile.am index a632d82..5fb714b 100644 --- a/src/examples/Makefile.am +++ b/src/examples/Makefile.am @@ -42,6 +42,10 @@ pkglib_PROGRAMS += evas_load_error_str evas_load_error_str_SOURCES = evas-load-error-str.c evas_load_error_str_LDADD = $(top_builddir)/src/lib/libevas.la @ECORE_EVAS_LIBS@ +pkglib_PROGRAMS += evas_events +evas_events_SOURCES = evas-events.c +evas_events_LDADD = $(top_builddir)/src/lib/libevas.la @ECORE_EVAS_LIBS@ + endif # if BUILD_EXAMPLES filesdir = $(datadir)/$(PACKAGE)/examples diff --git a/src/examples/evas-events.c b/src/examples/evas-events.c new file mode 100644 index 0000000..655ca27 --- /dev/null +++ b/src/examples/evas-events.c @@ -0,0 +1,262 @@ +/** + * Simple Evas example illustrating how to interact with canvas + * events and other canvas operations. + * + * You'll need at least one engine built for it (excluding the buffer + * one) and the png image loader also built. See stdout/stderr for + * output. + * + * @verbatim + * gcc -o evas-events evas-events.c `pkg-config --libs --cflags ecore-evas` + * @endverbatim + */ + +#ifdef HAVE_CONFIG_H + +#include "config.h" +#endif + +#include +#include +#include +#include + +#define WIDTH (320) +#define HEIGHT (240) + +static const char *img_path = PACKAGE_EXAMPLES_DIR "/enlightenment.png"; + +struct test_data +{ + Ecore_Evas *ee; + Evas *canvas; + Eina_Bool obscured; + Evas_Object *img, *img2, *bg; + Ecore_Timer *resize_timer, *freeze_timer; +}; + +static struct test_data d = {0}; + +/* here just to keep our example's window size and background image's + * size in synchrony */ +static void +_canvas_resize_cb(Ecore_Evas *ee) +{ + int w, h; + + ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); + evas_object_resize(d.bg, w, h); +} + +static void +/* called when our rectangle gets focus */ +_object_focus_in_cb(void *data __UNUSED__, + Evas *e, + void *event_info) +{ + fprintf(stdout, "An object got focused: %s\n", + evas_object_name_get(event_info)); + + fprintf(stdout, "Let's recheck it: %s\n", + evas_object_name_get(evas_focus_get(e))); +} + +static void +_render_flush_cb(void *data __UNUSED__, + Evas *e __UNUSED__, + void *event_info __UNUSED__) +{ + fprintf(stdout, "Canvas is about to flush its rendering pipeline!\n"); +} + +static Eina_Bool +/* put some action in the canvas */ +_resize_cb(void *data __UNUSED__) +{ + int w, h, cw, ch; + + evas_object_geometry_get(d.img, NULL, NULL, &w, &h); + ecore_evas_geometry_get(d.ee, NULL, NULL, &cw, &ch); + + if (w < cw) + evas_object_resize(d.img, cw, ch); + else + evas_object_resize(d.img, cw / 2, ch / 2); + + return EINA_TRUE; /* re-issue the timer */ +} + +static Eina_Bool +/* let's have our events back */ +_thaw_cb(void *data __UNUSED__) +{ + fprintf(stdout, "Canvas was frozen %d times, now thawing.\n", + evas_event_freeze_get(d.canvas)); + evas_event_thaw(d.canvas); + return EINA_FALSE; /* do not re-issue the timer */ +} + +static void +_on_keydown(void *data __UNUSED__, + Evas *evas, + Evas_Object *o __UNUSED__, + void *einfo) +{ + const Evas_Modifier *mods; + Evas_Event_Key_Down *ev = einfo; + + fprintf(stdout, "we've got key input: %s\n", ev->keyname); + + if (strcmp(ev->keyname, "a") == 0) /* toggle animation timer */ + { + if (d.resize_timer != NULL) + { + fprintf(stdout, "Stopping animation timer\n"); + ecore_timer_del(d.resize_timer); + d.resize_timer = NULL; + } + else + { + fprintf(stdout, "Re-issuing animation timer\n"); + d.resize_timer = ecore_timer_add(2, _resize_cb, NULL); + } + return; + } + + if (strcmp(ev->keyname, "d") == 0) /* delete canvas' callbacks */ + { + fprintf(stdout, "Deleting canvas event callbacks\n"); + evas_event_callback_del_full(evas, EVAS_CALLBACK_RENDER_FLUSH_PRE, + _render_flush_cb, NULL); + evas_event_callback_del_full( + evas, EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, + _object_focus_in_cb, NULL); + return; + } + + if (strcmp(ev->keyname, "f") == 0) /* freeze input for 3 seconds */ + { + fprintf(stdout, "Freezing input for 3 seconds\n"); + evas_event_freeze(evas); + d.freeze_timer = ecore_timer_add(3, _thaw_cb, NULL); + return; + } + + mods = evas_key_modifier_get(evas); + if (evas_key_modifier_is_set(mods, "Control") && + (strcmp(ev->keyname, "o") == 0)) /* add an obscured + * rectangle to the middle + * of the canvas */ + { + fprintf(stdout, "Toggling obscured rectangle on canvas\n"); + if (!d.obscured) + { + int w, h; + evas_output_viewport_get(evas, NULL, NULL, &w, &h); + evas_obscured_rectangle_add(evas, w / 4, h / 4, w / 2, h / 2); + } + else + { + int w, h; + Eina_Rectangle *rect; + Eina_List *updates, *l; + + evas_output_viewport_get(evas, NULL, NULL, &w, &h); + evas_obscured_clear(evas); + + /* we have to flag a damage region here because + * evas_obscured_clear() doesn't change the canvas' + * state. we'd have to wait for an animation step, for + * example, to get the result, without it */ + evas_damage_rectangle_add(evas, 0, 0, w, h); + + updates = evas_render_updates(evas); + + EINA_LIST_FOREACH(updates, l, rect) + { + fprintf(stdout, "Rectangle (%d, %d, %d, %d) on canvas got a" + " rendering update.\n", rect->x, rect->y, rect->w, + rect->h); + } + evas_render_updates_free(updates); + } + d.obscured = !d.obscured; + } +} + +int +main(void) +{ + int err; + + if (!ecore_evas_init()) + return EXIT_FAILURE; + + /* this will give you a window with an Evas canvas under the first + * engine available */ + d.ee = ecore_evas_new(NULL, 10, 10, WIDTH, HEIGHT, NULL); + if (!d.ee) + goto error; + + ecore_evas_callback_resize_set(d.ee, _canvas_resize_cb); + ecore_evas_show(d.ee); + + /* the canvas pointer, de facto */ + d.canvas = ecore_evas_get(d.ee); + + evas_event_callback_add(d.canvas, EVAS_CALLBACK_RENDER_FLUSH_PRE, + _render_flush_cb, NULL); + if (evas_alloc_error() != EVAS_ALLOC_ERROR_NONE) + { + fprintf(stderr, "ERROR: Callback registering failed! Abort!\n"); + goto panic; + } + + evas_event_callback_add(d.canvas, EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, + _object_focus_in_cb, NULL); + if (evas_alloc_error() != EVAS_ALLOC_ERROR_NONE) + { + fprintf(stderr, "ERROR: Callback registering failed! Abort!\n"); + goto panic; + } /* two canvas event callbacks */ + + d.bg = evas_object_rectangle_add(d.canvas); + evas_object_name_set(d.bg, "our dear rectangle"); + evas_object_color_set(d.bg, 255, 255, 255, 255); /* white bg */ + evas_object_move(d.bg, 0, 0); /* at canvas' origin */ + evas_object_resize(d.bg, WIDTH, HEIGHT); /* covers full canvas */ + evas_object_show(d.bg); + + evas_object_focus_set(d.bg, EINA_TRUE); + evas_object_event_callback_add( + d.bg, EVAS_CALLBACK_KEY_DOWN, _on_keydown, NULL); + + d.img = evas_object_image_filled_add(d.canvas); + evas_object_image_file_set(d.img, img_path, NULL); + err = evas_object_image_load_error_get(d.img); + if (err != EVAS_LOAD_ERROR_NONE) + { + goto panic; + } + else + { + evas_object_move(d.img, 0, 0); + evas_object_resize(d.img, WIDTH, HEIGHT); + evas_object_show(d.img); + } + + d.resize_timer = ecore_timer_add(2, _resize_cb, NULL); + + ecore_main_loop_begin(); + + ecore_evas_free(d.ee); + ecore_evas_shutdown(); + return 0; + +error: + fprintf(stderr, "you got to have at least one evas engine built and linked" + " up to ecore-evas for this example to run properly.\n"); +panic: + ecore_evas_shutdown(); + return -1; +} diff --git a/src/lib/Evas.h b/src/lib/Evas.h index e48980d..1f4d6d7 100644 --- a/src/lib/Evas.h +++ b/src/lib/Evas.h @@ -1288,9 +1288,26 @@ EAPI void evas_damage_rectangle_add (Evas *e, int x, int y, * @note This is a very low level function, which most of * Evas' users wouldn't care about. * + * @note This function does not flag the canvas as having its + * state changed. If you want to re-render it afterwards expecting new + * contents, you have to add "damage" regions yourself (see + * evas_damage_rectangle_add()). + * * @see evas_obscured_clear() * @see evas_render_updates() * + * Example code follows. + * @dontinclude evas-events.c + * @skip add an obscured + * @until evas_obscured_clear(evas); + * + * In that example, pressing the "Ctrl" and "o" keys will impose or + * remove an obscured region in the middle of the canvas. You'll get + * the same contents at the time the key was pressed, if toggling it + * on, until you toggle it off again (make sure the animation is + * running on to get the idea better). See the full @ref + * Example_Evas_Events "example". + * * @ingroup Evas_Canvas */ EAPI void evas_obscured_rectangle_add (Evas *e, int x, int y, int w, int h) EINA_ARG_NONNULL(1); @@ -1308,7 +1325,12 @@ EAPI void evas_obscured_rectangle_add (Evas *e, int x, int y, * @note This is a very low level function, which most of * Evas' users wouldn't care about. * - * @see evas_obscured_rectangle_add() + * @note This function does not flag the canvas as having its + * state changed. If you want to re-render it afterwards expecting new + * contents, you have to add "damage" regions yourself (see + * evas_damage_rectangle_add()). + * + * @see evas_obscured_rectangle_add() for an example * @see evas_render_updates() * * @ingroup Evas_Canvas @@ -1331,6 +1353,17 @@ EAPI void evas_obscured_clear (Evas *e) EINA_ARG_NONN * grab an Evas' canvas update regions and paint them back, using the * canvas' pixmap, on a displaying system working below Evas. * + * @note Evas is a stateful canvas. If no operations changing its + * state took place since the last rendering action, you won't see no + * changes and this call will be a no-op. + * + * Example code follows. + * @dontinclude evas-events.c + * @skip add an obscured + * @until d.obscured = !d.obscured; + * + * See the full @ref Example_Evas_Events "example". + * * @ingroup Evas_Canvas */ EAPI Eina_List *evas_render_updates (Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1); @@ -1343,6 +1376,8 @@ EAPI Eina_List *evas_render_updates (Evas *e) EINA_WARN_UNU * This function removes the region from the render updates list. It * makes the region doesn't be render updated anymore. * + * @see evas_render_updates() for an example + * * @ingroup Evas_Canvas */ EAPI void evas_render_updates_free (Eina_List *updates); @@ -1979,27 +2014,22 @@ EAPI Eina_Bool evas_pointer_inside_get (const Evas *e) EINA_WA * others the @p event_info pointer is going to be @c NULL. * * Example: - * @code - * extern Evas *e; - * extern void *my_data; - * void focus_in_callback(void *data, Evas *e, void *event_info); - * void focus_out_callback(void *data, Evas *e, void *event_info); + * @dontinclude evas-events.c + * @skip evas_event_callback_add(d.canvas, EVAS_CALLBACK_RENDER_FLUSH_PRE + * @until two canvas event callbacks * - * evas_event_callback_add(e, EVAS_CALLBACK_CANVAS_FOCUS_IN, focus_in_callback, - * my_data); - * if (evas_alloc_error() != EVAS_ALLOC_ERROR_NONE) - * { - * fprintf(stderr, "ERROR: Callback registering failed! Abort!\n"); - * exit(-1); - * } - * evas_event_callback_add(e, EVAS_CALLBACK_CANVAS_FOCUS_OUT, - * focus_out_callback, my_data); - * if (evas_alloc_error() != EVAS_ALLOC_ERROR_NONE) - * { - * fprintf(stderr, "ERROR: Callback registering failed! Abort!\n"); - * exit(-1); - * } - * @endcode + * Looking to the callbacks registered above, + * @dontinclude evas-events.c + * @skip called when our rectangle gets focus + * @until let's have our events back + * + * we see that the canvas flushes its rendering pipeline + * (#EVAS_CALLBACK_RENDER_FLUSH_PRE) whenever the @c _resize_cb + * routine takes place: it has to redraw that image at a different + * size. Also, the callback on an object being focused comes just + * after we focus it explicitly, on code. + * + * See the full @ref Example_Evas_Events "example". * * @note Be careful not to add the same callback multiple times, if * that's not what you want, because Evas won't check if a callback @@ -2056,14 +2086,11 @@ EAPI void *evas_event_callback_del (Evas *e, Evas_Callb * would be to remove an exact match of a callback. * * Example: - * @code - * extern Evas *e; - * void *my_data; - * void focus_in_callback(void *data, Evas *e, void *event_info); + * @dontinclude evas-events.c + * @skip evas_event_callback_del_full(evas, EVAS_CALLBACK_RENDER_FLUSH_PRE, + * @until _object_focus_in_cb, NULL); * - * my_data = evas_event_callback_del_full(object, EVAS_CALLBACK_CANVAS_FOCUS_IN, - * focus_in_callback, my_data); - * @endcode + * See the full @ref Example_Evas_Events "example". * * @note For deletion of canvas events callbacks filtering by just * type and function pointer, user evas_event_callback_del(). @@ -2160,16 +2187,19 @@ EAPI void evas_post_event_callback_remove_full (Evas *e, Evas_Objec * interface when you're populating a view or changing the layout. * * Example: - * @code - * extern Evas *evas; - * extern Evas_Object *object; + * @dontinclude evas-events.c + * @skip freeze input for 3 seconds + * @until } + * @dontinclude evas-events.c + * @skip let's have our events back + * @until } * - * evas_event_freeze(evas); - * evas_object_move(object, 50, 100); - * evas_object_resize(object, 200, 200); - * // more realistic code would be a toolkit or Edje doing some UI changes here - * evas_event_thaw(evas); - * @endcode + * See the full @ref Example_Evas_Events "example". + * + * If you run that example, you'll see the canvas ignoring all input + * events for 3 seconds, when the "f" key is pressed. In a more + * realistic code we would be freezing while a toolkit or Edje was + * doing some UI changes, thawing it back afterwards. */ EAPI void evas_event_freeze (Evas *e) EINA_ARG_NONNULL(1); @@ -4356,6 +4386,7 @@ EAPI Evas_Render_Op evas_object_render_op_get (const Evas_Obje * Retrieve the object that currently has focus. * * @param e The Evas canvas to query for focused object on. + * @return The object that has focus or NULL if there is not one. * * Evas can have (at most) one of its objects focused at a time. * Focused objects will be the ones having key events delivered @@ -4375,7 +4406,16 @@ EAPI Evas_Render_Op evas_object_render_op_get (const Evas_Obje * @see evas_object_key_grab * @see evas_object_key_ungrab * - * @return The object that has focus or NULL if there is not one. + * Example: + * @dontinclude evas-events.c + * @skip evas_event_callback_add(d.canvas, EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, + * @until evas_object_focus_set(d.bg, EINA_TRUE); + * @dontinclude evas-events.c + * @skip called when our rectangle gets focus + * @until } + * + * In this example the @c event_info is exactly a pointer to that + * focused rectangle. See the full @ref Example_Evas_Events "example". * * @ingroup Evas_Object_Group_Find */ @@ -8612,6 +8652,14 @@ EAPI int evas_string_char_len_get (const char *str) EINA_ * to your display engine's documentation when using evas through an * Ecore helper wrapper when you need the keynames. * + * Example: + * @dontinclude evas-events.c + * @skip mods = evas_key_modifier_get(evas); + * @until { + * + * All the other @c evas_key functions behave on the same manner. See + * the full @ref Example_Evas_Events "example". + * * @ingroup Evas_Canvas */ -- 2.7.4