diff --git a/CMakeLists.txt b/CMakeLists.txt index 8bc36ff..60e0fa6 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,7 @@ set(sources "src/main.cpp" "src/WorldGrid.cpp" "src/TimePoint.cpp" "src/InputManager.cpp" + "src/FingerInputTracker.cpp" "src/UndoManager.cpp" "src/CanvasTheme.cpp" "src/DrawCamera.cpp" diff --git a/src/DrawCamera.cpp b/src/DrawCamera.cpp index e937790..288b9b7 100755 --- a/src/DrawCamera.cpp +++ b/src/DrawCamera.cpp @@ -237,39 +237,56 @@ void DrawCamera::input_mouse_wheel_callback(World& w, const InputManager::MouseW } } -void DrawCamera::input_multi_finger_touch_callback(World& w, const InputManager::MultiFingerTouchCallbackArgs& touch) { - if(!smoothMove.occurring && !isAccurateZooming && !isTouchTransforming && touch.down) { - touchInitialPositions = touch.pos; - touchInitialC = c; - isTouchTransforming = true; - } - else +void DrawCamera::input_finger_touch_callback(World& w, const FingerInput::TouchCallbackArgs& touch) { + if(touch.fingers.size() != 2) isTouchTransforming = false; -} + else { + switch(touch.action.type) { + case FingerInput::ActionType::UP: { + break; + } + case FingerInput::ActionType::DOWN: { + if(!smoothMove.occurring && !isAccurateZooming && !isTouchTransforming) { + touchInitialPositions.clear(); + for(const FingerInput::FingerData& f : touch.fingers) + touchInitialPositions.emplace_back(f.pos); + touchInitialC = c; + isTouchTransforming = true; + } + else + isTouchTransforming = false; + break; + } + case FingerInput::ActionType::MOVE: { + if(!smoothMove.occurring && !isAccurateZooming && isTouchTransforming && touch.fingers.size() == 2) { + c = touchInitialC; -void DrawCamera::input_multi_finger_motion_callback(World& w, const InputManager::MultiFingerMotionCallbackArgs& motion) { - if(!smoothMove.occurring && !isAccurateZooming && isTouchTransforming) { - c = touchInitialC; + Vector2f initialCenter = (touchInitialPositions[0] + touchInitialPositions[1]) * 0.5f; + Vector2f newCenter = (touch.fingers[0].pos + touch.fingers[1].pos) * 0.5f; + c.pos -= c.dir_from_space(newCenter - initialCenter); + WorldVec newCenterWorld = c.from_space(newCenter); - Vector2f initialCenter = (touchInitialPositions[0] + touchInitialPositions[1]) * 0.5f; - Vector2f newCenter = (motion.pos[0] + motion.pos[1]) * 0.5f; - c.pos -= c.dir_from_space(newCenter - initialCenter); - WorldVec newCenterWorld = c.from_space(newCenter); + float initialDistance = vec_distance(touchInitialPositions[0], touchInitialPositions[1]); + float newDistance = vec_distance(touch.fingers[0].pos, touch.fingers[1].pos); + float scaleAmount = newDistance / initialDistance; + c.scale_about_double(newCenterWorld, scaleAmount); - float initialDistance = vec_distance(touchInitialPositions[0], touchInitialPositions[1]); - float newDistance = vec_distance(motion.pos[0], motion.pos[1]); - float scaleAmount = newDistance / initialDistance; - c.scale_about_double(newCenterWorld, scaleAmount); + Vector2f initialDiff = touchInitialPositions[0] - initialCenter; + float initialAngle = std::atan2(initialDiff.y(), initialDiff.x()) + std::numbers::pi; + Vector2f newDiff = touch.fingers[0].pos - newCenter; + float newAngle = std::atan2(newDiff.y(), newDiff.x()) + std::numbers::pi; + float rotateAngle = initialAngle - newAngle; + rotateAngle = std::fmod(rotateAngle + std::numbers::pi, std::numbers::pi * 2.0f) - std::numbers::pi; + c.rotate_about(newCenterWorld, rotateAngle); - Vector2f initialDiff = touchInitialPositions[0] - initialCenter; - float initialAngle = std::atan2(initialDiff.y(), initialDiff.x()) + std::numbers::pi; - Vector2f newDiff = motion.pos[0] - newCenter; - float newAngle = std::atan2(newDiff.y(), newDiff.x()) + std::numbers::pi; - float rotateAngle = initialAngle - newAngle; - rotateAngle = std::fmod(rotateAngle + std::numbers::pi, std::numbers::pi * 2.0f) - std::numbers::pi; - c.rotate_about(newCenterWorld, rotateAngle); - - checks_after_input(w); + checks_after_input(w); + } + else + isTouchTransforming = false; + break; + } + case FingerInput::ActionType::NONE: break; + } } } diff --git a/src/DrawCamera.hpp b/src/DrawCamera.hpp index 2bfdd0c..04b3b9f 100644 --- a/src/DrawCamera.hpp +++ b/src/DrawCamera.hpp @@ -19,6 +19,7 @@ #pragma once #include #include +#include "FingerInputTracker.hpp" #include "SharedTypes.hpp" #include #include "CoordSpaceHelper.hpp" @@ -52,8 +53,7 @@ class DrawCamera { void input_mouse_button_on_canvas_callback(World& w, const InputManager::MouseButtonCallbackArgs& button); void input_mouse_motion_callback(World& w, const InputManager::MouseMotionCallbackArgs& motion); void input_mouse_wheel_callback(World& w, const InputManager::MouseWheelCallbackArgs& wheel); - void input_multi_finger_touch_callback(World& w, const InputManager::MultiFingerTouchCallbackArgs& touch); - void input_multi_finger_motion_callback(World& w, const InputManager::MultiFingerMotionCallbackArgs& motion); + void input_finger_touch_callback(World& w, const FingerInput::TouchCallbackArgs& touch); private: struct SmoothMove { CoordSpaceHelper start; diff --git a/src/DrawingProgram/DrawingProgram.hpp b/src/DrawingProgram/DrawingProgram.hpp index c6836d4..adfe3bf 100644 --- a/src/DrawingProgram/DrawingProgram.hpp +++ b/src/DrawingProgram/DrawingProgram.hpp @@ -91,8 +91,6 @@ class DrawingProgram { void input_key_callback(const InputManager::KeyCallbackArgs& key); void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button); void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion); - void input_pure_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button); - void input_pure_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion); void input_pen_button_callback(const InputManager::PenButtonCallbackArgs& button); void input_pen_touch_callback(const InputManager::PenTouchCallbackArgs& touch); void input_pen_motion_callback(const InputManager::PenMotionCallbackArgs& motion); diff --git a/src/FingerInputTracker.cpp b/src/FingerInputTracker.cpp new file mode 100644 index 0000000..d9a4257 --- /dev/null +++ b/src/FingerInputTracker.cpp @@ -0,0 +1,143 @@ +#include "FingerInputTracker.hpp" +#include "Helpers/MathExtras.hpp" +#include + +namespace FingerInput { + +constexpr float MAX_DELTA_MOTION_TO_DISABLE_TAP_SQRD = 20.0f * 20.0f; +constexpr float MAX_DELTA_INITIAL_TO_DISABLE_TAP_SQRD = 20.0f * 20.0f; +constexpr std::chrono::duration DURATION_TO_HOLD = std::chrono::milliseconds(500); +constexpr std::chrono::duration MAX_DURATION_BETWEEN_TAPS = std::chrono::milliseconds(500); + +void FingerData::scale(float multiplier) { + pos /= multiplier; + initialTouchPos /= multiplier; +} + +GestureType TapGesture::get_type() const { return GestureType::TAP; } +GestureType HoldGesture::get_type() const { return GestureType::HOLD; } + +void TapGesture::scale(float multiplier) { + for(Vector2f& f : fingerPositions) + f /= multiplier; +} + +std::vector TapGesture::get_all_positions() const { + return fingerPositions; +} + +void HoldGesture::scale(float multiplier) { + fingerPosition /= multiplier; +} + +std::vector HoldGesture::get_all_positions() const { + return {fingerPosition}; +} + +void TouchCallbackArgs::scale(float multiplier) { + for(FingerData& f : fingers) + f.scale(multiplier); + action.motion /= multiplier; + action.pos /= multiplier; + if(gesture) + gesture->scale(multiplier); +} + +TouchCallbackArgs InputTracker::update_finger_data_input_callback(SDL_EventType eventType, SDL_TouchID touchDeviceID, SDL_FingerID fingerID, const Vector2f& pos, const Vector2f& delta) { + switch(eventType) { + case SDL_EVENT_FINGER_DOWN: { + auto touchTime = std::chrono::steady_clock::now(); + bool isFirstFingerDown = fingers.empty(); + if(tap.fingersGoingUp) + invalidate_tap(); + else if(touchTime - tap.lastTapTime > MAX_DURATION_BETWEEN_TAPS) + reset_tap(); + fingers.emplace_back(FingerData{ + .fingerID = fingerID, + .pos = pos, + .initialTouchPos = pos, + .initialTouchTime = touchTime, + .isFirstFingerDown = isFirstFingerDown + }); + break; + } + case SDL_EVENT_FINGER_MOTION: { + auto f = std::find_if(fingers.begin(), fingers.end(), [&](const FingerData& f) { return fingerID == f.fingerID; }); + if(f != fingers.end()) { + f->pos = pos; + if(vec_distance_sqrd(f->pos, f->initialTouchPos) > MAX_DELTA_MOTION_TO_DISABLE_TAP_SQRD) { + f->fingerMovedAlot = true; + invalidate_tap(); + } + } + break; + } + default: break; + } + TouchCallbackArgs toRet; + toRet.fingers = fingers; + toRet.action = { + .type = ActionType::NONE, + .fingerID = fingerID, + .pos = pos, + .motion = delta + }; + switch(eventType) { + case SDL_EVENT_FINGER_UP: { + toRet.action.type = ActionType::UP; + if(!tap.fingersGoingUp) { + if(fingers.size() != tap.fingerCount) { + tap.count = 0; + tap.fingerCount = fingers.size(); + } + tap.positions.clear(); + for(const FingerData& f : fingers) + tap.positions.emplace_back(f.pos); + } + tap.fingersGoingUp = true; + std::erase_if(fingers, [&](const FingerData& f) { return fingerID == f.fingerID; }); + if(fingers.empty()) { + if(tap.invalid) { + reset_tap(); + tap.invalid = false; + } + else { + auto tapGesture = std::make_shared(); + tap.count++; + tapGesture->fingerPositions = tap.positions; + tapGesture->numberOfTaps = tap.count; + toRet.gesture = tapGesture; + } + tap.fingersGoingUp = false; + } + break; + } + case SDL_EVENT_FINGER_DOWN: + toRet.action.type = ActionType::DOWN; + break; + case SDL_EVENT_FINGER_MOTION: + toRet.action.type = ActionType::MOVE; + break; + default: break; + } + return toRet; +} + +void InputTracker::update() { + if(!fingers.empty() && (std::chrono::steady_clock::now() - fingers[0].initialTouchTime) >= DURATION_TO_HOLD && fingers[0].isFirstFingerDown) { + // HOLD GESTURE + } +} + +void InputTracker::invalidate_tap() { + reset_tap(); + tap.invalid = true; +} + +void InputTracker::reset_tap() { + tap.count = 0; + tap.fingerCount = 0; + tap.positions.clear(); +} + +} diff --git a/src/FingerInputTracker.hpp b/src/FingerInputTracker.hpp new file mode 100644 index 0000000..9f7de8f --- /dev/null +++ b/src/FingerInputTracker.hpp @@ -0,0 +1,86 @@ +#pragma once +#include +#include "CustomEvents.hpp" + +namespace FingerInput { + +struct FingerData { + void scale(float multiplier); + SDL_FingerID fingerID; + Vector2f pos; + + Vector2f initialTouchPos; + std::chrono::steady_clock::time_point initialTouchTime; + bool fingerMovedAlot = false; + bool isFirstFingerDown = false; +}; + +enum class ActionType { + NONE, + DOWN, + UP, + MOVE +}; + +enum class GestureType { + NONE, + TAP, // Carries number of fingers, and number of taps + HOLD // Finger down, no movement for a long time. Hold position is position of first finger down +}; + +class BaseGesture { + public: + virtual void scale(float multiplier) = 0; + virtual GestureType get_type() const = 0; + virtual std::vector get_all_positions() const = 0; +}; + +class TapGesture : public BaseGesture { + public: + virtual void scale(float multiplier) override; + virtual GestureType get_type() const override; + virtual std::vector get_all_positions() const override; + std::vector fingerPositions; + unsigned numberOfTaps; +}; + +class HoldGesture : public BaseGesture { + public: + virtual void scale(float multiplier) override; + virtual GestureType get_type() const override; + virtual std::vector get_all_positions() const override; + Vector2f fingerPosition; +}; + +struct TouchCallbackArgs { + void scale(float multiplier); + std::vector fingers; + struct { + ActionType type; + SDL_FingerID fingerID; + Vector2f pos; + Vector2f motion; + } action; + std::shared_ptr gesture; +}; + +class InputTracker { + public: + TouchCallbackArgs update_finger_data_input_callback(SDL_EventType eventType, SDL_TouchID touchDeviceID, SDL_FingerID fingerID, const Vector2f& pos, const Vector2f& delta); + void update(); + private: + struct { + unsigned count = 0; + unsigned fingerCount = 0; + bool fingersGoingUp = false; + bool invalid = false; + std::vector positions; + std::chrono::steady_clock::time_point lastTapTime; + std::chrono::steady_clock::time_point firstFingerDownInCurrentTapTime; + } tap; + void invalidate_tap(); + void reset_tap(); + std::vector fingers; +}; + +} diff --git a/src/GUIHolder.cpp b/src/GUIHolder.cpp index 855450e..61e3386 100644 --- a/src/GUIHolder.cpp +++ b/src/GUIHolder.cpp @@ -175,14 +175,10 @@ void GUIHolder::input_mouse_wheel_callback(const InputManager::MouseWheelCallbac gui.input_mouse_wheel_callback(wheel); } -void GUIHolder::input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) { +void GUIHolder::input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch) { gui.input_finger_touch_callback(touch); } -void GUIHolder::input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) { - gui.input_finger_motion_callback(motion); -} - std::optional GUIHolder::get_text_box_start_info() { return gui.get_text_box_start_info(); } diff --git a/src/GUIHolder.hpp b/src/GUIHolder.hpp index 67d2d8a..b30116d 100644 --- a/src/GUIHolder.hpp +++ b/src/GUIHolder.hpp @@ -49,8 +49,7 @@ class GUIHolder { void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button); void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion); void input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel); - void input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch); - void input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion); + void input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch); std::optional get_text_box_start_info(); diff --git a/src/GUIStuff/Elements/CheckBox.cpp b/src/GUIStuff/Elements/CheckBox.cpp index 4daf224..1594405 100644 --- a/src/GUIStuff/Elements/CheckBox.cpp +++ b/src/GUIStuff/Elements/CheckBox.cpp @@ -50,25 +50,23 @@ void CheckBox::update() { } bool CheckBox::is_hovering_animation() { - return mouseHovering && (!gui.last_interaction_is_touch() || isHeld); + return touchHoverAnim || mouseHoverAnim; } void CheckBox::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) { - if(mouseHovering && button.button == InputManager::MouseButton::LEFT && button.down) { + mouseHoverAnim = mouseHovering; + if(mouseHovering && button.button == InputManager::MouseButton::LEFT && button.down) gui.set_post_callback_func([&](){if(onClick) onClick();}); - isHeld = true; - } - else - isHeld = false; } -void CheckBox::input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) { - if(mouseHovering && touch.down) { +void CheckBox::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) { + mouseHoverAnim = mouseHovering; +} + +void CheckBox::input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch) { + touchHoverAnim = mouseHovering && touch.action.type != FingerInput::ActionType::UP; + if(mouseHovering && touch.gesture && touch.gesture->get_type() == FingerInput::GestureType::TAP) gui.set_post_callback_func([&](){if(onClick) onClick();}); - isHeld = true; - } - else - isHeld = false; } void CheckBox::clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) { diff --git a/src/GUIStuff/Elements/CheckBox.hpp b/src/GUIStuff/Elements/CheckBox.hpp index 8d8963b..73a9dd7 100644 --- a/src/GUIStuff/Elements/CheckBox.hpp +++ b/src/GUIStuff/Elements/CheckBox.hpp @@ -27,7 +27,8 @@ class CheckBox : public Element { virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) override; virtual void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) override; - virtual void input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) override; + virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) override; + virtual void input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch) override; virtual void update() override; void layout(const Clay_ElementId& id, const std::function& isTicked, const std::function& onClick); @@ -35,7 +36,8 @@ class CheckBox : public Element { static constexpr float CHECKBOX_ANIMATION_TIME = 0.3; float hoverAnimation = 0.0; bool oldIsTicked = false; - bool isHeld = false; + bool touchHoverAnim = false; + bool mouseHoverAnim = false; bool is_hovering_animation(); std::function isTicked; std::function onClick; diff --git a/src/GUIStuff/Elements/Element.cpp b/src/GUIStuff/Elements/Element.cpp index 64232de..e30faed 100644 --- a/src/GUIStuff/Elements/Element.cpp +++ b/src/GUIStuff/Elements/Element.cpp @@ -33,11 +33,40 @@ namespace GUIStuff { void Element::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) { } void Element::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) { } void Element::input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel) { } - void Element::input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) { - input_mouse_button_callback(InputManager::convert_finger_touch_to_mouse_button(touch)); - } - void Element::input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) { - input_mouse_motion_callback(InputManager::convert_finger_motion_to_mouse_motion(motion)); + void Element::input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch) { + // Emulate a mouse by default + switch(touch.action.type) { + case FingerInput::ActionType::MOVE: { + InputManager::MouseMotionCallbackArgs motionArgs; + motionArgs.deviceType = InputManager::MouseDeviceType::TOUCH; + motionArgs.move = touch.action.motion; + motionArgs.pos = touch.action.pos; + input_mouse_motion_callback(motionArgs); + break; + } + case FingerInput::ActionType::UP: { + InputManager::MouseButtonCallbackArgs mouseArgs; + mouseArgs.deviceType = InputManager::MouseDeviceType::TOUCH; + mouseArgs.pos = touch.action.pos; + mouseArgs.down = false; + mouseArgs.clicks = 0; + mouseArgs.button = InputManager::MouseButton::LEFT; + input_mouse_button_callback(mouseArgs); + break; + } + case FingerInput::ActionType::DOWN: { + InputManager::MouseButtonCallbackArgs mouseArgs; + mouseArgs.deviceType = InputManager::MouseDeviceType::TOUCH; + mouseArgs.pos = touch.action.pos; + mouseArgs.down = true; + mouseArgs.clicks = 1; + mouseArgs.button = InputManager::MouseButton::LEFT; + input_mouse_button_callback(mouseArgs); + break; + } + case FingerInput::ActionType::NONE: + break; + } } void Element::input_key_callback(const InputManager::KeyCallbackArgs& key) {} std::optional Element::get_text_box_start_info() { return std::nullopt; } diff --git a/src/GUIStuff/Elements/Element.hpp b/src/GUIStuff/Elements/Element.hpp index 9cf1aff..bba1f18 100644 --- a/src/GUIStuff/Elements/Element.hpp +++ b/src/GUIStuff/Elements/Element.hpp @@ -51,8 +51,7 @@ namespace GUIStuff { virtual void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button); virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion); virtual void input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel); - virtual void input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch); - virtual void input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion); + virtual void input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch); virtual void input_key_callback(const InputManager::KeyCallbackArgs& key); virtual std::optional get_text_box_start_info(); protected: diff --git a/src/GUIStuff/Elements/LayoutElement.cpp b/src/GUIStuff/Elements/LayoutElement.cpp index e6354d9..2eac973 100644 --- a/src/GUIStuff/Elements/LayoutElement.cpp +++ b/src/GUIStuff/Elements/LayoutElement.cpp @@ -43,27 +43,39 @@ void LayoutElement::input_mouse_wheel_callback(const InputManager::MouseWheelCal if(c.mouseWheel) c.mouseWheel(this, wheel); } -void LayoutElement::input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) { +void LayoutElement::input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch) { if(c.fingerTouch) c.fingerTouch(this, touch); - if(c.onClick) { - c.onClick(this, { - .deviceType = InputManager::MouseDeviceType::TOUCH, - .button = InputManager::MouseButton::LEFT, - .down = touch.down, - .clicks = static_cast(touch.fingerTapCount), - .pos = touch.pos - }); - } -} - -void LayoutElement::input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) { - if(c.fingerMotion) c.fingerMotion(this, motion); - if(c.onMotion) { - c.onMotion(this, { - .deviceType = InputManager::MouseDeviceType::TOUCH, - .pos = motion.pos, - .move = motion.move - }); + switch(touch.action.type) { + case FingerInput::ActionType::MOVE: { + InputManager::MouseMotionCallbackArgs motionArgs; + motionArgs.deviceType = InputManager::MouseDeviceType::TOUCH; + motionArgs.move = touch.action.motion; + motionArgs.pos = touch.action.pos; + if(c.onMotion) c.onMotion(this, motionArgs); + break; + } + case FingerInput::ActionType::UP: { + InputManager::MouseButtonCallbackArgs mouseArgs; + mouseArgs.deviceType = InputManager::MouseDeviceType::TOUCH; + mouseArgs.pos = touch.action.pos; + mouseArgs.down = false; + mouseArgs.clicks = 0; + mouseArgs.button = InputManager::MouseButton::LEFT; + if(c.onClick) c.onClick(this, mouseArgs); + break; + } + case FingerInput::ActionType::DOWN: { + InputManager::MouseButtonCallbackArgs mouseArgs; + mouseArgs.deviceType = InputManager::MouseDeviceType::TOUCH; + mouseArgs.pos = touch.action.pos; + mouseArgs.down = true; + mouseArgs.clicks = 1; + mouseArgs.button = InputManager::MouseButton::LEFT; + if(c.onClick) c.onClick(this, mouseArgs); + break; + } + case FingerInput::ActionType::NONE: + break; } } diff --git a/src/GUIStuff/Elements/LayoutElement.hpp b/src/GUIStuff/Elements/LayoutElement.hpp index 8a29a51..2daf4d3 100644 --- a/src/GUIStuff/Elements/LayoutElement.hpp +++ b/src/GUIStuff/Elements/LayoutElement.hpp @@ -28,8 +28,7 @@ class LayoutElement : public Element { std::function mouseButton; std::function mouseMotion; std::function mouseWheel; - std::function fingerTouch; - std::function fingerMotion; + std::function fingerTouch; std::function onClick; std::function onMotion; std::function key; @@ -38,8 +37,7 @@ class LayoutElement : public Element { virtual void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) override; virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) override; virtual void input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel) override; - virtual void input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) override; - virtual void input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) override; + virtual void input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch) override; virtual void input_key_callback(const InputManager::KeyCallbackArgs& key) override; private: Callbacks c; diff --git a/src/GUIStuff/Elements/NumberSlider.hpp b/src/GUIStuff/Elements/NumberSlider.hpp index 7c79a13..77737b0 100644 --- a/src/GUIStuff/Elements/NumberSlider.hpp +++ b/src/GUIStuff/Elements/NumberSlider.hpp @@ -135,22 +135,22 @@ template class NumberSlider : public Element { update_slider_pos(motion.pos, false); } - virtual void input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) override { - bool oldIsHeld = dd.isHeld; - dd.isHeld = mouseHovering && touch.down; - if(oldIsHeld && !dd.isHeld) { - gui.set_post_callback_func([&] { - if(config.onRelease) config.onRelease(); - }); - } - else if(dd.isHeld && boundingBox.has_value()) - update_slider_pos(touch.pos, true); - } + //virtual void input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) override { + // bool oldIsHeld = dd.isHeld; + // dd.isHeld = mouseHovering && touch.down; + // if(oldIsHeld && !dd.isHeld) { + // gui.set_post_callback_func([&] { + // if(config.onRelease) config.onRelease(); + // }); + // } + // else if(dd.isHeld && boundingBox.has_value()) + // update_slider_pos(touch.pos, true); + //} - virtual void input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) override { - if(dd.isHeld && boundingBox.has_value()) - update_slider_pos(motion.pos, false); - } + //virtual void input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) override { + // if(dd.isHeld && boundingBox.has_value()) + // update_slider_pos(motion.pos, false); + //} private: void update_slider_pos(const Vector2f& p, bool justHeld) { diff --git a/src/GUIStuff/Elements/RadioButton.cpp b/src/GUIStuff/Elements/RadioButton.cpp index 5c24819..a19e6d4 100644 --- a/src/GUIStuff/Elements/RadioButton.cpp +++ b/src/GUIStuff/Elements/RadioButton.cpp @@ -48,25 +48,23 @@ void RadioButton::update() { } bool RadioButton::is_hovering_animation() { - return mouseHovering && (!gui.last_interaction_is_touch() || isHeld); + return touchHoverAnim || mouseHoverAnim; } void RadioButton::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) { - if(mouseHovering && button.button == InputManager::MouseButton::LEFT && button.down) { - gui.set_post_callback_func([&] { if(onClick) onClick(); }); - isHeld = true; - } - else - isHeld = false; + mouseHoverAnim = mouseHovering; + if(mouseHovering && button.button == InputManager::MouseButton::LEFT && button.down) + gui.set_post_callback_func([&](){if(onClick) onClick();}); } -void RadioButton::input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) { - if(mouseHovering && touch.down) { - gui.set_post_callback_func([&] { if(onClick) onClick(); }); - isHeld = true; - } - else - isHeld = false; +void RadioButton::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) { + mouseHoverAnim = mouseHovering; +} + +void RadioButton::input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch) { + touchHoverAnim = mouseHovering && touch.action.type != FingerInput::ActionType::UP; + if(mouseHovering && touch.gesture && touch.gesture->get_type() == FingerInput::GestureType::TAP) + gui.set_post_callback_func([&](){if(onClick) onClick();}); } void RadioButton::clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) { diff --git a/src/GUIStuff/Elements/RadioButton.hpp b/src/GUIStuff/Elements/RadioButton.hpp index fcd2018..9bcdb3a 100644 --- a/src/GUIStuff/Elements/RadioButton.hpp +++ b/src/GUIStuff/Elements/RadioButton.hpp @@ -26,16 +26,18 @@ class RadioButton : public Element { RadioButton(GUIManager& gui); virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) override; virtual void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) override; - virtual void input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) override; + virtual void input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch) override; + virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) override; virtual void update() override; void layout(const Clay_ElementId& id, const std::function& isTicked, const std::function& onClick); private: static constexpr float RADIOBUTTON_ANIMATION_TIME = 0.3; bool oldIsTicked = false; - bool isHeld = false; bool is_hovering_animation(); float hoverAnimation = 0.0; + bool touchHoverAnim = false; + bool mouseHoverAnim = false; std::function isTicked; std::function onClick; }; diff --git a/src/GUIStuff/Elements/ScrollArea.cpp b/src/GUIStuff/Elements/ScrollArea.cpp index 40aa97e..a26f86b 100644 --- a/src/GUIStuff/Elements/ScrollArea.cpp +++ b/src/GUIStuff/Elements/ScrollArea.cpp @@ -396,35 +396,35 @@ void ScrollArea::input_mouse_motion_callback(const InputManager::MouseMotionCall scrollAreaMotion = scrollAreaMotionMax = {0.0f, 0.0f}; } -void ScrollArea::input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) { - bool oldScrollAreaHeld = scrollAreaHeld; - scrollAreaHeld = mouseHovering && touch.down; - if(scrollAreaHeld) - scrollAreaMotionMax = scrollAreaMotion = {0.0f, 0.0f}; - else if(oldScrollAreaHeld) { - scrollAreaMotion = scrollAreaMotionMax; - if(std::fabs(scrollAreaMotion.x()) < SCROLL_MINIMUM_MOTION_TO_START_MOVE) - scrollAreaMotion.x() = 0.0f; - if(std::fabs(scrollAreaMotion.y()) < SCROLL_MINIMUM_MOTION_TO_START_MOVE) - scrollAreaMotion.y() = 0.0f; - } -} - -void ScrollArea::input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) { - if(scrollAreaHeld) { - scrollAreaMotion = {opts.scrollHorizontal ? motion.move.x() : 0.0f, opts.scrollVertical ? motion.move.y() : 0.0f}; - if(std::fabs(scrollAreaMotion.x()) > std::fabs(scrollAreaMotionMax.x())) - scrollAreaMotionMax.x() = scrollAreaMotion.x(); - if(std::fabs(scrollAreaMotion.y()) > std::fabs(scrollAreaMotionMax.y())) - scrollAreaMotionMax.y() = scrollAreaMotion.y(); - - Vector2f oldScrollOffset = scrollOffset; - scrollOffset.x() += scrollAreaMotion.x(); - scrollOffset.y() += scrollAreaMotion.y(); - clamp_scroll(); - if(oldScrollOffset != scrollOffset) - gui.set_to_layout(); - } -} +//void ScrollArea::input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) { +// bool oldScrollAreaHeld = scrollAreaHeld; +// scrollAreaHeld = mouseHovering && touch.down; +// if(scrollAreaHeld) +// scrollAreaMotionMax = scrollAreaMotion = {0.0f, 0.0f}; +// else if(oldScrollAreaHeld) { +// scrollAreaMotion = scrollAreaMotionMax; +// if(std::fabs(scrollAreaMotion.x()) < SCROLL_MINIMUM_MOTION_TO_START_MOVE) +// scrollAreaMotion.x() = 0.0f; +// if(std::fabs(scrollAreaMotion.y()) < SCROLL_MINIMUM_MOTION_TO_START_MOVE) +// scrollAreaMotion.y() = 0.0f; +// } +//} +// +//void ScrollArea::input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) { +// if(scrollAreaHeld) { +// scrollAreaMotion = {opts.scrollHorizontal ? motion.move.x() : 0.0f, opts.scrollVertical ? motion.move.y() : 0.0f}; +// if(std::fabs(scrollAreaMotion.x()) > std::fabs(scrollAreaMotionMax.x())) +// scrollAreaMotionMax.x() = scrollAreaMotion.x(); +// if(std::fabs(scrollAreaMotion.y()) > std::fabs(scrollAreaMotionMax.y())) +// scrollAreaMotionMax.y() = scrollAreaMotion.y(); +// +// Vector2f oldScrollOffset = scrollOffset; +// scrollOffset.x() += scrollAreaMotion.x(); +// scrollOffset.y() += scrollAreaMotion.y(); +// clamp_scroll(); +// if(oldScrollOffset != scrollOffset) +// gui.set_to_layout(); +// } +//} } diff --git a/src/GUIStuff/Elements/ScrollArea.hpp b/src/GUIStuff/Elements/ScrollArea.hpp index 9395d08..5cb2f38 100644 --- a/src/GUIStuff/Elements/ScrollArea.hpp +++ b/src/GUIStuff/Elements/ScrollArea.hpp @@ -59,8 +59,8 @@ class ScrollArea : public Element { virtual void input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel) override; virtual void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) override; virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) override; - virtual void input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) override; - virtual void input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) override; + //virtual void input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) override; + //virtual void input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) override; private: Options opts; bool scrollAreaHeld = false; diff --git a/src/GUIStuff/Elements/SelectableButton.cpp b/src/GUIStuff/Elements/SelectableButton.cpp index 7c7914f..bd0ec7e 100644 --- a/src/GUIStuff/Elements/SelectableButton.cpp +++ b/src/GUIStuff/Elements/SelectableButton.cpp @@ -111,31 +111,31 @@ void SelectableButton::input_mouse_motion_callback(const InputManager::MouseMoti isHovering = mouseHovering; } -void SelectableButton::input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) { - bool oldIsHeld = isHeld; - bool oldIsHovering = isHovering; - isHeld = mouseHovering && touch.down; - isHovering = mouseHovering && touch.down; - if(isHeld) { - if(instantResponse) - gui.set_post_callback_func(onClick); - gui.set_to_layout(); - } - else if(mouseHovering && oldIsHeld && !touch.down) { - if(!instantResponse) - gui.set_post_callback_func(onClick); - gui.set_to_layout(); - } - else if(oldIsHovering != isHovering || isHeld != oldIsHeld) - gui.set_to_layout(); -} - -void SelectableButton::input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) { - if((isHovering || isHeld) && (inDynamicArea || !mouseHovering)) { - isHovering = false; - isHeld = false; - gui.set_to_layout(); - } -} +//void SelectableButton::input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) { +// bool oldIsHeld = isHeld; +// bool oldIsHovering = isHovering; +// isHeld = mouseHovering && touch.down; +// isHovering = mouseHovering && touch.down; +// if(isHeld) { +// if(instantResponse) +// gui.set_post_callback_func(onClick); +// gui.set_to_layout(); +// } +// else if(mouseHovering && oldIsHeld && !touch.down) { +// if(!instantResponse) +// gui.set_post_callback_func(onClick); +// gui.set_to_layout(); +// } +// else if(oldIsHovering != isHovering || isHeld != oldIsHeld) +// gui.set_to_layout(); +//} +// +//void SelectableButton::input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) { +// if((isHovering || isHeld) && (inDynamicArea || !mouseHovering)) { +// isHovering = false; +// isHeld = false; +// gui.set_to_layout(); +// } +//} } diff --git a/src/GUIStuff/Elements/SelectableButton.hpp b/src/GUIStuff/Elements/SelectableButton.hpp index 0f9330d..680af56 100644 --- a/src/GUIStuff/Elements/SelectableButton.hpp +++ b/src/GUIStuff/Elements/SelectableButton.hpp @@ -49,8 +49,8 @@ class SelectableButton : public Element { void layout(const Clay_ElementId& id, const Data& d); virtual void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) override; virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) override; - virtual void input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) override; - virtual void input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) override; + //virtual void input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) override; + //virtual void input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) override; private: bool inDynamicArea = false; diff --git a/src/GUIStuff/Elements/TextBox.decl.hpp b/src/GUIStuff/Elements/TextBox.decl.hpp index 27dcab2..1c78787 100644 --- a/src/GUIStuff/Elements/TextBox.decl.hpp +++ b/src/GUIStuff/Elements/TextBox.decl.hpp @@ -57,8 +57,8 @@ template class TextBox : public Element { virtual void input_text_callback(const InputManager::TextCallbackArgs& text) override; virtual void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) override; virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) override; - virtual void input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) override; - virtual void input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) override; + //virtual void input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) override; + //virtual void input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) override; virtual std::optional get_text_box_start_info() override; ~TextBox(); private: diff --git a/src/GUIStuff/Elements/TextBox.impl.hpp b/src/GUIStuff/Elements/TextBox.impl.hpp index c6b8aad..372ddd4 100644 --- a/src/GUIStuff/Elements/TextBox.impl.hpp +++ b/src/GUIStuff/Elements/TextBox.impl.hpp @@ -217,33 +217,33 @@ template void TextBox::input_mouse_motion_callback(const InputMa edit->process_mouse_left_button(motion.pos - boundingBox.value().min, 0, isHeld, gui.io.input->key(InputManager::KEY_GENERIC_LSHIFT).held); } -template void TextBox::input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) { - if(boundingBox.has_value()) { - if(touch.down) { - if(mouseHovering) { - if(!is_selected()) { - select(); - gui.set_post_callback_func_high_priority([&] { - if(userInfo.onSelect) userInfo.onSelect(); - }); - } - isHeld = true; - edit->input_finger_touch_down(touch.pos - boundingBox.value().min); - } - else if(is_selected()) { - isHeld = false; - deselect(); - } - } - else - isHeld = false; - } -} - -template void TextBox::input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) { - if(boundingBox.has_value() && is_selected() && isHeld) - edit->input_finger_held_motion(motion.pos - boundingBox.value().min); -} +//template void TextBox::input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) { +// if(boundingBox.has_value()) { +// if(touch.down) { +// if(mouseHovering) { +// if(!is_selected()) { +// select(); +// gui.set_post_callback_func_high_priority([&] { +// if(userInfo.onSelect) userInfo.onSelect(); +// }); +// } +// isHeld = true; +// edit->input_finger_touch_down(touch.pos - boundingBox.value().min); +// } +// else if(is_selected()) { +// isHeld = false; +// deselect(); +// } +// } +// else +// isHeld = false; +// } +//} +// +//template void TextBox::input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) { +// if(boundingBox.has_value() && is_selected() && isHeld) +// edit->input_finger_held_motion(motion.pos - boundingBox.value().min); +//} template std::optional TextBox::get_text_box_start_info() { if(edit) { diff --git a/src/GUIStuff/GUIManager.cpp b/src/GUIStuff/GUIManager.cpp index 8736e25..6bc674f 100644 --- a/src/GUIStuff/GUIManager.cpp +++ b/src/GUIStuff/GUIManager.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,8 @@ GUIManager::GUIManager() setToLayout = true; postCallbackFuncIsHighPriority = false; lastInteractionIsTouch = false; + cursorObstructed = false; + touchObstructed = false; } Clay_Dimensions GUIManager::clay_skia_measure_text(Clay_StringSlice str, Clay_TextElementConfig* config, void* userData) { @@ -715,6 +718,10 @@ bool GUIManager::cursor_obstructed() const { return cursorObstructed; } +bool GUIManager::touch_obstructed() const { + return touchObstructed; +} + void GUIManager::deselect_all() { for(ElementContainer* e : orderedElements) e->elem->deselect(); @@ -749,7 +756,7 @@ void GUIManager::input_mouse_button_callback(InputManager::MouseButtonCallbackAr if(button.deviceType != InputManager::MouseDeviceType::TOUCH) { lastInteractionIsTouch = false; button.pos /= io.guiScaleMultiplier; - mouse_callback(button.pos, [&button] (ElementContainer* e) { e->elem->input_mouse_button_callback(button); }); + mouse_callback(button.pos, cursorObstructed, [&button] (ElementContainer* e) { e->elem->input_mouse_button_callback(button); }); } } @@ -758,26 +765,51 @@ void GUIManager::input_mouse_motion_callback(InputManager::MouseMotionCallbackAr lastInteractionIsTouch = false; motion.pos /= io.guiScaleMultiplier; motion.move /= io.guiScaleMultiplier; - mouse_callback(motion.pos, [&motion] (ElementContainer* e) { e->elem->input_mouse_motion_callback(motion); }); + mouse_callback(motion.pos, cursorObstructed, [&motion] (ElementContainer* e) { e->elem->input_mouse_motion_callback(motion); }); } } void GUIManager::input_mouse_wheel_callback(InputManager::MouseWheelCallbackArgs wheel) { wheel.mousePos /= io.guiScaleMultiplier; - mouse_callback(wheel.mousePos, [&wheel] (ElementContainer* e) { e->elem->input_mouse_wheel_callback(wheel); }); + mouse_callback(wheel.mousePos, cursorObstructed, [&wheel] (ElementContainer* e) { e->elem->input_mouse_wheel_callback(wheel); }); } -void GUIManager::input_finger_touch_callback(InputManager::FingerTouchCallbackArgs touch) { +void GUIManager::input_finger_touch_callback(FingerInput::TouchCallbackArgs touch) { lastInteractionIsTouch = true; - touch.pos /= io.guiScaleMultiplier; - mouse_callback(touch.pos, [&touch] (ElementContainer* e) { e->elem->input_finger_touch_callback(touch); }); -} - -void GUIManager::input_finger_motion_callback(InputManager::FingerMotionCallbackArgs motion) { - lastInteractionIsTouch = true; - motion.pos /= io.guiScaleMultiplier; - motion.move /= io.guiScaleMultiplier; - mouse_callback(motion.pos, [&motion] (ElementContainer* e) { e->elem->input_finger_motion_callback(motion); }); + touch.scale(io.guiScaleMultiplier); + // Don't use tap gesture if it uses more than one finger + if(touch.gesture && touch.gesture->get_type() == FingerInput::GestureType::TAP) { + if(std::static_pointer_cast(touch.gesture)->fingerPositions.size() != 1) + touch.gesture = nullptr; + } + // Mouse hovering calculations will only work when one finger is used + if(touch.fingers.size() != 1) { + // Still check if touch is obstructed by any finger + touchObstructed = false; + for(ElementContainer* e : orderedElements) { + e->elem->childMouseHovering = false; + e->elem->mouseHovering = false; + for(const FingerInput::FingerData& f : touch.fingers) { + if(e->elem->collides_with_point(f.pos)) { + touchObstructed = true; + break; + } + } + if(touch.gesture) { + auto positionsInGesture = touch.gesture->get_all_positions(); + for(const Vector2f& p : positionsInGesture) { + if(e->elem->collides_with_point(p)) { + touchObstructed = true; + break; + } + } + } + } + for(ElementContainer* e : orderedElements) + e->elem->input_finger_touch_callback(touch); + } + else + mouse_callback(touch.fingers[0].pos, touchObstructed, [&touch] (ElementContainer* e) { e->elem->input_finger_touch_callback(touch); }); } std::optional GUIManager::get_text_box_start_info() { @@ -789,17 +821,17 @@ std::optional GUIManager::get_text_box_start_inf return std::nullopt; } -void GUIManager::mouse_callback(const Vector2f& mousePos, const std::function& f) { - cursorObstructed = false; +void GUIManager::mouse_callback(const Vector2f& mousePos, bool& obstructed, const std::function& f) { + obstructed = false; int16_t zIndexObstructed = 0; for(ElementContainer* e : orderedElements) e->elem->childMouseHovering = false; for(ElementContainer* e : orderedElements) { - if((!cursorObstructed || zIndexObstructed == e->elem->zIndex) && e->elem->collides_with_point(mousePos)) { + if((!obstructed || zIndexObstructed == e->elem->zIndex) && e->elem->collides_with_point(mousePos)) { zIndexObstructed = e->elem->zIndex; - cursorObstructed = true; + obstructed = true; e->elem->mouseHovering = true; Element* nextParent = e->elem->parent; while(nextParent) { diff --git a/src/GUIStuff/GUIManager.hpp b/src/GUIStuff/GUIManager.hpp index 5de86d9..4d37f8e 100644 --- a/src/GUIStuff/GUIManager.hpp +++ b/src/GUIStuff/GUIManager.hpp @@ -125,11 +125,11 @@ class GUIManager { void input_mouse_button_callback(InputManager::MouseButtonCallbackArgs button); void input_mouse_motion_callback(InputManager::MouseMotionCallbackArgs motion); void input_mouse_wheel_callback(InputManager::MouseWheelCallbackArgs wheel); - void input_finger_touch_callback(InputManager::FingerTouchCallbackArgs touch); - void input_finger_motion_callback(InputManager::FingerMotionCallbackArgs motion); + void input_finger_touch_callback(FingerInput::TouchCallbackArgs touch); std::optional get_text_box_start_info(); bool cursor_obstructed() const; + bool touch_obstructed() const; private: std::unordered_map animations; @@ -138,7 +138,7 @@ class GUIManager { void layout_end(); void single_layout_run(); - void mouse_callback(const Vector2f& mousePos, const std::function& f); + void mouse_callback(const Vector2f& mousePos, bool& obstructed, const std::function& f); GUIManagerIDStack idStack; std::vector orderedElements; @@ -187,6 +187,7 @@ class GUIManager { bool setToLayout; bool setToUpdateInvalidateDrawAreaFromLayout; bool cursorObstructed; + bool touchObstructed; }; } diff --git a/src/InputManager.cpp b/src/InputManager.cpp index 5819d89..016652f 100644 --- a/src/InputManager.cpp +++ b/src/InputManager.cpp @@ -32,6 +32,7 @@ #include "Helpers/MathExtras.hpp" #include "MainProgram.hpp" #include "AndroidJNICalls.hpp" +#include "SDL3/SDL_events.h" #ifdef _WIN32 #include @@ -650,223 +651,9 @@ void InputManager::backend_pen_axis_update(const SDL_PenAxisEvent& e) { } } -InputManager::MouseButtonCallbackArgs InputManager::convert_finger_touch_to_mouse_button(const FingerTouchCallbackArgs& touch) { - return { - .deviceType = InputManager::MouseDeviceType::TOUCH, - .button = InputManager::MouseButton::LEFT, - .down = touch.down, - .clicks = static_cast(touch.fingerTapCount), - .pos = touch.pos - }; -} - -InputManager::MouseMotionCallbackArgs InputManager::convert_finger_motion_to_mouse_motion(const FingerMotionCallbackArgs& motion) { - return { - .deviceType = InputManager::MouseDeviceType::TOUCH, - .pos = motion.pos, - .move = motion.move - }; -} - -std::vector InputManager::get_multiple_finger_positions() { - std::vector pos; - for(const SDL_TouchFingerEvent& fingerEvent : touch.fingers) - pos.emplace_back(backend_touch_cursor_pos_calculation({fingerEvent.x, fingerEvent.y})); - return pos; -} - -std::vector InputManager::get_multiple_finger_motions() { - std::vector pos; - for(const SDL_TouchFingerEvent& fingerEvent : touch.fingers) - pos.emplace_back(backend_touch_cursor_delta_calculation({fingerEvent.dx, fingerEvent.dy})); - return pos; -} - -void InputManager::touch_finger_do_mouse_down() { - auto& prevTouch = touch.fingers[0]; - Vector2f mouseNewPos = backend_touch_cursor_pos_calculation({prevTouch.x, prevTouch.y}); - mouse.set_pos(mouseNewPos); - mouse.leftDown = true; - - if((std::chrono::steady_clock::now() - touch.lastLeftClickTime) > std::chrono::milliseconds(500)) - touch.leftClicksSaved = 0; - touch.leftClicksSaved++; - touch.lastLeftClickTime = std::chrono::steady_clock::now(); - - main.input_mouse_button_callback({ - .deviceType = MouseDeviceType::TOUCH, - .button = MouseButton::LEFT, - .down = true, - .clicks = touch.leftClicksSaved, - .pos = mouseNewPos - }); -} - -void InputManager::touch_finger_do_mouse_up(const SDL_TouchFingerEvent& e) { - Vector2f mouseNewPos = backend_touch_cursor_pos_calculation({e.x, e.y}); - mouse.set_pos(mouseNewPos); - mouse.leftDown = false; - - main.input_mouse_button_callback({ - .deviceType = MouseDeviceType::TOUCH, - .button = MouseButton::LEFT, - .down = false, - .clicks = 0, - .pos = mouseNewPos - }); -} - -void InputManager::touch_finger_do_mouse_motion(const SDL_TouchFingerEvent& e) { - Vector2f mouseNewPos = backend_touch_cursor_pos_calculation({e.x, e.y}); - mouse.set_pos(mouseNewPos); - Vector2f mouseRel = backend_touch_cursor_delta_calculation({e.dx, e.dy}); - main.input_mouse_motion_callback({ - .deviceType = MouseDeviceType::TOUCH, - .pos = mouseNewPos, - .move = mouseRel - }); -} - -void InputManager::backend_touch_finger_down_update(const SDL_TouchFingerEvent& e) { - touch.fingers.emplace_back(e); - auto fingerPosVec = get_multiple_finger_positions(); - switch(touch.touchEventType) { - case Touch::NO_TOUCH_EVENT: { - if(touch.fingers.size() == 2) { - touch.touchEventType = Touch::TWO_FINGER_EVENT; - main.input_multi_finger_touch_callback({ - .down = true, - .pos = fingerPosVec - }); - } - break; - } - case Touch::ONE_FINGER_EVENT: { - if(touch.fingers.size() == 2) { - touch_finger_do_mouse_up(e); - touch.touchEventType = Touch::TWO_FINGER_EVENT; - main.input_multi_finger_touch_callback({ - .down = true, - .pos = fingerPosVec - }); - } - break; - } - case Touch::TWO_FINGER_EVENT: { - break; - } - case Touch::EVENT_DONE: { - if(touch.fingers.size() == 1) - touch.touchEventType = Touch::NO_TOUCH_EVENT; - break; - } - } - - - if((std::chrono::steady_clock::now() - touch.lastFingerTapTime) > std::chrono::milliseconds(500)) - touch.fingerTapsSaved = 0; - touch.fingerTapsSaved++; - touch.lastFingerTapTime = std::chrono::steady_clock::now(); - - main.input_finger_touch_callback({ - .fingerID = e.fingerID, - .down = true, - .pos = fingerPosVec.back(), - .fingerDownCount = touch.fingers.size(), - .fingerTapCount = touch.fingerTapsSaved - }); - - isTouchDevice = true; -} - -void InputManager::backend_touch_finger_up_update(const SDL_TouchFingerEvent& e) { - switch(touch.touchEventType) { - case Touch::NO_TOUCH_EVENT: { - touch_finger_do_mouse_down(); - touch_finger_do_mouse_up(e); - touch.touchEventType = Touch::EVENT_DONE; - break; - } - case Touch::ONE_FINGER_EVENT: { - touch_finger_do_mouse_up(e); - touch.touchEventType = Touch::EVENT_DONE; - break; - } - case Touch::TWO_FINGER_EVENT: { - main.input_multi_finger_touch_callback({ - .down = false, - .pos = get_multiple_finger_positions() - }); - touch.touchEventType = Touch::EVENT_DONE; - break; - } - case Touch::EVENT_DONE: { - break; - } - } - - main.input_finger_touch_callback({ - .fingerID = e.fingerID, - .down = false, - .pos = backend_touch_cursor_pos_calculation({e.x, e.y}), - .fingerDownCount = touch.fingers.size(), - .fingerTapCount = 0 - }); - - std::erase_if(touch.fingers, [&e](auto& tE) { - return e.fingerID == tE.fingerID; - }); - - isTouchDevice = true; -} - -void InputManager::backend_touch_finger_motion_update(const SDL_TouchFingerEvent& e) { - constexpr float MINIMUM_MOTION_TO_CONSIDER_SQRD = 30.0f * 30.0f; - - isTouchDevice = true; - - if(touch.fingers.size() == 1 && touch.touchEventType == Touch::NO_TOUCH_EVENT) { - Vector2f newPos = backend_touch_cursor_pos_calculation({e.x, e.y}) * main.window.scale; - Vector2f oldPos = backend_touch_cursor_pos_calculation({touch.fingers[0].x, touch.fingers[0].y}) * main.window.scale; - if(vec_distance_sqrd(newPos, oldPos) < MINIMUM_MOTION_TO_CONSIDER_SQRD) - return; - } - - switch(touch.touchEventType) { - case Touch::NO_TOUCH_EVENT: { - touch_finger_do_mouse_down(); - touch_finger_do_mouse_motion(e); - touch.touchEventType = Touch::ONE_FINGER_EVENT; - break; - } - case Touch::ONE_FINGER_EVENT: { - touch_finger_do_mouse_motion(e); - break; - } - case Touch::TWO_FINGER_EVENT: { - main.input_multi_finger_motion_callback({ - .pos = get_multiple_finger_positions(), - .move = get_multiple_finger_motions() - }); - break; - } - case Touch::EVENT_DONE: { - break; - } - } - for(auto& tE : touch.fingers) { - if(tE.fingerID == e.fingerID) { - tE = e; - break; - } - } - - main.input_finger_motion_callback({ - .fingerID = e.fingerID, - .pos = backend_touch_cursor_pos_calculation({e.x, e.y}), - .move = backend_touch_cursor_delta_calculation({e.dx, e.dy}), - .fingerDownCount = touch.fingers.size() - }); +void InputManager::backend_touch_finger_update(const SDL_TouchFingerEvent& e) { + auto callbackArgs = fingerTracker.update_finger_data_input_callback(e.type, e.touchID, e.fingerID, backend_touch_cursor_pos_calculation({e.x, e.y}), backend_touch_cursor_delta_calculation({e.dx, e.dy})); + main.input_finger_touch_callback(callbackArgs); } void InputManager::update_safe_area() { @@ -1143,10 +930,6 @@ void InputManager::Mouse::set_pos(const Vector2f& newPos) { } void InputManager::update() { - //if(touch.touchEventType == Touch::NO_TOUCH_EVENT && (SDL_GetTicksNS() - touch.fingers[0].timestamp) > (200 * 1000000)) { // 200ms to determine whether touch is with a single finger - // touch_finger_do_mouse_down(); - // touch.touchEventType = Touch::ONE_FINGER_EVENT; - //} } void InputManager::frame_reset(const Vector2i& windowSize) { diff --git a/src/InputManager.hpp b/src/InputManager.hpp index 589d2be..f42b110 100644 --- a/src/InputManager.hpp +++ b/src/InputManager.hpp @@ -35,6 +35,7 @@ #include #include "CustomEvents.hpp" +#include "FingerInputTracker.hpp" using namespace Eigen; class MainProgram; @@ -90,20 +91,6 @@ struct InputManager { bool middleDown = false; } mouse; - struct Touch { - uint8_t leftClicksSaved = 0; - uint8_t fingerTapsSaved = 0; - std::chrono::steady_clock::time_point lastLeftClickTime; - std::chrono::steady_clock::time_point lastFingerTapTime; - std::vector fingers; - enum TypeOfTouchEvent { - NO_TOUCH_EVENT, - ONE_FINGER_EVENT, - TWO_FINGER_EVENT, - EVENT_DONE - } touchEventType = EVENT_DONE; - } touch; - struct Pen { bool inProximity = false; bool isDown = false; @@ -116,6 +103,8 @@ struct InputManager { std::array buttons; } pen; + FingerInput::InputTracker fingerTracker; + bool isTouchDevice = true; enum AndroidInputType : int { @@ -263,11 +252,6 @@ struct InputManager { uint32_t make_generic_key_mod(SDL_Keymod m); void set_key_up(const SDL_KeyboardEvent& e, KeyCode kCode, bool acceptingTextInput); void set_key_down(const SDL_KeyboardEvent& e, KeyCode kCode, bool acceptingTextInput); - std::vector get_multiple_finger_positions(); - std::vector get_multiple_finger_motions(); - void touch_finger_do_mouse_down(); - void touch_finger_do_mouse_up(const SDL_TouchFingerEvent& f); - void touch_finger_do_mouse_motion(const SDL_TouchFingerEvent& f); Vector2f backend_cursor_pos_calculation(const Vector2f& cursorPos); Vector2f backend_cursor_delta_calculation(const Vector2f& cursorDelta); @@ -289,9 +273,7 @@ struct InputManager { void backend_pen_touch_up_update(const SDL_PenTouchEvent& e); void backend_pen_motion_update(const SDL_PenMotionEvent& e); void backend_pen_axis_update(const SDL_PenAxisEvent& e); - void backend_touch_finger_down_update(const SDL_TouchFingerEvent& e); - void backend_touch_finger_up_update(const SDL_TouchFingerEvent& e); - void backend_touch_finger_motion_update(const SDL_TouchFingerEvent& e); + void backend_touch_finger_update(const SDL_TouchFingerEvent& e); void backend_window_resize_update(); void backend_window_scale_update(const SDL_WindowEvent& e); @@ -388,34 +370,6 @@ struct InputManager { const char* data; }; - struct MultiFingerTouchCallbackArgs { - bool down; - std::vector pos; - }; - - struct MultiFingerMotionCallbackArgs { - std::vector pos; - std::vector move; - }; - - struct FingerTouchCallbackArgs { - SDL_FingerID fingerID; - bool down; - Vector2f pos; - size_t fingerDownCount; - int fingerTapCount; - }; - - struct FingerMotionCallbackArgs { - SDL_FingerID fingerID; - Vector2f pos; - Vector2f move; - size_t fingerDownCount; - }; - - static MouseButtonCallbackArgs convert_finger_touch_to_mouse_button(const FingerTouchCallbackArgs& touch); - static MouseMotionCallbackArgs convert_finger_motion_to_mouse_motion(const FingerMotionCallbackArgs& motion); - struct WindowResizeCallbackArgs { Vector2i size; SCollision::AABB safeArea; diff --git a/src/MainProgram.cpp b/src/MainProgram.cpp index 619de18..0c4f4da 100755 --- a/src/MainProgram.cpp +++ b/src/MainProgram.cpp @@ -503,28 +503,12 @@ void MainProgram::input_pen_axis_callback(const InputManager::PenAxisCallbackArg post_callback(); } -void MainProgram::input_multi_finger_touch_callback(const InputManager::MultiFingerTouchCallbackArgs& touch) { - screen->input_multi_finger_touch_callback(touch); - post_callback(); -} - -void MainProgram::input_multi_finger_motion_callback(const InputManager::MultiFingerMotionCallbackArgs& motion) { - screen->input_multi_finger_motion_callback(motion); - post_callback(); -} - -void MainProgram::input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) { +void MainProgram::input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch) { g.input_finger_touch_callback(touch); screen->input_finger_touch_callback(touch); post_callback(); } -void MainProgram::input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) { - g.input_finger_motion_callback(motion); - screen->input_finger_motion_callback(motion); - post_callback(); -} - void MainProgram::input_window_resize_callback(const InputManager::WindowResizeCallbackArgs& w) { for(auto& wor : worlds) wor->drawData.cam.set_viewing_area(window.size.cast()); diff --git a/src/MainProgram.hpp b/src/MainProgram.hpp index bc4b343..ee8c62e 100644 --- a/src/MainProgram.hpp +++ b/src/MainProgram.hpp @@ -181,10 +181,7 @@ class MainProgram { void input_pen_touch_callback(const InputManager::PenTouchCallbackArgs& touch); void input_pen_motion_callback(const InputManager::PenMotionCallbackArgs& motion); void input_pen_axis_callback(const InputManager::PenAxisCallbackArgs& axis); - void input_multi_finger_touch_callback(const InputManager::MultiFingerTouchCallbackArgs& touch); - void input_multi_finger_motion_callback(const InputManager::MultiFingerMotionCallbackArgs& motion); - void input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch); - void input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion); + void input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch); void input_window_resize_callback(const InputManager::WindowResizeCallbackArgs& w); void input_window_scale_callback(const InputManager::WindowScaleCallbackArgs& w); void input_window_mouse_focus_gained(); diff --git a/src/Screens/DrawingProgramScreen.cpp b/src/Screens/DrawingProgramScreen.cpp index 63253b2..458e818 100644 --- a/src/Screens/DrawingProgramScreen.cpp +++ b/src/Screens/DrawingProgramScreen.cpp @@ -95,18 +95,8 @@ void DrawingProgramScreen::input_pen_axis_callback(const InputManager::PenAxisCa main.world->input_pen_axis_callback(axis); } -void DrawingProgramScreen::input_multi_finger_touch_callback(const InputManager::MultiFingerTouchCallbackArgs& touch) { - main.world->input_multi_finger_touch_callback(touch); -} - -void DrawingProgramScreen::input_multi_finger_motion_callback(const InputManager::MultiFingerMotionCallbackArgs& motion) { - main.world->input_multi_finger_motion_callback(motion); -} - -void DrawingProgramScreen::input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) { -} - -void DrawingProgramScreen::input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) { +void DrawingProgramScreen::input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch) { + main.world->input_finger_touch_callback(touch); } void DrawingProgramScreen::input_window_resize_callback(const InputManager::WindowResizeCallbackArgs& w) { diff --git a/src/Screens/DrawingProgramScreen.hpp b/src/Screens/DrawingProgramScreen.hpp index 7f9710c..8649b92 100644 --- a/src/Screens/DrawingProgramScreen.hpp +++ b/src/Screens/DrawingProgramScreen.hpp @@ -40,10 +40,7 @@ class DrawingProgramScreen : public Screen { virtual void input_pen_touch_callback(const InputManager::PenTouchCallbackArgs& touch) override; virtual void input_pen_motion_callback(const InputManager::PenMotionCallbackArgs& motion) override; virtual void input_pen_axis_callback(const InputManager::PenAxisCallbackArgs& axis) override; - virtual void input_multi_finger_touch_callback(const InputManager::MultiFingerTouchCallbackArgs& touch) override; - virtual void input_multi_finger_motion_callback(const InputManager::MultiFingerMotionCallbackArgs& motion) override; - virtual void input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) override; - virtual void input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) override; + virtual void input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch) override; virtual void input_window_resize_callback(const InputManager::WindowResizeCallbackArgs& w) override; virtual void input_window_scale_callback(const InputManager::WindowScaleCallbackArgs& w) override; virtual std::optional get_text_box_start_info() override; diff --git a/src/Screens/Screen.cpp b/src/Screens/Screen.cpp index 8a931f0..88d14dc 100644 --- a/src/Screens/Screen.cpp +++ b/src/Screens/Screen.cpp @@ -77,10 +77,7 @@ void Screen::input_pen_button_callback(const InputManager::PenButtonCallbackArgs void Screen::input_pen_touch_callback(const InputManager::PenTouchCallbackArgs& touch) {} void Screen::input_pen_motion_callback(const InputManager::PenMotionCallbackArgs& motion) {} void Screen::input_pen_axis_callback(const InputManager::PenAxisCallbackArgs& axis) {} -void Screen::input_multi_finger_touch_callback(const InputManager::MultiFingerTouchCallbackArgs& touch) {} -void Screen::input_multi_finger_motion_callback(const InputManager::MultiFingerMotionCallbackArgs& motion) {} -void Screen::input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch) {} -void Screen::input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion) {} +void Screen::input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch) {} void Screen::input_window_resize_callback(const InputManager::WindowResizeCallbackArgs& w) {} void Screen::input_window_scale_callback(const InputManager::WindowScaleCallbackArgs& w) {} void Screen::input_app_about_to_go_to_background_callback() {} diff --git a/src/Screens/Screen.hpp b/src/Screens/Screen.hpp index 26a674c..215ba20 100644 --- a/src/Screens/Screen.hpp +++ b/src/Screens/Screen.hpp @@ -59,10 +59,7 @@ class Screen { virtual void input_pen_touch_callback(const InputManager::PenTouchCallbackArgs& touch); virtual void input_pen_motion_callback(const InputManager::PenMotionCallbackArgs& motion); virtual void input_pen_axis_callback(const InputManager::PenAxisCallbackArgs& axis); - virtual void input_multi_finger_touch_callback(const InputManager::MultiFingerTouchCallbackArgs& touch); - virtual void input_multi_finger_motion_callback(const InputManager::MultiFingerMotionCallbackArgs& motion); - virtual void input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch); - virtual void input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion); + virtual void input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch); virtual void input_window_resize_callback(const InputManager::WindowResizeCallbackArgs& w); virtual void input_window_scale_callback(const InputManager::WindowScaleCallbackArgs& w); virtual void input_app_about_to_go_to_background_callback(); diff --git a/src/World.cpp b/src/World.cpp index 613cfac..9b41660 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -27,6 +27,7 @@ #include #include #include "DrawingProgram/Layers/DrawingProgramLayerListItem.hpp" +#include "FingerInputTracker.hpp" #include "Helpers/NetworkingObjects/NetObjOrderedList.hpp" #include "Helpers/NetworkingObjects/NetObjTemporaryPtr.decl.hpp" #include "Helpers/NetworkingObjects/NetObjUnorderedSet.hpp" @@ -371,14 +372,9 @@ void World::input_pen_axis_callback(const InputManager::PenAxisCallbackArgs& axi drawProg.input_pen_axis_callback(axis); } -void World::input_multi_finger_touch_callback(const InputManager::MultiFingerTouchCallbackArgs& touch) { +void World::input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch) { if(!clientStillConnecting) - drawData.cam.input_multi_finger_touch_callback(*this, touch); -} - -void World::input_multi_finger_motion_callback(const InputManager::MultiFingerMotionCallbackArgs& motion) { - if(!clientStillConnecting) - drawData.cam.input_multi_finger_motion_callback(*this, motion); + drawData.cam.input_finger_touch_callback(*this, touch); } std::optional World::get_text_box_start_info() { diff --git a/src/World.hpp b/src/World.hpp index 7529471..19639ee 100644 --- a/src/World.hpp +++ b/src/World.hpp @@ -128,8 +128,7 @@ class World { void input_pen_touch_callback(const InputManager::PenTouchCallbackArgs& touch); void input_pen_motion_callback(const InputManager::PenMotionCallbackArgs& motion); void input_pen_axis_callback(const InputManager::PenAxisCallbackArgs& axis); - void input_multi_finger_touch_callback(const InputManager::MultiFingerTouchCallbackArgs& touch); - void input_multi_finger_motion_callback(const InputManager::MultiFingerMotionCallbackArgs& motion); + void input_finger_touch_callback(const FingerInput::TouchCallbackArgs& touch); std::optional get_text_box_start_info(); private: bool saveThumbnail = false; diff --git a/src/main.cpp b/src/main.cpp index a8d4fe5..a5949d6 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -796,19 +796,11 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) { mS.m->input.backend_pen_button_down_update(event->pbutton); break; } - case SDL_EVENT_FINGER_DOWN: { - if(!mS.m->conf.tabletOptions.disableTouchWhenPenInProximity || !mS.m->input.pen.inProximity) - mS.m->input.backend_touch_finger_down_update(event->tfinger); - break; - } - case SDL_EVENT_FINGER_UP: { - if(!mS.m->conf.tabletOptions.disableTouchWhenPenInProximity || !mS.m->input.pen.inProximity) - mS.m->input.backend_touch_finger_up_update(event->tfinger); - break; - } + case SDL_EVENT_FINGER_DOWN: + case SDL_EVENT_FINGER_UP: case SDL_EVENT_FINGER_MOTION: { if(!mS.m->conf.tabletOptions.disableTouchWhenPenInProximity || !mS.m->input.pen.inProximity) - mS.m->input.backend_touch_finger_motion_update(event->tfinger); + mS.m->input.backend_touch_finger_update(event->tfinger); break; } case SDL_EVENT_DISPLAY_ORIENTATION: