Nav: added io.ConfigNavCursorVisibleAuto, io.ConfigNavCursorVisibleAlways. (#1074, #2048, #7237, #8059, #3200, #787)

Note: the NavCursorHideFrames addition is to support 88a354585 even though ConfigNavCursorVisibleAlways is set.
This commit is contained in:
ocornut 2024-10-18 18:28:27 +02:00
parent 3982cb35dc
commit ab9ce2a927
7 changed files with 55 additions and 24 deletions

View File

@ -69,20 +69,26 @@ Other changes:
state to draw callbacks. (#6969, #5834, #7468, #3590) state to draw callbacks. (#6969, #5834, #7468, #3590)
- IO: WantCaptureKeyboard is never set when ImGuiConfigFlags_NoKeyboard is enabled. (#4921) - IO: WantCaptureKeyboard is never set when ImGuiConfigFlags_NoKeyboard is enabled. (#4921)
- Error Handling: turned a few more functions into recoverable errors. (#1651) - Error Handling: turned a few more functions into recoverable errors. (#1651)
- Nav: added NavSetCursorVisible(bool visible) to manipulate visibility of keyboard/gamepad - Nav (Keyboard/Gamepad navigation):
navigation cursor. (#1074, #2048, #7237, #8059) - Nav: added io.ConfigNavCursorVisibleAuto and io.ConfigNavCursorVisibleAlways to configure
- Nav: added io.ConfigNavEscapeClearFocusItem and io.ConfigNavEscapeClearFocusWindow to change visibility of navigation cursor. (#1074, #2048, #7237, #8059, #3200, #787)
how pressing Escape affects navigation. (#8059, #2048, #1074, #3200) - Set io.ConfigNavCursorVisibleAuto = true (default) to enable automatic toggling
- Set io.ConfigNavEscapeClearFocusItem = true (default) to clear focused item and highlight. of cursor visibility (mouse click hide the cursor, arrow keys makes it visible).
- Set io.ConfigNavEscapeClearFocusItem = false for Escape to not have a specific effect. - Set io.ConfigNavCursorVisibleAlways to keep cursor always visible.
- Set io.ConfigNavEscapeClearFocusWindow = true to completely unfocus the dear imgui window, - Nav: added NavSetCursorVisible(bool visible) function to manipulate visibility of
is for some reason your app relies on imgui focus to take other decisions. navigation cursor (e.g. set default state, or after some actions). (#1074, #2048, #7237, #8059)
- Nav: pressing escape to hide nav highlight doesn't clear location from when ctrl+tabbing - Nav: added io.ConfigNavEscapeClearFocusItem and io.ConfigNavEscapeClearFocusWindow to change
back into same window later. how pressing Escape affects navigation. (#8059, #2048, #1074, #3200)
- Nav: fixed Ctrl+Tab so when starting with no focused window it starts from the top-most - Set io.ConfigNavEscapeClearFocusItem = true (default) to clear focused item and highlight.
window. (#3200) - Set io.ConfigNavEscapeClearFocusItem = false for Escape to not have a specific effect.
- Nav: rectangle highlight not rendered for items with ImGuiItemFlags_NoNav. Can be relevant - Set io.ConfigNavEscapeClearFocusWindow = true to completely unfocus the dear imgui window,
when e.g activating the item with mouse, then Ctrl+Tabbing back and forth. is for some reason your app relies on imgui focus to take other decisions.
- Nav: pressing escape to hide nav highlight doesn't clear location from when Ctrl+Tabbing
back into same window later.
- Nav: fixed Ctrl+Tab so when starting with no focused window it starts from the top-most
window. (#3200)
- Nav: rectangle highlight not rendered for items with ImGuiItemFlags_NoNav. Can be relevant
when e.g activating the item with mouse, then Ctrl+Tabbing back and forth.
- Disabled: clicking a disabled item focuses parent window. (#8064) - Disabled: clicking a disabled item focuses parent window. (#8064)
- InvisibleButton, Nav: fixed an issue when InvisibleButton() would be navigable into but - InvisibleButton, Nav: fixed an issue when InvisibleButton() would be navigable into but
not display navigation highlight. Properly navigation on it by default. (#8057) not display navigation highlight. Properly navigation on it by default. (#8057)

View File

@ -274,7 +274,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- font/opt: Glyph currently 40 bytes (2+9*4). Consider storing UV as 16-bits integer? (->32 bytes). X0/Y0/X1/Y1 as 16 fixed-point integers? Or X0/Y0 as float and X1/Y1 as fixed8_8? - font/opt: Glyph currently 40 bytes (2+9*4). Consider storing UV as 16-bits integer? (->32 bytes). X0/Y0/X1/Y1 as 16 fixed-point integers? Or X0/Y0 as float and X1/Y1 as fixed8_8?
- nav: some features such as PageUp/Down/Home/End should probably work without ImGuiConfigFlags_NavEnableKeyboard? (where do we draw the line? how about CTRL+Tab) - nav: some features such as PageUp/Down/Home/End should probably work without ImGuiConfigFlags_NavEnableKeyboard? (where do we draw the line? how about CTRL+Tab)
! nav: never clear NavId on some setup (e.g. gamepad centric)
- nav: Home/End behavior when navigable item is not fully visible at the edge of scrolling? should be backtrack to keep item into view? - nav: Home/End behavior when navigable item is not fully visible at the edge of scrolling? should be backtrack to keep item into view?
- nav: NavScrollToBringItemIntoView() with item bigger than view should focus top-right? Repro: using Nav in "About Window" - nav: NavScrollToBringItemIntoView() with item bigger than view should focus top-right? Repro: using Nav in "About Window"
- nav: expose wrap around flags/logic to allow e.g. grid based layout (pressing NavRight on the right-most element would go to the next row, etc.). see internal's NavMoveRequestTryWrapping(). - nav: expose wrap around flags/logic to allow e.g. grid based layout (pressing NavRight on the right-most element would go to the next row, etc.). see internal's NavMoveRequestTryWrapping().

View File

@ -1406,6 +1406,8 @@ ImGuiIO::ImGuiIO()
ConfigNavCaptureKeyboard = true; ConfigNavCaptureKeyboard = true;
ConfigNavEscapeClearFocusItem = true; ConfigNavEscapeClearFocusItem = true;
ConfigNavEscapeClearFocusWindow = false; ConfigNavEscapeClearFocusWindow = false;
ConfigNavCursorVisibleAuto = true;
ConfigNavCursorVisibleAlways = false;
// Miscellaneous options // Miscellaneous options
MouseDrawCursor = false; MouseDrawCursor = false;
@ -3916,6 +3918,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas)
NavHighlightActivatedTimer = 0.0f; NavHighlightActivatedTimer = 0.0f;
NavInputSource = ImGuiInputSource_Keyboard; NavInputSource = ImGuiInputSource_Keyboard;
NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid; NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid;
NavCursorHideFrames = 0;
NavAnyRequest = false; NavAnyRequest = false;
NavInitRequest = false; NavInitRequest = false;
@ -4828,7 +4831,8 @@ void ImGui::StartMouseMovingWindow(ImGuiWindow* window)
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
FocusWindow(window); FocusWindow(window);
SetActiveID(window->MoveId, window); SetActiveID(window->MoveId, window);
g.NavCursorVisible = false; if (g.IO.ConfigNavCursorVisibleAuto)
g.NavCursorVisible = false;
g.ActiveIdClickOffset = g.IO.MouseClickedPos[0] - window->RootWindow->Pos; g.ActiveIdClickOffset = g.IO.MouseClickedPos[0] - window->RootWindow->Pos;
g.ActiveIdNoClearOnFocusLoss = true; g.ActiveIdNoClearOnFocusLoss = true;
SetActiveIdUsingAllKeyboardKeys(); SetActiveIdUsingAllKeyboardKeys();
@ -12216,6 +12220,8 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
void ImGui::SetNavCursorVisible(bool visible) void ImGui::SetNavCursorVisible(bool visible)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (g.IO.ConfigNavCursorVisibleAlways)
visible = true;
g.NavCursorVisible = visible; g.NavCursorVisible = visible;
} }
@ -12223,7 +12229,8 @@ void ImGui::SetNavCursorVisible(bool visible)
void ImGui::SetNavCursorVisibleAfterMove() void ImGui::SetNavCursorVisibleAfterMove()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
g.NavCursorVisible = true; if (g.IO.ConfigNavCursorVisibleAuto)
g.NavCursorVisible = true;
g.NavHighlightItemUnderNav = g.NavMousePosDirty = true; g.NavHighlightItemUnderNav = g.NavMousePosDirty = true;
} }
@ -12289,7 +12296,7 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad)
g.NavHighlightItemUnderNav = true; g.NavHighlightItemUnderNav = true;
else else if (g.IO.ConfigNavCursorVisibleAuto)
g.NavCursorVisible = false; g.NavCursorVisible = false;
// Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it) // Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it)
@ -12904,6 +12911,9 @@ static void ImGui::NavUpdate()
NavMoveRequestApplyResult(); NavMoveRequestApplyResult();
g.NavTabbingCounter = 0; g.NavTabbingCounter = 0;
g.NavMoveSubmitted = g.NavMoveScoringItems = false; g.NavMoveSubmitted = g.NavMoveScoringItems = false;
if (g.NavCursorHideFrames > 0)
if (--g.NavCursorHideFrames == 0)
g.NavCursorVisible = true;
// Schedule mouse position update (will be done at the bottom of this function, after 1) processing all move requests and 2) updating scrolling) // Schedule mouse position update (will be done at the bottom of this function, after 1) processing all move requests and 2) updating scrolling)
bool set_mouse_pos = false; bool set_mouse_pos = false;
@ -12958,6 +12968,8 @@ static void ImGui::NavUpdate()
} }
if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
g.NavCursorVisible = false; g.NavCursorVisible = false;
else if (g.IO.ConfigNavCursorVisibleAlways && g.NavCursorHideFrames == 0)
g.NavCursorVisible = true;
if (g.NavActivateId != 0) if (g.NavActivateId != 0)
IM_ASSERT(g.NavActivateDownId == g.NavActivateId); IM_ASSERT(g.NavActivateDownId == g.NavActivateId);
@ -13158,7 +13170,8 @@ void ImGui::NavUpdateCreateMoveRequest()
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", window ? window->Name : "<NULL>", g.NavLayer); IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", window ? window->Name : "<NULL>", g.NavLayer);
g.NavInitRequest = g.NavInitRequestFromMove = true; g.NavInitRequest = g.NavInitRequestFromMove = true;
g.NavInitResult.ID = 0; g.NavInitResult.ID = 0;
g.NavCursorVisible = true; if (g.IO.ConfigNavCursorVisibleAuto)
g.NavCursorVisible = true;
} }
// When using gamepad, we project the reference nav bounding box into window visible area. // When using gamepad, we project the reference nav bounding box into window visible area.

View File

@ -2252,6 +2252,8 @@ struct ImGuiIO
bool ConfigNavCaptureKeyboard; // = true // Sets io.WantCaptureKeyboard when io.NavActive is set. bool ConfigNavCaptureKeyboard; // = true // Sets io.WantCaptureKeyboard when io.NavActive is set.
bool ConfigNavEscapeClearFocusItem; // = true // Pressing Escape can clear focused item + navigation id/highlight. Set to false if you want to always keep highlight on. bool ConfigNavEscapeClearFocusItem; // = true // Pressing Escape can clear focused item + navigation id/highlight. Set to false if you want to always keep highlight on.
bool ConfigNavEscapeClearFocusWindow;// = false // Pressing Escape can clear focused window as well (super set of io.ConfigNavEscapeClearFocusItem). bool ConfigNavEscapeClearFocusWindow;// = false // Pressing Escape can clear focused window as well (super set of io.ConfigNavEscapeClearFocusItem).
bool ConfigNavCursorVisibleAuto; // = true // Using directional navigation key makes the cursor visible. Mouse click hides the cursor.
bool ConfigNavCursorVisibleAlways; // = false // Navigation cursor is always visible.
// Miscellaneous options // Miscellaneous options
// (you can visualize and interact with all options in 'Demo->Configuration') // (you can visualize and interact with all options in 'Demo->Configuration')

View File

@ -527,7 +527,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).");
ImGui::SeparatorText("Navigation"); ImGui::SeparatorText("Keyboard/Gamepad Navigation");
ImGui::Checkbox("io.ConfigNavSwapGamepadButtons", &io.ConfigNavSwapGamepadButtons); ImGui::Checkbox("io.ConfigNavSwapGamepadButtons", &io.ConfigNavSwapGamepadButtons);
ImGui::Checkbox("io.ConfigNavMoveSetMousePos", &io.ConfigNavMoveSetMousePos); ImGui::Checkbox("io.ConfigNavMoveSetMousePos", &io.ConfigNavMoveSetMousePos);
ImGui::SameLine(); HelpMarker("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult"); ImGui::SameLine(); HelpMarker("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult");
@ -536,6 +536,10 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::SameLine(); HelpMarker("Pressing Escape clears focused item."); ImGui::SameLine(); HelpMarker("Pressing Escape clears focused item.");
ImGui::Checkbox("io.ConfigNavEscapeClearFocusWindow", &io.ConfigNavEscapeClearFocusWindow); ImGui::Checkbox("io.ConfigNavEscapeClearFocusWindow", &io.ConfigNavEscapeClearFocusWindow);
ImGui::SameLine(); HelpMarker("Pressing Escape clears focused window."); ImGui::SameLine(); HelpMarker("Pressing Escape clears focused window.");
ImGui::Checkbox("io.ConfigNavCursorVisibleAuto", &io.ConfigNavCursorVisibleAuto);
ImGui::SameLine(); HelpMarker("Using directional navigation key makes the cursor visible. Mouse click hides the cursor.");
ImGui::Checkbox("io.ConfigNavCursorVisibleAlways", &io.ConfigNavCursorVisibleAlways);
ImGui::SameLine(); HelpMarker("Navigation cursor is always visible.");
ImGui::SeparatorText("Widgets"); ImGui::SeparatorText("Widgets");
ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);

