From 050ae159aea39c3f56aa31d35790d6ee71c557c4 Mon Sep 17 00:00:00 2001 From: "r.kuznetsov" Date: Thu, 31 Mar 2016 16:56:38 +0300 Subject: [PATCH] Added "double tap and hold" zooming --- drape_frontend/drape_engine.hpp | 2 +- drape_frontend/user_event_stream.cpp | 78 ++++++++++++++++++++++++---- drape_frontend/user_event_stream.hpp | 11 ++++ 3 files changed, 81 insertions(+), 10 deletions(-) diff --git a/drape_frontend/drape_engine.hpp b/drape_frontend/drape_engine.hpp index 3e666e80c9..d63ec55e7b 100644 --- a/drape_frontend/drape_engine.hpp +++ b/drape_frontend/drape_engine.hpp @@ -74,7 +74,7 @@ public: void Invalidate(); void AddTouchEvent(TouchEvent const & event); - void Scale(double factor, m2::PointD const & pxPoint, bool isAnim); + void Scale(double factor, m2::PointD const & pxPoint, bool isAnim); /// if zoom == -1, then current zoom will not change void SetModelViewCenter(m2::PointD const & centerPt, int zoom, bool isAnim); diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index 5e923752bb..128a1f5720 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -56,6 +56,9 @@ char const * UserEventStream::TRY_FILTER = "TryFilter"; char const * UserEventStream::END_FILTER = "EndFilter"; char const * UserEventStream::CANCEL_FILTER = "CancelFilter"; char const * UserEventStream::TWO_FINGERS_TAP = "TwoFingersTap"; +char const * UserEventStream::BEGIN_DOUBLE_TAP_AND_HOLD = "BeginDoubleTapAndHold"; +char const * UserEventStream::DOUBLE_TAP_AND_HOLD = "DoubleTapAndHold"; +char const * UserEventStream::END_DOUBLE_TAP_AND_HOLD = "EndDoubleTapAndHold"; #endif uint8_t const TouchEvent::INVALID_MASKED_POINTER = 0xFF; @@ -114,6 +117,7 @@ void TouchEvent::Swap() UserEventStream::UserEventStream() : m_state(STATE_EMPTY) , m_startDragOrg(m2::PointD::Zero()) + , m_startDoubleTapAndHold(m2::PointD::Zero()) { } @@ -639,9 +643,14 @@ bool UserEventStream::TouchDown(array const & touches) break; case STATE_TAP_DETECTION: case STATE_WAIT_DOUBLE_TAP: + case STATE_WAIT_DOUBLE_TAP_HOLD: CancelTapDetector(); BeginTwoFingersTap(touches[0], touches[1]); break; + case STATE_DOUBLE_TAP_HOLD: + EndDoubleTapAndHold(touches[0]); + BeginScale(touches[0], touches[1]); + break; case STATE_DRAG: isMapTouch = EndDrag(touches[0], true /* cancelled */); BeginScale(touches[0], touches[1]); @@ -657,7 +666,7 @@ bool UserEventStream::TouchDown(array const & touches) bool UserEventStream::TouchMove(array const & touches, double timestamp) { - double const dragThreshold = my::sq(VisualParams::Instance().GetDragThreshold()); + double const kDragThreshold = my::sq(VisualParams::Instance().GetDragThreshold()); size_t touchCount = GetValidTouchesCount(touches); bool isMapTouch = true; @@ -666,7 +675,7 @@ bool UserEventStream::TouchMove(array const & touches, double timestam case STATE_EMPTY: if (touchCount == 1) { - if (m_startDragOrg.SquareLength(touches[0].m_location) > dragThreshold) + if (m_startDragOrg.SquareLength(touches[0].m_location) > kDragThreshold) BeginDrag(touches[0], timestamp); else isMapTouch = false; @@ -679,7 +688,7 @@ bool UserEventStream::TouchMove(array const & touches, double timestam case STATE_TAP_TWO_FINGERS: if (touchCount == 2) { - float const threshold = static_cast(dragThreshold); + float const threshold = static_cast(kDragThreshold); if (m_twoFingersTouches[0].SquareLength(touches[0].m_location) > threshold || m_twoFingersTouches[1].SquareLength(touches[1].m_location) > threshold) BeginScale(touches[0], touches[1]); @@ -693,11 +702,18 @@ bool UserEventStream::TouchMove(array const & touches, double timestam break; case STATE_TAP_DETECTION: case STATE_WAIT_DOUBLE_TAP: - if (m_startDragOrg.SquareLength(touches[0].m_location) > dragThreshold) + if (m_startDragOrg.SquareLength(touches[0].m_location) > kDragThreshold) CancelTapDetector(); else isMapTouch = false; break; + case STATE_WAIT_DOUBLE_TAP_HOLD: + if (m_startDragOrg.SquareLength(touches[0].m_location) > kDragThreshold) + StartDoubleTapAndHold(touches[0]); + break; + case STATE_DOUBLE_TAP_HOLD: + UpdateDoubleTapAndHold(touches[0]); + break; case STATE_DRAG: if (touchCount > 1) { @@ -741,6 +757,11 @@ bool UserEventStream::TouchCancel(array const & touches) case STATE_TAP_TWO_FINGERS: isMapTouch = false; break; + case STATE_WAIT_DOUBLE_TAP_HOLD: + case STATE_DOUBLE_TAP_HOLD: + ASSERT_EQUAL(touchCount, 1, ()); + EndDoubleTapAndHold(touches[0]); + break; case STATE_FILTER: ASSERT_EQUAL(touchCount, 1, ()); CancelFilter(touches[0]); @@ -787,10 +808,15 @@ bool UserEventStream::TouchUp(array const & touches) break; case STATE_TAP_TWO_FINGERS: if (touchCount == 2) - { EndTwoFingersTap(); - isMapTouch = true; - } + break; + case STATE_WAIT_DOUBLE_TAP_HOLD: + ASSERT_EQUAL(touchCount, 1, ()); + PerformDoubleTap(touches[0]); + break; + case STATE_DOUBLE_TAP_HOLD: + ASSERT_EQUAL(touchCount, 1, ()); + EndDoubleTapAndHold(touches[0]); break; case STATE_DRAG: ASSERT_EQUAL(touchCount, 1, ()); @@ -993,11 +1019,17 @@ bool UserEventStream::DetectDoubleTap(Touch const & touch) if (m_state != STATE_WAIT_DOUBLE_TAP || ms > kDoubleTapPauseMs) return false; + m_state = STATE_WAIT_DOUBLE_TAP_HOLD; + + return true; +} + +void UserEventStream::PerformDoubleTap(Touch const & touch) +{ + ASSERT_EQUAL(m_state, STATE_WAIT_DOUBLE_TAP_HOLD, ()); m_state = STATE_EMPTY; if (m_listener) m_listener->OnDoubleTap(touch.m_location); - - return true; } bool UserEventStream::DetectForceTap(Touch const & touch) @@ -1057,6 +1089,34 @@ void UserEventStream::CancelFilter(Touch const & t) if (m_listener) m_listener->OnSingleTouchFiltrate(t.m_location, TouchEvent::TOUCH_CANCEL); } + +void UserEventStream::StartDoubleTapAndHold(Touch const & touch) +{ + TEST_CALL(BEGIN_DOUBLE_TAP_AND_HOLD); + ASSERT_EQUAL(m_state, STATE_WAIT_DOUBLE_TAP_HOLD, ()); + m_state = STATE_DOUBLE_TAP_HOLD; + m_startDoubleTapAndHold = m_startDragOrg; +} + +void UserEventStream::UpdateDoubleTapAndHold(Touch const & touch) +{ + TEST_CALL(DOUBLE_TAP_AND_HOLD); + ASSERT_EQUAL(m_state, STATE_DOUBLE_TAP_HOLD, ()); + float const kPowerModifier = 10.0f; + float const scaleFactor = exp(kPowerModifier * (touch.m_location.y - m_startDoubleTapAndHold.y) / GetCurrentScreen().PixelRect().SizeY()); + m_startDoubleTapAndHold = touch.m_location; + m2::PointD scaleCenter = m_startDragOrg; + if (m_listener) + m_listener->CorrectScalePoint(scaleCenter); + m_navigator.Scale(scaleCenter, scaleFactor); +} + +void UserEventStream::EndDoubleTapAndHold(Touch const & touch) +{ + TEST_CALL(END_DOUBLE_TAP_AND_HOLD); + ASSERT_EQUAL(m_state, STATE_DOUBLE_TAP_HOLD, ()); + m_state = STATE_EMPTY; +} bool UserEventStream::IsInUserAction() const { diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index 28be3c2fa6..e248910851 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -291,6 +291,9 @@ public: static char const * END_FILTER; static char const * CANCEL_FILTER; static char const * TWO_FINGERS_TAP; + static char const * BEGIN_DOUBLE_TAP_AND_HOLD; + static char const * DOUBLE_TAP_AND_HOLD; + static char const * END_DOUBLE_TAP_AND_HOLD; using TTestBridge = function; void SetTestBridge(TTestBridge const & fn) { m_testFn = fn; } @@ -333,9 +336,14 @@ private: void DetectShortTap(Touch const & touch); void DetectLongTap(Touch const & touch); bool DetectDoubleTap(Touch const & touch); + void PerformDoubleTap(Touch const & touch); bool DetectForceTap(Touch const & touch); void EndTapDetector(Touch const & touch); void CancelTapDetector(); + + void StartDoubleTapAndHold(Touch const & touch); + void UpdateDoubleTapAndHold(Touch const & touch); + void EndDoubleTapAndHold(Touch const & touch); void BeginTwoFingersTap(Touch const & t1, Touch const & t2); void EndTwoFingersTap(); @@ -358,6 +366,8 @@ private: STATE_TAP_DETECTION, STATE_WAIT_DOUBLE_TAP, STATE_TAP_TWO_FINGERS, + STATE_WAIT_DOUBLE_TAP_HOLD, + STATE_DOUBLE_TAP_HOLD, STATE_DRAG, STATE_SCALE } m_state; @@ -379,6 +389,7 @@ private: #endif m2::PointD m_startDragOrg; array m_twoFingersTouches; + m2::PointD m_startDoubleTapAndHold; KineticScroller m_scroller; my::Timer m_kineticTimer;