/** * Example of multi-touch in Evas. * * You'll need at least one engine built for it (excluding the buffer * one) and the png image loader also built. * * @verbatim * gcc -o evas-multi-touch evas-multi-touch.c `pkg-config --libs --cflags evas ecore ecore-evas eina` -lm * @endverbatim */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #define WIDTH (800) #define HEIGHT (600) #define RED 0 #define GREEN 85 #define BLUE 170 #define ALPHA_BEGIN 64 #define ALPHA_END 192 #define ALPHA_MOVE 255 #define RECT_SIZE 50 struct test_data { Ecore_Evas *ee; Evas *canvas; Evas_Object *bg; Eina_Hash *hash; }; typedef struct touch_point { Evas_Object *begin; Evas_Object *end; Evas_Object *move; int r, g, b; int dev; } Touch_Point; static struct test_data d = {0}; 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 Evas_Object * _rect_add(int x, int y, int r, int g, int b, int alpha) { int ar, ag, ab; Evas_Object *rect = evas_object_rectangle_add(d.canvas); evas_object_resize(rect, RECT_SIZE, RECT_SIZE); evas_object_move(rect, x - (RECT_SIZE / 2), y - (RECT_SIZE / 2)); ar = r * alpha / 255; ag = g * alpha / 255; ab = b * alpha / 255; evas_object_color_set(rect, ar, ag, ab, alpha); return rect; } /* Create 3 rectangles, one to mark the beginning of the touch movement, * another one for the move itself, and the last one to mark the end of the * movement. */ static Touch_Point * _touch_add(int dev, int x, int y) { Touch_Point *tp = calloc(1, sizeof(*tp)); tp->r = (((dev * 50) + RED) % 256); tp->g = (((dev * 50) + GREEN) % 256); tp->b = (((dev * 50) + BLUE) % 256); tp->begin = _rect_add(x, y, tp->r, tp->g, tp->b, ALPHA_BEGIN); tp->end = _rect_add(x, y, tp->r, tp->g, tp->b, ALPHA_END); tp->move = _rect_add(x, y, tp->r, tp->g, tp->b, ALPHA_MOVE); evas_object_show(tp->begin); evas_object_show(tp->move); return tp; } static void _touch_move(Touch_Point *tp, int x, int y) { evas_object_move(tp->move, x - (RECT_SIZE / 2), y - (RECT_SIZE / 2)); } static void _touch_update(Touch_Point *tp, float azimuth, float tilt, float twist, float pressure) { Evas_Map* m = evas_map_new(4); evas_map_util_points_populate_from_object(m, tp->move); int r = tp->r * (1+pressure); int g = tp->g * (1+pressure); int b = tp->b * (1+pressure); int x, y, w, h; evas_object_geometry_get(tp->move, &x, &y, &w, &h); float vheight = cos(tilt); float vbase = sin(tilt); float vx = cos(azimuth) * vbase; float vy = sin(azimuth) * vbase; float rx = (-atan2(vheight,vy) + M_PI/2) * 180.0/M_PI; float ry = (-atan2(vheight,vx) + M_PI/2) * 180.0/M_PI; float rz = (twist) * 180.0/M_PI; /* apply */ evas_object_color_set(tp->move, r, g, b, ALPHA_MOVE); evas_map_util_3d_rotate(m, rx, ry, rz, x+w/2, y+w/2, 0); evas_map_util_3d_perspective(m, x+w/2, y+w/2, 10, 100); evas_map_util_3d_lighting(m, WIDTH/2,HEIGHT/2, -500, 255, 255, 255, 192, 192, 192 ); evas_object_map_set(tp->move, m); evas_object_map_enable_set(tp->move, EINA_TRUE); evas_map_free(m); } static void _touch_end(Touch_Point *tp, int x, int y) { evas_object_hide(tp->move); evas_object_move(tp->end, x - (RECT_SIZE / 2), y - (RECT_SIZE / 2)); evas_object_show(tp->end); } static void _touch_del(Touch_Point *tp) { evas_object_del(tp->begin); evas_object_del(tp->end); evas_object_del(tp->move); free(tp); } static void _mouse_down_handle(int device, int x, int y) { Touch_Point *tp = NULL, *old_tp; tp = _touch_add(device, x, y); old_tp = eina_hash_set(d.hash, &device, tp); if (old_tp) _touch_del(old_tp); } static void _mouse_move_handle(int device, int x, int y) { Touch_Point *tp; tp = eina_hash_find(d.hash, &device); if (!tp) return; _touch_move(tp, x, y); } static void _mouse_update_handle(int device, float azimuth, float tilt, float twist, float pressure) { Touch_Point *tp; tp = eina_hash_find(d.hash, &device); if (!tp) return; _touch_update(tp, azimuth, tilt, twist, pressure); } static void _mouse_up_handle(int device, int x, int y) { Touch_Point *tp; tp = eina_hash_find(d.hash, &device); if (!tp) { printf("ERR: Could not find Touch Point for dev: %d\n", device); return; } _touch_end(tp, x, y); } static void _mouse_down_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_Down *ev = event_info; _mouse_down_handle(0, ev->canvas.x, ev->canvas.y); } static void _multi_down_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Multi_Down *ev = event_info; _mouse_down_handle(ev->device, ev->canvas.x, ev->canvas.y); } static void _mouse_move_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_Move *ev = event_info; _mouse_move_handle(0, ev->cur.canvas.x, ev->cur.canvas.y); } static void _multi_move_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Multi_Move *ev = event_info; _mouse_move_handle(ev->device, ev->cur.canvas.x, ev->cur.canvas.y); } static void _mouse_up_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_Move *ev = event_info; _mouse_up_handle(0, ev->cur.canvas.x, ev->cur.canvas.y); } static void _multi_up_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Multi_Move *ev = event_info; _mouse_up_handle(ev->device, ev->cur.canvas.x, ev->cur.canvas.y); } static void _axis_update_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Axis_Update *ev = event_info; float twist = 0, azimuth = 0, tilt = 0; float pressure = 1, distance = 0; int i; for (i = 0; i < ev->naxis; i++) { float val = ev->axis[i].value; switch (ev->axis[i].label) { case EVAS_AXIS_LABEL_PRESSURE: pressure = val; break; case EVAS_AXIS_LABEL_TWIST: twist = val; break; case EVAS_AXIS_LABEL_AZIMUTH: azimuth = val; break; case EVAS_AXIS_LABEL_TILT: tilt = val; break; case EVAS_AXIS_LABEL_DISTANCE: distance = val; break; default: break; } } printf("distance %.2f, pressure %.2f, twist %.2f, azimuth %.2f, tilt %.2f\n", distance, pressure, twist, azimuth, tilt); _mouse_update_handle(ev->toolid, azimuth, tilt, twist, pressure); } int main(void) { if (!eina_init()) return EXIT_FAILURE; if (!ecore_evas_init()) return EXIT_FAILURE; /* initialize a hash to store the touch points/rectangles */ d.hash = eina_hash_int32_new(EINA_FREE_CB(_touch_del)); /* 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); 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_event_callback_add(d.bg, EVAS_CALLBACK_MULTI_DOWN, _multi_down_cb, &d); evas_object_event_callback_add(d.bg, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, &d); evas_object_event_callback_add(d.bg, EVAS_CALLBACK_MULTI_UP, _multi_up_cb, &d); evas_object_event_callback_add(d.bg, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, &d); evas_object_event_callback_add(d.bg, EVAS_CALLBACK_MULTI_MOVE, _multi_move_cb, &d); evas_object_event_callback_add(d.bg, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, &d); evas_object_event_callback_add(d.bg, EVAS_CALLBACK_AXIS_UPDATE, _axis_update_cb, &d); evas_object_focus_set(d.bg, EINA_TRUE); /* so we get input events */ ecore_main_loop_begin(); evas_object_event_callback_del(d.bg, EVAS_CALLBACK_MULTI_DOWN, _multi_down_cb); evas_object_event_callback_del(d.bg, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb); ecore_evas_free(d.ee); ecore_evas_shutdown(); eina_shutdown(); return 0; error: fprintf(stderr, "error: Requires at least one Evas engine built and linked" " to ecore-evas for this example to run properly.\n"); ecore_evas_shutdown(); return -1; }