Merge branch 'master' into docking

# Conflicts:
#	backends/imgui_impl_vulkan.cpp
This commit is contained in:
ocornut
2024-01-22 19:01:25 +01:00
15 changed files with 420 additions and 259 deletions

View File

@@ -1055,6 +1055,8 @@ CODE
static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in
static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear
static const float NAV_ACTIVATE_HIGHLIGHT_TIMER = 0.10f; // Time to highlight an item activated by a shortcut.
// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by backend)
static const float WINDOWS_HOVER_PADDING = 4.0f; // Extend outside window for hovering/resizing (maxxed with TouchPadding) and inside windows for borders. Affect FindHoveredWindow().
static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time.
@@ -3980,6 +3982,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
g.ActiveIdNoClearOnFocusLoss = false;
g.ActiveIdWindow = window;
g.ActiveIdHasBeenEditedThisFrame = false;
g.ActiveIdFromShortcut = false;
if (id)
{
g.ActiveIdIsAlive = id;
@@ -4197,7 +4200,8 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag
if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap)
return false;
if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
return false;
if (!g.ActiveIdFromShortcut)
return false;
// Done with rectangle culling so we can perform heavier checks now.
if (!(item_flags & ImGuiItemFlags_NoWindowHoverableCheck) && !IsWindowContentHoverable(window, ImGuiHoveredFlags_None))
@@ -4257,12 +4261,13 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag
}
// FIXME: This is inlined/duplicated in ItemAdd()
// FIXME: The id != 0 path is not used by our codebase, may get rid of it?
bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (!bb.Overlaps(window->ClipRect))
if (id == 0 || (id != g.ActiveId && id != g.NavId))
if (id == 0 || (id != g.ActiveId && id != g.ActiveIdPreviousFrame && id != g.NavId && id != g.NavActivateId))
if (!g.LogEnabled)
return true;
return false;
@@ -9020,8 +9025,6 @@ static bool IsKeyChordPotentiallyCharInput(ImGuiKeyChord key_chord)
// - Routes and key ownership are attributed at the beginning of next frame based on best score and mod state.
// (Conceptually this does a "Submit for next frame" + "Test for current frame".
// As such, it could be called TrySetXXX or SubmitXXX, or the Submit and Test operations should be separate.)
// - Using 'owner_id == ImGuiKeyOwner_Any/0': auto-assign an owner based on current focus scope (each window has its focus scope by default)
// - Using 'owner_id == ImGuiKeyOwner_None': allows disabling/locking a shortcut.
bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags)
{
ImGuiContext& g = *GImGui;
@@ -9029,6 +9032,8 @@ bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiI
flags |= ImGuiInputFlags_RouteGlobalHigh; // IMPORTANT: This is the default for SetShortcutRouting() but NOT Shortcut()
else
IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiInputFlags_RouteMask_)); // Check that only 1 routing flag is used
IM_ASSERT(owner_id != ImGuiKeyOwner_Any && owner_id != ImGuiKeyOwner_None);
if (key_chord & ImGuiMod_Shortcut)
key_chord = ConvertShortcutMod(key_chord);
@@ -9059,6 +9064,7 @@ bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiI
return false;
}
// FIXME-SHORTCUT: A way to configure the location/focus-scope to test would render this more flexible.
const int score = CalcRoutingScore(g.CurrentFocusScopeId, owner_id, flags);
IMGUI_DEBUG_LOG_INPUTROUTING("SetShortcutRouting(%s, owner_id=0x%08X, flags=%04X) -> score %d\n", GetKeyChordName(key_chord), owner_id, flags, score);
if (score == 255)
@@ -9067,18 +9073,17 @@ bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiI
// Submit routing for NEXT frame (assuming score is sufficient)
// FIXME: Could expose a way to use a "serve last" policy for same score resolution (using <= instead of <).
ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord);
const ImGuiID routing_id = GetRoutingIdFromOwnerId(owner_id);
//const bool set_route = (flags & ImGuiInputFlags_ServeLast) ? (score <= routing_data->RoutingNextScore) : (score < routing_data->RoutingNextScore);
if (score < routing_data->RoutingNextScore)
{
routing_data->RoutingNext = routing_id;
routing_data->RoutingNext = owner_id;
routing_data->RoutingNextScore = (ImU8)score;
}
// Return routing state for CURRENT frame
if (routing_data->RoutingCurr == routing_id)
if (routing_data->RoutingCurr == owner_id)
IMGUI_DEBUG_LOG_INPUTROUTING("--> granting current route\n");
return routing_data->RoutingCurr == routing_id;
return routing_data->RoutingCurr == owner_id;
}
// Currently unused by core (but used by tests)
@@ -10043,6 +10048,13 @@ bool ImGui::IsKeyChordPressed(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiIn
return true;
}
void ImGui::SetNextItemShortcut(ImGuiKeyChord key_chord)
{
ImGuiContext& g = *GImGui;
g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasShortcut;
g.NextItemData.Shortcut = key_chord;
}
bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags)
{
//ImGuiContext& g = *GImGui;
@@ -10051,6 +10063,13 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags
// When using (owner_id == 0/Any): SetShortcutRouting() will use CurrentFocusScopeId and filter with this, so IsKeyPressed() is fine with he 0/Any.
if ((flags & ImGuiInputFlags_RouteMask_) == 0)
flags |= ImGuiInputFlags_RouteFocused;
// Using 'owner_id == ImGuiKeyOwner_Any/0': auto-assign an owner based on current focus scope (each window has its focus scope by default)
// Effectively makes Shortcut() always input-owner aware.
if (owner_id == ImGuiKeyOwner_Any || owner_id == ImGuiKeyOwner_None)
owner_id = GetRoutingIdFromOwnerId(owner_id);
// Submit route
if (!SetShortcutRouting(key_chord, owner_id, flags))
return false;
@@ -10385,6 +10404,7 @@ void ImGuiStackSizes::CompareWithContextState(ImGuiContext* ctx)
// [SECTION] ITEM SUBMISSION
//-----------------------------------------------------------------------------
// - KeepAliveID()
// - ItemHandleShortcut() [Internal]
// - ItemAdd()
//-----------------------------------------------------------------------------
@@ -10398,6 +10418,20 @@ void ImGui::KeepAliveID(ImGuiID id)
g.ActiveIdPreviousFrameIsAlive = true;
}
static void ItemHandleShortcut(ImGuiID id)
{
// FIXME: Generalize Activation queue?
ImGuiContext& g = *GImGui;
if (ImGui::Shortcut(g.NextItemData.Shortcut, id, ImGuiInputFlags_None) && g.NavActivateId == 0)
{
g.NavActivateId = id; // Will effectively disable clipping.
g.NavActivateFlags = ImGuiActivateFlags_PreferInput | ImGuiActivateFlags_FromShortcut;
if (g.ActiveId == 0 || g.ActiveId == id)
g.NavActivateDownId = g.NavActivatePressedId = id;
ImGui::NavHighlightActivated(id);
}
}
// 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.
@@ -10439,6 +10473,9 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
NavProcessItem();
}
if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasShortcut)
ItemHandleShortcut(id);
}
// Lightweight clear of SetNextItemXXX data.
@@ -10455,9 +10492,10 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
//const bool is_clipped = IsClippedEx(bb, id);
//if (is_clipped)
// return false;
// g.NavActivateId is not necessarily == g.NavId, in the case of remote activation (e.g. shortcuts)
const bool is_rect_visible = bb.Overlaps(window->ClipRect);
if (!is_rect_visible)
if (id == 0 || (id != g.ActiveId && id != g.ActiveIdPreviousFrame && id != g.NavId))
if (id == 0 || (id != g.ActiveId && id != g.ActiveIdPreviousFrame && id != g.NavId && id != g.NavActivateId))
if (!g.LogEnabled)
return false;
@@ -11836,6 +11874,13 @@ void ImGui::SetNavWindow(ImGuiWindow* window)
NavUpdateAnyRequestFlag();
}
void ImGui::NavHighlightActivated(ImGuiID id)
{
ImGuiContext& g = *GImGui;
g.NavHighlightActivatedId = id;
g.NavHighlightActivatedTimer = NAV_ACTIVATE_HIGHLIGHT_TIMER;
}
void ImGui::NavClearPreferredPosForAxis(ImGuiAxis axis)
{
ImGuiContext& g = *GImGui;
@@ -12503,10 +12548,10 @@ static void ImGui::NavUpdate()
g.NavActivateFlags = ImGuiActivateFlags_None;
if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
{
const bool activate_down = (nav_keyboard_active && IsKeyDown(ImGuiKey_Space)) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadActivate));
const bool activate_pressed = activate_down && ((nav_keyboard_active && IsKeyPressed(ImGuiKey_Space, false)) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadActivate, false)));
const bool input_down = (nav_keyboard_active && (IsKeyDown(ImGuiKey_Enter) || IsKeyDown(ImGuiKey_KeypadEnter))) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadInput));
const bool input_pressed = input_down && ((nav_keyboard_active && (IsKeyPressed(ImGuiKey_Enter, false) || IsKeyPressed(ImGuiKey_KeypadEnter, false))) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadInput, false)));
const bool activate_down = (nav_keyboard_active && IsKeyDown(ImGuiKey_Space, ImGuiKeyOwner_None)) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadActivate, ImGuiKeyOwner_None));
const bool activate_pressed = activate_down && ((nav_keyboard_active && IsKeyPressed(ImGuiKey_Space, ImGuiKeyOwner_None)) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadActivate, ImGuiKeyOwner_None)));
const bool input_down = (nav_keyboard_active && (IsKeyDown(ImGuiKey_Enter, ImGuiKeyOwner_None) || IsKeyDown(ImGuiKey_KeypadEnter, ImGuiKeyOwner_None))) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadInput, ImGuiKeyOwner_None));
const bool input_pressed = input_down && ((nav_keyboard_active && (IsKeyPressed(ImGuiKey_Enter, ImGuiKeyOwner_None) || IsKeyPressed(ImGuiKey_KeypadEnter, ImGuiKeyOwner_None))) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadInput, ImGuiKeyOwner_None)));
if (g.ActiveId == 0 && activate_pressed)
{
g.NavActivateId = g.NavId;
@@ -12520,13 +12565,22 @@ static void ImGui::NavUpdate()
if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_down || input_down))
g.NavActivateDownId = g.NavId;
if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_pressed || input_pressed))
{
g.NavActivatePressedId = g.NavId;
NavHighlightActivated(g.NavId);
}
}
if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
g.NavDisableHighlight = true;
if (g.NavActivateId != 0)
IM_ASSERT(g.NavActivateDownId == g.NavActivateId);
// Highlight
if (g.NavHighlightActivatedTimer > 0.0f)
g.NavHighlightActivatedTimer = ImMax(0.0f, g.NavHighlightActivatedTimer - io.DeltaTime);
if (g.NavHighlightActivatedTimer == 0.0f)
g.NavHighlightActivatedId = 0;
// Process programmatic activation request
// FIXME-NAV: Those should eventually be queued (unlike focus they don't cancel each others)
if (g.NavNextActivateId != 0)
@@ -12918,15 +12972,14 @@ static void ImGui::NavUpdateCancelRequest()
NavRestoreLayer(ImGuiNavLayer_Main);
NavRestoreHighlightAfterMove();
}
else if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
else if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow && !(g.NavWindow->RootWindowForNav->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->RootWindowForNav->ParentWindow)
{
// Exit child window
ImGuiWindow* child_window = g.NavWindow;
ImGuiWindow* parent_window = g.NavWindow->ParentWindow;
ImGuiWindow* child_window = g.NavWindow->RootWindowForNav;
ImGuiWindow* parent_window = child_window->ParentWindow;
IM_ASSERT(child_window->ChildId != 0);
ImRect child_rect = child_window->Rect();
FocusWindow(parent_window);
SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, WindowRectAbsToRel(parent_window, child_rect));
SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, WindowRectAbsToRel(parent_window, child_window->Rect()));
NavRestoreHighlightAfterMove();
}
else if (g.OpenPopupStack.Size > 0 && g.OpenPopupStack.back().Window != NULL && !(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
@@ -21107,6 +21160,7 @@ void ImGui::DebugLocateItem(ImGuiID target_id)
g.DebugBreakInLocateId = false;
}
// FIXME: Doesn't work over through a modal window, because they clear HoveredWindow.
void ImGui::DebugLocateItemOnHover(ImGuiID target_id)
{
if (target_id == 0 || !IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenBlockedByPopup))