Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed same-frame click/release bug #2525

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions examples/imgui_impl_allegro5.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,19 +319,25 @@ bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT *ev)
}
return true;
case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
if (ev->mouse.display == g_Display && ev->mouse.button <= 5)
io.InputMouseClicked[ev->mouse.button - 1] = true;
return true;
case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
if (ev->mouse.display == g_Display && ev->mouse.button <= 5)
io.MouseDown[ev->mouse.button - 1] = (ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN);
io.InputMouseReleased[ev->mouse.button - 1] = true;
return true;
case ALLEGRO_EVENT_TOUCH_MOVE:
if (ev->touch.display == g_Display)
io.MousePos = ImVec2(ev->touch.x, ev->touch.y);
return true;
case ALLEGRO_EVENT_TOUCH_BEGIN:
if (ev->touch.display == g_Display && ev->touch.primary)
io.InputMouseClicked[0] = true;
return true;
case ALLEGRO_EVENT_TOUCH_END:
case ALLEGRO_EVENT_TOUCH_CANCEL:
if (ev->touch.display == g_Display && ev->touch.primary)
io.MouseDown[0] = (ev->type == ALLEGRO_EVENT_TOUCH_BEGIN);
io.InputMouseReleased[0] = true;
return true;
case ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY:
if (ev->mouse.display == g_Display)
Expand Down
23 changes: 12 additions & 11 deletions examples/imgui_impl_glfw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ enum GlfwClientApi
static GLFWwindow* g_Window = NULL;
static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown;
static double g_Time = 0.0;
static bool g_MouseJustPressed[5] = { false, false, false, false, false };
static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = { 0 };

// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
Expand All @@ -79,11 +78,19 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)

void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
{
ImGuiIO& io = ImGui::GetIO();

if (g_PrevUserCallbackMousebutton != NULL)
g_PrevUserCallbackMousebutton(window, button, action, mods);

if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed))
g_MouseJustPressed[button] = true;
// Test mouse button is valid
if(button < 0 || button >= IM_ARRAYSIZE(io.InputMouseClicked))
return;

if (action == GLFW_PRESS)
io.InputMouseClicked[button] = true;
else if(action == GLFW_RELEASE)
io.InputMouseReleased[button] = true;
}

void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
Expand Down Expand Up @@ -211,16 +218,10 @@ void ImGui_ImplGlfw_Shutdown()
g_ClientApi = GlfwClientApi_Unknown;
}

static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
static void ImGui_ImplGlfw_UpdateMousePos()
{
// Update buttons
ImGuiIO& io = ImGui::GetIO();
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
{
// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0;
g_MouseJustPressed[i] = false;
}

// Update mouse position
const ImVec2 mouse_pos_backup = io.MousePos;
Expand Down Expand Up @@ -322,7 +323,7 @@ void ImGui_ImplGlfw_NewFrame()
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f);
g_Time = current_time;

ImGui_ImplGlfw_UpdateMousePosAndButtons();
ImGui_ImplGlfw_UpdateMousePos();
ImGui_ImplGlfw_UpdateMouseCursor();

// Update game controllers (if enabled and available)
Expand Down
4 changes: 2 additions & 2 deletions examples/imgui_impl_glut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,9 @@ void ImGui_ImplGLUT_MouseFunc(int glut_button, int state, int x, int y)
if (glut_button == GLUT_RIGHT_BUTTON) button = 1;
if (glut_button == GLUT_MIDDLE_BUTTON) button = 2;
if (button != -1 && state == GLUT_DOWN)
io.MouseDown[button] = true;
io.InputMouseClicked[button] = true;
if (button != -1 && state == GLUT_UP)
io.MouseDown[button] = false;
io.InputMouseReleased[button] = true;
}

#ifdef __FREEGLUT_EXT_H__
Expand Down
34 changes: 17 additions & 17 deletions examples/imgui_impl_marmalade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@

// Data
static double g_Time = 0.0f;
static bool g_MousePressed[3] = { false, false, false };
static CIwTexture* g_FontTexture = NULL;
static char* g_ClipboardText = NULL;
static bool g_osdKeyboardEnabled = false;
Expand Down Expand Up @@ -130,16 +129,23 @@ int32 ImGui_Marmalade_PointerButtonEventCallback(void* system_data, void* user_d

if (pEvent->m_Pressed == 1)
{
if (pEvent->m_Button == S3E_POINTER_BUTTON_LEFTMOUSE)
g_MousePressed[0] = true;
if (pEvent->m_Button == S3E_POINTER_BUTTON_RIGHTMOUSE)
g_MousePressed[1] = true;
if (pEvent->m_Button == S3E_POINTER_BUTTON_MIDDLEMOUSE)
g_MousePressed[2] = true;
if (pEvent->m_Button == S3E_POINTER_BUTTON_MOUSEWHEELUP)
io.MouseWheel += pEvent->m_y;
if (pEvent->m_Button == S3E_POINTER_BUTTON_MOUSEWHEELDOWN)
io.MouseWheel += pEvent->m_y;
switch(pEvent->m_Button)
{
case S3E_POINTER_BUTTON_LEFTMOUSE: { io.InputMouseClicked[0] = true; } break;
case S3E_POINTER_BUTTON_RIGHTMOUSE: { io.InputMouseClicked[1] = true; } break;
case S3E_POINTER_BUTTON_MIDDLEMOUSE: { io.InputMouseClicked[2] = true; } break;
case S3E_POINTER_BUTTON_MOUSEWHEELUP: { io.MouseWheel += pEvent->m_y; } break;
case S3E_POINTER_BUTTON_MOUSEWHEELDOWN: { io.MouseWheel += pEvent->m_y; } break;
}
}
else if(pEvent->m_Pressed == 0)
{
switch(pEvent->m_Button)
{
case S3E_POINTER_BUTTON_LEFTMOUSE: { io.InputMouseReleased[0] = true; } break;
case S3E_POINTER_BUTTON_RIGHTMOUSE: { io.InputMouseReleased[1] = true; } break;
case S3E_POINTER_BUTTON_MIDDLEMOUSE: { io.InputMouseReleased[2] = true; } break;
}
}

return 0;
Expand Down Expand Up @@ -283,12 +289,6 @@ void ImGui_Marmalade_NewFrame()
mouse_y = s3ePointerGetY();
io.MousePos = ImVec2((float)mouse_x/g_scale.x, (float)mouse_y/g_scale.y); // Mouse position (set to -FLT_MAX,-FLT_MAX if no mouse / on another screen, etc.)

for (int i = 0; i < 3; i++)
{
io.MouseDown[i] = g_MousePressed[i] || s3ePointerGetState((s3ePointerButton)i) != S3E_POINTER_STATE_UP; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
g_MousePressed[i] = false;
}

// TODO: Hide OS mouse cursor if ImGui is drawing it
// s3ePointerSetInt(S3E_POINTER_HIDE_CURSOR,(io.MouseDrawCursor ? 0 : 1));

Expand Down
4 changes: 2 additions & 2 deletions examples/imgui_impl_osx.mm
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,15 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view)
{
int button = (int)[event buttonNumber];
if (button >= 0 && button < IM_ARRAYSIZE(io.MouseDown))
io.MouseDown[button] = true;
io.InputMouseClicked[button] = true;
return io.WantCaptureMouse;
}

if (event.type == NSEventTypeLeftMouseUp || event.type == NSEventTypeRightMouseUp || event.type == NSEventTypeOtherMouseUp)
{
int button = (int)[event buttonNumber];
if (button >= 0 && button < IM_ARRAYSIZE(io.MouseDown))
io.MouseDown[button] = false;
io.InputMouseReleased[button] = false;
return io.WantCaptureMouse;
}

Expand Down
30 changes: 21 additions & 9 deletions examples/imgui_impl_sdl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@
// Data
static SDL_Window* g_Window = NULL;
static Uint64 g_Time = 0;
static bool g_MousePressed[3] = { false, false, false };
static SDL_Cursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = { 0 };
static char* g_ClipboardTextData = NULL;

