Merge branch 'master' into docking

+ fix warning fix for mingw+dx9
# Conflicts:
#	backends/imgui_impl_dx9.cpp
#	imgui.cpp
This commit is contained in:
ocornut
2021-04-30 22:48:16 +02:00
14 changed files with 302 additions and 187 deletions

187
imgui.cpp
View File

@ -826,6 +826,9 @@ CODE
#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later
#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types
#endif
#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).
#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6).
#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).
#endif
// Clang/GCC warnings with -Weverything
@ -910,8 +913,8 @@ static void NavUpdateInitResult();
static float NavUpdatePageUpPageDown();
static inline void NavUpdateAnyRequestFlag();
static void NavEndFrame();
static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand);
static void NavApplyItemToResult(ImGuiNavMoveResult* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel);
static bool NavScoreItem(ImGuiNavItemData* result, ImRect cand);
static void NavApplyItemToResult(ImGuiNavItemData* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel);
static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id);
static ImVec2 NavCalcPreferredRefPos();
static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window);
@ -3223,7 +3226,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
return false;
// Test if the item is disabled
if ((window->DC.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
if ((g.CurrentItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
return false;
// Special handling for calling after Begin() which represent the title bar or tab.
@ -3249,7 +3252,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id)
return false;
if (g.NavDisableMouseHover)
return false;
if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None) || (window->DC.ItemFlags & ImGuiItemFlags_Disabled))
if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None) || (g.CurrentItemFlags & ImGuiItemFlags_Disabled))
{
g.HoveredIdDisabled = true;
return false;
@ -3296,15 +3299,21 @@ void ImGui::SetLastItemData(ImGuiWindow* window, ImGuiID item_id, ImGuiItemStatu
}
// Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out.
bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id)
void ImGui::ItemFocusable(ImGuiWindow* window, ImGuiID id)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(id != 0 && id == window->DC.LastItemId);
// Increment counters
const bool is_tab_stop = (window->DC.ItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0;
// FIXME: ImGuiItemFlags_Disabled should disable more.
const bool is_tab_stop = (g.CurrentItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0;
window->DC.FocusCounterRegular++;
if (is_tab_stop)
{
window->DC.FocusCounterTabStop++;
if (g.NavId == id)
g.NavIdTabCounter = window->DC.FocusCounterTabStop;
}
// Process TAB/Shift-TAB to tab *OUT* of the currently focused item.
// (Note that we can always TAB out of a widget that doesn't allow tabbing in)
@ -3318,25 +3327,21 @@ bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id)
if (g.TabFocusRequestCurrWindow == window)
{
if (window->DC.FocusCounterRegular == g.TabFocusRequestCurrCounterRegular)
return true;
{
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_FocusedByCode;
return;
}
if (is_tab_stop && window->DC.FocusCounterTabStop == g.TabFocusRequestCurrCounterTabStop)
{
g.NavJustTabbedId = id;
return true;
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_FocusedByTabbing;
return;
}
// If another item is about to be focused, we clear our own active id
if (g.ActiveId == id)
ClearActiveID();
}
return false;
}
void ImGui::FocusableItemUnregister(ImGuiWindow* window)
{
window->DC.FocusCounterRegular--;
window->DC.FocusCounterTabStop--;
}
float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
@ -3909,12 +3914,14 @@ void ImGui::UpdateTabFocus()
g.TabFocusPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab));
if (g.ActiveId == 0 && g.TabFocusPressed)
{
// Note that SetKeyboardFocusHere() sets the Next fields mid-frame. To be consistent we also
// manipulate the Next fields even, even though they will be turned into Curr fields by the code below.
// - This path is only taken when no widget are active/tabbed-into yet.
// Subsequent tabbing will be processed by FocusableItemRegister()
// - Note that SetKeyboardFocusHere() sets the Next fields mid-frame. To be consistent we also
// manipulate the Next fields here even though they will be turned into Curr fields below.
g.TabFocusRequestNextWindow = g.NavWindow;
g.TabFocusRequestNextCounterRegular = INT_MAX;
if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX)
g.TabFocusRequestNextCounterTabStop = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1);
g.TabFocusRequestNextCounterTabStop = g.NavIdTabCounter + (g.IO.KeyShift ? -1 : 0);
else
g.TabFocusRequestNextCounterTabStop = g.IO.KeyShift ? -1 : 0;
}
@ -4201,7 +4208,7 @@ void ImGui::NewFrame()
g.CurrentWindowStack.resize(0);
g.BeginPopupStack.resize(0);
g.ItemFlagsStack.resize(0);
g.ItemFlagsStack.push_back(ImGuiItemFlags_Default_);
g.ItemFlagsStack.push_back(ImGuiItemFlags_None);
g.GroupStack.resize(0);
ClosePopupsOverWindow(g.NavWindow, false);
@ -4710,6 +4717,7 @@ void ImGui::Render()
for (int n = 0; n != g.Windows.Size; n++)
{
ImGuiWindow* window = g.Windows[n];
IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'"
if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1])
AddRootWindowToDrawData(window);
}
@ -4801,6 +4809,7 @@ static void FindHoveredWindow()
for (int i = g.Windows.Size - 1; i >= 0; i--)
{
ImGuiWindow* window = g.Windows[i];
IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer.
if (!window->Active || window->Hidden)
continue;
if (window->Flags & ImGuiWindowFlags_NoMouseInputs)
@ -4830,6 +4839,7 @@ static void FindHoveredWindow()
if (hovered_window == NULL)
hovered_window = window;
IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer.
if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindowDockTree != g.MovingWindow->RootWindowDockTree))
hovered_window_ignoring_moving_window = window;
if (hovered_window && hovered_window_ignoring_moving_window)
@ -5254,7 +5264,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, b
parent_window->DC.CursorPos = child_window->Pos;
// Process navigation-in immediately so NavInit can run on first frame
if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll))
if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavHasScroll))
{
FocusWindow(child_window);
NavInitWindow(child_window, false);
@ -5301,13 +5311,13 @@ void ImGui::EndChild()
ImGuiWindow* parent_window = g.CurrentWindow;
ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);
ItemSize(sz);
if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened))
if ((window->DC.NavLayersActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened))
{
ItemAdd(bb, window->ChildId);
RenderNavHighlight(bb, window->ChildId);
// When browsing a window that has no activable items (scroll only) we keep a highlight on the child
if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow)
if (window->DC.NavLayersActiveMask == 0 && window == g.NavWindow)
RenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_TypeThin);
}
else
@ -5952,8 +5962,8 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None);
// Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer)
const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
const ImGuiItemFlags item_flags_backup = g.CurrentItemFlags;
g.CurrentItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
// Layout buttons
@ -5990,7 +6000,7 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
*p_open = false;
window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
window->DC.ItemFlags = item_flags_backup;
g.CurrentItemFlags = item_flags_backup;
// Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker)
// FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code..
@ -6743,8 +6753,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext;
window->DC.NavLayerActiveMaskNext = 0x00;
window->DC.NavLayersActiveMask = window->DC.NavLayersActiveMaskNext;
window->DC.NavLayersActiveMaskNext = 0x00;
window->DC.NavHideHighlightOneFrame = false;
window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f);
@ -6840,7 +6850,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
}
// Pull/inherit current state
window->DC.ItemFlags = g.ItemFlagsStack.back(); // Inherit from shared stack
g.CurrentItemFlags = g.ItemFlagsStack.back(); // Inherit from shared stack
window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : 0; // Inherit from parent only // -V595
if (!(flags & ImGuiWindowFlags_DockNodeHost))
@ -7115,24 +7125,22 @@ void ImGui::PopFont()
void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiItemFlags item_flags = window->DC.ItemFlags;
ImGuiItemFlags item_flags = g.CurrentItemFlags;
IM_ASSERT(item_flags == g.ItemFlagsStack.back());
if (enabled)
item_flags |= option;
else
item_flags &= ~option;
window->DC.ItemFlags = item_flags;
g.CurrentItemFlags = item_flags;
g.ItemFlagsStack.push_back(item_flags);
}
void ImGui::PopItemFlag()
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
IM_ASSERT(g.ItemFlagsStack.Size > 1); // Too many calls to PopItemFlag() - we always leave a 0 at the bottom of the stack.
g.ItemFlagsStack.pop_back();
window->DC.ItemFlags = g.ItemFlagsStack.back();
g.CurrentItemFlags = g.ItemFlagsStack.back();
}
// FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system.
@ -7608,11 +7616,11 @@ void ImGui::SetItemDefaultFocus()
ImGuiWindow* window = g.CurrentWindow;
if (!window->Appearing)
return;
if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent)
if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == window->DC.NavLayerCurrent)
{
g.NavInitRequest = false;
g.NavInitResultId = g.NavWindow->DC.LastItemId;
g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos);
g.NavInitResultId = window->DC.LastItemId;
g.NavInitResultRectRel = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
NavUpdateAnyRequestFlag();
if (!IsItemVisible())
SetScrollHereY();
@ -8045,7 +8053,7 @@ void ImGui::ItemSize(const ImRect& bb, float text_baseline_y)
// Declare item bounding box for clipping and interaction.
// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
// declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction.
bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGuiItemAddFlags flags)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
@ -8061,7 +8069,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
// to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).
// We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null.
// If we crash on a NULL g.NavWindow we need to fix the bug elsewhere.
window->DC.NavLayerActiveMaskNext |= (1 << window->DC.NavLayerCurrent);
window->DC.NavLayersActiveMaskNext |= (1 << window->DC.NavLayerCurrent);
if (g.NavId == id || g.NavAnyRequest)
if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
@ -8094,6 +8102,11 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
return false;
//if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
// Tab stop handling (previously was using internal ItemFocusable() api)
// FIXME-NAV: We would now want to move this above the clipping test, but this would require being able to scroll and currently this would mean an extra frame. (#4079, #343)
if (flags & ImGuiItemAddFlags_Focusable)
ItemFocusable(window, id);
// We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
if (IsMouseHoveringRect(bb.Min, bb.Max))
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect;
@ -9240,13 +9253,13 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
//-----------------------------------------------------------------------------
// FIXME-NAV: The existence of SetNavID vs SetFocusID properly needs to be clarified/reworked.
void ImGui::SetNavID(ImGuiID id, int nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel)
void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(g.NavWindow != NULL);
IM_ASSERT(nav_layer == ImGuiNavLayer_Main || nav_layer == ImGuiNavLayer_Menu);
g.NavId = id;
g.NavLayer = (ImGuiNavLayer)nav_layer;
g.NavLayer = nav_layer;
g.NavFocusScopeId = focus_scope_id;
g.NavWindow->NavLastIds[nav_layer] = id;
g.NavWindow->NavRectRel[nav_layer] = rect_rel;
@ -9309,7 +9322,7 @@ static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect
}
// Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057
static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
@ -9440,7 +9453,7 @@ static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
return new_best;
}
static void ImGui::NavApplyItemToResult(ImGuiNavMoveResult* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel)
static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel)
{
result->Window = window;
result->ID = id;
@ -9455,7 +9468,7 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con
//if (!g.IO.NavActive) // [2017/10/06] Removed this possibly redundant test but I am not sure of all the side-effects yet. Some of the feature here will need to work regardless of using a _NoNavInputs flag.
// return;
const ImGuiItemFlags item_flags = window->DC.ItemFlags;
const ImGuiItemFlags item_flags = g.CurrentItemFlags;
const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
// Process Init Request
@ -9478,7 +9491,7 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con
// FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy)
if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNav)))
{
ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
#if IMGUI_DEBUG_NAV_SCORING
// [DEBUG] Score all items in NavWindow at all times
if (!g.NavMoveRequest)
@ -9505,7 +9518,6 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con
g.NavLayer = window->DC.NavLayerCurrent;
g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
g.NavIdIsAlive = true;
g.NavIdTabCounter = window->DC.FocusCounterTabStop;
window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel; // Store item bounding box (relative to window position)
}
}
@ -9601,10 +9613,16 @@ void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
// FIXME: ChildWindow test here is wrong for docking
ImGuiContext& g = *GImGui;
IM_ASSERT(window == g.NavWindow);
if (window->Flags & ImGuiWindowFlags_NoNavInputs)
{
g.NavId = g.NavFocusScopeId = 0;
return;
}
bool init_for_nav = false;
if (!(window->Flags & ImGuiWindowFlags_NoNavInputs))
if (window == window->RootWindow || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
init_for_nav = true;
if (window == window->RootWindow || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
init_for_nav = true;
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer);
if (init_for_nav)
{
@ -9718,8 +9736,16 @@ static void ImGui::NavUpdate()
io.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
if (io.KeyShift)
io.NavInputs[ImGuiNavInput_TweakFast] = 1.0f;
if (io.KeyAlt && !io.KeyCtrl) // AltGR is Alt+Ctrl, also even on keyboards without AltGR we don't want Alt+Ctrl to open menu.
// AltGR is normally Alt+Ctrl but we can't reliably detect it (not all backends/systems/layout emit it as Alt+Ctrl)
// But also even on keyboards without AltGR we don't want Alt+Ctrl to open menu anyway.
if (io.KeyAlt && !io.KeyCtrl)
io.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f;
// We automatically cancel toggling nav layer when any text has been typed while holding Alt. (See #370)
if (io.KeyAlt && !io.KeyCtrl && g.NavWindowingToggleLayer && io.InputQueueCharacters.Size > 0)
g.NavWindowingToggleLayer = false;
#undef NAV_MAP_KEY
}
memcpy(io.NavInputsDownDurationPrev, io.NavInputsDownDuration, sizeof(io.NavInputsDownDuration));
@ -9785,6 +9811,11 @@ static void ImGui::NavUpdate()
if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel))
ClearActiveID();
}
else if (g.NavLayer != ImGuiNavLayer_Main)
{
// Leave the "menu" layer
NavRestoreLayer(ImGuiNavLayer_Main);
}
else if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
{
// Exit child window
@ -9801,11 +9832,6 @@ static void ImGui::NavUpdate()
if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
}
else if (g.NavLayer != ImGuiNavLayer_Main)
{
// Leave the "menu" layer
NavRestoreLayer(ImGuiNavLayer_Main);
}
else
{
// Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
@ -9895,7 +9921,7 @@ static void ImGui::NavUpdate()
// *Fallback* manual-scroll with Nav directional keys when window has no navigable item
ImGuiWindow* window = g.NavWindow;
const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
{
if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
@ -9961,6 +9987,7 @@ static void ImGui::NavUpdateInitResult()
return;
// Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
// FIXME-NAV: On _NavFlattened windows, g.NavWindow will only be updated during subsequent frame. Not a problem currently.
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name);
SetNavID(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel);
if (g.NavInitRequestFromMove)
@ -9986,7 +10013,7 @@ static void ImGui::NavUpdateMoveResult()
}
// Select which result to use
ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
ImGuiNavItemData* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
// PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page.
if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet)
@ -10053,7 +10080,7 @@ static float ImGui::NavUpdatePageUpPageDown()
const bool end_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End);
if (page_up_held != page_down_held || home_pressed != end_pressed) // If either (not both) are pressed
{
if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll)
if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll)
{
// Fallback manual-scroll when window has no navigable item
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
@ -10174,6 +10201,7 @@ static void ImGui::NavEndFrame()
static int ImGui::FindWindowFocusIndex(ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
IM_UNUSED(g);
int order = window->FocusOrder;
IM_ASSERT(g.WindowsFocusOrder[order] == window);
return order;
@ -10316,8 +10344,9 @@ static void ImGui::NavUpdateWindowing()
if (apply_focus_window->NavLastIds[0] == 0)
NavInitWindow(apply_focus_window, false);
// If the window only has a menu layer, select it directly
if (apply_focus_window->DC.NavLayerActiveMask == (1 << ImGuiNavLayer_Menu))
// If the window has ONLY a menu layer (no main layer), select it directly
// FIXME-NAV: This should be done in NavInit.. or in FocusWindow..
if (apply_focus_window->DC.NavLayersActiveMask == (1 << ImGuiNavLayer_Menu))
g.NavLayer = ImGuiNavLayer_Menu;
// Request OS level focus
@ -10330,10 +10359,12 @@ static void ImGui::NavUpdateWindowing()
// Apply menu/layer toggle
if (apply_toggle_layer && g.NavWindow)
{
ClearActiveID();
// Move to parent menu if necessary
ImGuiWindow* new_nav_window = g.NavWindow;
while (new_nav_window->ParentWindow
&& (new_nav_window->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) == 0
&& (new_nav_window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) == 0
&& (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0
&& (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
new_nav_window = new_nav_window->ParentWindow;
@ -10346,8 +10377,8 @@ static void ImGui::NavUpdateWindowing()
g.NavDisableHighlight = false;
g.NavDisableMouseHover = true;
// Reinitialize navigation when entering menu bar with the Alt key. We make it persist on Docking Tab Bars.
const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main;
// Reinitialize navigation when entering menu bar with the Alt key.
const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main;
const bool preserve_layer_1_nav_id = (new_nav_window->DockNodeAsHost != NULL);
if (new_nav_layer == ImGuiNavLayer_Menu && !preserve_layer_1_nav_id)
g.NavWindow->NavLastIds[new_nav_layer] = 0;
@ -10386,6 +10417,7 @@ void ImGui::NavUpdateWindowingOverlay()
for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--)
{
ImGuiWindow* window = g.WindowsFocusOrder[n];
IM_ASSERT(window != NULL); // Fix static analyzers
if (!IsWindowNavFocusable(window))
continue;
const char* label = window->Name;
@ -13929,7 +13961,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
window->DockTabItemRect = host_window->DC.LastItemRect;
// Update navigation ID on menu layer
if (g.NavWindow && g.NavWindow->RootWindow == window && (window->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) == 0)
if (g.NavWindow && g.NavWindow->RootWindow == window && (window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) == 0)
host_window->NavLastIds[1] = window->ID;
}
}
@ -16828,21 +16860,30 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label)
BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : "");
BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1);
BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems);
BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask);
BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
if (!window->NavRectRel[0].IsInverted())
BulletText("NavRectRel[0]: (%.1f,%.1f)(%.1f,%.1f)", window->NavRectRel[0].Min.x, window->NavRectRel[0].Min.y, window->NavRectRel[0].Max.x, window->NavRectRel[0].Max.y);
else
BulletText("NavRectRel[0]: <None>");
for (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++)
{
ImRect r = window->NavRectRel[layer];
if (r.Min.x >= r.Max.y && r.Min.y >= r.Max.y)
{
BulletText("NavLastIds[%d]: 0x%08X", layer, window->NavLastIds[layer]);
continue;
}
BulletText("NavLastIds[%d]: 0x%08X at +(%.1f,%.1f)(%.1f,%.1f)", layer, window->NavLastIds[layer], r.Min.x, r.Min.y, r.Max.x, r.Max.y);
if (IsItemHovered())
GetForegroundDrawList(window)->AddRect(r.Min + window->Pos, r.Max + window->Pos, IM_COL32(255, 255, 0, 255));
}
BulletText("NavLayersActiveMask: %X, NavLastChildNavWindow: %s", window->DC.NavLayersActiveMask, window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
BulletText("Viewport: %d%s, ViewportId: 0x%08X, ViewportPos: (%.1f,%.1f)", window->Viewport ? window->Viewport->Idx : -1, window->ViewportOwned ? " (Owned)" : "", window->ViewportId, window->ViewportPos.x, window->ViewportPos.y);
BulletText("ViewportMonitor: %d", window->Viewport ? window->Viewport->PlatformMonitor : -1);
BulletText("DockId: 0x%04X, DockOrder: %d, Act: %d, Vis: %d", window->DockId, window->DockOrder, window->DockIsActive, window->DockTabIsVisible);
if (window->DockNode || window->DockNodeAsHost)
DebugNodeDockNode(window->DockNodeAsHost ? window->DockNodeAsHost : window->DockNode, window->DockNodeAsHost ? "DockNodeAsHost" : "DockNode");
if (window->RootWindow != window) { DebugNodeWindow(window->RootWindow, "RootWindow"); }
if (window->RootWindow != window) { DebugNodeWindow(window->RootWindow, "RootWindow"); }
if (window->RootWindowDockTree != window->RootWindow) { DebugNodeWindow(window->RootWindowDockTree, "RootWindowDockTree"); }
if (window->ParentWindow != NULL) { DebugNodeWindow(window->ParentWindow, "ParentWindow"); }
if (window->DC.ChildWindows.Size > 0) { DebugNodeWindowsList(&window->DC.ChildWindows, "ChildWindows"); }
if (window->ParentWindow != NULL) { DebugNodeWindow(window->ParentWindow, "ParentWindow"); }
if (window->DC.ChildWindows.Size > 0) { DebugNodeWindowsList(&window->DC.ChildWindows, "ChildWindows"); }
if (window->ColumnsStorage.Size > 0 && TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size))
{
for (int n = 0; n < window->ColumnsStorage.Size; n++)