1 /* Copyright (c) 2010-2014 Samsung Electronics Co., Ltd. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "gesture_processor.h"
21 #include <math.h> /* for sqrt */
22 #include "gesture_detector_statemachine.h"
23 #include "maps_view_plugin.h"
26 #define GESTURE_ZOOM_STATIC_FRICTION 0.15
27 #define GESTURE_ZOOM_MOVEMENT_UNIT 0.02
29 #define GESTURE_ROTATION_STATIC_FRICTION 15.0
30 #define GESTURE_ROTATION_MOVEMENT_UNIT 0.15
32 /*----------------------------------------------------------------------------*/
35 /* Using protected functions of Map View */
36 extern bool _maps_view_is_gesture_available(maps_view_h view, maps_view_gesture_e gesture);
37 extern maps_view_action_e _maps_view_get_gesture_action(maps_view_h view, maps_view_gesture_e gesture);
38 extern void *_maps_view_get_maps_service_ptr(maps_view_h view);
39 extern maps_view_object_h _maps_view_object_hit_test(maps_view_h view, int x, int y, maps_view_gesture_e gesture);
40 extern int _maps_view_event_data_set_gesture_type(maps_view_event_data_h event, maps_view_gesture_e gesture_type);
41 extern int _maps_view_event_data_set_position(maps_view_event_data_h event, int x, int y);
42 extern int _maps_view_event_data_set_coordinates(maps_view_event_data_h event, maps_coordinates_h coordinates);
43 extern int _maps_view_event_data_set_center(maps_view_event_data_h event, maps_coordinates_h center);
44 extern int _maps_view_event_data_set_fingers(maps_view_event_data_h event, int fingers);
45 extern int _maps_view_event_data_set_zoom_factor(maps_view_event_data_h event, double zoom_factor);
46 extern int _maps_view_event_data_set_rotation_angle(maps_view_event_data_h event, double rotation_angle);
47 extern maps_view_event_data_h _maps_view_create_event_data(maps_view_event_type_e type);
48 extern void _maps_view_invoke_event_callback(maps_view_h view, maps_view_event_data_h event_data);
50 #ifdef _MOVE_CENTER_COMMAND_DEFINED_
51 extern int _maps_view_set_center_directly(maps_view_h view, maps_coordinates_h coordinates);
52 extern int _maps_view_get_plugin_center(const maps_view_h view, maps_coordinates_h *center);
53 #endif /* _MOVE_CENTER_COMMAND_DEFINED_ */
55 /* ---------------------------------------------------------------------------*/
58 view::zoom_calculator::zoom_calculator(const touch_point &start_tp_f1,
59 const touch_point &cur_tp_f1,
60 const touch_point &start_tp_f2,
61 const touch_point &cur_tp_f2)
62 : _start_tp_f1(start_tp_f1)
63 , _cur_tp_f1(cur_tp_f1)
64 , _start_tp_f2(start_tp_f2)
65 , _cur_tp_f2(cur_tp_f2)
66 , _new_zoom_factor(.0)
67 , _new_rotation_angle(.0)
68 , _zoom_happend(false)
69 , _rotation_happend(false)
71 /* Finding the start radius */
72 const int start_dx = _start_tp_f2._x - _start_tp_f1._x;
73 const int start_dy = _start_tp_f2._y - _start_tp_f1._y;
74 const double start_r = sqrt(start_dx * start_dx + start_dy * start_dy) / 2;
76 /* Finding the cur radius */
77 const int cur_dx = _cur_tp_f2._x - _cur_tp_f1._x;
78 const int cur_dy = _cur_tp_f2._y - _cur_tp_f1._y;
79 const double cur_r = sqrt(cur_dx * cur_dx + cur_dy * cur_dy) / 2;
81 /* Calculating the zoom factor */
82 if ((start_r != .0) && (cur_r != .0) && (start_r != cur_r)) {
84 maps_get_screen_dpi(&dpi);
86 /* basically change 1 zoom level per inch */
87 /* additional adjust depending on the size of gesture which a user operates */
88 if (cur_r > start_r) {
89 _new_zoom_factor = ((cur_r - start_r) / dpi)
90 + ((cur_r / start_r) - 1) * 0.05;
92 _new_zoom_factor = -((start_r - cur_r) / dpi)
93 + -((start_r / cur_r) - 1) * 0.05;
98 /* Calculating the rotation angle */
99 const double inner1 = sqrt(start_dx * start_dx + start_dy * start_dy);
100 const double inner2 = sqrt(cur_dx * cur_dx + cur_dy * cur_dy);
101 const double norm = inner1 * inner2;
102 const double inner = (cur_dx * start_dx) + (cur_dy * start_dy);
103 const double angle = acos(inner / norm);
104 const double curl = (cur_dx * start_dy) - (cur_dy * start_dx);
107 _new_rotation_angle = (angle / M_PI * 180.);
108 _rotation_happend = true;
109 } else if (curl > 0) {
110 _new_rotation_angle = -(angle / M_PI * 180.);
111 _rotation_happend = true;
116 /* ---------------------------------------------------------------------------*/
119 view::gesture_processor::gesture_processor(gesture_detector *gd)
124 view::gesture_processor::~gesture_processor()
128 extern session::command_queue *__maps_view_select_q();
130 session::command_queue *view::gesture_processor::q()
132 /* This is a thread-friendly mode, when all heavy computations
133 * are performed in the "idle" mode.
134 * This mode is good for apps, which has other active widgets in
135 * addition to Map View.
137 /* return session::command_queue_view::interface(); */
140 /* This is a draw-enforcing mode, when the rendering and drawing
141 * of the map is happening as fast as it possible.
142 * This mode is good when the Map View is a single active widget
144 /*return session::command_queue_sync::interface();*/
146 /* Will use the same queue as used in Map View */
147 return __maps_view_select_q();
150 void *view::gesture_processor::get_maps()
152 return _maps_view_get_maps_service_ptr(_gd->_view);
155 session::command *view::gesture_processor::construct_gesture_command(
156 maps_view_gesture_e gesture,
157 const maps_coordinates_h c,
158 const bool zoom_changed,
160 const bool rotation_changed,
163 double zoom_factor = zoom;
164 double rotation_angle = angle;
166 /* Check if the gesture is available */
167 if (!_maps_view_is_gesture_available(_gd->_view, gesture)) {
168 return session::command::empty_ptr();
171 /* Perform gesture action */
172 switch(_maps_view_get_gesture_action(_gd->_view, gesture)) {
173 case MAPS_VIEW_ACTION_SCROLL: {
174 maps_coordinates_h coords = c;
175 maps_coordinates_h center_clone = NULL;
177 maps_view_get_center(_gd->_view, ¢er_clone);
178 coords = center_clone;
180 session::command *cmd =
181 new session::command_view_set_center(get_maps(), _gd->_view, coords);
182 maps_coordinates_destroy(center_clone);
185 case MAPS_VIEW_ACTION_ZOOM_IN: {
186 MAPS_LOGD("MAPS_VIEW_ACTION_ZOOM_IN");
187 if (zoom_factor == .0 || !zoom_changed)
188 maps_view_get_zoom_factor(_gd->_view, &zoom_factor);
189 return new session::command_view_zoom(get_maps(), _gd->_view, zoom_factor + 1.);
191 case MAPS_VIEW_ACTION_ZOOM_OUT: {
192 MAPS_LOGD("MAPS_VIEW_ACTION_ZOOM_OUT");
193 if (zoom_factor == .0 || !zoom_changed)
194 maps_view_get_zoom_factor(_gd->_view, &zoom_factor);
195 return new session::command_view_zoom(get_maps(), _gd->_view, zoom_factor - 1.);
197 case MAPS_VIEW_ACTION_ZOOM_AND_SCROLL: {
198 MAPS_LOGD("MAPS_VIEW_ACTION_ZOOM_AND_SCROLL");
199 double cur_zoom_factor;
200 maps_view_get_zoom_factor(_gd->_view, &cur_zoom_factor);
202 if (zoom_factor == .0 || !zoom_changed)
203 maps_view_get_zoom_factor(_gd->_view, &zoom_factor);
205 if (zoom_factor == cur_zoom_factor) zoom_factor++;
206 maps_view_set_zoom_factor(_gd->_view, zoom_factor);
208 maps_coordinates_h coords = c;
209 maps_coordinates_h center_clone = NULL;
211 maps_view_get_center(_gd->_view, ¢er_clone);
212 coords = center_clone;
214 session::command *cmd =
215 new session::command_view_set_center(get_maps(), _gd->_view, coords);
216 maps_coordinates_destroy(center_clone);
219 case MAPS_VIEW_ACTION_ZOOM:
220 case MAPS_VIEW_ACTION_ROTATE: {
221 if (zoom_changed & rotation_changed) {
222 MAPS_LOGD("rotation_angle=%f", rotation_angle);
223 if (zoom_factor == .0)
224 maps_view_get_zoom_factor(_gd->_view, &zoom_factor);
225 if (rotation_angle == .0)
226 maps_view_get_orientation(_gd->_view, &rotation_angle);
227 rotation_angle -= (int(rotation_angle) / 360) * 360;
228 return new session::command_view_zoom_rotate(get_maps(), _gd->_view, zoom_factor, rotation_angle);
229 } else if (zoom_changed) {
230 if (zoom_factor == .0)
231 maps_view_get_zoom_factor(_gd->_view, &zoom_factor);
232 MAPS_LOGI("\t set new zoom command: %f\n", zoom_factor);
233 return new session::command_view_zoom(get_maps(), _gd->_view, zoom_factor);
234 } else if (rotation_changed) {
235 if (rotation_angle == .0)
236 maps_view_get_orientation(_gd->_view, &rotation_angle);
237 rotation_angle -= (int(rotation_angle) / 360) * 360;
238 return new session::command_view_rotate(get_maps(), _gd->_view, rotation_angle);
242 case MAPS_VIEW_ACTION_NONE:
243 MAPS_LOGI("GESTURE: This Gesture is assigned with no Action");
248 return session::command::empty_ptr();
251 void view::gesture_processor::on_long_press()
253 /* Assumed that we can tap only with a single finger */
254 touch_point tp = _gd->_info._finger_move[0];
256 /* Check if any object was affected */
257 maps_view_object_h hit = _maps_view_object_hit_test(_gd->_view,
260 MAPS_VIEW_GESTURE_LONG_PRESS);
263 /* Enqueue the detected command */
264 maps_coordinates_h c = NULL;
265 maps_view_screen_to_geolocation(_gd->_view, tp._x, tp._y, &c);
266 q()->push(construct_gesture_command(MAPS_VIEW_GESTURE_LONG_PRESS, c,
267 false, .0, false, .0));
269 /* Invoke user registered event callback */
270 maps_view_event_data_h ed = _maps_view_create_event_data(MAPS_VIEW_EVENT_GESTURE);
272 _maps_view_event_data_set_gesture_type(ed, MAPS_VIEW_GESTURE_LONG_PRESS);
273 _maps_view_event_data_set_position(ed, tp._x, tp._y);
274 _maps_view_event_data_set_coordinates(ed, c);
275 _maps_view_event_data_set_fingers(ed, 1);
276 _maps_view_invoke_event_callback(_gd->_view, ed);
277 maps_view_event_data_destroy(ed);
279 maps_coordinates_destroy(c);
282 void view::gesture_processor::on_double_tap()
284 /* Assumed that we can tap only with a single finger */
285 touch_point tp = _gd->_info_history._finger_up[0];
287 /* Check if any object was affected */
288 maps_view_object_h hit = _maps_view_object_hit_test(_gd->_view,
291 MAPS_VIEW_GESTURE_DOUBLE_TAP);
294 /* Enqueue the detected command */
295 maps_coordinates_h c = NULL;
296 maps_view_screen_to_geolocation(_gd->_view, tp._x, tp._y, &c);
297 q()->push(construct_gesture_command(MAPS_VIEW_GESTURE_DOUBLE_TAP, c,
298 false, .0, false, .0));
300 /* Invoke user registered event callback */
301 maps_view_event_data_h ed = _maps_view_create_event_data(MAPS_VIEW_EVENT_GESTURE);
303 _maps_view_event_data_set_gesture_type(ed, MAPS_VIEW_GESTURE_DOUBLE_TAP);
304 _maps_view_event_data_set_position(ed, tp._x, tp._y);
305 _maps_view_event_data_set_coordinates(ed, c);
306 _maps_view_event_data_set_fingers(ed, 1);
307 _maps_view_invoke_event_callback(_gd->_view, ed);
308 maps_view_event_data_destroy(ed);
310 maps_coordinates_destroy(c);
313 void view::gesture_processor::on_tap()
315 /* Assumed that we can tap only with a single finger */
316 touch_point tp = _gd->_info_history._finger_up[0];
318 /* Check if any object was affected */
319 maps_view_object_h hit = _maps_view_object_hit_test(_gd->_view,
322 MAPS_VIEW_GESTURE_TAP);
325 /* Enqueue the detected command */
326 maps_coordinates_h c = NULL;
327 maps_view_screen_to_geolocation(_gd->_view, tp._x, tp._y, &c);
328 q()->push(construct_gesture_command(MAPS_VIEW_GESTURE_TAP, c,
329 false, .0, false, .0));
331 /* Invoke user registered event callback */
332 maps_view_event_data_h ed = _maps_view_create_event_data(MAPS_VIEW_EVENT_GESTURE);
334 _maps_view_event_data_set_gesture_type(ed, MAPS_VIEW_GESTURE_TAP);
335 _maps_view_event_data_set_position(ed, tp._x, tp._y);
336 _maps_view_event_data_set_coordinates(ed, c);
337 _maps_view_event_data_set_fingers(ed, 1);
338 _maps_view_invoke_event_callback(_gd->_view, ed);
339 maps_view_event_data_destroy(ed);
341 maps_coordinates_destroy(c);
344 void view::gesture_processor::on_two_finger_tap()
346 MAPS_LOGW("\nON TWO FINGER TAP\n");
348 const touch_point tp_f1 = _gd->_info._finger_move[0];
349 const touch_point tp_f2 = _gd->_info._finger_move[1];
350 const touch_point gesture_center = calc_center(tp_f1, tp_f2);
352 /* Enqueue the detected command */
353 maps_coordinates_h c = NULL;
354 maps_view_screen_to_geolocation(_gd->_view, gesture_center._x,
355 gesture_center._y, &c);
357 /* Enqueue the detected command */
358 q()->push(construct_gesture_command(MAPS_VIEW_GESTURE_2_FINGER_TAP, c,
359 false, .0, false, .0));
361 /* Invoke user registered event callback */
362 maps_view_event_data_h ed = _maps_view_create_event_data(MAPS_VIEW_EVENT_GESTURE);
364 _maps_view_event_data_set_gesture_type(ed, MAPS_VIEW_GESTURE_2_FINGER_TAP);
365 _maps_view_event_data_set_position(ed, gesture_center._x, gesture_center._y);
366 _maps_view_event_data_set_coordinates(ed, c);
367 _maps_view_event_data_set_fingers(ed, 2);
368 _maps_view_invoke_event_callback(_gd->_view, ed);
369 maps_view_event_data_destroy(ed);
371 maps_coordinates_destroy(c);
374 void view::gesture_processor::on_panning_finished(int finger_no)
376 const touch_point cur_tp = _gd->_info._finger_move[finger_no];
378 /* Obtain fresh central coordinates of the map in the Plugin */
379 maps_coordinates_h c = NULL;
380 _maps_view_get_plugin_center(_gd->_view, &c);
382 /* Directly set the updated center of the map */
383 _maps_view_set_center_directly(_gd->_view, c);
384 maps_coordinates_destroy(c);
387 maps_view_screen_to_geolocation(_gd->_view, cur_tp._x, cur_tp._y, &c);
389 /* Invoke user registered event callback */
390 maps_view_event_data_h ed = _maps_view_create_event_data(MAPS_VIEW_EVENT_GESTURE);
392 _maps_view_event_data_set_gesture_type(ed, MAPS_VIEW_GESTURE_SCROLL);
393 _maps_view_event_data_set_position(ed, cur_tp._x, cur_tp._y);
394 _maps_view_event_data_set_coordinates(ed, c);
395 _maps_view_event_data_set_fingers(ed, 1);
396 _maps_view_invoke_event_callback(_gd->_view, ed);
397 maps_view_event_data_destroy(ed);
399 maps_coordinates_destroy(c);
402 void view::gesture_processor::on_pan(int finger_no)
404 /* Assumed that we can tap only with a single finger */
405 const touch_point cur_tp = _gd->_info._finger_move[finger_no];
408 /* Calculate the new center of the map by adding the delta
409 * to the original center (e.g. the center of the map before the event
412 /* Check if the gesture is available */
413 if (!_maps_view_is_gesture_available(_gd->_view, MAPS_VIEW_GESTURE_SCROLL))
416 touch_point prev_tp = _gd->_info._prev_finger_down[finger_no];
418 prev_tp = _gd->_info._finger_down[finger_no];
420 /* a. Calculating the delta of the gesture */
421 int delta_x = cur_tp._x - prev_tp._x;
422 int delta_y = cur_tp._y - prev_tp._y;
424 /* b. Enque the command to move the center */
425 q()->push(new session::command_view_move_center(get_maps(),
430 /* c. Get coordinates after delta_x and delta_y are updated */
431 maps_coordinates_h c = NULL;
432 maps_view_screen_to_geolocation(_gd->_view, cur_tp._x, cur_tp._y, &c);
434 /* Invoke user registered event callback */
435 maps_view_event_data_h ed = _maps_view_create_event_data(MAPS_VIEW_EVENT_GESTURE);
437 _maps_view_event_data_set_gesture_type(ed, MAPS_VIEW_GESTURE_SCROLL);
438 _maps_view_event_data_set_position(ed, cur_tp._x, cur_tp._y);
439 _maps_view_event_data_set_coordinates(ed, c);
440 _maps_view_event_data_set_fingers(ed, 1);
441 _maps_view_invoke_event_callback(_gd->_view, ed);
442 maps_view_event_data_destroy(ed);
444 maps_coordinates_destroy(c);
447 view::touch_point view::gesture_processor::calc_center(
448 const touch_point &tp1,
449 const touch_point &tp2) const
451 const unsigned int timestamp = (tp2._timestamp > tp1._timestamp)
454 return touch_point(tp1._x + (tp2._x - tp1._x) / 2,
455 tp1._y + (tp2._y - tp1._y) / 2,
459 double view::gesture_processor::calc_angle(
461 const double angle2) const
463 if (angle2 - angle1 <= 180)
464 return (angle2 - angle1);
466 return -(angle1 + (360 - angle2));
469 double view::gesture_processor::calc_angle(
470 const touch_point tp1,
471 const touch_point tp2) const
473 const int dx = tp2._x - tp1._x;
474 const int dy = tp2._y - tp1._y;
475 // const double r = sqrt(dx * dx + dy * dy) / 2;
476 const double angle = atan2(dy, dx) / M_PI * 180. + 180.0;
480 bool view::gesture_processor::on_zoom(bool zoom_changed, bool rotation_changed, double &zoom_factor)
482 /* Check if the gesture is available */
483 if (!_maps_view_is_gesture_available(_gd->_view, MAPS_VIEW_GESTURE_ZOOM))
486 /* gesture_detector::log("view::gesture_processor::on_zoom", gesture_detector::FG_LITE_GREEN); */
488 /* First finger effective way by now */
489 const touch_point start_tp_f1 = _gd->_info._finger_down[0];
490 const touch_point cur_tp_f1 = _gd->_info._finger_move[0];
492 /* Second finger effective way by now */
493 const touch_point start_tp_f2 = _gd->_info._finger_down[1];
494 const touch_point cur_tp_f2 = _gd->_info._finger_move[1];
496 /* Calculating the current zoom factor, accordingly to effecitve ways of fingers */
497 zoom_calculator zc(start_tp_f1, cur_tp_f1, start_tp_f2, cur_tp_f2);
498 double new_zoom_factor = zc.get_zoom_factor();
500 /* Analyse zoom factor changes */
501 if (zc.zoom_happend()) {
502 /* Apply newly calculated zoom factor */
503 new_zoom_factor += _gd->_info._start_view_state._zoom_factor;
505 /* Correct the zoom factor accordingly to allowed limits */
506 /* TODO: it also may be cashed in the _info._start_view_state */
507 int min_zoom_level = 0;
508 int max_zoom_level = 0;
509 maps_view_get_min_zoom_level(_gd->_view, &min_zoom_level);
510 maps_view_get_max_zoom_level(_gd->_view, &max_zoom_level);
511 new_zoom_factor = MIN(MAX(new_zoom_factor, min_zoom_level), max_zoom_level);
513 /* Check if the zoom changed relatively to initial state */
514 double diff = new_zoom_factor - _gd->_info._start_view_state._prev_zoom_factor;
515 static double compensation = 0.;
516 static double prev_diff = 0.;
518 if (!zoom_changed && (fabs(diff) > GESTURE_ZOOM_STATIC_FRICTION * (1 + rotation_changed))) {
519 compensation = diff * -1;
521 } else if (zoom_changed && (fabs(diff - prev_diff) > GESTURE_ZOOM_MOVEMENT_UNIT)) {
524 zoom_changed = false;
528 new_zoom_factor += compensation;
529 MAPS_LOGD("[zoom_changed] %f + %f -> %f",
530 _gd->_info._start_view_state._prev_zoom_factor, diff - prev_diff, new_zoom_factor);
538 zoom_factor = new_zoom_factor;
542 bool view::gesture_processor::on_rotate(bool zoom_changed, bool rotation_changed, double &rotation_angle)
544 /* Check if the gesture is available */
545 if (!_maps_view_is_gesture_available(_gd->_view, MAPS_VIEW_GESTURE_ROTATE))
548 /* gesture_detector::log("view::gesture_processor::on_rotate", gesture_detector::FG_LITE_GREEN); */
550 /* First finger effective way by now */
551 const touch_point start_tp_f1 = _gd->_info._finger_down[0];
552 const touch_point cur_tp_f1 = _gd->_info._finger_move[0];
554 /* Second finger effective way by now */
555 const touch_point start_tp_f2 = _gd->_info._finger_down[1];
556 const touch_point cur_tp_f2 = _gd->_info._finger_move[1];
558 /* Calculating the current zoom factor, accordingly to effecitve ways of fingers */
559 zoom_calculator zc(start_tp_f1, cur_tp_f1, start_tp_f2, cur_tp_f2);
560 double new_rotation_angle = zc.get_rotation_angle();
562 /* Analyze rotation angle changes */
563 if (zc.rotation_happend()) {
564 /* Apply newly calculated rotation angle */
565 new_rotation_angle += _gd->_info._start_view_state._rotation_angle;
567 /* Check if the zoom changed relatively to initial state */
568 double diff = calc_angle(_gd->_info._start_view_state._prev_rotation_angle, new_rotation_angle);
569 static double compensation = 0.;
570 static double prev_diff = 0.;
572 if (!rotation_changed && (fabs(diff) > GESTURE_ROTATION_STATIC_FRICTION * (1 + zoom_changed))) {
573 compensation = diff * -1;
574 rotation_changed = true;
575 } else if (rotation_changed && (fabs(diff - prev_diff) > GESTURE_ROTATION_MOVEMENT_UNIT)) {
576 rotation_changed = true;
578 rotation_changed = false;
581 if (rotation_changed) {
582 new_rotation_angle = fmod(new_rotation_angle + compensation, 360.);
583 MAPS_LOGD("[rotation_changed] %f + %f -> %f",
584 _gd->_info._start_view_state._prev_rotation_angle, diff - prev_diff, new_rotation_angle);
589 if (!rotation_changed)
590 return false; // Seems nothing changed, we can return
592 rotation_angle = new_rotation_angle;
596 bool view::gesture_processor::on_two_fingers_pan(bool panning_changed, int *delta_x, int *delta_y)
598 /* Check if the gesture is available */
599 if (!_maps_view_is_gesture_available(_gd->_view, MAPS_VIEW_GESTURE_SCROLL))
602 /* gesture_detector::log("view::gesture_processor::on_two_fingers_pan", gesture_detector::FG_LITE_GREEN); */
604 /* First finger effective way by now */
605 const touch_point start_tp_f1 = _gd->_info._finger_down[0];
606 const touch_point cur_tp_f1 = _gd->_info._finger_move[0];
608 /* Second finger effective way by now */
609 const touch_point start_tp_f2 = _gd->_info._finger_down[1];
610 const touch_point cur_tp_f2 = _gd->_info._finger_move[1];
612 const touch_point start_center = calc_center(start_tp_f1, start_tp_f2);
613 const touch_point cur_center = calc_center(cur_tp_f1, cur_tp_f2);
615 int diff = _gd->get_trajectory_effective_length(start_center, cur_center);
616 static int compen_x = 0;
617 static int compen_y = 0;
619 if (!panning_changed && diff > _gd->__CLICK_AREA * 2) {
620 compen_x = cur_center._x - start_center._x;
621 compen_y = cur_center._y - start_center._y;
622 if (delta_x) *delta_x = 0;
623 if (delta_y) *delta_y = 0;
624 panning_changed = true;
625 } else if (panning_changed && diff > 1) {
626 if (delta_x) *delta_x = (cur_center._x - start_center._x) - compen_x;
627 if (delta_y) *delta_y = (cur_center._y - start_center._y) - compen_y;
628 panning_changed = true;
630 panning_changed = false;
633 if (!panning_changed)
640 void view::gesture_processor::on_zoom_rotate(bool zoom_changed, double zoom_factor, bool rotation_changed, double rotation_angle, bool panning_changed,
641 int panning_x, int panning_y)
643 if (!zoom_changed && !rotation_changed && !panning_changed)
646 /* a. Get the initial screen coordinates of the center */
649 maps_view_geolocation_to_screen(_gd->_view, _gd->_info._start_view_state._center, ¢er_x, ¢er_y);
651 /* b. Apply the delta to the intital center coordinates */
652 if (panning_changed) {
653 center_x -= panning_x;
654 center_y -= panning_y;
657 /* c. Send event data */
658 maps_coordinates_h center = NULL;
659 maps_view_screen_to_geolocation(_gd->_view, center_x, center_y, ¢er);
661 maps_view_event_data_h ed = _maps_view_create_event_data(MAPS_VIEW_EVENT_GESTURE);
663 _maps_view_event_data_set_position(ed, center_x, center_y);
664 _maps_view_event_data_set_coordinates(ed, center);
665 _maps_view_event_data_set_fingers(ed, 2);
668 _maps_view_event_data_set_gesture_type(ed, MAPS_VIEW_GESTURE_ZOOM);
669 _maps_view_event_data_set_zoom_factor(ed, zoom_factor);
670 _maps_view_event_data_set_rotation_angle(ed, 0.);
671 _maps_view_invoke_event_callback(_gd->_view, ed);
673 if (rotation_changed) {
674 _maps_view_event_data_set_gesture_type(ed, MAPS_VIEW_GESTURE_ROTATE);
675 _maps_view_event_data_set_zoom_factor(ed, 0.);
676 _maps_view_event_data_set_rotation_angle(ed, rotation_angle);
677 _maps_view_invoke_event_callback(_gd->_view, ed);
679 maps_view_event_data_destroy(ed);
682 /* d. Enque the command to move the center */
683 q()->push(new session::command_view_set_center(get_maps(), _gd->_view, center));
685 /* e. Enqueue the detected zomm command */
686 maps_view_gesture_e gesture = MAPS_VIEW_GESTURE_SCROLL;
687 if (zoom_changed) gesture = MAPS_VIEW_GESTURE_ZOOM;
688 if (rotation_changed) gesture = MAPS_VIEW_GESTURE_ROTATE;
690 q()->push(construct_gesture_command(gesture, center,
691 zoom_changed, zoom_factor, rotation_changed, rotation_angle));
693 maps_coordinates_destroy(center);
697 /* ---------------------------------------------------------------------------*/
698 /* VIEW EVENT STREAM */
699 /* ---------------------------------------------------------------------------*/
701 view::finger_event_stream::finger_event_stream(maps_view_h v)
704 /* TODO: extract in dedicated factory in maps_view.cpp */
705 /* Issuing an instance of gestuer detector */
706 _d = new gesture_detector_statemachine(v);
707 /*_d = new inertial_gesture(v);*/
708 /*_d = new gesture_detector(v);*/
710 /* All fingers are un-pressed initially */
711 for(int i = 0; i < MAX_FINGERS; i ++) {
712 _finger_pressed[i] = false;
713 _finger_moving[i] = false;
717 void view::finger_event_stream::set_gesture_detector(gesture_detector *d)
728 view::finger_event_stream::~finger_event_stream()
737 void view::finger_event_stream::tap(Evas_Event_Mouse_Down *ev)
739 MAPS_LOGI("finger_event_stream::tap");
744 * The Ecore sends "move" event before "press" event
745 * so we have to skip this "late" event "press" for the sake of
746 * detector simplicity
748 if (_finger_pressed[0]) {
749 MAPS_LOGI("finger_event_stream::tap [SKIPED]");
753 /* Current touch point info */
754 const touch_point tp(ev->canvas.x, ev->canvas.y, ev->timestamp);
756 _finger_pressed[0] = true;
757 _finger_down[0] = tp;
759 /* Process first finger press */
763 void view::finger_event_stream::move(Evas_Event_Mouse_Move *ev)
768 if (_finger_pressed[0] == false)
771 /* Current touch point info */
772 const touch_point tp(ev->cur.canvas.x, ev->cur.canvas.y, ev->timestamp);
774 MAPS_LOGI("finger_event_stream::move to (%d, %d)", tp._x, tp._y);
777 * We think that the movement happend when the finger moved out of
780 if (_finger_moving[0] || _finger_moving[1]
781 || finger_dragged_enough(0, tp)) {
782 _finger_moving[0] = true;
784 /* Process finger move */
787 MAPS_LOGI("finger_event_stream::move "
788 "Not Moved Enough [SKIPED]");
793 void view::finger_event_stream::up(Evas_Event_Mouse_Up *ev)
795 MAPS_LOGI("finger_event_stream::up");
799 /* Process finger up */
800 _d->up(0, view::touch_point(ev->canvas.x, ev->canvas.y, ev->timestamp));
802 _finger_pressed[0] = false;
803 _finger_moving[0] = false;
804 _finger_down[0].reset();
807 void view::finger_event_stream::multi_tap(Evas_Event_Multi_Down *ev)
809 MAPS_LOGI("finger_event_stream::multi_tap");
813 const int finger_no = (ev->device > 0 ? 1 : 0);
814 if (finger_no >= MAX_FINGERS)
817 /* Current touch point info */
818 const touch_point tp(ev->canvas.x, ev->canvas.y, ev->timestamp);
821 * The Ecore sends "move" event before "press" event
822 * so we have to skip this "late" event "press" for the sake of
823 * detector simplicity
825 if (_finger_pressed[finger_no]) {
826 MAPS_LOGI("finger_event_stream::multi_tap [SKIPED]");
830 _finger_pressed[finger_no] = true;
831 _finger_down[finger_no] = tp;
833 /* Process finger press */
834 _d->tap(finger_no, tp);
837 void view::finger_event_stream::multi_move(Evas_Event_Multi_Move *ev)
842 const int finger_no = (ev->device > 0 ? 1 : 0);
843 if (finger_no >= MAX_FINGERS)
846 if (_finger_pressed[finger_no] == false)
849 /* Current touch point info */
850 const touch_point tp(ev->cur.canvas.x, ev->cur.canvas.y, ev->timestamp);
852 MAPS_LOGI("finger_event_stream::multi_move to (%d, %d)", tp._x, tp._y);
855 * We think that the movement happend when the finger moved out of
858 if (_finger_moving[0] || _finger_moving[1]
859 || finger_dragged_enough(finger_no, tp)) {
860 _finger_moving[finger_no] = true;
862 /* Process finger move */
863 _d->move(finger_no, tp);
865 MAPS_LOGI("finger_event_stream::multi_move "
866 "Not Moved Enough [SKIPED]");
871 void view::finger_event_stream::multi_up(Evas_Event_Multi_Up *ev)
873 MAPS_LOGI("finger_event_stream::multi_up");
877 const int finger_no = (ev->device > 0 ? 1 : 0);
878 if (finger_no >= MAX_FINGERS)
881 /* Process finger up */
882 _d->up(finger_no, view::touch_point(ev->canvas.x,
886 _finger_pressed[finger_no] = false;
887 _finger_moving[finger_no] = false;
888 _finger_down[finger_no].reset();
892 bool view::finger_event_stream::finger_dragged_enough(int finger_no,
893 const touch_point &tp)
895 const touch_point start = _finger_down[finger_no];
896 const int trajectory =
897 gesture_detector::get_trajectory_effective_length(tp, start);
898 return (trajectory >= gesture_detector::__CLICK_AREA);