diff --git a/src/ui/Application.cpp b/src/ui/Application.cpp index d316d8d..9ec8abb 100644 --- a/src/ui/Application.cpp +++ b/src/ui/Application.cpp @@ -143,6 +143,7 @@ void Application::mainLoopStep() { SDL_Event event; while (SDL_PollEvent(&event)) { ImGui_ImplSDL2_ProcessEvent(&event); + handleTouchEvent(event); if (event.type == SDL_QUIT) running_ = false; if (event.type == SDL_KEYDOWN) { @@ -1122,6 +1123,75 @@ void Application::renderWaterfallPanel() { ImGui::Dummy({availW, availH}); } +void Application::handleTouchEvent(const SDL_Event& event) { + if (event.type == SDL_FINGERDOWN) { + ++touch_.count; + } else if (event.type == SDL_FINGERUP) { + touch_.count = std::max(0, touch_.count - 1); + } + + // Two-finger gesture start: snapshot state + if (touch_.count == 2 && event.type == SDL_FINGERDOWN) { + int w, h; + SDL_GetWindowSize(window_, &w, &h); + // Get both finger positions from SDL touch API + SDL_TouchID tid = event.tfinger.touchId; + int nf = SDL_GetNumTouchFingers(tid); + if (nf >= 2) { + SDL_Finger* f0 = SDL_GetTouchFinger(tid, 0); + SDL_Finger* f1 = SDL_GetTouchFinger(tid, 1); + float x0 = f0->x * w, x1 = f1->x * w; + float dx = x1 - x0, dy = (f1->y - f0->y) * h; + touch_.startDist = std::sqrt(dx * dx + dy * dy); + touch_.lastDist = touch_.startDist; + touch_.startCenterX = (x0 + x1) * 0.5f; + touch_.lastCenterX = touch_.startCenterX; + touch_.startLo = viewLo_; + touch_.startHi = viewHi_; + } + } + + // Two-finger motion: pinch + pan + if (touch_.count == 2 && event.type == SDL_FINGERMOTION) { + int w, h; + SDL_GetWindowSize(window_, &w, &h); + SDL_TouchID tid = event.tfinger.touchId; + int nf = SDL_GetNumTouchFingers(tid); + if (nf >= 2) { + SDL_Finger* f0 = SDL_GetTouchFinger(tid, 0); + SDL_Finger* f1 = SDL_GetTouchFinger(tid, 1); + float x0 = f0->x * w, x1 = f1->x * w; + float dx = x1 - x0, dy = (f1->y - f0->y) * h; + float dist = std::sqrt(dx * dx + dy * dy); + float centerX = (x0 + x1) * 0.5f; + + if (touch_.startDist > 1.0f) { + // Zoom: scale the span by start/current distance ratio + float span0 = touch_.startHi - touch_.startLo; + float ratio = touch_.startDist / std::max(dist, 1.0f); + float newSpan = std::clamp(span0 * ratio, 0.001f, 1.0f); + + // Anchor zoom at the initial midpoint (in view-fraction space) + float panelW = wfSizeX_ > 0 ? wfSizeX_ : static_cast(w); + float panelX = wfPosX_; + float midFrac = (touch_.startCenterX - panelX) / panelW; + float midView = touch_.startLo + midFrac * span0; + + // Pan: shift by finger midpoint movement + float panDelta = -(centerX - touch_.startCenterX) / panelW * newSpan; + + float newLo = midView - midFrac * newSpan + panDelta; + float newHi = newLo + newSpan; + + if (newLo < 0.0f) { newHi -= newLo; newLo = 0.0f; } + if (newHi > 1.0f) { newLo -= (newHi - 1.0f); newHi = 1.0f; } + viewLo_ = std::clamp(newLo, 0.0f, 1.0f); + viewHi_ = std::clamp(newHi, 0.0f, 1.0f); + } + } + } +} + void Application::handleSpectrumInput(float posX, float posY, float sizeX, float sizeY) { ImGuiIO& io = ImGui::GetIO(); diff --git a/src/ui/Application.h b/src/ui/Application.h index 424cea9..5deb90d 100644 --- a/src/ui/Application.h +++ b/src/ui/Application.h @@ -184,6 +184,18 @@ private: HoverPanel hoverPanel_ = HoverPanel::None; float hoverWfTimeOffset_ = 0.0f; // seconds from newest line + // Touch gesture state (pinch-zoom / two-finger pan) + struct TouchState { + int count = 0; // active finger count + float startDist = 0.0f; // initial distance between two fingers + float startLo = 0.0f; // viewLo_ at gesture start + float startHi = 0.0f; // viewHi_ at gesture start + float startCenterX = 0.0f; // midpoint screen-X at gesture start + float lastCenterX = 0.0f; // last midpoint screen-X + float lastDist = 0.0f; // last distance between fingers + } touch_; + void handleTouchEvent(const SDL_Event& event); + // Config persistence Config config_;