mirror of
https://github.com/Drezil/imgui.git
synced 2025-07-06 13:08:47 +02:00
Merge branch 'master' into docking
# Conflicts: # backends/imgui_impl_opengl3.cpp # examples/imgui_examples.sln # imgui.cpp # imgui.h
This commit is contained in:
525
imgui.cpp
525
imgui.cpp
@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.84
|
||||
// dear imgui, v1.85 WIP
|
||||
// (main code and documentation)
|
||||
|
||||
// Help:
|
||||
@ -15,7 +15,10 @@
|
||||
// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there)
|
||||
// - Glossary https://github.com/ocornut/imgui/wiki/Glossary
|
||||
// - Issues & support https://github.com/ocornut/imgui/issues
|
||||
// - Discussions https://github.com/ocornut/imgui/discussions
|
||||
|
||||
// Getting Started?
|
||||
// - For first-time users having issues compiling/linking/running or issues loading fonts:
|
||||
// please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above.
|
||||
|
||||
// Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
|
||||
// See LICENSE.txt for copyright and licensing details (standard MIT License).
|
||||
@ -386,6 +389,7 @@ CODE
|
||||
- 2021/XX/XX (1.XX) - Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api.
|
||||
|
||||
|
||||
- 2021/08/23 (1.85) - removed GetWindowContentRegionWidth() function. keep inline redirection helper. can use 'GetWindowContentRegionMax().x - GetWindowContentRegionMin().x' instead.
|
||||
- 2021/07/26 (1.84) - commented out redirecting functions/enums names that were marked obsolete in 1.67 and 1.69 (March 2019):
|
||||
- ImGui::GetOverlayDrawList() -> use ImGui::GetForegroundDrawList()
|
||||
- ImFont::GlyphRangesBuilder -> use ImFontGlyphRangesBuilder
|
||||
@ -919,8 +923,9 @@ namespace ImGui
|
||||
static void NavUpdate();
|
||||
static void NavUpdateWindowing();
|
||||
static void NavUpdateWindowingOverlay();
|
||||
static void NavUpdateMoveResult();
|
||||
static void NavUpdateInitResult();
|
||||
static void NavUpdateCancelRequest();
|
||||
static void NavUpdateCreateMoveRequest();
|
||||
static float NavUpdatePageUpPageDown();
|
||||
static inline void NavUpdateAnyRequestFlag();
|
||||
static void NavEndFrame();
|
||||
@ -4004,6 +4009,7 @@ void ImGui::UpdateTabFocus()
|
||||
void ImGui::UpdateHoveredWindowAndCaptureFlags()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiIO& io = g.IO;
|
||||
g.WindowsHoverPadding = ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_HOVER_PADDING, WINDOWS_HOVER_PADDING));
|
||||
|
||||
// Find the window hovered by mouse:
|
||||
@ -4020,48 +4026,61 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
|
||||
clear_hovered_windows = true;
|
||||
|
||||
// Disabled mouse?
|
||||
if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse)
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
|
||||
clear_hovered_windows = true;
|
||||
|
||||
// We track click ownership. When clicked outside of a window the click is owned by the application and won't report hovering nor request capture even while dragging over our windows afterward.
|
||||
int mouse_earliest_button_down = -1;
|
||||
// We track click ownership. When clicked outside of a window the click is owned by the application and
|
||||
// won't report hovering nor request capture even while dragging over our windows afterward.
|
||||
const bool has_open_popup = (g.OpenPopupStack.Size > 0);
|
||||
const bool has_open_modal = (modal_window != NULL);
|
||||
int mouse_earliest_down = -1;
|
||||
bool mouse_any_down = false;
|
||||
for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
|
||||
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
|
||||
{
|
||||
if (g.IO.MouseClicked[i])
|
||||
g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (g.OpenPopupStack.Size > 0);
|
||||
mouse_any_down |= g.IO.MouseDown[i];
|
||||
if (g.IO.MouseDown[i])
|
||||
if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down])
|
||||
mouse_earliest_button_down = i;
|
||||
if (io.MouseClicked[i])
|
||||
{
|
||||
io.MouseDownOwned[i] = (g.HoveredWindow != NULL) || has_open_popup;
|
||||
io.MouseDownOwnedUnlessPopupClose[i] = (g.HoveredWindow != NULL) || has_open_modal;
|
||||
}
|
||||
mouse_any_down |= io.MouseDown[i];
|
||||
if (io.MouseDown[i])
|
||||
if (mouse_earliest_down == -1 || io.MouseClickedTime[i] < io.MouseClickedTime[mouse_earliest_down])
|
||||
mouse_earliest_down = i;
|
||||
}
|
||||
const bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down];
|
||||
const bool mouse_avail = (mouse_earliest_down == -1) || io.MouseDownOwned[mouse_earliest_down];
|
||||
const bool mouse_avail_unless_popup_close = (mouse_earliest_down == -1) || io.MouseDownOwnedUnlessPopupClose[mouse_earliest_down];
|
||||
|
||||
// If mouse was first clicked outside of ImGui bounds we also cancel out hovering.
|
||||
// FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02)
|
||||
const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0;
|
||||
if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload)
|
||||
if (!mouse_avail && !mouse_dragging_extern_payload)
|
||||
clear_hovered_windows = true;
|
||||
|
||||
if (clear_hovered_windows)
|
||||
g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL;
|
||||
|
||||
// Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to Dear ImGui + app)
|
||||
// Update io.WantCaptureMouse for the user application (true = dispatch mouse info to Dear ImGui only, false = dispatch mouse to Dear ImGui + underlying app)
|
||||
// Update io.WantCaptureMouseAllowPopupClose (experimental) to give a chance for app to react to popup closure with a drag
|
||||
if (g.WantCaptureMouseNextFrame != -1)
|
||||
g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0);
|
||||
{
|
||||
io.WantCaptureMouse = io.WantCaptureMouseUnlessPopupClose = (g.WantCaptureMouseNextFrame != 0);
|
||||
}
|
||||
else
|
||||
g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (g.OpenPopupStack.Size > 0);
|
||||
{
|
||||
io.WantCaptureMouse = (mouse_avail && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_popup;
|
||||
io.WantCaptureMouseUnlessPopupClose = (mouse_avail_unless_popup_close && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_modal;
|
||||
}
|
||||
|
||||
// Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to Dear ImGui + app)
|
||||
// Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to Dear ImGui only, false = dispatch keyboard info to Dear ImGui + underlying app)
|
||||
if (g.WantCaptureKeyboardNextFrame != -1)
|
||||
g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0);
|
||||
io.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0);
|
||||
else
|
||||
g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL);
|
||||
if (g.IO.NavActive && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard))
|
||||
g.IO.WantCaptureKeyboard = true;
|
||||
io.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL);
|
||||
if (io.NavActive && (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard))
|
||||
io.WantCaptureKeyboard = true;
|
||||
|
||||
// Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible
|
||||
g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
|
||||
io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
|
||||
}
|
||||
|
||||
ImGuiKeyModFlags ImGui::GetMergedKeyModFlags()
|
||||
@ -6687,18 +6706,23 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
||||
window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding);
|
||||
}
|
||||
|
||||
// Since 1.71, child window can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call.
|
||||
// Child windows can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call (since 1.71)
|
||||
// When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order.
|
||||
// We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping child.
|
||||
// We also disabled this when we have dimming overlay behind this specific one child.
|
||||
// FIXME: More code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected.
|
||||
// FIXME: User code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected (github #4493)
|
||||
const bool is_undocked_or_docked_visible = !window->DockIsActive || window->DockTabIsVisible;
|
||||
if (is_undocked_or_docked_visible)
|
||||
{
|
||||
bool render_decorations_in_parent = false;
|
||||
if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)
|
||||
if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_window->DrawList->VtxBuffer.Size > 0)
|
||||
{
|
||||
// - We test overlap with the previous child window only (testing all would end up being O(log N) not a good investment here)
|
||||
// - We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping childs
|
||||
ImGuiWindow* previous_child = parent_window->DC.ChildWindows.Size >= 2 ? parent_window->DC.ChildWindows[parent_window->DC.ChildWindows.Size - 2] : NULL;
|
||||
bool previous_child_overlapping = previous_child ? previous_child->Rect().Overlaps(window->Rect()) : false;
|
||||
bool parent_is_empty = parent_window->DrawList->VtxBuffer.Size > 0;
|
||||
if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_is_empty && !previous_child_overlapping)
|
||||
render_decorations_in_parent = true;
|
||||
}
|
||||
if (render_decorations_in_parent)
|
||||
window->DrawList = parent_window->DrawList;
|
||||
|
||||
@ -7162,7 +7186,7 @@ void ImGui::PopItemFlag()
|
||||
}
|
||||
|
||||
// BeginDisabled()/EndDisabled()
|
||||
// - Those can be nested but this cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep things disabled)
|
||||
// - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled)
|
||||
// - Visually this is currently altering alpha, but it is expected that in a future styling system this would work differently.
|
||||
// - Feedback welcome at https://github.com/ocornut/imgui/issues/211
|
||||
// - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it.
|
||||
@ -7173,7 +7197,10 @@ void ImGui::BeginDisabled(bool disabled)
|
||||
bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
|
||||
g.DisabledAlphaBackup = g.Style.Alpha;
|
||||
if (!was_disabled && disabled)
|
||||
{
|
||||
g.DisabledAlphaBackup = g.Style.Alpha;
|
||||
g.Style.Alpha *= g.Style.DisabledAlpha; // PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * g.Style.DisabledAlpha);
|
||||
}
|
||||
if (was_disabled || disabled)
|
||||
g.CurrentItemFlags |= ImGuiItemFlags_Disabled;
|
||||
g.ItemFlagsStack.push_back(g.CurrentItemFlags);
|
||||
@ -7185,7 +7212,7 @@ void ImGui::EndDisabled()
|
||||
bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
|
||||
//PopItemFlag();
|
||||
g.ItemFlagsStack.pop_back();
|
||||
g.CurrentItemFlags &= ~ImGuiItemFlags_Disabled;
|
||||
g.CurrentItemFlags = g.ItemFlagsStack.back();
|
||||
if (was_disabled && (g.CurrentItemFlags & ImGuiItemFlags_Disabled) == 0)
|
||||
g.Style.Alpha = g.DisabledAlphaBackup; //PopStyleVar();
|
||||
}
|
||||
@ -8048,7 +8075,6 @@ void ImGuiStackSizes::CompareWithCurrentState()
|
||||
// - GetContentRegionMaxAbs() [Internal]
|
||||
// - GetContentRegionAvail(),
|
||||
// - GetWindowContentRegionMin(), GetWindowContentRegionMax()
|
||||
// - GetWindowContentRegionWidth()
|
||||
// - BeginGroup()
|
||||
// - EndGroup()
|
||||
// Also see in imgui_widgets: tab bars, columns.
|
||||
@ -8416,12 +8442,6 @@ ImVec2 ImGui::GetWindowContentRegionMax()
|
||||
return window->ContentRegionRect.Max - window->Pos;
|
||||
}
|
||||
|
||||
float ImGui::GetWindowContentRegionWidth()
|
||||
{
|
||||
ImGuiWindow* window = GImGui->CurrentWindow;
|
||||
return window->ContentRegionRect.GetWidth();
|
||||
}
|
||||
|
||||
// Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.)
|
||||
// Groups are currently a mishmash of functionalities which should perhaps be clarified and separated.
|
||||
void ImGui::BeginGroup()
|
||||
@ -9074,7 +9094,7 @@ void ImGui::EndPopup()
|
||||
IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls
|
||||
IM_ASSERT(g.BeginPopupStack.Size > 0);
|
||||
|
||||
// Make all menus and popups wrap around for now, may need to expose that policy.
|
||||
// Make all menus and popups wrap around for now, may need to expose that policy (e.g. focus scope could include wrap/loop policy flags used by new move requests)
|
||||
if (g.NavWindow == window)
|
||||
NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY);
|
||||
|
||||
@ -9587,26 +9607,26 @@ void ImGui::NavMoveRequestCancel()
|
||||
NavUpdateAnyRequestFlag();
|
||||
}
|
||||
|
||||
void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags)
|
||||
// Forward will reuse the move request again on the next frame (generally with modifications done to it)
|
||||
void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None);
|
||||
IM_ASSERT(g.NavMoveRequestForwardToNextFrame == false);
|
||||
NavMoveRequestCancel();
|
||||
g.NavMoveRequestForwardToNextFrame = true;
|
||||
g.NavMoveDir = move_dir;
|
||||
g.NavMoveClipDir = clip_dir;
|
||||
g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
|
||||
g.NavMoveRequestFlags = move_flags;
|
||||
g.NavWindow->NavRectRel[g.NavLayer] = bb_rel;
|
||||
g.NavMoveRequestFlags = move_flags | ImGuiNavMoveFlags_Forwarded;
|
||||
}
|
||||
|
||||
void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags)
|
||||
// Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire
|
||||
// popup is assembled and in case of appended popups it is not clear which EndPopup() call is final.
|
||||
void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags wrap_flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
|
||||
// Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire
|
||||
// popup is assembled and in case of appended popups it is not clear which EndPopup() call is final.
|
||||
g.NavWrapRequestWindow = window;
|
||||
g.NavWrapRequestFlags = move_flags;
|
||||
IM_ASSERT(wrap_flags != 0); // Call with _WrapX, _WrapY, _LoopX, _LoopY
|
||||
if (g.NavWindow == window && g.NavMoveRequest && g.NavLayer == ImGuiNavLayer_Main)
|
||||
g.NavMoveRequestFlags |= wrap_flags;
|
||||
}
|
||||
|
||||
// FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0).
|
||||
@ -9756,16 +9776,14 @@ static void ImGui::NavUpdate()
|
||||
ImGuiIO& io = g.IO;
|
||||
|
||||
io.WantSetMousePos = false;
|
||||
g.NavWrapRequestWindow = NULL;
|
||||
g.NavWrapRequestFlags = ImGuiNavMoveFlags_None;
|
||||
#if 0
|
||||
if (g.NavScoringCount > 0) IMGUI_DEBUG_LOG("NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
|
||||
#endif
|
||||
|
||||
// Set input source as Gamepad when buttons are pressed (as some features differs when used with Gamepad vs Keyboard)
|
||||
// (do it before we map Keyboard input!)
|
||||
bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
|
||||
bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
|
||||
const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
|
||||
const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
|
||||
if (nav_gamepad_active && g.NavInputSource != ImGuiInputSource_Gamepad)
|
||||
{
|
||||
if (io.NavInputs[ImGuiNavInput_Activate] > 0.0f || io.NavInputs[ImGuiNavInput_Input] > 0.0f || io.NavInputs[ImGuiNavInput_Cancel] > 0.0f || io.NavInputs[ImGuiNavInput_Menu] > 0.0f
|
||||
@ -9804,16 +9822,8 @@ static void ImGui::NavUpdate()
|
||||
|
||||
// Process navigation move request
|
||||
if (g.NavMoveRequest)
|
||||
NavUpdateMoveResult();
|
||||
|
||||
// When a forwarded move request failed, we restore the highlight that we disabled during the forward frame
|
||||
if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive)
|
||||
{
|
||||
IM_ASSERT(g.NavMoveRequest);
|
||||
if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
|
||||
g.NavDisableHighlight = false;
|
||||
g.NavMoveRequestForward = ImGuiNavForward_None;
|
||||
}
|
||||
NavMoveRequestApplyResult();
|
||||
g.NavMoveRequest = false;
|
||||
|
||||
// Apply application mouse position movement, after we had a chance to process move request result.
|
||||
if (g.NavMousePosDirty && g.NavIdIsAlive)
|
||||
@ -9831,7 +9841,7 @@ static void ImGui::NavUpdate()
|
||||
g.NavJustTabbedId = 0;
|
||||
IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1);
|
||||
|
||||
// Store our return window (for returning from Layer 1 to Layer 0) and clear it as soon as we step back in our own Layer 0
|
||||
// Store our return window (for returning from Menu Layer to Main Layer) and clear it as soon as we step back in our own Layer 0
|
||||
if (g.NavWindow)
|
||||
NavSaveLastChildNavWindowIntoParent(g.NavWindow);
|
||||
if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == ImGuiNavLayer_Main)
|
||||
@ -9845,43 +9855,7 @@ static void ImGui::NavUpdate()
|
||||
io.NavVisible = (io.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL);
|
||||
|
||||
// Process NavCancel input (to close a popup, get back to parent, clear focus)
|
||||
if (IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed))
|
||||
{
|
||||
IMGUI_DEBUG_LOG_NAV("[nav] ImGuiNavInput_Cancel\n");
|
||||
if (g.ActiveId != 0)
|
||||
{
|
||||
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
|
||||
ImGuiWindow* child_window = g.NavWindow;
|
||||
ImGuiWindow* parent_window = g.NavWindow->ParentWindow;
|
||||
IM_ASSERT(child_window->ChildId != 0);
|
||||
ImRect child_rect = child_window->Rect();
|
||||
FocusWindow(parent_window);
|
||||
SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, ImRect(child_rect.Min - parent_window->Pos, child_rect.Max - parent_window->Pos));
|
||||
}
|
||||
else if (g.OpenPopupStack.Size > 0)
|
||||
{
|
||||
// Close open popup/menu
|
||||
if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
|
||||
ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
|
||||
if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow)))
|
||||
g.NavWindow->NavLastIds[0] = 0;
|
||||
g.NavId = g.NavFocusScopeId = 0;
|
||||
}
|
||||
}
|
||||
NavUpdateCancelRequest();
|
||||
|
||||
// Process manual activation request
|
||||
g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0;
|
||||
@ -9902,59 +9876,14 @@ static void ImGui::NavUpdate()
|
||||
g.NavDisableHighlight = true;
|
||||
if (g.NavActivateId != 0)
|
||||
IM_ASSERT(g.NavActivateDownId == g.NavActivateId);
|
||||
g.NavMoveRequest = false;
|
||||
|
||||
// Process programmatic activation request
|
||||
if (g.NavNextActivateId != 0)
|
||||
g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId;
|
||||
g.NavNextActivateId = 0;
|
||||
|
||||
// Initiate directional inputs request
|
||||
if (g.NavMoveRequestForward == ImGuiNavForward_None)
|
||||
{
|
||||
g.NavMoveDir = ImGuiDir_None;
|
||||
g.NavMoveRequestFlags = ImGuiNavMoveFlags_None;
|
||||
if (g.NavWindow && !g.NavWindowingTarget && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
|
||||
{
|
||||
const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat;
|
||||
if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && (IsNavInputTest(ImGuiNavInput_DpadLeft, read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_, read_mode))) { g.NavMoveDir = ImGuiDir_Left; }
|
||||
if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; }
|
||||
if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && (IsNavInputTest(ImGuiNavInput_DpadUp, read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_, read_mode))) { g.NavMoveDir = ImGuiDir_Up; }
|
||||
if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && (IsNavInputTest(ImGuiNavInput_DpadDown, read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_, read_mode))) { g.NavMoveDir = ImGuiDir_Down; }
|
||||
}
|
||||
g.NavMoveClipDir = g.NavMoveDir;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window)
|
||||
// (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function)
|
||||
IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);
|
||||
IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued);
|
||||
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir);
|
||||
g.NavMoveRequestForward = ImGuiNavForward_ForwardActive;
|
||||
}
|
||||
|
||||
// Update PageUp/PageDown/Home/End scroll
|
||||
// FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag?
|
||||
float nav_scoring_rect_offset_y = 0.0f;
|
||||
if (nav_keyboard_active)
|
||||
nav_scoring_rect_offset_y = NavUpdatePageUpPageDown();
|
||||
|
||||
// If we initiate a movement request and have no current NavId, we initiate a InitDefautRequest that will be used as a fallback if the direction fails to find a match
|
||||
if (g.NavMoveDir != ImGuiDir_None)
|
||||
{
|
||||
g.NavMoveRequest = true;
|
||||
g.NavMoveRequestKeyMods = io.KeyMods;
|
||||
g.NavMoveDirLast = g.NavMoveDir;
|
||||
}
|
||||
if (g.NavMoveRequest && g.NavId == 0)
|
||||
{
|
||||
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer);
|
||||
g.NavInitRequest = g.NavInitRequestFromMove = true;
|
||||
// Reassigning with same value, we're being explicit here.
|
||||
g.NavInitResultId = 0; // -V1048
|
||||
g.NavDisableHighlight = false;
|
||||
}
|
||||
// Process move requests
|
||||
NavUpdateCreateMoveRequest();
|
||||
NavUpdateAnyRequestFlag();
|
||||
|
||||
// Scrolling
|
||||
@ -9963,7 +9892,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.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
|
||||
if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest) //-V560
|
||||
{
|
||||
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));
|
||||
@ -9980,36 +9909,7 @@ static void ImGui::NavUpdate()
|
||||
SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
|
||||
}
|
||||
|
||||
// Reset search results
|
||||
g.NavMoveResultLocal.Clear();
|
||||
g.NavMoveResultLocalVisibleSet.Clear();
|
||||
g.NavMoveResultOther.Clear();
|
||||
|
||||
// When using gamepad, we project the reference nav bounding box into window visible area.
|
||||
// This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad every movements are relative
|
||||
// (can't focus a visible object like we can with the mouse).
|
||||
if (g.NavMoveRequest && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main)
|
||||
{
|
||||
ImGuiWindow* window = g.NavWindow;
|
||||
ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1));
|
||||
if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
|
||||
{
|
||||
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel\n");
|
||||
float pad = window->CalcFontSize() * 0.5f;
|
||||
window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intent of starting navigation from first fully visible item
|
||||
window->NavRectRel[g.NavLayer].ClipWithFull(window_rect_rel);
|
||||
g.NavId = g.NavFocusScopeId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items)
|
||||
ImRect nav_rect_rel = (g.NavWindow && !g.NavWindow->NavRectRel[g.NavLayer].IsInverted()) ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0);
|
||||
g.NavScoringRect = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : ImRect(0, 0, 0, 0);
|
||||
g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y);
|
||||
g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x);
|
||||
g.NavScoringRect.Max.x = g.NavScoringRect.Min.x;
|
||||
IM_ASSERT(!g.NavScoringRect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem().
|
||||
//GetForegroundDrawList()->AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG]
|
||||
// [DEBUG]
|
||||
g.NavScoringCount = 0;
|
||||
#if IMGUI_DEBUG_NAV_RECTS
|
||||
if (g.NavWindow)
|
||||
@ -10039,10 +9939,100 @@ static void ImGui::NavUpdateInitResult()
|
||||
}
|
||||
}
|
||||
|
||||
// Apply result from previous frame navigation directional move request
|
||||
static void ImGui::NavUpdateMoveResult()
|
||||
void ImGui::NavUpdateCreateMoveRequest()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiIO& io = g.IO;
|
||||
ImGuiWindow* window = g.NavWindow;
|
||||
|
||||
if (g.NavMoveRequestForwardToNextFrame)
|
||||
{
|
||||
// Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window)
|
||||
// (preserve most state, which were already set by the NavMoveRequestForward() function)
|
||||
IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);
|
||||
IM_ASSERT(g.NavMoveRequestFlags & ImGuiNavMoveFlags_Forwarded);
|
||||
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir);
|
||||
g.NavMoveRequestForwardToNextFrame = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Initiate directional inputs request
|
||||
g.NavMoveDir = ImGuiDir_None;
|
||||
g.NavMoveRequestFlags = ImGuiNavMoveFlags_None;
|
||||
if (window && !g.NavWindowingTarget && !(window->Flags & ImGuiWindowFlags_NoNavInputs))
|
||||
{
|
||||
const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat;
|
||||
if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && (IsNavInputTest(ImGuiNavInput_DpadLeft, read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_, read_mode))) { g.NavMoveDir = ImGuiDir_Left; }
|
||||
if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; }
|
||||
if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && (IsNavInputTest(ImGuiNavInput_DpadUp, read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_, read_mode))) { g.NavMoveDir = ImGuiDir_Up; }
|
||||
if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && (IsNavInputTest(ImGuiNavInput_DpadDown, read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_, read_mode))) { g.NavMoveDir = ImGuiDir_Down; }
|
||||
}
|
||||
g.NavMoveClipDir = g.NavMoveDir;
|
||||
}
|
||||
|
||||
// Update PageUp/PageDown/Home/End scroll
|
||||
// FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag?
|
||||
const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
|
||||
float nav_scoring_rect_offset_y = 0.0f;
|
||||
if (nav_keyboard_active)
|
||||
nav_scoring_rect_offset_y = NavUpdatePageUpPageDown();
|
||||
|
||||
// If we initiate a movement request and have no current NavId, we initiate a InitDefaultRequest that will be used as a fallback if the direction fails to find a match
|
||||
if (g.NavMoveDir != ImGuiDir_None)
|
||||
{
|
||||
IM_ASSERT(window != NULL);
|
||||
g.NavMoveRequest = true;
|
||||
g.NavMoveRequestKeyMods = io.KeyMods;
|
||||
g.NavMoveDirLast = g.NavMoveDir;
|
||||
g.NavMoveResultLocal.Clear();
|
||||
g.NavMoveResultLocalVisibleSet.Clear();
|
||||
g.NavMoveResultOther.Clear();
|
||||
}
|
||||
|
||||
// Moving with no reference triggers a init request
|
||||
if (g.NavMoveRequest && g.NavId == 0)
|
||||
{
|
||||
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer);
|
||||
g.NavInitRequest = g.NavInitRequestFromMove = true;
|
||||
g.NavInitResultId = 0;
|
||||
g.NavDisableHighlight = false;
|
||||
}
|
||||
|
||||
// When using gamepad, we project the reference nav bounding box into window visible area.
|
||||
// This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad every movements are relative
|
||||
// (can't focus a visible object like we can with the mouse).
|
||||
if (g.NavMoveRequest && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)
|
||||
{
|
||||
ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1));
|
||||
if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
|
||||
{
|
||||
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel\n");
|
||||
float pad = window->CalcFontSize() * 0.5f;
|
||||
window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intent of starting navigation from first fully visible item
|
||||
window->NavRectRel[g.NavLayer].ClipWithFull(window_rect_rel);
|
||||
g.NavId = g.NavFocusScopeId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items)
|
||||
g.NavScoringRect = ImRect();
|
||||
if (window)
|
||||
{
|
||||
ImRect nav_rect_rel = !window->NavRectRel[g.NavLayer].IsInverted() ? window->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0);
|
||||
g.NavScoringRect = ImRect(window->Pos + nav_rect_rel.Min, window->Pos + nav_rect_rel.Max);
|
||||
g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y);
|
||||
g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x);
|
||||
g.NavScoringRect.Max.x = g.NavScoringRect.Min.x;
|
||||
IM_ASSERT(!g.NavScoringRect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem().
|
||||
//GetForegroundDrawList()->AddRect(g.NavScoringRect.Min, g.NavScoringRect.Max, IM_COL32(255,200,0,255)); // [DEBUG]
|
||||
}
|
||||
}
|
||||
|
||||
// Apply result from previous frame navigation directional move request. Always called from NavUpdate()
|
||||
void ImGui::NavMoveRequestApplyResult()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
|
||||
if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
|
||||
{
|
||||
// In a situation when there is no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result)
|
||||
@ -10104,7 +10094,54 @@ static void ImGui::NavUpdateMoveResult()
|
||||
g.NavDisableMouseHover = g.NavMousePosDirty = true;
|
||||
}
|
||||
|
||||
// Process NavCancel input (to close a popup, get back to parent, clear focus)
|
||||
// FIXME: In order to support e.g. Escape to clear a selection we'll need:
|
||||
// - either to store the equivalent of ActiveIdUsingKeyInputMask for a FocusScope and test for it.
|
||||
// - either to move most/all of those tests to the epilogue/end functions of the scope they are dealing with (e.g. exit child window in EndChild()) or in EndFrame(), to allow an earlier intercept
|
||||
static void ImGui::NavUpdateCancelRequest()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (!IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed))
|
||||
return;
|
||||
|
||||
IMGUI_DEBUG_LOG_NAV("[nav] ImGuiNavInput_Cancel\n");
|
||||
if (g.ActiveId != 0)
|
||||
{
|
||||
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
|
||||
ImGuiWindow* child_window = g.NavWindow;
|
||||
ImGuiWindow* parent_window = g.NavWindow->ParentWindow;
|
||||
IM_ASSERT(child_window->ChildId != 0);
|
||||
ImRect child_rect = child_window->Rect();
|
||||
FocusWindow(parent_window);
|
||||
SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, ImRect(child_rect.Min - parent_window->Pos, child_rect.Max - parent_window->Pos));
|
||||
}
|
||||
else if (g.OpenPopupStack.Size > 0)
|
||||
{
|
||||
// Close open popup/menu
|
||||
if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
|
||||
ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
|
||||
if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow)))
|
||||
g.NavWindow->NavLastIds[0] = 0;
|
||||
g.NavId = g.NavFocusScopeId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle PageUp/PageDown/Home/End keys
|
||||
// FIXME-NAV: how to get Home/End to aim at the beginning/end of a 2D grid?
|
||||
static float ImGui::NavUpdatePageUpPageDown()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@ -10120,60 +10157,60 @@ static float ImGui::NavUpdatePageUpPageDown()
|
||||
const bool page_down_held = IsKeyDown(io.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown);
|
||||
const bool home_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home);
|
||||
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 (page_up_held == page_down_held && home_pressed == end_pressed) // Proceed if either (not both) are pressed, otherwise early out
|
||||
return 0.0f;
|
||||
|
||||
if (window->DC.NavLayersActiveMask == 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))
|
||||
SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
|
||||
else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
|
||||
SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
|
||||
else if (home_pressed)
|
||||
SetScrollY(window, 0.0f);
|
||||
else if (end_pressed)
|
||||
SetScrollY(window, window->ScrollMax.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
|
||||
const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
|
||||
float nav_scoring_rect_offset_y = 0.0f;
|
||||
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
|
||||
{
|
||||
// Fallback manual-scroll when window has no navigable item
|
||||
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
|
||||
SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
|
||||
else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
|
||||
SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
|
||||
else if (home_pressed)
|
||||
SetScrollY(window, 0.0f);
|
||||
else if (end_pressed)
|
||||
SetScrollY(window, window->ScrollMax.y);
|
||||
nav_scoring_rect_offset_y = -page_offset_y;
|
||||
g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item)
|
||||
g.NavMoveClipDir = ImGuiDir_Up;
|
||||
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
|
||||
}
|
||||
else
|
||||
else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
|
||||
{
|
||||
ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
|
||||
const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
|
||||
float nav_scoring_rect_offset_y = 0.0f;
|
||||
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
|
||||
{
|
||||
nav_scoring_rect_offset_y = -page_offset_y;
|
||||
g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item)
|
||||
g.NavMoveClipDir = ImGuiDir_Up;
|
||||
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
|
||||
}
|
||||
else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
|
||||
{
|
||||
nav_scoring_rect_offset_y = +page_offset_y;
|
||||
g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item)
|
||||
g.NavMoveClipDir = ImGuiDir_Down;
|
||||
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
|
||||
}
|
||||
else if (home_pressed)
|
||||
{
|
||||
// FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y
|
||||
// Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdge flag, we don't scroll immediately to avoid scrolling happening before nav result.
|
||||
// Preserve current horizontal position if we have any.
|
||||
nav_rect_rel.Min.y = nav_rect_rel.Max.y = -window->Scroll.y;
|
||||
if (nav_rect_rel.IsInverted())
|
||||
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
|
||||
g.NavMoveDir = ImGuiDir_Down;
|
||||
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
|
||||
}
|
||||
else if (end_pressed)
|
||||
{
|
||||
nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ScrollMax.y + window->SizeFull.y - window->Scroll.y;
|
||||
if (nav_rect_rel.IsInverted())
|
||||
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
|
||||
g.NavMoveDir = ImGuiDir_Up;
|
||||
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
|
||||
}
|
||||
return nav_scoring_rect_offset_y;
|
||||
nav_scoring_rect_offset_y = +page_offset_y;
|
||||
g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item)
|
||||
g.NavMoveClipDir = ImGuiDir_Down;
|
||||
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
|
||||
}
|
||||
else if (home_pressed)
|
||||
{
|
||||
// FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y
|
||||
// Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdge flag, we don't scroll immediately to avoid scrolling happening before nav result.
|
||||
// Preserve current horizontal position if we have any.
|
||||
nav_rect_rel.Min.y = nav_rect_rel.Max.y = -window->Scroll.y;
|
||||
if (nav_rect_rel.IsInverted())
|
||||
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
|
||||
g.NavMoveDir = ImGuiDir_Down;
|
||||
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
|
||||
}
|
||||
else if (end_pressed)
|
||||
{
|
||||
nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ScrollMax.y + window->SizeFull.y - window->Scroll.y;
|
||||
if (nav_rect_rel.IsInverted())
|
||||
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
|
||||
g.NavMoveDir = ImGuiDir_Up;
|
||||
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
|
||||
}
|
||||
return nav_scoring_rect_offset_y;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
@ -10187,13 +10224,14 @@ static void ImGui::NavEndFrame()
|
||||
NavUpdateWindowingOverlay();
|
||||
|
||||
// Perform wrap-around in menus
|
||||
ImGuiWindow* window = g.NavWrapRequestWindow;
|
||||
ImGuiNavMoveFlags move_flags = g.NavWrapRequestFlags;
|
||||
if (window != NULL && g.NavWindow == window && NavMoveRequestButNoResultYet() && g.NavMoveRequestForward == ImGuiNavForward_None && g.NavLayer == ImGuiNavLayer_Main)
|
||||
// FIXME-NAV: Wrap (not Loop) support could be handled by the scoring function and then WrapX would function without an extra frame.
|
||||
ImGuiWindow* window = g.NavWindow;
|
||||
const ImGuiNavMoveFlags move_flags = g.NavMoveRequestFlags;
|
||||
const ImGuiNavMoveFlags wanted_flags = ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY;
|
||||
if (window && NavMoveRequestButNoResultYet() && (g.NavMoveRequestFlags & wanted_flags) && (g.NavMoveRequestFlags & ImGuiNavMoveFlags_Forwarded) == 0)
|
||||
{
|
||||
IM_ASSERT(move_flags != 0); // No points calling this with no wrapping
|
||||
ImRect bb_rel = window->NavRectRel[0];
|
||||
|
||||
bool do_forward = false;
|
||||
ImRect bb_rel = window->NavRectRel[g.NavLayer];
|
||||
ImGuiDir clip_dir = g.NavMoveDir;
|
||||
if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
|
||||
{
|
||||
@ -10204,7 +10242,7 @@ static void ImGui::NavEndFrame()
|
||||
bb_rel.TranslateY(-bb_rel.GetHeight());
|
||||
clip_dir = ImGuiDir_Up;
|
||||
}
|
||||
NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
|
||||
do_forward = true;
|
||||
}
|
||||
if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
|
||||
{
|
||||
@ -10214,7 +10252,7 @@ static void ImGui::NavEndFrame()
|
||||
bb_rel.TranslateY(+bb_rel.GetHeight());
|
||||
clip_dir = ImGuiDir_Down;
|
||||
}
|
||||
NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
|
||||
do_forward = true;
|
||||
}
|
||||
if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
|
||||
{
|
||||
@ -10225,7 +10263,7 @@ static void ImGui::NavEndFrame()
|
||||
bb_rel.TranslateX(-bb_rel.GetWidth());
|
||||
clip_dir = ImGuiDir_Left;
|
||||
}
|
||||
NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
|
||||
do_forward = true;
|
||||
}
|
||||
if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
|
||||
{
|
||||
@ -10235,7 +10273,12 @@ static void ImGui::NavEndFrame()
|
||||
bb_rel.TranslateX(+bb_rel.GetWidth());
|
||||
clip_dir = ImGuiDir_Right;
|
||||
}
|
||||
NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
|
||||
do_forward = true;
|
||||
}
|
||||
if (do_forward)
|
||||
{
|
||||
window->NavRectRel[g.NavLayer] = bb_rel;
|
||||
NavMoveRequestForward(g.NavMoveDir, clip_dir, move_flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user