174 lines
3.6 KiB
C++
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.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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |