From feaacced6d2d217fa095be8feae04d34af99b1e1 Mon Sep 17 00:00:00 2001 From: JengHyun Kang Date: Wed, 10 May 2017 20:59:07 +0900 Subject: [PATCH] Add a pinch gesture Change-Id: Ibb1c9e342cb44632cc7bb5ad8b9ac49143d3a648 --- src/e_mod_gesture_events.c | 216 ++++++++++++++++++++++++++++++++++++++++++--- src/e_mod_main.c | 108 ++++++++++++++++++++++- src/e_mod_main.h | 32 +++++-- 3 files changed, 335 insertions(+), 21 deletions(-) diff --git a/src/e_mod_gesture_events.c b/src/e_mod_gesture_events.c index 4bdcc1d..fa2992d 100644 --- a/src/e_mod_gesture_events.c +++ b/src/e_mod_gesture_events.c @@ -473,13 +473,13 @@ _e_gesture_pan_cancel(void) pans->move_timer = NULL; } - if (pans->state == E_GESTURE_PAN_STATE_MOVING) + if (pans->state == E_GESTURE_PANPINCH_STATE_MOVING) _e_gesture_pan_send(TIZEN_GESTURE_MODE_END, pans->num_pan_fingers, 0, 0, pans->fingers[pans->num_pan_fingers].res, pans->fingers[pans->num_pan_fingers].client); gesture->gesture_filter |= TIZEN_GESTURE_TYPE_PAN; - pans->state = E_GESTURE_PAN_STATE_DONE; + pans->state = E_GESTURE_PANPINCH_STATE_DONE; } static void @@ -501,6 +501,50 @@ _e_gesture_util_center_axis_get(int num_finger, int *x, int *y) *y = calc_y; } +static int +_e_gesture_util_distance_get(int x1, int y1, int x2, int y2) +{ + int distance; + + distance = sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))); + + return distance; +} + +static int +_e_gesture_util_distances_get(int num_finger) +{ + int i; + int cx = 0, cy = 0, distance = 0; + + _e_gesture_util_center_axis_get(num_finger, &cx, &cy); + + for (i = 1; i <= num_finger; i++) + { + distance += _e_gesture_util_distance_get(cx, cy, + gesture->gesture_events.base_point[i].axis.x, + gesture->gesture_events.base_point[i].axis.y); + } + + return distance; +} + +static double +_e_gesture_util_angle_get(int x1, int y1, int x2, int y2) +{ + double angle, xx, yy; + + xx = fabs(x2 - x1); + yy = fabs(y2 - y1); + + angle = atan2(yy, xx); + if ((x1 > x2) && (y1 > y2)) angle = angle + M_PI_2; + else if ((x2 > x1) && (y2 > y1)) angle = angle + M_PI_2; + + angle = RAD2DEG(angle); + return angle; +} + static Eina_Bool _e_gesture_timer_pan_start(void *data) { @@ -517,7 +561,7 @@ _e_gesture_timer_pan_start(void *data) } pans->center_point.x = pans->start_point.x = (int)(pans->start_point.x / num_pressed); pans->center_point.y = pans->start_point.y = (int)(pans->start_point.y / num_pressed); - pans->state = E_GESTURE_PAN_STATE_START; + pans->state = E_GESTURE_PANPINCH_STATE_START; } else { @@ -532,12 +576,13 @@ _e_gesture_process_pan_down(Ecore_Event_Mouse_Button *ev) E_Gesture_Event_Pan *pans = &gesture->gesture_events.pans; if (gesture->gesture_events.recognized_gesture && - !((gesture->gesture_events.recognized_gesture & TIZEN_GESTURE_TYPE_PAN))) + !((gesture->gesture_events.recognized_gesture & TIZEN_GESTURE_TYPE_PAN) || + (gesture->gesture_events.recognized_gesture & TIZEN_GESTURE_TYPE_PINCH))) _e_gesture_pan_cancel(); if (gesture->gesture_events.num_pressed == 1) { - pans->state = E_GESTURE_PAN_STATE_READY; + pans->state = E_GESTURE_PANPINCH_STATE_READY; if (pans->start_timer) ecore_timer_del(pans->start_timer); pans->start_timer = ecore_timer_add(E_GESTURE_PAN_START_TIME, _e_gesture_timer_pan_start, NULL); } @@ -551,12 +596,13 @@ _e_gesture_process_pan_move(Ecore_Event_Mouse_Move *ev) int idx, diff_x, diff_y, mode; if (gesture->gesture_events.recognized_gesture && - !((gesture->gesture_events.recognized_gesture & TIZEN_GESTURE_TYPE_PAN))) + !((gesture->gesture_events.recognized_gesture & TIZEN_GESTURE_TYPE_PAN) || + (gesture->gesture_events.recognized_gesture & TIZEN_GESTURE_TYPE_PINCH))) _e_gesture_pan_cancel(); idx = gesture->gesture_events.num_pressed; if (idx <= 0) return; - if (pans->state == E_GESTURE_PAN_STATE_READY) return; + if (pans->state == E_GESTURE_PANPINCH_STATE_READY) return; _e_gesture_util_center_axis_get(gesture->gesture_events.num_pressed, &cur_point.x, &cur_point.y); @@ -567,12 +613,12 @@ _e_gesture_process_pan_move(Ecore_Event_Mouse_Move *ev) { switch (pans->state) { - case E_GESTURE_PAN_STATE_START: + case E_GESTURE_PANPINCH_STATE_START: mode = TIZEN_GESTURE_MODE_BEGIN; - pans->state = E_GESTURE_PAN_STATE_MOVING; + pans->state = E_GESTURE_PANPINCH_STATE_MOVING; pans->num_pan_fingers = idx; break; - case E_GESTURE_PAN_STATE_MOVING: + case E_GESTURE_PANPINCH_STATE_MOVING: mode = TIZEN_GESTURE_MODE_UPDATE; break; default: @@ -595,6 +641,144 @@ _e_gesture_process_pan_up(Ecore_Event_Mouse_Button *ev) _e_gesture_pan_cancel(); } +static void +_e_gesture_pinch_send(int mode, int fingers, int distance, int angle, int cx, int cy, struct wl_resource *res, struct wl_client *client) +{ + Ecore_Event_Mouse_Button *ev_cancel; + + if (mode == TIZEN_GESTURE_MODE_BEGIN) + { + ev_cancel = E_NEW(Ecore_Event_Mouse_Button, 1); + EINA_SAFETY_ON_NULL_RETURN(ev_cancel); + + ev_cancel->timestamp = (int)(ecore_time_get()*1000); + ev_cancel->same_screen = 1; + + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_CANCEL, ev_cancel, NULL, NULL); + } + + GTINF("Send pinch gesture (fingers: %d, distance: %d, angle: %d, cx: %d, cy: %d) to client: %p, mode: %d\n", fingers, distance, angle, cx, cy, client, mode); + + tizen_gesture_send_pinch(res, mode, fingers, distance, angle, cx, cy); + + gesture->gesture_events.recognized_gesture |= TIZEN_GESTURE_TYPE_PINCH; +} + +static void +_e_gesture_pinch_cancel(void) +{ + E_Gesture_Event_Pinch *pinchs = &gesture->gesture_events.pinchs; + + if (pinchs->start_timer) + { + ecore_timer_del(pinchs->start_timer); + pinchs->start_timer = NULL; + } + if (pinchs->move_timer) + { + ecore_timer_del(pinchs->move_timer); + pinchs->move_timer = NULL; + } + + if (pinchs->state == E_GESTURE_PANPINCH_STATE_MOVING) + _e_gesture_pinch_send(TIZEN_GESTURE_MODE_END, pinchs->num_pinch_fingers, 0, 0, 0, 0, + pinchs->fingers[pinchs->num_pinch_fingers].res, + pinchs->fingers[pinchs->num_pinch_fingers].client); + + gesture->gesture_filter |= TIZEN_GESTURE_TYPE_PINCH; + pinchs->state = E_GESTURE_PANPINCH_STATE_DONE; +} + +static Eina_Bool +_e_gesture_timer_pinch_start(void *data) +{ + E_Gesture_Event_Pinch *pinch = &gesture->gesture_events.pinchs; + int num_pressed = gesture->gesture_events.num_pressed; + + if (pinch->fingers[num_pressed].client) + { + pinch->distance = _e_gesture_util_distances_get(num_pressed); + pinch->state = E_GESTURE_PANPINCH_STATE_START; + } + else + { + _e_gesture_pinch_cancel(); + } + return ECORE_CALLBACK_CANCEL; +} + +static void +_e_gesture_process_pinch_down(Ecore_Event_Mouse_Button *ev) +{ + E_Gesture_Event_Pinch *pinch = &gesture->gesture_events.pinchs; + + if (gesture->gesture_events.recognized_gesture && + !((gesture->gesture_events.recognized_gesture & TIZEN_GESTURE_TYPE_PAN) || + (gesture->gesture_events.recognized_gesture & TIZEN_GESTURE_TYPE_PINCH))) + _e_gesture_pinch_cancel(); + + if (gesture->gesture_events.num_pressed == 1) + { + pinch->state = E_GESTURE_PANPINCH_STATE_READY; + if (pinch->start_timer) ecore_timer_del(pinch->start_timer); + pinch->start_timer = ecore_timer_add(E_GESTURE_PAN_START_TIME, _e_gesture_timer_pinch_start, NULL); + } +} + +static void +_e_gesture_process_pinch_move(Ecore_Event_Mouse_Move *ev) +{ + E_Gesture_Event_Pinch *pinch = &gesture->gesture_events.pinchs; + int idx, current_distance, mode, diff, angle, cx = 0, cy = 0; + + if (gesture->gesture_events.recognized_gesture && + !((gesture->gesture_events.recognized_gesture & TIZEN_GESTURE_TYPE_PAN) || + (gesture->gesture_events.recognized_gesture & TIZEN_GESTURE_TYPE_PINCH))) + _e_gesture_pan_cancel(); + + idx = gesture->gesture_events.num_pressed; + if (idx <= 0) return; + if (pinch->state == E_GESTURE_PANPINCH_STATE_READY) return; + + current_distance = _e_gesture_util_distances_get(idx); + diff = current_distance - pinch->distance; + + if (ABS(diff) > E_GESTURE_PINCH_MOVING_DISTANCE_RANGE) + { + pinch->distance = current_distance; + switch (pinch->state) + { + case E_GESTURE_PANPINCH_STATE_START: + mode = TIZEN_GESTURE_MODE_BEGIN; + pinch->state = E_GESTURE_PANPINCH_STATE_MOVING; + pinch->num_pinch_fingers = idx; + break; + case E_GESTURE_PANPINCH_STATE_MOVING: + mode = TIZEN_GESTURE_MODE_UPDATE; + break; + default: + return; + } + + if (idx == 2) angle = _e_gesture_util_angle_get(gesture->gesture_events.base_point[1].axis.x, + gesture->gesture_events.base_point[1].axis.y, + gesture->gesture_events.base_point[2].axis.x, + gesture->gesture_events.base_point[2].axis.y); + else angle = 0; + + _e_gesture_util_center_axis_get(idx, &cx, &cy); + + _e_gesture_pinch_send(mode, idx, pinch->distance, angle, cx, cy, pinch->fingers[idx].res, pinch->fingers[idx].client); + } +} + +static void +_e_gesture_process_pinch_up(Ecore_Event_Mouse_Button *ev) +{ + _e_gesture_pinch_cancel(); +} + + unsigned int e_gesture_util_tap_max_fingers_get(void) { @@ -932,6 +1116,10 @@ _e_gesture_process_mouse_button_down(void *event) { _e_gesture_process_pan_down(ev); } + if (!(gesture->gesture_filter & TIZEN_GESTURE_TYPE_PINCH)) + { + _e_gesture_process_pinch_down(ev); + } if (!(gesture->gesture_filter & TIZEN_GESTURE_TYPE_TAP)) { _e_gesture_process_tap_down(ev); @@ -970,6 +1158,10 @@ _e_gesture_process_mouse_button_up(void *event) { _e_gesture_process_pan_up(ev); } + if (!(gesture->gesture_filter & TIZEN_GESTURE_TYPE_PINCH)) + { + _e_gesture_process_pinch_up(ev); + } if (!(gesture->gesture_filter & TIZEN_GESTURE_TYPE_TAP)) { _e_gesture_process_tap_up(ev); @@ -1025,6 +1217,10 @@ _e_gesture_process_mouse_move(void *event) { _e_gesture_process_pan_move(ev); } + if (!(gesture->gesture_filter & TIZEN_GESTURE_TYPE_PINCH)) + { + _e_gesture_process_pinch_move(ev); + } if (!(gesture->gesture_filter & TIZEN_GESTURE_TYPE_TAP)) { _e_gesture_process_tap_move(ev); diff --git a/src/e_mod_main.c b/src/e_mod_main.c index 4223b31..627f303 100644 --- a/src/e_mod_main.c +++ b/src/e_mod_main.c @@ -92,7 +92,7 @@ _e_gesture_grab_pan(struct wl_client *client, struct wl_resource *resource, uint gev->pans.fingers[num_of_fingers].client = client; gev->pans.fingers[num_of_fingers].res = resource; - gev->pans.state = E_GESTURE_PAN_STATE_READY; + gev->pans.state = E_GESTURE_PANPINCH_STATE_READY; gesture->grabbed_gesture |= TIZEN_GESTURE_TYPE_PAN; gesture->gesture_filter = E_GESTURE_TYPE_ALL & ~gesture->grabbed_gesture; @@ -126,14 +126,90 @@ _e_gesture_ungrab_pan(struct wl_client *client, struct wl_resource *resource, ui } gesture->grabbed_gesture &= ~TIZEN_GESTURE_TYPE_TAP; - gev->pans.state = E_GESTURE_PAN_STATE_NONE; + gev->pans.state = E_GESTURE_PANPINCH_STATE_NONE; for (i = 0; i < E_GESTURE_FINGER_MAX; i++) { if (gev->pans.fingers[i].client) { gesture->grabbed_gesture |= TIZEN_GESTURE_TYPE_PAN; - gev->pans.state = E_GESTURE_PAN_STATE_READY; + gev->pans.state = E_GESTURE_PANPINCH_STATE_READY; + break; + } + } + +finish: + return ret; +} + +static int +_e_gesture_grab_pinch(struct wl_client *client, struct wl_resource *resource, uint32_t num_of_fingers) +{ + E_Gesture_Event *gev; + int ret = TIZEN_GESTURE_ERROR_NONE; + + GTINF("The client %p request to grab pinch gesture, fingers: %d\n", client, num_of_fingers); + + if (num_of_fingers > E_GESTURE_FINGER_MAX) + { + GTWRN("Do not support %d fingers (max: %d)\n", num_of_fingers, E_GESTURE_FINGER_MAX); + ret = TIZEN_GESTURE_ERROR_INVALID_DATA; + goto finish; + } + + gev = &gesture->gesture_events; + + if (gev->pinchs.fingers[num_of_fingers].client) + { + GTWRN("%d finger is already grabbed by %p client\n", num_of_fingers, gev->pinchs.fingers[num_of_fingers].client); + ret = TIZEN_GESTURE_ERROR_GRABBED_ALREADY; + goto finish; + } + + gev->pinchs.fingers[num_of_fingers].client = client; + gev->pinchs.fingers[num_of_fingers].res = resource; + + gev->pinchs.state = E_GESTURE_PANPINCH_STATE_READY; + gesture->grabbed_gesture |= TIZEN_GESTURE_TYPE_PINCH; + gesture->gesture_filter = E_GESTURE_TYPE_ALL & ~gesture->grabbed_gesture; + +finish: + return ret; +} + +static int +_e_gesture_ungrab_pinch(struct wl_client *client, struct wl_resource *resource, uint32_t num_of_fingers) +{ + int i; + E_Gesture_Event *gev; + int ret = TIZEN_GESTURE_ERROR_NONE; + + GTINF("The client %p request to ungrab pinch gesture, fingers: %d\n", client, num_of_fingers); + + if (num_of_fingers > E_GESTURE_FINGER_MAX) + { + GTWRN("Do not support %d fingers (max: %d)\n", num_of_fingers, E_GESTURE_FINGER_MAX); + ret = TIZEN_GESTURE_ERROR_INVALID_DATA; + goto finish; + } + + gev = &gesture->gesture_events; + + if (gev->pinchs.fingers[num_of_fingers].client == client) + { + gev->pinchs.fingers[num_of_fingers].client = NULL; + gev->pinchs.fingers[num_of_fingers].res = NULL; + } + + gesture->grabbed_gesture &= ~TIZEN_GESTURE_TYPE_PINCH; + gev->pinchs.state = E_GESTURE_PANPINCH_STATE_NONE; + + for (i = 0; i < E_GESTURE_FINGER_MAX; i++) + { + if (gev->pinchs.fingers[i].client) + { + gesture->grabbed_gesture |= TIZEN_GESTURE_TYPE_PINCH; + gev->pinchs.state = E_GESTURE_PANPINCH_STATE_READY; break; } } @@ -492,6 +568,30 @@ _e_gesture_cb_ungrab_pan(struct wl_client *client, tizen_gesture_send_pan_notify(resource, num_of_fingers, ret); } +static void +_e_gesture_cb_grab_pinch(struct wl_client *client, + struct wl_resource *resource, + uint32_t num_of_fingers) +{ + int ret = TIZEN_GESTURE_ERROR_NONE; + + ret = _e_gesture_grab_pinch(client, resource, num_of_fingers); + + tizen_gesture_send_pinch_notify(resource, num_of_fingers, ret); +} + +static void +_e_gesture_cb_ungrab_pinch(struct wl_client *client, + struct wl_resource *resource, + uint32_t num_of_fingers) +{ + int ret = TIZEN_GESTURE_ERROR_NONE; + + ret = _e_gesture_ungrab_pinch(client, resource, num_of_fingers); + + tizen_gesture_send_pinch_notify(resource, num_of_fingers, ret); +} + static const struct tizen_gesture_interface _e_gesture_implementation = { _e_gesture_cb_grab_edge_swipe, _e_gesture_cb_ungrab_edge_swipe, @@ -499,6 +599,8 @@ static const struct tizen_gesture_interface _e_gesture_implementation = { _e_gesture_cb_ungrab_tap, _e_gesture_cb_grab_pan, _e_gesture_cb_ungrab_pan, + _e_gesture_cb_grab_pinch, + _e_gesture_cb_ungrab_pinch }; /* tizen_gesture global object destroy function */ diff --git a/src/e_mod_main.h b/src/e_mod_main.h index a8dc2ac..4564713 100644 --- a/src/e_mod_main.h +++ b/src/e_mod_main.h @@ -39,6 +39,8 @@ #define E_GESTURE_PAN_START_TIME 0.05 #define E_GESTURE_PAN_MOVING_RANGE 15 +#define E_GESTURE_PINCH_MOVING_DISTANCE_RANGE 15 + #define ABS(x) (((x)>0)?(x):-(x)) #define RAD2DEG(x) ((x) * 57.295779513) @@ -59,6 +61,8 @@ typedef struct _E_Gesture_Event_Tap E_Gesture_Event_Tap; typedef struct _E_Gesture_Event_Pan E_Gesture_Event_Pan; +typedef struct _E_Gesture_Event_Pinch E_Gesture_Event_Pinch; + typedef struct _Coords Coords; typedef struct _E_Gesture_Finger E_Gesture_Finger; typedef struct _E_Gesture_Event_Info E_Gesture_Event_Info; @@ -67,7 +71,7 @@ typedef struct _E_Gesture_Event_Client E_Gesture_Event_Client; typedef enum _E_Gesture_Edge E_Gesture_Edge; typedef enum _E_Gesture_Event_State E_Gesture_Event_State; typedef enum _E_Gesture_Tap_State E_Gesture_Tap_State; -typedef enum _E_Gesture_Pan_State E_Gesture_Pan_State; +typedef enum _E_Gesture_PanPinch_State E_Gesture_PanPinch_State; extern E_GesturePtr gesture; @@ -100,13 +104,13 @@ enum _E_Gesture_Tap_State E_GESTURE_TAP_STATE_DONE }; -enum _E_Gesture_Pan_State +enum _E_Gesture_PanPinch_State { - E_GESTURE_PAN_STATE_NONE, - E_GESTURE_PAN_STATE_READY, - E_GESTURE_PAN_STATE_START, - E_GESTURE_PAN_STATE_MOVING, - E_GESTURE_PAN_STATE_DONE + E_GESTURE_PANPINCH_STATE_NONE, + E_GESTURE_PANPINCH_STATE_READY, + E_GESTURE_PANPINCH_STATE_START, + E_GESTURE_PANPINCH_STATE_MOVING, + E_GESTURE_PANPINCH_STATE_DONE }; struct _Coords @@ -228,7 +232,7 @@ struct _E_Gesture_Event_Tap struct _E_Gesture_Event_Pan { E_Gesture_Event_Client fingers[E_GESTURE_FINGER_MAX + 2]; - E_Gesture_Pan_State state; + E_Gesture_PanPinch_State state; Coords start_point; Coords prev_point; Coords center_point; @@ -238,11 +242,23 @@ struct _E_Gesture_Event_Pan Ecore_Timer *move_timer; }; +struct _E_Gesture_Event_Pinch +{ + E_Gesture_Event_Client fingers[E_GESTURE_FINGER_MAX + 2]; + E_Gesture_PanPinch_State state; + int distance; + int num_pinch_fingers; + + Ecore_Timer *start_timer; + Ecore_Timer *move_timer; +}; + struct _E_Gesture_Event { E_Gesture_Event_Edge_Swipe edge_swipes; E_Gesture_Event_Tap taps; E_Gesture_Event_Pan pans; + E_Gesture_Event_Pinch pinchs; E_Gesture_Finger base_point[E_GESTURE_FINGER_MAX + 2]; -- 2.7.4