imgui/renderer: Hide Cursor on Idle Implementation (#1266)

Implement hide cursor on idle w/ idle timeout duration (configurable via GUI). While at it add always and never to hide the cursor options as well.

* Revert commit #1211 as to not interfere with the cursor states.
* Make hide cursor on idle as the default setting w/ timeout duration of 5 seconds to hide.
* Add an input tab in the settings page to add the hide cursor setting, with hiding the idle timeout box with respect to the cursor hide option.

Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
This commit is contained in:
Exhigh 2024-10-08 10:47:42 +04:00 committed by GitHub
parent 96344873d6
commit f139762c64
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 296 additions and 12 deletions

View file

@ -4,6 +4,7 @@
// Based on imgui_impl_sdl3.cpp from Dear ImGui repository
#include <imgui.h>
#include "common/config.h"
#include "imgui_impl_sdl3.h"
// SDL
@ -36,6 +37,8 @@ struct SdlData {
SDL_Cursor* mouse_cursors[ImGuiMouseCursor_COUNT]{};
SDL_Cursor* mouse_last_cursor{};
int mouse_pending_leave_frame{};
ImVec2 prev_mouse_pos{0, 0};
Uint64 lastCursorMoveTime{};
// Gamepad handling
ImVector<SDL_Gamepad*> gamepads{};
@ -371,6 +374,13 @@ bool ProcessEvent(const SDL_Event* event) {
? ImGuiMouseSource_TouchScreen
: ImGuiMouseSource_Mouse);
io.AddMousePosEvent(mouse_pos.x, mouse_pos.y);
if (mouse_pos.x != bd->prev_mouse_pos.x || mouse_pos.y != bd->prev_mouse_pos.y) {
bd->prev_mouse_pos.x = mouse_pos.x;
bd->prev_mouse_pos.y = mouse_pos.y;
if (Config::getCursorState() == Config::HideCursorState::Idle) {
bd->lastCursorMoveTime = bd->time;
}
}
return true;
}
case SDL_EVENT_MOUSE_WHEEL: {
@ -447,6 +457,7 @@ bool ProcessEvent(const SDL_Event* event) {
return false;
bd->mouse_window_id = event->window.windowID;
bd->mouse_pending_leave_frame = 0;
bd->lastCursorMoveTime = bd->time;
return true;
}
// - In some cases, when detaching a window from main viewport SDL may send
@ -459,6 +470,7 @@ bool ProcessEvent(const SDL_Event* event) {
if (GetViewportForWindowId(event->window.windowID) == NULL)
return false;
bd->mouse_pending_leave_frame = ImGui::GetFrameCount() + 1;
bd->lastCursorMoveTime = bd->time;
return true;
}
case SDL_EVENT_WINDOW_FOCUS_GAINED:
@ -600,7 +612,18 @@ static void UpdateMouseData() {
int window_x, window_y;
SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global);
SDL_GetWindowPosition(focused_window, &window_x, &window_y);
io.AddMousePosEvent(mouse_x_global - (float)window_x, mouse_y_global - (float)window_y);
mouse_x_global -= (float)window_x;
mouse_y_global -= (float)window_y;
io.AddMousePosEvent(mouse_x_global, mouse_y_global);
// SDL_EVENT_MOUSE_MOTION isn't triggered before the first frame is rendered
// force update the prev_cursor coords
if (mouse_x_global != bd->prev_mouse_pos.x || mouse_y_global != bd->prev_mouse_pos.y &&
bd->prev_mouse_pos.y == 0 &&
bd->prev_mouse_pos.x == 0) {
bd->prev_mouse_pos.x = mouse_x_global;
bd->prev_mouse_pos.y = mouse_y_global;
bd->lastCursorMoveTime = bd->time;
}
}
}
}
@ -611,10 +634,25 @@ static void UpdateMouseCursor() {
return;
SdlData* bd = GetBackendData();
s16 cursorState = Config::getCursorState();
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None) {
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None ||
cursorState == Config::HideCursorState::Always) {
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
SDL_HideCursor();
} else if (cursorState == Config::HideCursorState::Idle &&
bd->time - bd->lastCursorMoveTime >=
Config::getCursorHideTimeout() * SDL_GetPerformanceFrequency()) {
bool wasCursorVisible = SDL_CursorVisible();
SDL_HideCursor();
if (wasCursorVisible) {
SDL_WarpMouseInWindow(SDL_GetKeyboardFocus(), bd->prev_mouse_pos.x,
bd->prev_mouse_pos.y); // Force refresh the cursor state
}
} else {
// Show OS mouse cursor
SDL_Cursor* expected_cursor = bd->mouse_cursors[imgui_cursor]