Files
OpenVulkano/openVulkanoCpp/Input/Touch/GesturePan.cpp
2023-10-15 13:39:22 +02:00

174 lines
3.6 KiB
C++

/*
* 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.size() > 0)
{
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);
}
}
}
}
}