Expand Down Expand Up @@ -93,9 +92,26 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
}
case SDL_MOUSEBUTTONDOWN:
{
if (event->button.button == SDL_BUTTON_LEFT) g_MousePressed[0] = true;
if (event->button.button == SDL_BUTTON_RIGHT) g_MousePressed[1] = true;
if (event->button.button == SDL_BUTTON_MIDDLE) g_MousePressed[2] = true;
int button = 0;
switch (event->button.button)
{
case SDL_BUTTON_LEFT: { button = 0; } break;
case SDL_BUTTON_RIGHT: { button = 1; } break;
case SDL_BUTTON_MIDDLE: { button = 2; } break;
}
io.InputMouseClicked[button] = true;
return true;
}
case SDL_MOUSEBUTTONUP:
{
int button = 0;
switch (event->button.button)
{
case SDL_BUTTON_LEFT: { button = 0; } break;
case SDL_BUTTON_RIGHT: { button = 1; } break;
case SDL_BUTTON_MIDDLE: { button = 2; } break;
}
io.InputMouseReleased[button] = true;
return true;
}
case SDL_TEXTINPUT:
Expand Down Expand Up @@ -217,11 +233,7 @@ static void ImGui_ImplSDL2_UpdateMousePosAndButtons()
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);

int mx, my;
Uint32 mouse_buttons = SDL_GetMouseState(&mx, &my);
io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[1] = g_MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false;
const Uint32 mouse_buttons = SDL_GetMouseState(&mx, &my);

