Skip to content

Separating click and double-click events #8337

@wusikijeronii

Description

@wusikijeronii

Version/Branch of Dear ImGui:

v1.91.8 WIP master

Back-ends:

custom

Compiler, OS:

Windows 11 + clang 18.1.8

Full config/build information:

No response

Details:

Hi,
I hope I'm not being too much of a bother ;)

I have a situation where I need to distinguish single click and double click events separately for an element. However, no matter what I try, I always run into one of these issues:

  • After a double click, the single click event also fires.
  • Instead of a double click event, I receive two separate single click events.

As a workaround, I implemented a structure similar to ImGui’s mouse state tracking. If MouseDoubleClickTime passes without a second click, I return a clickPended state. This works for me, but effectively, it's a simplified duplicate of ImGui’s internal context doing the same thing.

It would be great to have a native way to distinguish single clicks from double clicks, so they don't interfere with each other.

Would it be possible to introduce a built-in mechanism in ImGui to separate click and double-click logic more cleanly?

Screenshots/Video:

No response

Minimal, Complete and Verifiable Example code:

    extern APPLIB_API struct Context
    {
        ImGuiMouseCursor last_cursor = ImGuiMouseCursor_None;
        struct MouseData
        {
            int click_count = 0;
            f64 last_click_time = 0.0;
            bool is_dragging = false;
            MouseAction action = MouseAction::none;
        } mouse_data;
    } g_Ctx;

    inline bool isClicked() { return g_Ctx.mouse_data.action == MouseAction::click; }

    inline bool isClickedPended() { return g_Ctx.mouse_data.action == MouseAction::clickPended; }

    inline bool isDragStart() { return g_Ctx.mouse_data.action == MouseAction::dragStart; }

    inline bool isDragEnd() { return g_Ctx.mouse_data.action == MouseAction::dragEnd; }

    inline bool isDragging() { return g_Ctx.mouse_data.is_dragging; }

    inline bool isDoubleClicked() { return g_Ctx.mouse_data.action == MouseAction::doubleClick; }

    void updateMouseData()
    {
        static f64 thresold = ImGui::GetIO().MouseDoubleClickTime;
        auto &m = g_Ctx.mouse_data;
        m.action = MouseAction::none;
        if (ImGui::IsMouseClicked(0))
        {
            m.click_count++;
            m.last_click_time = window::getTime();
            m.is_dragging = false;
            m.action = MouseAction::click;
            window::pushEmptyEvent();
        }
        else if (m.click_count > 0)
        {
            ImVec2 dragDelta = ImGui::GetMouseDragDelta(0);
            if (!m.is_dragging && dragDelta != ImVec2())
            {
                m.is_dragging = true;
                m.action = MouseAction::dragStart;
            }
            window::pushEmptyEvent();
        }

        if (!m.is_dragging && m.click_count > 0)
        {
            if ((window::getTime() - m.last_click_time) > thresold)
            {
                if (m.click_count == 1)
                    m.action = MouseAction::clickPended;
                else if (m.click_count >= 2)
                    m.action = MouseAction::doubleClick;
                m.click_count = 0;
            }
        }
        if (m.is_dragging)
        {
            if (ImGui::IsMouseReleased(0))
            {
                m.is_dragging = false;
                m.click_count = 0;
                m.action = MouseAction::dragEnd;
            }
        }
    }

Here I also handle dragging since the click event is also triggered if the mouse is released (But ImGui has DragAPI to get around this, but that's just for the record.)
Example Callee code:

                        if (uikit::isDragStart())
                            logTrace("dragStart");
                        else if (uikit::isDragging())
                            logTrace("dragging");
                        else if (uikit::isDragEnd())
                            logTrace("dragEnd");
                        else if (uikit::isDoubleClicked())
                            logTrace("Double clicked");
                        else if (uikit::isClickedPended())
                            logTrace("Click");

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions