mirror of
https://github.com/Drezil/imgui.git
synced 2025-07-13 00:09:55 +02:00
Merge branch 'master' into docking
# Conflicts: # imgui.cpp
This commit is contained in:
400
imgui.cpp
400
imgui.cpp
@ -83,6 +83,7 @@ CODE
|
||||
// [SECTION] DOCKING
|
||||
// [SECTION] PLATFORM DEPENDENT HELPERS
|
||||
// [SECTION] METRICS/DEBUGGER WINDOW
|
||||
// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL)
|
||||
|
||||
*/
|
||||
|
||||
@ -937,16 +938,17 @@ static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window);
|
||||
static void NavRestoreLayer(ImGuiNavLayer layer);
|
||||
static int FindWindowFocusIndex(ImGuiWindow* window);
|
||||
|
||||
// Error Checking
|
||||
// Error Checking and Debug Tools
|
||||
static void ErrorCheckNewFrameSanityChecks();
|
||||
static void ErrorCheckEndFrameSanityChecks();
|
||||
static void UpdateDebugToolItemPicker();
|
||||
static void UpdateDebugToolStackQueries();
|
||||
|
||||
// Misc
|
||||
static void UpdateSettings();
|
||||
static void UpdateMouseInputs();
|
||||
static void UpdateMouseWheel();
|
||||
static void UpdateTabFocus();
|
||||
static void UpdateDebugToolItemPicker();
|
||||
static bool UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect);
|
||||
static void RenderWindowOuterBorders(ImGuiWindow* window);
|
||||
static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size);
|
||||
@ -3013,10 +3015,9 @@ ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
|
||||
ImGuiID seed = IDStack.back();
|
||||
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
|
||||
ImGui::KeepAliveID(id);
|
||||
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
||||
ImGuiContext& g = *GImGui;
|
||||
IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end);
|
||||
#endif
|
||||
if (g.DebugHookIdInfo == id)
|
||||
ImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);
|
||||
return id;
|
||||
}
|
||||
|
||||
@ -3025,10 +3026,9 @@ ImGuiID ImGuiWindow::GetID(const void* ptr)
|
||||
ImGuiID seed = IDStack.back();
|
||||
ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
|
||||
ImGui::KeepAliveID(id);
|
||||
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
||||
ImGuiContext& g = *GImGui;
|
||||
IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr);
|
||||
#endif
|
||||
if (g.DebugHookIdInfo == id)
|
||||
ImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL);
|
||||
return id;
|
||||
}
|
||||
|
||||
@ -3037,10 +3037,9 @@ ImGuiID ImGuiWindow::GetID(int n)
|
||||
ImGuiID seed = IDStack.back();
|
||||
ImGuiID id = ImHashData(&n, sizeof(n), seed);
|
||||
ImGui::KeepAliveID(id);
|
||||
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
||||
ImGuiContext& g = *GImGui;
|
||||
IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n);
|
||||
#endif
|
||||
if (g.DebugHookIdInfo == id)
|
||||
ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);
|
||||
return id;
|
||||
}
|
||||
|
||||
@ -3048,10 +3047,9 @@ ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
|
||||
{
|
||||
ImGuiID seed = IDStack.back();
|
||||
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
|
||||
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
||||
ImGuiContext& g = *GImGui;
|
||||
IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end);
|
||||
#endif
|
||||
if (g.DebugHookIdInfo == id)
|
||||
ImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);
|
||||
return id;
|
||||
}
|
||||
|
||||
@ -3059,10 +3057,9 @@ ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr)
|
||||
{
|
||||
ImGuiID seed = IDStack.back();
|
||||
ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
|
||||
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
||||
ImGuiContext& g = *GImGui;
|
||||
IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr);
|
||||
#endif
|
||||
if (g.DebugHookIdInfo == id)
|
||||
ImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL);
|
||||
return id;
|
||||
}
|
||||
|
||||
@ -3070,10 +3067,9 @@ ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n)
|
||||
{
|
||||
ImGuiID seed = IDStack.back();
|
||||
ImGuiID id = ImHashData(&n, sizeof(n), seed);
|
||||
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
||||
ImGuiContext& g = *GImGui;
|
||||
IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n);
|
||||
#endif
|
||||
if (g.DebugHookIdInfo == id)
|
||||
ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);
|
||||
return id;
|
||||
}
|
||||
|
||||
@ -3251,7 +3247,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
|
||||
ImGuiItemStatusFlags status_flags = g.LastItemData.StatusFlags;
|
||||
if (!(status_flags & ImGuiItemStatusFlags_HoveredRect))
|
||||
return false;
|
||||
IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0); // Flags not supported by this function
|
||||
IM_ASSERT((flags & (ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy | ImGuiHoveredFlags_DockHierarchy)) == 0); // Flags not supported by this function
|
||||
|
||||
// Test if we are hovering the right window (our window could be behind another window)
|
||||
// [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851)
|
||||
@ -3380,7 +3376,7 @@ void ImGui::ItemInputable(ImGuiWindow* window, ImGuiID id)
|
||||
|
||||
// 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)
|
||||
if (g.ActiveId == id && g.TabFocusPressed && !IsActiveIdUsingKey(ImGuiKey_Tab) && g.TabFocusRequestNextWindow == NULL)
|
||||
if (g.ActiveId == id && g.TabFocusPressed && g.TabFocusRequestNextWindow == NULL)
|
||||
{
|
||||
g.TabFocusRequestNextWindow = window;
|
||||
g.TabFocusRequestNextCounterTabStop = window->DC.FocusCounterTabStop + (g.IO.KeyShift ? (is_tab_stop ? -1 : 0) : +1); // Modulo on index will be applied at the end of frame once we've got the total counter of items.
|
||||
@ -3981,7 +3977,7 @@ void ImGui::UpdateTabFocus()
|
||||
ImGuiContext& g = *GImGui;
|
||||
|
||||
// Pressing TAB activate widget focus
|
||||
g.TabFocusPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab));
|
||||
g.TabFocusPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && !IsActiveIdUsingKey(ImGuiKey_Tab));
|
||||
if (g.ActiveId == 0 && g.TabFocusPressed)
|
||||
{
|
||||
// - This path is only taken when no widget are active/tabbed-into yet.
|
||||
@ -4314,8 +4310,9 @@ void ImGui::NewFrame()
|
||||
// Docking
|
||||
DockContextNewFrameUpdateDocking(&g);
|
||||
|
||||
// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.
|
||||
// [DEBUG] Update debug features
|
||||
UpdateDebugToolItemPicker();
|
||||
UpdateDebugToolStackQueries();
|
||||
|
||||
// Create implicit/fallback window - which we will only render it if the user has added something to it.
|
||||
// We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags.
|
||||
@ -4328,31 +4325,6 @@ void ImGui::NewFrame()
|
||||
CallContextHooks(&g, ImGuiContextHookType_NewFramePost);
|
||||
}
|
||||
|
||||
// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.
|
||||
void ImGui::UpdateDebugToolItemPicker()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.DebugItemPickerBreakId = 0;
|
||||
if (g.DebugItemPickerActive)
|
||||
{
|
||||
const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
|
||||
SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
if (IsKeyPressedMap(ImGuiKey_Escape))
|
||||
g.DebugItemPickerActive = false;
|
||||
if (IsMouseClicked(0) && hovered_id)
|
||||
{
|
||||
g.DebugItemPickerBreakId = hovered_id;
|
||||
g.DebugItemPickerActive = false;
|
||||
}
|
||||
SetNextWindowBgAlpha(0.60f);
|
||||
BeginTooltip();
|
||||
Text("HoveredId: 0x%08X", hovered_id);
|
||||
Text("Press ESC to abort picking.");
|
||||
TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!");
|
||||
EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui::Initialize(ImGuiContext* context)
|
||||
{
|
||||
ImGuiContext& g = *context;
|
||||
@ -7312,7 +7284,7 @@ bool ImGui::IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_b
|
||||
|
||||
bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags)
|
||||
{
|
||||
IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0); // Flags not supported by this function
|
||||
IM_ASSERT((flags & (ImGuiHoveredFlags_AllowWhenOverlapped | ImGuiHoveredFlags_AllowWhenDisabled)) == 0); // Flags not supported by this function
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* ref_window = g.HoveredWindow;
|
||||
ImGuiWindow* cur_window = g.CurrentWindow;
|
||||
@ -7779,6 +7751,8 @@ void ImGui::PushOverrideID(ImGuiID id)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
if (g.DebugHookIdInfo == id)
|
||||
DebugHookIdInfo(id, ImGuiDataType_ID, NULL, NULL);
|
||||
window->IDStack.push_back(id);
|
||||
}
|
||||
|
||||
@ -7788,11 +7762,10 @@ void ImGui::PushOverrideID(ImGuiID id)
|
||||
ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed)
|
||||
{
|
||||
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
|
||||
ImGui::KeepAliveID(id);
|
||||
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
||||
KeepAliveID(id);
|
||||
ImGuiContext& g = *GImGui;
|
||||
IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end);
|
||||
#endif
|
||||
if (g.DebugHookIdInfo == id)
|
||||
DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);
|
||||
return id;
|
||||
}
|
||||
|
||||
@ -8643,32 +8616,80 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window)
|
||||
return scroll;
|
||||
}
|
||||
|
||||
void ImGui::ScrollToItem(ImGuiScrollFlags flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
ScrollToRectEx(window, g.LastItemData.NavRect, flags);
|
||||
}
|
||||
|
||||
void ImGui::ScrollToRect(ImGuiWindow* window, const ImRect& item_rect, ImGuiScrollFlags flags)
|
||||
{
|
||||
ScrollToRectEx(window, item_rect, flags);
|
||||
}
|
||||
|
||||
// Scroll to keep newly navigated item fully into view
|
||||
ImVec2 ImGui::ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect)
|
||||
ImVec2 ImGui::ScrollToRectEx(ImGuiWindow* window, const ImRect& item_rect, ImGuiScrollFlags flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImRect window_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1));
|
||||
//GetForegroundDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG]
|
||||
|
||||
ImVec2 delta_scroll;
|
||||
if (!window_rect.Contains(item_rect))
|
||||
{
|
||||
if (window->ScrollbarX && item_rect.Min.x < window_rect.Min.x)
|
||||
SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x - g.Style.ItemSpacing.x, 0.0f);
|
||||
else if (window->ScrollbarX && item_rect.Max.x >= window_rect.Max.x)
|
||||
SetScrollFromPosX(window, item_rect.Max.x - window->Pos.x + g.Style.ItemSpacing.x, 1.0f);
|
||||
if (item_rect.Min.y < window_rect.Min.y)
|
||||
SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y - g.Style.ItemSpacing.y, 0.0f);
|
||||
else if (item_rect.Max.y >= window_rect.Max.y)
|
||||
SetScrollFromPosY(window, item_rect.Max.y - window->Pos.y + g.Style.ItemSpacing.y, 1.0f);
|
||||
// Check that only one behavior is selected per axis
|
||||
IM_ASSERT((flags & ImGuiScrollFlags_MaskX_) == 0 || ImIsPowerOfTwo(flags & ImGuiScrollFlags_MaskX_));
|
||||
IM_ASSERT((flags & ImGuiScrollFlags_MaskY_) == 0 || ImIsPowerOfTwo(flags & ImGuiScrollFlags_MaskY_));
|
||||
|
||||
ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window);
|
||||
delta_scroll = next_scroll - window->Scroll;
|
||||
// Defaults
|
||||
ImGuiScrollFlags in_flags = flags;
|
||||
if ((flags & ImGuiScrollFlags_MaskX_) == 0 && window->ScrollbarX)
|
||||
flags |= ImGuiScrollFlags_KeepVisibleEdgeX;
|
||||
if ((flags & ImGuiScrollFlags_MaskY_) == 0)
|
||||
flags |= window->Appearing ? ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeY;
|
||||
|
||||
const bool fully_visible_x = item_rect.Min.x >= window_rect.Min.x && item_rect.Max.x <= window_rect.Max.x;
|
||||
const bool fully_visible_y = item_rect.Min.y >= window_rect.Min.y && item_rect.Max.y <= window_rect.Max.y;
|
||||
const bool can_be_fully_visible_x = item_rect.GetWidth() <= window_rect.GetWidth();
|
||||
const bool can_be_fully_visible_y = item_rect.GetHeight() <= window_rect.GetHeight();
|
||||
|
||||
if ((flags & ImGuiScrollFlags_KeepVisibleEdgeX) && !fully_visible_x)
|
||||
{
|
||||
if (item_rect.Min.x < window_rect.Min.x || !can_be_fully_visible_x)
|
||||
SetScrollFromPosX(window, item_rect.Min.x - g.Style.ItemSpacing.x - window->Pos.x, 0.0f);
|
||||
else if (item_rect.Max.x >= window_rect.Max.x)
|
||||
SetScrollFromPosX(window, item_rect.Max.x + g.Style.ItemSpacing.x - window->Pos.x, 1.0f);
|
||||
}
|
||||
else if (((flags & ImGuiScrollFlags_KeepVisibleCenterX) && !fully_visible_x) || (flags & ImGuiScrollFlags_AlwaysCenterX))
|
||||
{
|
||||
float target_x = can_be_fully_visible_x ? ImFloor((item_rect.Min.x + item_rect.Max.x - window->InnerRect.GetWidth()) * 0.5f) : item_rect.Min.x;
|
||||
SetScrollFromPosX(window, target_x - window->Pos.x, 0.0f);
|
||||
}
|
||||
|
||||
if ((flags & ImGuiScrollFlags_KeepVisibleEdgeY) && !fully_visible_y)
|
||||
{
|
||||
if (item_rect.Min.y < window_rect.Min.y || !can_be_fully_visible_y)
|
||||
SetScrollFromPosY(window, item_rect.Min.y - g.Style.ItemSpacing.y - window->Pos.y, 0.0f);
|
||||
else if (item_rect.Max.y >= window_rect.Max.y)
|
||||
SetScrollFromPosY(window, item_rect.Max.y + g.Style.ItemSpacing.y - window->Pos.y, 1.0f);
|
||||
}
|
||||
else if (((flags & ImGuiScrollFlags_KeepVisibleCenterY) && !fully_visible_y) || (flags & ImGuiScrollFlags_AlwaysCenterY))
|
||||
{
|
||||
float target_y = can_be_fully_visible_y ? ImFloor((item_rect.Min.y + item_rect.Max.y - window->InnerRect.GetHeight()) * 0.5f) : item_rect.Min.y;
|
||||
SetScrollFromPosY(window, target_y - window->Pos.y, 0.0f);
|
||||
}
|
||||
|
||||
ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window);
|
||||
ImVec2 delta_scroll = next_scroll - window->Scroll;
|
||||
|
||||
// Also scroll parent window to keep us into view if necessary
|
||||
if (window->Flags & ImGuiWindowFlags_ChildWindow)
|
||||
delta_scroll += ScrollToBringRectIntoView(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll));
|
||||
if (!(flags & ImGuiScrollFlags_NoScrollParent) && (window->Flags & ImGuiWindowFlags_ChildWindow))
|
||||
{
|
||||
// FIXME-SCROLL: May be an option?
|
||||
if ((in_flags & (ImGuiScrollFlags_AlwaysCenterX | ImGuiScrollFlags_KeepVisibleCenterX)) != 0)
|
||||
in_flags = (in_flags & ~ImGuiScrollFlags_MaskX_) | ImGuiScrollFlags_KeepVisibleEdgeX;
|
||||
if ((in_flags & (ImGuiScrollFlags_AlwaysCenterY | ImGuiScrollFlags_KeepVisibleCenterY)) != 0)
|
||||
in_flags = (in_flags & ~ImGuiScrollFlags_MaskY_) | ImGuiScrollFlags_KeepVisibleEdgeY;
|
||||
delta_scroll += ScrollToRectEx(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll), in_flags);
|
||||
}
|
||||
|
||||
return delta_scroll;
|
||||
}
|
||||
@ -9671,7 +9692,7 @@ bool ImGui::NavMoveRequestButNoResultYet()
|
||||
}
|
||||
|
||||
// FIXME: ScoringRect is not set
|
||||
void ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags)
|
||||
void ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(g.NavWindow != NULL);
|
||||
@ -9680,6 +9701,7 @@ void ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavM
|
||||
g.NavMoveDirForDebug = move_dir;
|
||||
g.NavMoveClipDir = clip_dir;
|
||||
g.NavMoveFlags = move_flags;
|
||||
g.NavMoveScrollFlags = scroll_flags;
|
||||
g.NavMoveForwardToNextFrame = false;
|
||||
g.NavMoveKeyMods = g.IO.KeyMods;
|
||||
g.NavMoveResultLocal.Clear();
|
||||
@ -9696,7 +9718,7 @@ void ImGui::NavMoveRequestCancel()
|
||||
}
|
||||
|
||||
// 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)
|
||||
void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(g.NavMoveForwardToNextFrame == false);
|
||||
@ -9705,6 +9727,7 @@ void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNav
|
||||
g.NavMoveDir = move_dir;
|
||||
g.NavMoveClipDir = clip_dir;
|
||||
g.NavMoveFlags = move_flags | ImGuiNavMoveFlags_Forwarded;
|
||||
g.NavMoveScrollFlags = scroll_flags;
|
||||
}
|
||||
|
||||
// Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire
|
||||
@ -10071,6 +10094,7 @@ void ImGui::NavUpdateCreateMoveRequest()
|
||||
// Initiate directional inputs request
|
||||
g.NavMoveDir = ImGuiDir_None;
|
||||
g.NavMoveFlags = ImGuiNavMoveFlags_None;
|
||||
g.NavMoveScrollFlags = ImGuiScrollFlags_None;
|
||||
if (window && !g.NavWindowingTarget && !(window->Flags & ImGuiWindowFlags_NoNavInputs))
|
||||
{
|
||||
const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat;
|
||||
@ -10103,7 +10127,7 @@ void ImGui::NavUpdateCreateMoveRequest()
|
||||
// Submit
|
||||
g.NavMoveForwardToNextFrame = false;
|
||||
if (g.NavMoveDir != ImGuiDir_None)
|
||||
NavMoveRequestSubmit(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags);
|
||||
NavMoveRequestSubmit(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags);
|
||||
|
||||
// Moving with no reference triggers a init request (will be used as a fallback if the direction fails to find a match)
|
||||
if (g.NavMoveSubmitted && g.NavId == 0)
|
||||
@ -10183,8 +10207,9 @@ void ImGui::NavMoveRequestApplyResult()
|
||||
if (g.NavLayer == ImGuiNavLayer_Main)
|
||||
{
|
||||
ImVec2 delta_scroll;
|
||||
if (g.NavMoveFlags & ImGuiNavMoveFlags_ScrollToEdge)
|
||||
if (g.NavMoveFlags & ImGuiNavMoveFlags_ScrollToEdgeY)
|
||||
{
|
||||
// FIXME: Should remove this
|
||||
float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f;
|
||||
delta_scroll.y = result->Window->Scroll.y - scroll_target;
|
||||
SetScrollY(result->Window, scroll_target);
|
||||
@ -10192,7 +10217,7 @@ void ImGui::NavMoveRequestApplyResult()
|
||||
else
|
||||
{
|
||||
ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos);
|
||||
delta_scroll = ScrollToBringRectIntoView(result->Window, rect_abs);
|
||||
delta_scroll = ScrollToRectEx(result->Window, rect_abs, g.NavMoveScrollFlags);
|
||||
}
|
||||
|
||||
// Offset our result position so mouse position can be applied immediately after in NavUpdate()
|
||||
@ -10319,13 +10344,13 @@ static float ImGui::NavUpdatePageUpPageDown()
|
||||
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.
|
||||
// Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdgeY 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.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
|
||||
g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdgeY;
|
||||
// FIXME-NAV: MoveClipDir left to _None, intentional?
|
||||
}
|
||||
else if (end_pressed)
|
||||
@ -10334,7 +10359,7 @@ static float ImGui::NavUpdatePageUpPageDown()
|
||||
if (nav_rect_rel.IsInverted())
|
||||
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
|
||||
g.NavMoveDir = ImGuiDir_Up;
|
||||
g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
|
||||
g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdgeY;
|
||||
// FIXME-NAV: MoveClipDir left to _None, intentional?
|
||||
}
|
||||
return nav_scoring_rect_offset_y;
|
||||
@ -10405,7 +10430,7 @@ static void ImGui::NavEndFrame()
|
||||
if (do_forward)
|
||||
{
|
||||
window->NavRectRel[g.NavLayer] = bb_rel;
|
||||
NavMoveRequestForward(g.NavMoveDir, clip_dir, move_flags);
|
||||
NavMoveRequestForward(g.NavMoveDir, clip_dir, move_flags, g.NavMoveScrollFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -16543,22 +16568,23 @@ namespace ImGui { void ShowFontAtlas(ImFontAtlas* atlas); }
|
||||
|
||||
void ImGui::ShowMetricsWindow(bool* p_open)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiIO& io = g.IO;
|
||||
ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig;
|
||||
if (cfg->ShowStackTool)
|
||||
ShowStackToolWindow(&cfg->ShowStackTool);
|
||||
|
||||
if (!Begin("Dear ImGui Metrics/Debugger", p_open))
|
||||
{
|
||||
End();
|
||||
return;
|
||||
}
|
||||
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiIO& io = g.IO;
|
||||
ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig;
|
||||
|
||||
// Basic info
|
||||
Text("Dear ImGui %s", GetVersion());
|
||||
Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
|
||||
Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3);
|
||||
Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows);
|
||||
Text("%d active allocations", io.MetricsActiveAllocations);
|
||||
Text("%d visible windows, %d active allocations", io.MetricsRenderWindows, io.MetricsActiveAllocations);
|
||||
//SameLine(); if (SmallButton("GC")) { g.GcCompactAll = true; }
|
||||
|
||||
Separator();
|
||||
@ -16612,11 +16638,10 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
||||
// Tools
|
||||
if (TreeNode("Tools"))
|
||||
{
|
||||
// The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted.
|
||||
if (Button("Item Picker.."))
|
||||
DebugStartItemPicker();
|
||||
// Stack Tool is your best friend!
|
||||
Checkbox("Show stack tool", &cfg->ShowStackTool);
|
||||
SameLine();
|
||||
MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash.");
|
||||
MetricsHelpMarker("You can also call ImGui::ShowStackToolWindow() from your code.");
|
||||
|
||||
Checkbox("Show windows begin order", &cfg->ShowWindowsBeginOrder);
|
||||
Checkbox("Show windows rectangles", &cfg->ShowWindowsRects);
|
||||
@ -16634,8 +16659,6 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
||||
}
|
||||
Unindent();
|
||||
}
|
||||
Checkbox("Show ImDrawCmd mesh when hovering", &cfg->ShowDrawCmdMesh);
|
||||
Checkbox("Show ImDrawCmd bounding boxes when hovering", &cfg->ShowDrawCmdBoundingBoxes);
|
||||
|
||||
Checkbox("Show tables rectangles", &cfg->ShowTablesRects);
|
||||
SameLine();
|
||||
@ -16682,6 +16705,12 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
||||
}
|
||||
}
|
||||
|
||||
// The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted.
|
||||
if (Button("Item Picker.."))
|
||||
DebugStartItemPicker();
|
||||
SameLine();
|
||||
MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash.");
|
||||
|
||||
TreePop();
|
||||
}
|
||||
|
||||
@ -16695,6 +16724,8 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
||||
drawlist_count += g.Viewports[viewport_i]->DrawDataBuilder.GetDrawListCount();
|
||||
if (TreeNode("DrawLists", "DrawLists (%d)", drawlist_count))
|
||||
{
|
||||
Checkbox("Show ImDrawCmd mesh when hovering", &cfg->ShowDrawCmdMesh);
|
||||
Checkbox("Show ImDrawCmd bounding boxes when hovering", &cfg->ShowDrawCmdBoundingBoxes);
|
||||
for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++)
|
||||
{
|
||||
ImGuiViewportP* viewport = g.Viewports[viewport_i];
|
||||
@ -17508,6 +17539,186 @@ void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>* windows, const char* la
|
||||
TreePop();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.
|
||||
void ImGui::UpdateDebugToolItemPicker()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.DebugItemPickerBreakId = 0;
|
||||
if (!g.DebugItemPickerActive)
|
||||
return;
|
||||
|
||||
const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
|
||||
SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
if (IsKeyPressedMap(ImGuiKey_Escape))
|
||||
g.DebugItemPickerActive = false;
|
||||
if (IsMouseClicked(0) && hovered_id)
|
||||
{
|
||||
g.DebugItemPickerBreakId = hovered_id;
|
||||
g.DebugItemPickerActive = false;
|
||||
}
|
||||
SetNextWindowBgAlpha(0.60f);
|
||||
BeginTooltip();
|
||||
Text("HoveredId: 0x%08X", hovered_id);
|
||||
Text("Press ESC to abort picking.");
|
||||
TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!");
|
||||
EndTooltip();
|
||||
}
|
||||
|
||||
// [DEBUG] Stack Tool: update queries. Called by NewFrame()
|
||||
void ImGui::UpdateDebugToolStackQueries()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiStackTool* tool = &g.DebugStackTool;
|
||||
|
||||
// Clear hook when stack tool is not visible
|
||||
g.DebugHookIdInfo = 0;
|
||||
if (g.FrameCount != tool->LastActiveFrame + 1)
|
||||
return;
|
||||
|
||||
// Update queries. The steps are: -1: query Stack, >= 0: query each stack item
|
||||
// We can only perform 1 ID Info query every frame. This is designed so the GetID() tests are cheap and constant-time
|
||||
const ImGuiID query_id = g.ActiveId ? g.ActiveId : g.HoveredIdPreviousFrame;
|
||||
if (tool->QueryId != query_id)
|
||||
{
|
||||
tool->QueryId = query_id;
|
||||
tool->StackLevel = -1;
|
||||
tool->Results.resize(0);
|
||||
}
|
||||
if (query_id == 0)
|
||||
return;
|
||||
|
||||
// Advance to next stack level when we got our result, or after 2 frames (in case we never get a result)
|
||||
int stack_level = tool->StackLevel;
|
||||
if (stack_level >= 0 && stack_level < tool->Results.Size)
|
||||
if (tool->Results[stack_level].QuerySuccess || tool->Results[stack_level].QueryFrameCount > 2)
|
||||
tool->StackLevel++;
|
||||
|
||||
// Update hook
|
||||
stack_level = tool->StackLevel;
|
||||
if (stack_level == -1)
|
||||
g.DebugHookIdInfo = query_id;
|
||||
if (stack_level >= 0 && stack_level < tool->Results.Size)
|
||||
{
|
||||
g.DebugHookIdInfo = tool->Results[stack_level].ID;
|
||||
tool->Results[stack_level].QueryFrameCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// [DEBUG] Stack tool: hooks called by GetID() family functions
|
||||
void ImGui::DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
ImGuiStackTool* tool = &g.DebugStackTool;
|
||||
|
||||
// Step 0: stack query
|
||||
// This assume that the ID was computed with the current ID stack, which tends to be the case for our widget.
|
||||
if (tool->StackLevel == -1)
|
||||
{
|
||||
tool->StackLevel++;
|
||||
tool->Results.resize(window->IDStack.Size + 1, ImGuiStackLevelInfo());
|
||||
for (int n = 0; n < window->IDStack.Size + 1; n++)
|
||||
tool->Results[n].ID = (n < window->IDStack.Size) ? window->IDStack[n] : id;
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 1+: query for individual level
|
||||
IM_ASSERT(tool->StackLevel >= 0);
|
||||
if (tool->StackLevel != window->IDStack.Size)
|
||||
return;
|
||||
ImGuiStackLevelInfo* info = &tool->Results[tool->StackLevel];
|
||||
IM_ASSERT(info->ID == id && info->QueryFrameCount > 0);
|
||||
|
||||
int data_len;
|
||||
switch (data_type)
|
||||
{
|
||||
case ImGuiDataType_S32:
|
||||
ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%d", (int)(intptr_t)data_id);
|
||||
break;
|
||||
case ImGuiDataType_String:
|
||||
data_len = data_id_end ? (int)((const char*)data_id_end - (const char*)data_id) : (int)strlen((const char*)data_id);
|
||||
ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "\"%.*s\"", data_len, (const char*)data_id);
|
||||
break;
|
||||
case ImGuiDataType_Pointer:
|
||||
ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "(void*)0x%p", data_id);
|
||||
break;
|
||||
case ImGuiDataType_ID:
|
||||
if (info->Desc[0] == 0) // PushOverrideID() is often used to avoid hashing twice, which would lead to 2 calls to DebugHookIdInfo(). We prioritize the first one.
|
||||
ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "0x%08X [override]", id);
|
||||
break;
|
||||
default:
|
||||
IM_ASSERT(0);
|
||||
}
|
||||
info->QuerySuccess = true;
|
||||
}
|
||||
|
||||
// Stack Tool: Display UI
|
||||
void ImGui::ShowStackToolWindow(bool* p_open)
|
||||
{
|
||||
if (!Begin("Dear ImGui Stack Tool", p_open) || GetCurrentWindow()->BeginCount > 1)
|
||||
{
|
||||
End();
|
||||
return;
|
||||
}
|
||||
|
||||
// Display hovered/active status
|
||||
ImGuiContext& g = *GImGui;
|
||||
const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
|
||||
const ImGuiID active_id = g.ActiveId;
|
||||
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
||||
Text("HoveredId: 0x%08X (\"%s\"), ActiveId: 0x%08X (\"%s\")", hovered_id, hovered_id ? ImGuiTestEngine_FindItemDebugLabel(&g, hovered_id) : "", active_id, active_id ? ImGuiTestEngine_FindItemDebugLabel(&g, active_id) : "");
|
||||
#else
|
||||
Text("HoveredId: 0x%08X, ActiveId: 0x%08X", hovered_id, active_id);
|
||||
#endif
|
||||
SameLine();
|
||||
MetricsHelpMarker("Hover an item with the mouse to display elements of the ID Stack leading to the item's final ID.\nEach level of the stack correspond to a PushID() call.\nAll levels of the stack are hashed together to make the final ID of a widget (ID displayed at the bottom level of the stack).\nRead FAQ entry about the ID stack for details.");
|
||||
|
||||
// Display decorated stack
|
||||
ImGuiStackTool* tool = &g.DebugStackTool;
|
||||
tool->LastActiveFrame = g.FrameCount;
|
||||
if (tool->Results.Size > 0 && BeginTable("##table", 3, ImGuiTableFlags_Borders))
|
||||
{
|
||||
const float id_width = CalcTextSize("0xDDDDDDDD").x;
|
||||
TableSetupColumn("Seed", ImGuiTableColumnFlags_WidthFixed, id_width);
|
||||
TableSetupColumn("PushID", ImGuiTableColumnFlags_WidthStretch);
|
||||
TableSetupColumn("Result", ImGuiTableColumnFlags_WidthFixed, id_width);
|
||||
TableHeadersRow();
|
||||
for (int n = 0; n < tool->Results.Size; n++)
|
||||
{
|
||||
ImGuiStackLevelInfo* info = &tool->Results[n];
|
||||
TableNextColumn();
|
||||
Text("0x%08X", (n > 0) ? tool->Results[n - 1].ID : 0);
|
||||
|
||||
TableNextColumn();
|
||||
ImGuiWindow* window = (info->Desc[0] == 0 && n == 0) ? FindWindowByID(info->ID) : NULL;
|
||||
if (window) // Source: window name (because the root ID don't call GetID() and so doesn't get hooked)
|
||||
Text("\"%s\" [window]", window->Name);
|
||||
else if (info->QuerySuccess) // Source: GetID() hooks (prioritize over ItemInfo() because we frequently use patterns like: PushID(str), Button("") where they both have same id)
|
||||
TextUnformatted(info->Desc);
|
||||
else if (tool->StackLevel >= tool->Results.Size) // Only start using fallback below when all queries are done, so during queries we don't flickering ??? markers.
|
||||
{
|
||||
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
||||
if (const char* label = ImGuiTestEngine_FindItemDebugLabel(&g, info->ID)) // Source: ImGuiTestEngine's ItemInfo()
|
||||
Text("??? \"%s\"", label);
|
||||
else
|
||||
#endif
|
||||
TextUnformatted("???");
|
||||
}
|
||||
|
||||
TableNextColumn();
|
||||
Text("0x%08X", info->ID);
|
||||
if (n == tool->Results.Size - 1)
|
||||
TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_Header));
|
||||
}
|
||||
EndTable();
|
||||
}
|
||||
End();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void ImGui::ShowMetricsWindow(bool*) {}
|
||||
@ -17523,7 +17734,12 @@ void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings*) {}
|
||||
void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>*, const char*) {}
|
||||
void ImGui::DebugNodeViewport(ImGuiViewportP*) {}
|
||||
|
||||
#endif
|
||||
void ImGui::ShowStackToolWindow(bool*) {}
|
||||
void ImGui::DebugHookIdInfo(ImGuiID, ImGuiDataType, const void*, const void*) {}
|
||||
void ImGui::UpdateDebugToolItemPicker() {}
|
||||
void ImGui::UpdateDebugToolStackQueries() {}
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE_METRICS_WINDOW
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
Reference in New Issue
Block a user