Skip to content

Commit

Permalink
Nav: added io.ConfigNavCursorVisibleAuto, io.ConfigNavCursorVisibleAl…
Browse files Browse the repository at this point in the history
…ways. (#1074, #2048, #7237, #8059, #3200, #787)

Note: the NavCursorHideFrames addition is to support 88a3545 even though ConfigNavCursorVisibleAlways is set.
  • Loading branch information
ocornut committed Oct 18, 2024
1 parent 3982cb3 commit ab9ce2a
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 24 deletions.
34 changes: 20 additions & 14 deletions docs/CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,26 @@ Other changes:
state to draw callbacks. (#6969, #5834, #7468, #3590)
- IO: WantCaptureKeyboard is never set when ImGuiConfigFlags_NoKeyboard is enabled. (#4921)
- Error Handling: turned a few more functions into recoverable errors. (#1651)
- Nav: added NavSetCursorVisible(bool visible) to manipulate visibility of keyboard/gamepad
navigation cursor. (#1074, #2048, #7237, #8059)
- Nav: added io.ConfigNavEscapeClearFocusItem and io.ConfigNavEscapeClearFocusWindow to change
how pressing Escape affects navigation. (#8059, #2048, #1074, #3200)
- Set io.ConfigNavEscapeClearFocusItem = true (default) to clear focused item and highlight.
- Set io.ConfigNavEscapeClearFocusItem = false for Escape to not have a specific effect.
- Set io.ConfigNavEscapeClearFocusWindow = true to completely unfocus the dear imgui window,
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.
- Nav (Keyboard/Gamepad navigation):
- Nav: added io.ConfigNavCursorVisibleAuto and io.ConfigNavCursorVisibleAlways to configure
visibility of navigation cursor. (#1074, #2048, #7237, #8059, #3200, #787)
- Set io.ConfigNavCursorVisibleAuto = true (default) to enable automatic toggling
of cursor visibility (mouse click hide the cursor, arrow keys makes it visible).
- Set io.ConfigNavCursorVisibleAlways to keep cursor always visible.
- Nav: added NavSetCursorVisible(bool visible) function to manipulate visibility of
navigation cursor (e.g. set default state, or after some actions). (#1074, #2048, #7237, #8059)
- Nav: added io.ConfigNavEscapeClearFocusItem and io.ConfigNavEscapeClearFocusWindow to change
how pressing Escape affects navigation. (#8059, #2048, #1074, #3200)
- Set io.ConfigNavEscapeClearFocusItem = true (default) to clear focused item and highlight.
- Set io.ConfigNavEscapeClearFocusItem = false for Escape to not have a specific effect.
- Set io.ConfigNavEscapeClearFocusWindow = true to completely unfocus the dear imgui window,
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)
- InvisibleButton, Nav: fixed an issue when InvisibleButton() would be navigable into but
not display navigation highlight. Properly navigation on it by default. (#8057)
Expand Down
1 change: 0 additions & 1 deletion docs/TODO.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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?

- 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: 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().
Expand Down
21 changes: 17 additions & 4 deletions imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1406,6 +1406,8 @@ ImGuiIO::ImGuiIO()
ConfigNavCaptureKeyboard = true;
ConfigNavEscapeClearFocusItem = true;
ConfigNavEscapeClearFocusWindow = false;
ConfigNavCursorVisibleAuto = true;
ConfigNavCursorVisibleAlways = false;

// Miscellaneous options
MouseDrawCursor = false;
Expand Down Expand Up @@ -3916,6 +3918,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas)
NavHighlightActivatedTimer = 0.0f;
NavInputSource = ImGuiInputSource_Keyboard;
NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid;
NavCursorHideFrames = 0;

NavAnyRequest = false;
NavInitRequest = false;
Expand Down Expand Up @@ -4828,7 +4831,8 @@ void ImGui::StartMouseMovingWindow(ImGuiWindow* window)
ImGuiContext& g = *GImGui;
FocusWindow(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.ActiveIdNoClearOnFocusLoss = true;
SetActiveIdUsingAllKeyboardKeys();
Expand Down Expand Up @@ -12216,14 +12220,17 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
void ImGui::SetNavCursorVisible(bool visible)
{
ImGuiContext& g = *GImGui;
if (g.IO.ConfigNavCursorVisibleAlways)
visible = true;
g.NavCursorVisible = visible;
}

// (was called NavRestoreHighlightAfterMove() before 1.91.4)
void ImGui::SetNavCursorVisibleAfterMove()
{
ImGuiContext& g = *GImGui;
g.NavCursorVisible = true;
if (g.IO.ConfigNavCursorVisibleAuto)
g.NavCursorVisible = true;
g.NavHighlightItemUnderNav = g.NavMousePosDirty = true;
}

Expand Down Expand Up @@ -12289,7 +12296,7 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)

if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad)
g.NavHighlightItemUnderNav = true;
else
else if (g.IO.ConfigNavCursorVisibleAuto)
g.NavCursorVisible = false;

// Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it)
Expand Down Expand Up @@ -12904,6 +12911,9 @@ static void ImGui::NavUpdate()
NavMoveRequestApplyResult();
g.NavTabbingCounter = 0;
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)
bool set_mouse_pos = false;
Expand Down Expand Up @@ -12958,6 +12968,8 @@ static void ImGui::NavUpdate()
}
if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
g.NavCursorVisible = false;
else if (g.IO.ConfigNavCursorVisibleAlways && g.NavCursorHideFrames == 0)
g.NavCursorVisible = true;
if (g.NavActivateId != 0)
IM_ASSERT(g.NavActivateDownId == g.NavActivateId);

Expand Down Expand Up @@ -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);
g.NavInitRequest = g.NavInitRequestFromMove = true;
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.
Expand Down
2 changes: 2 additions & 0 deletions imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -2252,6 +2252,8 @@ struct ImGuiIO
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 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
// (you can visualize and interact with all options in 'Demo->Configuration')
Expand Down
6 changes: 5 additions & 1 deletion imgui_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
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::SeparatorText("Navigation");
ImGui::SeparatorText("Keyboard/Gamepad Navigation");
ImGui::Checkbox("io.ConfigNavSwapGamepadButtons", &io.ConfigNavSwapGamepadButtons);
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");
Expand All @@ -536,6 +536,10 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::SameLine(); HelpMarker("Pressing Escape clears focused item.");
ImGui::Checkbox("io.ConfigNavEscapeClearFocusWindow", &io.ConfigNavEscapeClearFocusWindow);
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::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
Expand Down
1 change: 1 addition & 0 deletions imgui_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -2154,6 +2154,7 @@ struct ImGuiContext
ImGuiActivateFlags NavNextActivateFlags;
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.
ImS8 NavCursorHideFrames;

// Navigation: Init & Move Requests
bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest this is to perform early out in ItemAdd()
Expand Down
14 changes: 10 additions & 4 deletions imgui_widgets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
pressed = true;
}

if (pressed)
if (pressed && g.IO.ConfigNavCursorVisibleAuto)
g.NavCursorVisible = false;
}

Expand Down Expand Up @@ -688,7 +688,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
}
ClearActiveID();
}
if (!(flags & ImGuiButtonFlags_NoNavFocus))
if (!(flags & ImGuiButtonFlags_NoNavFocus) && g.IO.ConfigNavCursorVisibleAuto)
g.NavCursorVisible = false;
}
else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad)
Expand Down Expand Up @@ -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)
{
SetNavID(id, window->DC.NavLayerCurrent, g.CurrentFocusScopeId, WindowRectAbsToRel(window, bb)); // (bb == NavRect)
g.NavCursorVisible = false;
if (g.IO.ConfigNavCursorVisibleAuto)
g.NavCursorVisible = false;
}
}
if (pressed)
Expand Down Expand Up @@ -8624,7 +8625,12 @@ void ImGui::EndMenuBar()
IM_ASSERT(window->DC.NavLayersActiveMaskNext & (1 << layer)); // Sanity check (FIXME: Seems unnecessary)
FocusWindow(window);
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;
NavMoveRequestForward(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags); // Repeat
}
Expand Down

0 comments on commit ab9ce2a

Please sign in to comment.