#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS)
SDL_Window* focused_window = SDL_GetKeyboardFocus();
Expand Down
26 changes: 16 additions & 10 deletions examples/imgui_impl_win32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,13 +263,16 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK:
{
int button = 0;
if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; }
if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; }
if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; }
if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
switch(msg)
{
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: { button = 0; } break;
case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: { button = 1; } break;
case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: { button = 2; } break;
case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; } break;
}
if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL)
::SetCapture(hwnd);
io.MouseDown[button] = true;
io.InputMouseClicked[button] = true;
return 0;
}
case WM_LBUTTONUP:
Expand All @@ -278,11 +281,14 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
case WM_XBUTTONUP:
{
int button = 0;
if (msg == WM_LBUTTONUP) { button = 0; }
if (msg == WM_RBUTTONUP) { button = 1; }
if (msg == WM_MBUTTONUP) { button = 2; }
if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
io.MouseDown[button] = false;
switch (msg)
{
case WM_LBUTTONUP: { button = 0; } break;
case WM_RBUTTONUP: { button = 1; } break;
case WM_MBUTTONUP: { button = 2; } break;
case WM_XBUTTONUP: { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; } break;
}
io.InputMouseReleased[button] = true;
if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not get called in case of a mouseup happening before NewFrame() since this is where io.MouseDown gets updated.
As a result clicking on an imgui window does not release mouse capture and trying to click on the main window bar at the top to move, minimise or close it does not work.
An easy fix is to make ::ReleaseCapture not based on io.MouseDown but on the actual hardware inputs WM_LBUTTONUP etc...

::ReleaseCapture();
return 0;
Expand Down
41 changes: 27 additions & 14 deletions imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,10 @@ CODE
io.DisplaySize.x = 1920.0f; // set the current display width
io.DisplaySize.y = 1280.0f; // set the current display height here
io.MousePos = my_mouse_pos; // set the mouse position
io.MouseDown[0] = my_mouse_buttons[0]; // set the mouse button states
io.MouseDown[1] = my_mouse_buttons[1];
io.InputMouseClicked[0] = my_mouse_clicked[0]; // set the mouse button states
io.InputMouseClicked[1] = my_mouse_clicked[1];
io.InputMouseReleased[0] = my_mouse_released[0];
io.InputMouseReleased[1] = my_mouse_released[1];

// Call NewFrame(), after this point you can use ImGui::* functions anytime
// (So you want to try calling NewFrame() as early as you can in your mainloop to be able to use imgui everywhere)
Expand Down Expand Up @@ -562,17 +564,17 @@ CODE
Q: Where is the documentation?
A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
- Run the examples/ and explore them.
- See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
- The demo covers most features of Dear ImGui, so you can read the code and see its output.
- See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
- The demo covers most features of Dear ImGui, so you can read the code and see its output.
- See documentation and comments at the top of imgui.cpp + effectively imgui.h.
- Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/
- Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/
folder to explain how to integrate Dear ImGui with your own engine/application.
- Your programming IDE is your friend, find the type or function declaration to find comments
- Your programming IDE is your friend, find the type or function declaration to find comments
associated to it.

Q: Which version should I get?
A: I occasionally tag Releases (https://github.com/ocornut/imgui/releases) but it is generally safe
and recommended to sync to master/latest. The library is fairly stable and regressions tend to be
A: I occasionally tag Releases (https://github.com/ocornut/imgui/releases) but it is generally safe
and recommended to sync to master/latest. The library is fairly stable and regressions tend to be
fixed fast when reported. You may also peak at the 'docking' branch which includes:
- Docking/Merging features (https://github.com/ocornut/imgui/issues/2109)
- Multi-viewport features (https://github.com/ocornut/imgui/issues/1542)
Expand All @@ -584,11 +586,11 @@ CODE
for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!

Q: Why the odd dual naming, "Dear ImGui" vs "ImGui"?
A: The library started its life as "ImGui" due to the fact that I didn't give it a proper name when
when I released 1.0, and had no particular expectation that it would take off. However, the term IMGUI
(immediate-mode graphical user interface) was coined before and is being used in variety of other
situations (e.g. Unity uses it own implementation of the IMGUI paradigm).
To reduce the ambiguity without affecting existing code bases, I have decided on an alternate,
A: The library started its life as "ImGui" due to the fact that I didn't give it a proper name when
when I released 1.0, and had no particular expectation that it would take off. However, the term IMGUI
(immediate-mode graphical user interface) was coined before and is being used in variety of other
situations (e.g. Unity uses it own implementation of the IMGUI paradigm).
To reduce the ambiguity without affecting existing code bases, I have decided on an alternate,
longer name "Dear ImGui" that people can use to refer to this specific library.
Please try to refer to this library as "Dear ImGui".

Expand Down Expand Up @@ -3262,6 +3264,17 @@ static void ImGui::UpdateMouseInputs()
g.IO.MousePosPrev = g.IO.MousePos;
for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
{
// If the button was clicked, load to the current state
if (g.IO.InputMouseClicked[i]) {
g.IO.MouseDown[i] = true;
g.IO.InputMouseClicked[i] = false;
}
// If we have no click and a release, load to the current state
else if (g.IO.InputMouseReleased[i]) {
g.IO.MouseDown[i] = false;
g.IO.InputMouseReleased[i] = false;
}

g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f;
g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f;
g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i];
Expand Down Expand Up @@ -5791,7 +5804,7 @@ void ImGui::PopItemWidth()
}

// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth(),
// Then consume the
// Then consume the
float ImGui::GetNextItemWidth()
{
ImGuiWindow* window = GImGui->CurrentWindow;
Expand Down
4 changes: 3 additions & 1 deletion imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ namespace ImGui
IMGUI_API ImU32 GetColorU32(ImU32 col); // retrieve given color with style alpha applied

// Parameters stacks (current window)
IMGUI_API void PushItemWidth(float item_width); // set width of items for common large "item+label" widgets. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side). 0.0f = default to ~2/3 of windows width,
IMGUI_API void PushItemWidth(float item_width); // set width of items for common large "item+label" widgets. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side). 0.0f = default to ~2/3 of windows width,
IMGUI_API void PopItemWidth();
IMGUI_API void SetNextItemWidth(float item_width); // set width of the _next_ common large "item+label" widget. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side)
IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position
Expand Down Expand Up @@ -1433,6 +1433,8 @@ struct ImGuiIO
ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid)
ImVec2 MouseClickedPos[5]; // Position at time of clicking
double MouseClickedTime[5]; // Time of last click (used to figure out double-click)
bool InputMouseClicked[5]; // Mouse button was clicked. Set in app impl.
bool InputMouseReleased[5]; // Mouse button was released. Set in app impl.
bool MouseClicked[5]; // Mouse button went from !Down to Down
bool MouseDoubleClicked[5]; // Has mouse button been double-clicked?
bool MouseReleased[5]; // Mouse button went from Down to !Down
Expand Down