View File

@ -2154,6 +2154,7 @@ struct ImGuiContext
ImGuiActivateFlags NavNextActivateFlags; ImGuiActivateFlags NavNextActivateFlags;
ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Mouse ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Mouse
ImGuiSelectionUserData NavLastValidSelectionUserData; // Last valid data passed to SetNextItemSelectionUser(), or -1. For current window. Not reset when focusing an item that doesn't have selection data. ImGuiSelectionUserData NavLastValidSelectionUserData; // Last valid data passed to SetNextItemSelectionUser(), or -1. For current window. Not reset when focusing an item that doesn't have selection data.
ImS8 NavCursorHideFrames;
// Navigation: Init & Move Requests // Navigation: Init & Move Requests
bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest this is to perform early out in ItemAdd() bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest this is to perform early out in ItemAdd()

View File

@ -619,7 +619,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
pressed = true; pressed = true;
} }
if (pressed) if (pressed && g.IO.ConfigNavCursorVisibleAuto)
g.NavCursorVisible = false; g.NavCursorVisible = false;
} }
@ -688,7 +688,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
} }
ClearActiveID(); ClearActiveID();
} }
if (!(flags & ImGuiButtonFlags_NoNavFocus)) if (!(flags & ImGuiButtonFlags_NoNavFocus) && g.IO.ConfigNavCursorVisibleAuto)
g.NavCursorVisible = false; g.NavCursorVisible = false;
} }
else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad)
@ -7001,7 +7001,8 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
if (!g.NavHighlightItemUnderNav && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) if (!g.NavHighlightItemUnderNav && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent)
{ {
SetNavID(id, window->DC.NavLayerCurrent, g.CurrentFocusScopeId, WindowRectAbsToRel(window, bb)); // (bb == NavRect) SetNavID(id, window->DC.NavLayerCurrent, g.CurrentFocusScopeId, WindowRectAbsToRel(window, bb)); // (bb == NavRect)
g.NavCursorVisible = false; if (g.IO.ConfigNavCursorVisibleAuto)
g.NavCursorVisible = false;
} }
} }
if (pressed) if (pressed)
@ -8624,7 +8625,12 @@ void ImGui::EndMenuBar()
IM_ASSERT(window->DC.NavLayersActiveMaskNext & (1 << layer)); // Sanity check (FIXME: Seems unnecessary) IM_ASSERT(window->DC.NavLayersActiveMaskNext & (1 << layer)); // Sanity check (FIXME: Seems unnecessary)
FocusWindow(window); FocusWindow(window);
SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]);
g.NavCursorVisible = false; // Hide nav cursor for the current frame so we don't see the intermediary selection. // FIXME-NAV: How to deal with this when not using g.IO.ConfigNavCursorVisibleAuto?
if (g.NavCursorVisible)
{
g.NavCursorVisible = false; // Hide nav cursor for the current frame so we don't see the intermediary selection. Will be set again
g.NavCursorHideFrames = 2;
}
g.NavHighlightItemUnderNav = g.NavMousePosDirty = true; g.NavHighlightItemUnderNav = g.NavMousePosDirty = true;
NavMoveRequestForward(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags); // Repeat NavMoveRequestForward(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags); // Repeat
} }