-
-
Notifications
You must be signed in to change notification settings - Fork 11.7k
Separating click and double-click events #8337
Description
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");