forked from enlightenment/efl
294 lines
10 KiB
C
294 lines
10 KiB
C
#include "efl_canvas_gesture_private.h"
|
|
|
|
#define MY_CLASS EFL_CANVAS_GESTURE_RECOGNIZER_ZOOM_CLASS
|
|
|
|
static void
|
|
_reset_recognizer(Efl_Canvas_Gesture_Recognizer_Zoom_Data *pd)
|
|
{
|
|
memset(&pd->zoom_st, 0, sizeof(Efl_Gesture_Touch_Point_Data));
|
|
memset(&pd->zoom_st1, 0, sizeof(Efl_Gesture_Touch_Point_Data));
|
|
memset(&pd->zoom_mv, 0, sizeof(Efl_Gesture_Touch_Point_Data));
|
|
memset(&pd->zoom_mv1, 0, sizeof(Efl_Gesture_Touch_Point_Data));
|
|
pd->zoom_base = 0;
|
|
pd->zoom_step = pd->next_step = pd->zoom_finger_factor = pd->zoom_distance_tolerance = 0;
|
|
pd->calc_temp = EINA_FALSE;
|
|
}
|
|
|
|
#define memset do not use memset to reset zoom data, use _reset_recognizer
|
|
|
|
static Evas_Coord
|
|
_finger_gap_length_get(Evas_Coord xx1,
|
|
Evas_Coord yy1,
|
|
Evas_Coord xx2,
|
|
Evas_Coord yy2,
|
|
Evas_Coord *x,
|
|
Evas_Coord *y)
|
|
{
|
|
double a, b, xx, yy, gap;
|
|
xx = abs(xx2 - xx1);
|
|
yy = abs(yy2 - yy1);
|
|
gap = sqrt((xx * xx) + (yy * yy));
|
|
|
|
/* START - Compute zoom center point */
|
|
/* The triangle defined as follows:
|
|
* B
|
|
* / |
|
|
* / |
|
|
* gap / | a
|
|
* / |
|
|
* A-----C
|
|
* b
|
|
* http://en.wikipedia.org/wiki/Trigonometric_functions
|
|
*************************************/
|
|
if (((int)xx) && ((int)yy))
|
|
{
|
|
double A = atan((yy / xx));
|
|
a = (Evas_Coord)((gap / 2) * sin(A));
|
|
b = (Evas_Coord)((gap / 2) * cos(A));
|
|
*x = (Evas_Coord)((xx2 > xx1) ? (xx1 + b) : (xx2 + b));
|
|
*y = (Evas_Coord)((yy2 > yy1) ? (yy1 + a) : (yy2 + a));
|
|
}
|
|
else
|
|
{
|
|
if ((int)xx) /* horiz line, take half width */
|
|
{
|
|
*x = (Evas_Coord)((xx1 + xx2) / 2);
|
|
*y = (Evas_Coord)(yy1);
|
|
}
|
|
|
|
if ((int)yy) /* vert line, take half width */
|
|
{
|
|
*x = (Evas_Coord)(xx1);
|
|
*y = (Evas_Coord)((yy1 + yy2) / 2);
|
|
}
|
|
}
|
|
/* END - Compute zoom center point */
|
|
|
|
return (Evas_Coord)gap;
|
|
}
|
|
|
|
static double
|
|
_zoom_compute(Efl_Canvas_Gesture_Recognizer_Zoom_Data *pd,
|
|
Efl_Canvas_Gesture_Zoom_Data *zd,
|
|
Evas_Coord xx1,
|
|
Evas_Coord yy1,
|
|
Evas_Coord xx2,
|
|
Evas_Coord yy2,
|
|
double zoom_finger_factor)
|
|
{
|
|
double rt = 1.0;
|
|
//TODO: Enable below code if the zoom momentum is need
|
|
//unsigned int tm_end = (pd->zoom_mv.cur.timestamp > pd->zoom_mv1.cur.timestamp) ?
|
|
// pd->zoom_mv.cur.timestamp : pd->zoom_mv1.cur.timestamp;
|
|
|
|
int x, y; //Hot spot
|
|
Evas_Coord diam = _finger_gap_length_get(xx1, yy1, xx2, yy2,
|
|
&x, &y);
|
|
|
|
zd->radius = diam / 2.0;
|
|
|
|
if (!pd->zoom_base)
|
|
{
|
|
pd->zoom_base = diam;
|
|
return zd->zoom;
|
|
}
|
|
|
|
if (pd->zoom_distance_tolerance) /* zoom tolerance <> ZERO, means
|
|
* zoom action NOT started yet */
|
|
{
|
|
/* avoid jump with zoom value when break tolerance */
|
|
if (diam < (pd->zoom_base - pd->zoom_distance_tolerance))
|
|
{
|
|
pd->zoom_base -= pd->zoom_distance_tolerance;
|
|
pd->zoom_distance_tolerance = 0;
|
|
}
|
|
|
|
/* avoid jump with zoom value when break tolerance */
|
|
if (diam > (pd->zoom_base + pd->zoom_distance_tolerance))
|
|
{
|
|
pd->zoom_base += pd->zoom_distance_tolerance;
|
|
pd->zoom_distance_tolerance = 0;
|
|
}
|
|
|
|
return rt;
|
|
}
|
|
|
|
/* We use factor only on the difference between gap-base */
|
|
/* if gap=120, base=100, we get ((120-100)/100)=0.2*factor */
|
|
rt = ((1.0) + ((((float)diam - (float)pd->zoom_base) /
|
|
(float)pd->zoom_base) * zoom_finger_factor));
|
|
|
|
//TODO: Enable below code if the zoom momentum is need
|
|
/* Momentum: zoom per second: */
|
|
//zd->momentum = _zoom_momentum_get(st, tm_end, rt);
|
|
|
|
return rt;
|
|
}
|
|
|
|
EOLIAN static Efl_Canvas_Gesture *
|
|
_efl_canvas_gesture_recognizer_zoom_efl_canvas_gesture_recognizer_add(Eo *obj,
|
|
Efl_Canvas_Gesture_Recognizer_Zoom_Data *pd EINA_UNUSED,
|
|
Efl_Object *target EINA_UNUSED)
|
|
{
|
|
return efl_add(EFL_CANVAS_GESTURE_ZOOM_CLASS, obj);
|
|
}
|
|
|
|
EOLIAN static Efl_Canvas_Gesture_Recognizer_Result
|
|
_efl_canvas_gesture_recognizer_zoom_efl_canvas_gesture_recognizer_recognize(Eo *obj,
|
|
Efl_Canvas_Gesture_Recognizer_Zoom_Data *pd,
|
|
Efl_Canvas_Gesture *gesture,
|
|
Efl_Object *watched,
|
|
Efl_Canvas_Gesture_Touch *event)
|
|
{
|
|
Eina_Value *val;
|
|
unsigned char zoom_finger_enable;
|
|
unsigned char glayer_continues_enable;
|
|
Efl_Canvas_Gesture_Recognizer_Result result = EFL_GESTURE_RECOGNIZER_RESULT_CANCEL;
|
|
Efl_Canvas_Gesture_Zoom_Data *zd = efl_data_scope_get(gesture, EFL_CANVAS_GESTURE_ZOOM_CLASS);
|
|
Efl_Canvas_Gesture_Touch_Data *td = efl_data_scope_get(event, EFL_CANVAS_GESTURE_TOUCH_CLASS);
|
|
Efl_Canvas_Gesture_Recognizer_Data *rd = efl_data_scope_get(obj, EFL_CANVAS_GESTURE_RECOGNIZER_CLASS);
|
|
|
|
//FIXME: Wheel zoom test first here.
|
|
|
|
val = _recognizer_config_get(obj, "glayer_continues_enable");
|
|
if (val) eina_value_get(val, &glayer_continues_enable);
|
|
else glayer_continues_enable = 1;
|
|
|
|
val = _recognizer_config_get(obj, "glayer_zoom_finger_enable");
|
|
if (val) eina_value_get(val, &zoom_finger_enable);
|
|
else zoom_finger_enable = 1;
|
|
|
|
val = _recognizer_config_get(obj, "glayer_zoom_finger_factor");
|
|
if (val) eina_value_get(val, &pd->zoom_finger_factor);
|
|
else pd->zoom_finger_factor = 1.0;
|
|
|
|
rd->continues = EINA_TRUE;
|
|
|
|
if (!pd->zoom_distance_tolerance && !pd->calc_temp)
|
|
{
|
|
pd->calc_temp = EINA_TRUE;
|
|
val = _recognizer_config_get(obj, "glayer_zoom_distance_tolerance");
|
|
if (val) eina_value_get(val, &pd->zoom_distance_tolerance);
|
|
else pd->zoom_distance_tolerance = 1.0;
|
|
|
|
pd->zoom_distance_tolerance *= pd->finger_size;
|
|
}
|
|
|
|
switch (efl_gesture_touch_state_get(event))
|
|
{
|
|
case EFL_GESTURE_TOUCH_STATE_UPDATE:
|
|
{
|
|
if ((!glayer_continues_enable) && (!pd->zoom_st.cur.timestamp))
|
|
{
|
|
return EFL_GESTURE_RECOGNIZER_RESULT_IGNORE;
|
|
}
|
|
EINA_FALLTHROUGH;
|
|
}
|
|
|
|
case EFL_GESTURE_TOUCH_STATE_BEGIN:
|
|
{
|
|
if (td->touch_down > 2)
|
|
{
|
|
_reset_recognizer(pd);
|
|
return EFL_GESTURE_RECOGNIZER_RESULT_CANCEL;
|
|
}
|
|
if (td->touch_down == 1)
|
|
{
|
|
return EFL_GESTURE_RECOGNIZER_RESULT_MAYBE;
|
|
}
|
|
|
|
if (!pd->zoom_st.cur.timestamp) /* Now scan touched-devices list
|
|
* and find other finger */
|
|
{
|
|
if (!efl_gesture_touch_multi_touch_get(event))
|
|
return EFL_GESTURE_RECOGNIZER_RESULT_IGNORE;
|
|
|
|
const Efl_Gesture_Touch_Point_Data *p1 = efl_gesture_touch_data_get(event, 0);
|
|
const Efl_Gesture_Touch_Point_Data *p2 = efl_gesture_touch_data_get(event, 1);
|
|
|
|
memcpy(&pd->zoom_st, p2, sizeof(Efl_Gesture_Touch_Point_Data));
|
|
memcpy(&pd->zoom_st1, p1, sizeof(Efl_Gesture_Touch_Point_Data));
|
|
|
|
memcpy(&pd->zoom_mv, p2, sizeof(Efl_Gesture_Touch_Point_Data));
|
|
memcpy(&pd->zoom_mv1, p1, sizeof(Efl_Gesture_Touch_Point_Data));
|
|
|
|
int x, y; //Hot spot
|
|
zd->zoom = 1.0;
|
|
pd->zoom_base = _finger_gap_length_get(pd->zoom_st1.cur.pos.x,
|
|
pd->zoom_st1.cur.pos.y,
|
|
pd->zoom_st.cur.pos.x,
|
|
pd->zoom_st.cur.pos.y,
|
|
&x, &y);
|
|
|
|
zd->radius = pd->zoom_base / 2.0;
|
|
|
|
if ((efl_gesture_state_get(gesture) != EFL_GESTURE_STATE_STARTED) &&
|
|
(efl_gesture_state_get(gesture) != EFL_GESTURE_STATE_UPDATED))
|
|
return EFL_GESTURE_RECOGNIZER_RESULT_TRIGGER;
|
|
|
|
return EFL_GESTURE_RECOGNIZER_RESULT_CANCEL;
|
|
}
|
|
|
|
const Efl_Gesture_Touch_Point_Data *p2 = efl_gesture_touch_data_get(event, 1);
|
|
if (p2->id == pd->zoom_mv.id)
|
|
memcpy(&pd->zoom_mv, p2, sizeof(Efl_Gesture_Touch_Point_Data));
|
|
else if (p2->id == pd->zoom_mv1.id)
|
|
memcpy(&pd->zoom_mv1, p2, sizeof(Efl_Gesture_Touch_Point_Data));
|
|
|
|
zd->zoom = _zoom_compute(pd, zd, pd->zoom_mv.cur.pos.x,
|
|
pd->zoom_mv.cur.pos.y, pd->zoom_mv1.cur.pos.x,
|
|
pd->zoom_mv1.cur.pos.y, pd->zoom_finger_factor);
|
|
|
|
if (!pd->zoom_distance_tolerance)
|
|
{
|
|
double d = zd->zoom - pd->next_step;
|
|
|
|
if (d < 0.0) d = (-d);
|
|
|
|
if (d >= pd->zoom_step)
|
|
{
|
|
pd->next_step = zd->zoom;
|
|
|
|
return EFL_GESTURE_RECOGNIZER_RESULT_TRIGGER;
|
|
}
|
|
}
|
|
|
|
return EFL_GESTURE_RECOGNIZER_RESULT_IGNORE;
|
|
}
|
|
|
|
case EFL_GESTURE_TOUCH_STATE_END:
|
|
{
|
|
if (td->touch_down == 0)
|
|
{
|
|
rd->continues = EINA_FALSE;
|
|
|
|
_reset_recognizer(pd);
|
|
efl_gesture_manager_gesture_clean_up(efl_provider_find(obj, EFL_CANVAS_GESTURE_MANAGER_CLASS), watched, EFL_EVENT_GESTURE_ZOOM);
|
|
|
|
return EFL_GESTURE_RECOGNIZER_RESULT_IGNORE;
|
|
}
|
|
if ((pd->zoom_base) && (pd->zoom_distance_tolerance == 0))
|
|
{
|
|
_reset_recognizer(pd);
|
|
|
|
return EFL_GESTURE_RECOGNIZER_RESULT_FINISH;
|
|
}
|
|
|
|
if (efl_gesture_state_get(gesture) != EFL_GESTURE_STATE_NONE)
|
|
{
|
|
_reset_recognizer(pd);
|
|
|
|
return EFL_GESTURE_RECOGNIZER_RESULT_CANCEL;
|
|
}
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#include "efl_canvas_gesture_recognizer_zoom.eo.c"
|