/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "GesturePan.hpp" namespace OpenVulkano::Input { namespace { constexpr float MIN_DISTANCE = 20; constexpr float MIN_DISTANCE2 = MIN_DISTANCE * MIN_DISTANCE; } void GesturePan::TryStart(const Touch& touch) { uint32_t dragCount = 0, existingActive = 0; for (const auto& t : m_pendingTouches) { if (t.isDrag) dragCount++; if (t.active) existingActive++; } if (dragCount >= m_requiredTouchInputs) { if (!IsActive() && !ResolveConflicts()) return; uint32_t activeCount = existingActive; for (auto& t : m_pendingTouches) { if (t.isDrag && !t.active && activeCount < m_requiredTouchInputs) { t.active = true; activeCount++; } } m_paused = false; if (IsActive()) { m_panInfo.position = CalculatePosition(); OnPanMoved(this, m_panInfo); } else { SetActive(true); m_panInfo.position = CalculatePosition(); m_panInfo.distance = Math::Vector2f(); m_panInfo.delta = Math::Vector2f(); OnPanStarted.NotifyAll(this, m_panInfo); } } } Math::Vector2f GesturePan::CalculatePosition() const { Math::Vector2f gesturePos = Math::Vector2f(); if (m_pendingTouches.size() >= m_requiredTouchInputs && IsActive() && !m_paused) { int activePointers = 0; for (const auto& t : m_pendingTouches) { gesturePos += t.currentPosition; activePointers++; } gesturePos /= activePointers > 0 ? activePointers : 1; } return gesturePos; } void GesturePan::Cancel() { for (auto& pointer : m_pendingTouches) { pointer.active = false; } SetActive(false); m_paused = false; m_panInfo.delta = Math::Vector2f(); OnPanEnded(this, m_panInfo); m_panInfo.distance = Math::Vector2f(); m_panInfo.position = Math::Vector2f(); } void GesturePan::TouchDown(const Touch& touch) { TouchInfo ti; ti.touchId = touch.GetId(); ti.currentPosition = touch.GetPosition(); ti.initialPosition = touch.GetPosition(); m_pendingTouches.push_back(ti); if (IsActive()) { m_panInfo.position = CalculatePosition(); } } void GesturePan::TouchUp(const Touch& touch) { if (!m_pendingTouches.empty()) { for (auto touchIter = m_pendingTouches.begin(); touchIter != m_pendingTouches.end(); touchIter++) { if (touch.GetId() == touchIter->touchId) { if (touchIter->active) m_paused = true; m_pendingTouches.erase(touchIter); break; } } if (m_pendingTouches.empty() && IsActive()) { Cancel(); } else if (IsActive()) { m_panInfo.position = CalculatePosition(); } } } void GesturePan::TouchMoved(const Touch& touch) { if (!m_pendingTouches.empty()) { bool isPending = false; bool isActive = false; for (auto& t : m_pendingTouches) { if (touch.GetId() == t.touchId) { t.currentPosition = touch.GetPosition(); Math::Vector2f displacement = t.currentPosition - t.initialPosition; if (Math::Utils::length2(displacement) > MIN_DISTANCE2) { t.isDrag = true; } if (t.active) isActive = true; isPending = true; } } if (isPending) { if (!IsActive() || m_paused) { TryStart(touch); } else if (isActive) { Math::Vector2f newPosition = CalculatePosition(); m_panInfo.delta = newPosition - m_panInfo.position; m_panInfo.distance += m_panInfo.delta; m_panInfo.position = newPosition; OnPanMoved.NotifyAll(this, m_panInfo); } } } } }