pthom / hello_imgui_template

A quick start template to work with Hello ImGui
17 stars 6 forks source link

Using zoom and second mouse click over phone. #8

Open saboTec opened 1 week ago

saboTec commented 1 week ago

Hello, i am using a implot and zooming and "right" click are very usefull for my case, however i did not find how can i use the 2 finger on phones or "second" click. Is there any option for it? Thanks a lot.

saboTec commented 2 days ago

This workaround helped. i can use the finger ids to make the zoom and other options.


    // Event handling and GUI rendering
    runnerParams.callbacks.AnyBackendEventCallback = [&](void *pEvent) -> bool {
        const auto event = static_cast<SDL_Event*>(pEvent);

        ImGuiIO& io = ImGui::GetIO();
        static ImPlotFlags plotFlags = ImPlotFlags_None;
        return HandleTouchForPlotTools(*event, io, plotFlags);
    };

    runnerParams.callbacks.BeforeImGuiRender = [&]() {

        // Declare and initialize plotFlags

        SDL_Event event;
        while (SDL_PollEvent(&event)) {
            // Handle SDL events (e.g., mouse, touch, keyboard)
            if (event.type == SDL_QUIT) {
                exit(0); // Terminate application when the user closes the app
            }
            // Additional event handling (e.g., custom touch support) can go here
        }
    };
pthom commented 2 days ago

Hello,

I'm interested. Would you mind giving me more info about HandleTouchForPlotTools, as I could not find info about it online.

Thanks!

saboTec commented 2 days ago

Hello, it is just own method to work with the implot simulating mouse. But it is still buggy, like when i open the implot popup with flags then the event one finger just stays on the whole time. When i do it i will give an update. Thanks

bool HandleTouchForPlotTools(SDL_Event& event, ImGuiIO& io, ImPlotFlags& plotFlags) {
    static bool twoFingerTouch = false;
    static float initialDistance = 0.0f;
    static float initialMouseWheel = 0.0f;
    static std::map<SDL_FingerID, ImVec2> pressedFingers;
    static auto clickCount = 0;

    if (event.type == SDL_MULTIGESTURE) {
        if (event.mgesture.numFingers == 2) {
            // Two-finger touch detected
            twoFingerTouch = true;

            if (initialDistance == 0.0f) {
                initialDistance = event.mgesture.dDist; // Initialize zoom distance
                initialMouseWheel = io.MouseWheel;
            } else {
                // Handle zoom in/out
                float delta = event.mgesture.dDist; // - initialDistance;
                io.MouseWheel = initialMouseWheel + delta * 0.03f;

                std::cout << "Delta: " << delta << ", wheel: " << io.MouseWheel << std::endl;
            }
        }
    }

    if (event.type == SDL_FINGERDOWN) {
        const auto fingerId = event.tfinger.fingerId;
        if(pressedFingers.find(fingerId) == pressedFingers.end()) {
            pressedFingers[fingerId] = ImVec2(event.tfinger.x, event.tfinger.y);
            std::cout << "Added finger " << fingerId << std::endl;
            if(pressedFingers.size() == 3) {
                io.MouseDown[1] = true;
            }
        }
    } else if (event.type == SDL_FINGERUP) {
        const auto fingerId = event.tfinger.fingerId;
        if(pressedFingers.find(fingerId) != pressedFingers.end()) {
            if(pressedFingers.size() == 3) {
                io.MouseDown[1] = false;
            }

            pressedFingers.erase(fingerId);
            std::cout << "Removed finger " << fingerId << std::endl;
        }
    }

    std::cout << "Number of pressed fingers: " << pressedFingers.size() << ", event " << event.type << std::endl;

    if(pressedFingers.size() == 2) {
        return true;
    }

    return false;
}
pthom commented 2 days ago

Hum, interesting :-)

This could serve as a later inspiration for a possible patch to ImGui_ImplSDL2_ProcessEvent inside imgui itself.

saboTec commented 2 days ago

That sounds good :) It would be great if implot would built this option for phones like it already has for a mouse.

pthom commented 2 days ago

If you do it in ImGui_ImplSDL2_ProcessEvent, you will have it everywhere (including ImPlot an all ImGui based libraries).

saboTec commented 1 day ago

I did it there and works great. Now the finger is not stucked on the popup of the implot. Thanks a lot.

pthom commented 1 day ago

Could you share the diff or the patch you did in imgui_impl_sdl2.cpp ?

saboTec commented 1 day ago

I did not do much, just copied the one method to it, and from the main.cpp i remove the event code and works great. When i have more time i will try to do it "cleaner"

bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event event) { ImGui_ImplSDL2_Data bd = ImGui_ImplSDL2_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDL2_Init()?"); ImGuiIO& io = ImGui::GetIO();

// Static variables for multi-touch handling
static bool twoFingerTouch = false;
static float initialDistance = 0.0f;
static float initialMouseWheel = 0.0f;
static std::map<SDL_FingerID, ImVec2> pressedFingers;

switch (event->type)
{
    case SDL_FINGERDOWN:
    {
        const auto fingerId = event->tfinger.fingerId;
        if (pressedFingers.find(fingerId) == pressedFingers.end())
        {
            pressedFingers[fingerId] = ImVec2(event->tfinger.x, event->tfinger.y);
            if (pressedFingers.size() == 3)
            {
                io.MouseDown[1] = true; // Simulate right-click on three fingers
            }
        }
        return true;
    }
    case SDL_FINGERUP:
    {
        const auto fingerId = event->tfinger.fingerId;
        if (pressedFingers.find(fingerId) != pressedFingers.end())
        {
            if (pressedFingers.size() == 3)
            {
                io.MouseDown[1] = false; // Release right-click on three fingers
            }
            pressedFingers.erase(fingerId);
        }
        return true;
    }
    case SDL_MULTIGESTURE:
    {
        if (event->mgesture.numFingers == 2)
        {
            // Two-finger gesture handling
            twoFingerTouch = true;

            if (initialDistance == 0.0f)
            {
                initialDistance = event->mgesture.dDist; // Initialize zoom distance
                initialMouseWheel = io.MouseWheel;
            }
            else
            {
                // Handle zoom in/out
                float delta = event->mgesture.dDist;
                io.MouseWheel = initialMouseWheel + delta * 0.03f;
            }
        }
        return true;
    }

    rest of the code is the same from the  line       case SDL_MOUSEMOTION: