diff --git a/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp b/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp index ffe9d08327..dadbfebe23 100644 --- a/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp +++ b/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp @@ -25,6 +25,7 @@ public: void OnTap(m2::PointD const & pt, bool isLong) override {} void OnDoubleTap(m2::PointD const & pt) override {} + void OnTwoFingersTap() override {} bool OnSingleTouchFiltrate(m2::PointD const & pt, df::TouchEvent::ETouchType type) override { return m_filtrate; } void OnDragStarted() override {} void OnDragEnded(m2::PointD const & /*distance*/) override {} diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 5722df9b20..a3d6ca58e1 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -681,7 +681,13 @@ void FrontendRenderer::OnTap(m2::PointD const & pt, bool isLongTap) void FrontendRenderer::OnDoubleTap(m2::PointD const & pt) { - m_userEventStream.AddEvent(ScaleEvent(2.0 /*scale factor*/, pt, true /*animated*/)); + m_userEventStream.AddEvent(ScaleEvent(2.0 /* scale factor */, pt, true /* animated */)); +} + +void FrontendRenderer::OnTwoFingersTap() +{ + ScreenBase const & screen = m_userEventStream.GetCurrentScreen(); + m_userEventStream.AddEvent(ScaleEvent(0.5 /* scale factor */, screen.PixelRect().Center(), true /* animated */)); } bool FrontendRenderer::OnSingleTouchFiltrate(m2::PointD const & pt, TouchEvent::ETouchType type) diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index 1f0b418669..45f6cbb7eb 100755 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -147,6 +147,7 @@ private: void OnTap(m2::PointD const & pt, bool isLong) override; void OnDoubleTap(m2::PointD const & pt) override; + void OnTwoFingersTap() override; bool OnSingleTouchFiltrate(m2::PointD const & pt, TouchEvent::ETouchType type) override; void OnDragStarted() override; void OnDragEnded(m2::PointD const & distance) override; diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index df415acc54..1ec93d821c 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -383,16 +383,16 @@ bool UserEventStream::ProcessTouch(TouchEvent const & touch) switch (touchEvent.m_type) { case TouchEvent::TOUCH_DOWN: - isMapTouch |= TouchDown(touchEvent.m_touches); + isMapTouch = TouchDown(touchEvent.m_touches); break; case TouchEvent::TOUCH_MOVE: - isMapTouch |= TouchMove(touchEvent.m_touches, touch.m_timeStamp); + isMapTouch = TouchMove(touchEvent.m_touches, touch.m_timeStamp); break; case TouchEvent::TOUCH_CANCEL: - isMapTouch |= TouchCancel(touchEvent.m_touches); + isMapTouch = TouchCancel(touchEvent.m_touches); break; case TouchEvent::TOUCH_UP: - isMapTouch |= TouchUp(touchEvent.m_touches); + isMapTouch = TouchUp(touchEvent.m_touches); break; default: ASSERT(false, ()); @@ -430,22 +430,24 @@ bool UserEventStream::TouchDown(array const & touches) switch (m_state) { case STATE_EMPTY: + BeginTwoFingersTap(touches[0], touches[1]); break; case STATE_FILTER: CancelFilter(touches[0]); + BeginScale(touches[0], touches[1]); break; case STATE_TAP_DETECTION: case STATE_WAIT_DOUBLE_TAP: CancelTapDetector(); + BeginTwoFingersTap(touches[0], touches[1]); break; case STATE_DRAG: isMapTouch = EndDrag(touches[0], true /* cancelled */); + BeginScale(touches[0], touches[1]); break; default: break; } - - BeginScale(touches[0], touches[1]); } UpdateTouches(touches); @@ -454,6 +456,7 @@ bool UserEventStream::TouchDown(array const & touches) bool UserEventStream::TouchMove(array const & touches, double timestamp) { + double const dragThreshold = VisualParams::Instance().GetDragThreshold(); size_t touchCount = GetValidTouchesCount(touches); bool isMapTouch = true; @@ -461,9 +464,27 @@ bool UserEventStream::TouchMove(array const & touches, double timestam { case STATE_EMPTY: if (touchCount == 1) - BeginDrag(touches[0], timestamp); + { + if (m_startDragOrg.Length(touches[0].m_location) > dragThreshold) + BeginDrag(touches[0], timestamp); + else + isMapTouch = false; + } else + { BeginScale(touches[0], touches[1]); + } + break; + case STATE_TAP_TWO_FINGERS: + if (touchCount == 2) + { + float const threshold = static_cast(dragThreshold); + if (m_twoFingersTouches[0].Length(touches[0].m_location) > threshold || + m_twoFingersTouches[1].Length(touches[1].m_location) > threshold) + BeginScale(touches[0], touches[1]); + else + isMapTouch = false; + } break; case STATE_FILTER: ASSERT_EQUAL(touchCount, 1, ()); @@ -472,8 +493,10 @@ bool UserEventStream::TouchMove(array const & touches, double timestam case STATE_TAP_DETECTION: case STATE_WAIT_DOUBLE_TAP: ASSERT_EQUAL(touchCount, 1, ()); - if (m_startDragOrg.Length(touches[0].m_location) > VisualParams::Instance().GetDragThreshold()) + if (m_startDragOrg.Length(touches[0].m_location) > dragThreshold) CancelTapDetector(); + else + isMapTouch = false; break; case STATE_DRAG: ASSERT_EQUAL(touchCount, 1, ()); @@ -500,6 +523,7 @@ bool UserEventStream::TouchCancel(array const & touches) { case STATE_EMPTY: case STATE_WAIT_DOUBLE_TAP: + case STATE_TAP_TWO_FINGERS: isMapTouch = false; break; case STATE_FILTER: @@ -531,6 +555,7 @@ bool UserEventStream::TouchUp(array const & touches) { size_t touchCount = GetValidTouchesCount(touches); bool isMapTouch = true; + LOG(LINFO, (m_state, touchCount)); switch (m_state) { case STATE_EMPTY: @@ -546,6 +571,13 @@ bool UserEventStream::TouchUp(array const & touches) ASSERT_EQUAL(touchCount, 1, ()); EndTapDetector(touches[0]); break; + case STATE_TAP_TWO_FINGERS: + if(touchCount == 2) + { + EndTwoFingersTap(); + isMapTouch = true; + } + break; case STATE_DRAG: ASSERT_EQUAL(touchCount, 1, ()); isMapTouch = EndDrag(touches[0], false /* cancelled */); @@ -568,6 +600,23 @@ void UserEventStream::UpdateTouches(array const & touches) m_touches = touches; } +void UserEventStream::BeginTwoFingersTap(Touch const & t1, Touch const & t2) +{ + ASSERT_EQUAL(m_state, STATE_EMPTY, ()); + m_state = STATE_TAP_TWO_FINGERS; + m_twoFingersTouches[0] = t1.m_location; + m_twoFingersTouches[1] = t2.m_location; +} + +void UserEventStream::EndTwoFingersTap() +{ + ASSERT_EQUAL(m_state, STATE_TAP_TWO_FINGERS, ()); + m_state = STATE_EMPTY; + + if (m_listener) + m_listener->OnTwoFingersTap(); +} + void UserEventStream::BeginDrag(Touch const & t, double timestamp) { TEST_CALL(BEGIN_DRAG); @@ -629,7 +678,7 @@ void UserEventStream::BeginScale(Touch const & t1, Touch const & t2) return; } - ASSERT_EQUAL(m_state, STATE_EMPTY, ()); + ASSERT(m_state == STATE_EMPTY || m_state == STATE_TAP_TWO_FINGERS, ()); m_state = STATE_SCALE; m2::PointD touch1 = t1.m_location; m2::PointD touch2 = t2.m_location; @@ -692,7 +741,8 @@ void UserEventStream::BeginTapDetector() void UserEventStream::DetectShortTap(Touch const & touch) { - if (m_touchTimer.ElapsedMillis() > kDoubleTapPauseMs) + uint64_t const ms = m_touchTimer.TimeElapsedAs().count(); + if (ms > kDoubleTapPauseMs) { m_state = STATE_EMPTY; if (m_listener) @@ -703,7 +753,8 @@ void UserEventStream::DetectShortTap(Touch const & touch) void UserEventStream::DetectLongTap(Touch const & touch) { ASSERT_EQUAL(m_state, STATE_TAP_DETECTION, ()); - if (m_touchTimer.ElapsedMillis() > kLongTouchMs) + uint64_t const ms = m_touchTimer.TimeElapsedAs().count(); + if (ms > kLongTouchMs) { TEST_CALL(LONG_TAP_DETECTED); m_state = STATE_EMPTY; @@ -714,7 +765,8 @@ void UserEventStream::DetectLongTap(Touch const & touch) bool UserEventStream::DetectDoubleTap(Touch const & touch) { - if (m_state != STATE_WAIT_DOUBLE_TAP || m_touchTimer.ElapsedMillis() > kDoubleTapPauseMs) + uint64_t const ms = m_touchTimer.TimeElapsedAs().count(); + if (m_state != STATE_WAIT_DOUBLE_TAP || ms > kDoubleTapPauseMs) return false; m_state = STATE_EMPTY; @@ -776,7 +828,7 @@ bool UserEventStream::IsInUserAction() const bool UserEventStream::IsWaitingForActionCompletion() const { - return m_state == STATE_TAP_DETECTION || m_state == STATE_WAIT_DOUBLE_TAP; + return m_state != STATE_EMPTY; } } diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index 5f18c51e43..fb16e75c95 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -205,6 +205,7 @@ public: virtual void OnTap(m2::PointD const & pt, bool isLong) = 0; virtual void OnDoubleTap(m2::PointD const & pt) = 0; + virtual void OnTwoFingersTap() = 0; virtual bool OnSingleTouchFiltrate(m2::PointD const & pt, TouchEvent::ETouchType type) = 0; virtual void OnDragStarted() = 0; virtual void OnDragEnded(m2::PointD const & distance) = 0; @@ -284,6 +285,9 @@ private: void EndTapDetector(Touch const & touch); void CancelTapDetector(); + void BeginTwoFingersTap(Touch const & t1, Touch const & t2); + void EndTwoFingersTap(); + bool TryBeginFilter(Touch const & t); void EndFilter(Touch const & t); void CancelFilter(Touch const & t); @@ -297,13 +301,14 @@ private: mutable mutex m_lock; Navigator m_navigator; - my::HighResTimer m_touchTimer; + my::Timer m_touchTimer; enum ERecognitionState { STATE_EMPTY, STATE_FILTER, STATE_TAP_DETECTION, STATE_WAIT_DOUBLE_TAP, + STATE_TAP_TWO_FINGERS, STATE_DRAG, STATE_SCALE } m_state; @@ -317,6 +322,7 @@ private: TTestBridge m_testFn; #endif m2::PointD m_startDragOrg; + array m_twoFingersTouches; KineticScroller m_scroller; my::Timer m_kineticTimer;