1
0
Fork 0
mirror of https://github.com/ocornut/imgui.git synced 2026-02-03 03:50:06 +00:00

Merge branch 'master' into docking

This commit is contained in:
ocornut 2024-06-03 19:08:37 +02:00
commit fdc084f532
12 changed files with 211 additions and 137 deletions

188
imgui.cpp
View file

@ -4336,7 +4336,7 @@ bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id)
ImGuiWindow* window = g.CurrentWindow;
if (!bb.Overlaps(window->ClipRect))
if (id == 0 || (id != g.ActiveId && id != g.ActiveIdPreviousFrame && id != g.NavId && id != g.NavActivateId))
if (!g.LogEnabled)
if (!g.ItemUnclipByLog)
return true;
return false;
}
@ -6972,6 +6972,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window_stack_data.Window = window;
window_stack_data.ParentLastItemDataBackup = g.LastItemData;
window_stack_data.StackSizesOnBegin.SetToContextState(&g);
window_stack_data.DisabledOverrideReenable = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
g.CurrentWindowStack.push_back(window_stack_data);
if (flags & ImGuiWindowFlags_ChildMenu)
g.BeginMenuDepth++;
@ -7071,6 +7072,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// [EXPERIMENTAL] Skip Refresh mode
UpdateWindowSkipRefresh(window);
// Nested root windows (typically tooltips) override disabled state
if (window_stack_data.DisabledOverrideReenable && window->RootWindow == window)
BeginDisabledOverrideReenable();
// We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow()
g.CurrentWindow = NULL;
@ -7418,7 +7423,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));
if (window->ScrollbarX && !window->ScrollbarY)
window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar);
window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar);
window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
// Amend the partially filled window->DecorationXXX values.
@ -7798,7 +7803,7 @@ void ImGui::End()
IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!");
return;
}
IM_ASSERT(g.CurrentWindowStack.Size > 0);
ImGuiWindowStackData& window_stack_data = g.CurrentWindowStack.back();
// Error checking: verify that user doesn't directly call End() on a child window.
if ((window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_DockNodeHost) && !window->DockIsActive)
@ -7810,6 +7815,8 @@ void ImGui::End()
if (!(window->Flags & ImGuiWindowFlags_DockNodeHost) && !window->SkipRefresh) // Pop inner window clip rectangle
PopClipRect();
PopFocusScope();
if (window_stack_data.DisabledOverrideReenable && window->RootWindow == window)
EndDisabledOverrideReenable();
if (window->SkipRefresh)
{
@ -7830,12 +7837,12 @@ void ImGui::End()
host_window->DC.CursorMaxPos = window->DC.CursorMaxPos + window->WindowPadding - host_window->WindowPadding;
// Pop from window stack
g.LastItemData = g.CurrentWindowStack.back().ParentLastItemDataBackup;
g.LastItemData = window_stack_data.ParentLastItemDataBackup;
if (window->Flags & ImGuiWindowFlags_ChildMenu)
g.BeginMenuDepth--;
if (window->Flags & ImGuiWindowFlags_Popup)
g.BeginPopupStack.pop_back();
g.CurrentWindowStack.back().StackSizesOnBegin.CompareWithContextState(&g);
window_stack_data.StackSizesOnBegin.CompareWithContextState(&g);
g.CurrentWindowStack.pop_back();
SetCurrentWindow(g.CurrentWindowStack.Size == 0 ? NULL : g.CurrentWindowStack.back().Window);
if (g.CurrentWindow)
@ -8096,7 +8103,7 @@ void ImGui::BeginDisabled(bool disabled)
}
if (was_disabled || disabled)
g.CurrentItemFlags |= ImGuiItemFlags_Disabled;
g.ItemFlagsStack.push_back(g.CurrentItemFlags);
g.ItemFlagsStack.push_back(g.CurrentItemFlags); // FIXME-OPT: can we simply skip this and use DisabledStackSize?
g.DisabledStackSize++;
}
@ -8113,6 +8120,29 @@ void ImGui::EndDisabled()
g.Style.Alpha = g.DisabledAlphaBackup; //PopStyleVar();
}
// Could have been called BeginDisabledDisable() but it didn't want to be award nominated for most awkward function name.
// Ideally we would use a shared e.g. BeginDisabled()->BeginDisabledEx() but earlier needs to be optimal.
// The whole code for this is awkward, will reevaluate if we find a way to implement SetNextItemDisabled().
void ImGui::BeginDisabledOverrideReenable()
{
ImGuiContext& g = *GImGui;
IM_ASSERT(g.CurrentItemFlags & ImGuiItemFlags_Disabled);
g.Style.Alpha = g.DisabledAlphaBackup;
g.CurrentItemFlags &= ~ImGuiItemFlags_Disabled;
g.ItemFlagsStack.push_back(g.CurrentItemFlags);
g.DisabledStackSize++;
}
void ImGui::EndDisabledOverrideReenable()
{
ImGuiContext& g = *GImGui;
g.DisabledStackSize--;
IM_ASSERT(g.DisabledStackSize > 0);
g.ItemFlagsStack.pop_back();
g.CurrentItemFlags = g.ItemFlagsStack.back();
g.Style.Alpha = g.DisabledAlphaBackup * g.Style.DisabledAlpha;
}
void ImGui::PushTabStop(bool tab_stop)
{
PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop);
@ -10671,7 +10701,13 @@ void ImGui::ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, vo
while (g.DisabledStackSize > stack_sizes->SizeOfDisabledStack) //-V1044
{
if (log_callback) log_callback(user_data, "Recovered from missing EndDisabled() in '%s'", window->Name);
EndDisabled();
if (g.CurrentItemFlags & ImGuiItemFlags_Disabled)
EndDisabled();
else
{
EndDisabledOverrideReenable();
g.CurrentWindowStack.back().DisabledOverrideReenable = false;
}
}
while (g.ColorStack.Size > stack_sizes->SizeOfColorStack)
{
@ -10760,6 +10796,7 @@ void ImGui::KeepAliveID(ImGuiID id)
// 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.
// THIS IS IN THE PERFORMANCE CRITICAL PATH (UNTIL THE CLIPPING TEST AND EARLY-RETURN)
IM_MSVC_RUNTIME_CHECKS_OFF
bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGuiItemFlags extra_flags)
{
ImGuiContext& g = *GImGui;
@ -10812,15 +10849,12 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
#endif
// Clipping test
// (this is a modified copy of IsClippedEx() so we can reuse the is_rect_visible value)
//const bool is_clipped = IsClippedEx(bb, id);
//if (is_clipped)
// return false;
// (this is an inline copy of IsClippedEx() so we can reuse the is_rect_visible value, otherwise we'd do 'if (IsClippedEx(bb, id)) 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 && id != g.NavActivateId))
if (!g.LogEnabled)
if (!g.ItemUnclipByLog)
return false;
// [DEBUG]
@ -10847,7 +10881,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect;
return true;
}
IM_MSVC_RUNTIME_CHECKS_RESTORE
//-----------------------------------------------------------------------------
// [SECTION] LAYOUT
@ -10884,6 +10918,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
// Register minimum needed size so it can extend the bounding box used for auto-fit calculation.
// See comments in ItemAdd() about how/why the size provided to ItemSize() vs ItemAdd() may often different.
// THIS IS IN THE PERFORMANCE CRITICAL PATH.
IM_MSVC_RUNTIME_CHECKS_OFF
void ImGui::ItemSize(const ImVec2& size, float text_baseline_y)
{
ImGuiContext& g = *GImGui;
@ -10919,6 +10954,7 @@ void ImGui::ItemSize(const ImVec2& size, float text_baseline_y)
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
SameLine();
}
IM_MSVC_RUNTIME_CHECKS_RESTORE
// Gets back to previous line and continue with horizontal layout
// offset_from_start_x == 0 : follow right after previous item
@ -13797,6 +13833,8 @@ bool ImGui::IsDragDropActive()
void ImGui::ClearDragDrop()
{
ImGuiContext& g = *GImGui;
if (g.DragDropActive)
IMGUI_DEBUG_LOG_ACTIVEID("[dragdrop] ClearDragDrop()\n");
g.DragDropActive = false;
g.DragDropPayload.Clear();
g.DragDropAcceptFlags = ImGuiDragDropFlags_None;
@ -13835,7 +13873,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
bool source_drag_active = false;
ImGuiID source_id = 0;
ImGuiID source_parent_id = 0;
if (!(flags & ImGuiDragDropFlags_SourceExtern))
if ((flags & ImGuiDragDropFlags_SourceExtern) == 0)
{
source_id = g.LastItemData.ID;
if (source_id != 0)
@ -13897,43 +13935,44 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
}
IM_ASSERT(g.DragDropWithinTarget == false); // Can't nest BeginDragDropSource() and BeginDragDropTarget()
if (source_drag_active)
if (!source_drag_active)
return false;
// Activate drag and drop
if (!g.DragDropActive)
{
if (!g.DragDropActive)
{
IM_ASSERT(source_id != 0);
ClearDragDrop();
ImGuiPayload& payload = g.DragDropPayload;
payload.SourceId = source_id;
payload.SourceParentId = source_parent_id;
g.DragDropActive = true;
g.DragDropSourceFlags = flags;
g.DragDropMouseButton = mouse_button;
if (payload.SourceId == g.ActiveId)
g.ActiveIdNoClearOnFocusLoss = true;
}
g.DragDropSourceFrameCount = g.FrameCount;
g.DragDropWithinSource = true;
if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
{
// Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit)
// We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents.
bool ret;
if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip))
ret = BeginTooltipHidden();
else
ret = BeginTooltip();
IM_ASSERT(ret); // FIXME-NEWBEGIN: If this ever becomes false, we need to Begin("##Hidden", NULL, ImGuiWindowFlags_NoSavedSettings) + SetWindowHiddendAndSkipItemsForCurrentFrame().
IM_UNUSED(ret);
}
if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern))
g.LastItemData.StatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
return true;
IM_ASSERT(source_id != 0);
ClearDragDrop();
IMGUI_DEBUG_LOG_ACTIVEID("[dragdrop] BeginDragDropSource() DragDropActive = true, source_id = %08X\n", source_id);
ImGuiPayload& payload = g.DragDropPayload;
payload.SourceId = source_id;
payload.SourceParentId = source_parent_id;
g.DragDropActive = true;
g.DragDropSourceFlags = flags;
g.DragDropMouseButton = mouse_button;
if (payload.SourceId == g.ActiveId)
g.ActiveIdNoClearOnFocusLoss = true;
}
return false;
g.DragDropSourceFrameCount = g.FrameCount;
g.DragDropWithinSource = true;
if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
{
// Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit)
// We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents.
bool ret;
if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip))
ret = BeginTooltipHidden();
else
ret = BeginTooltip();
IM_ASSERT(ret); // FIXME-NEWBEGIN: If this ever becomes false, we need to Begin("##Hidden", NULL, ImGuiWindowFlags_NoSavedSettings) + SetWindowHiddendAndSkipItemsForCurrentFrame().
IM_UNUSED(ret);
}
if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern))
g.LastItemData.StatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
return true;
}
void ImGui::EndDragDropSource()
@ -14244,7 +14283,7 @@ void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth)
IM_ASSERT(g.LogEnabled == false);
IM_ASSERT(g.LogFile == NULL);
IM_ASSERT(g.LogBuffer.empty());
g.LogEnabled = true;
g.LogEnabled = g.ItemUnclipByLog = true;
g.LogType = type;
g.LogNextPrefix = g.LogNextSuffix = NULL;
g.LogDepthRef = window->DC.TreeDepth;
@ -14343,7 +14382,7 @@ void ImGui::LogFinish()
break;
}
g.LogEnabled = false;
g.LogEnabled = g.ItemUnclipByLog = false;
g.LogType = ImGuiLogType_None;
g.LogFile = NULL;
g.LogBuffer.clear();
@ -21414,8 +21453,11 @@ void ImGui::DebugLogV(const char* fmt, va_list args)
if (g.DebugLogFlags & ImGuiDebugLogFlags_OutputToTTY)
IMGUI_DEBUG_PRINTF("%s", g.DebugLogBuf.begin() + old_size);
#ifdef IMGUI_ENABLE_TEST_ENGINE
// IMGUI_TEST_ENGINE_LOG() adds a trailing \n automatically
const int new_size = g.DebugLogBuf.size();
const bool trailing_carriage_return = (g.DebugLogBuf[new_size - 1] == '\n');
if (g.DebugLogFlags & ImGuiDebugLogFlags_OutputToTestEngine)
IMGUI_TEST_ENGINE_LOG("%s", g.DebugLogBuf.begin() + old_size);
IMGUI_TEST_ENGINE_LOG("%.*s", new_size - old_size - (trailing_carriage_return ? 1 : 0), g.DebugLogBuf.begin() + old_size);
#endif
}
@ -21485,25 +21527,7 @@ void ImGui::ShowDebugLogWindow(bool* p_open)
clipper.Begin(g.DebugLogIndex.size());
while (clipper.Step())
for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
{
const char* line_begin = g.DebugLogIndex.get_line_begin(g.DebugLogBuf.c_str(), line_no);
const char* line_end = g.DebugLogIndex.get_line_end(g.DebugLogBuf.c_str(), line_no);
TextUnformatted(line_begin, line_end); // Display line
ImRect text_rect = g.LastItemData.Rect;
if (IsItemHovered())
for (const char* p = line_begin; p <= line_end - 10; p++) // Search for 0x???????? identifiers
{
ImGuiID id = 0;
if (p[0] != '0' || (p[1] != 'x' && p[1] != 'X') || sscanf(p + 2, "%X", &id) != 1)
continue;
ImVec2 p0 = CalcTextSize(line_begin, p);
ImVec2 p1 = CalcTextSize(p, p + 10);
g.LastItemData.Rect = ImRect(text_rect.Min + ImVec2(p0.x, 0.0f), text_rect.Min + ImVec2(p0.x + p1.x, p1.y));
if (IsMouseHoveringRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, true))
DebugLocateItemOnHover(id);
p += 10;
}
}
DebugTextUnformattedWithLocateItem(g.DebugLogIndex.get_line_begin(g.DebugLogBuf.c_str(), line_no), g.DebugLogIndex.get_line_end(g.DebugLogBuf.c_str(), line_no));
g.DebugLogFlags = backup_log_flags;
if (GetScrollY() >= GetScrollMaxY())
SetScrollHereY(1.0f);
@ -21512,6 +21536,28 @@ void ImGui::ShowDebugLogWindow(bool* p_open)
End();
}
// Display line, search for 0xXXXXXXXX identifiers and call DebugLocateItemOnHover() when hovered.
void ImGui::DebugTextUnformattedWithLocateItem(const char* line_begin, const char* line_end)
{
TextUnformatted(line_begin, line_end);
if (!IsItemHovered())
return;
ImGuiContext& g = *GImGui;
ImRect text_rect = g.LastItemData.Rect;
for (const char* p = line_begin; p <= line_end - 10; p++)
{
ImGuiID id = 0;
if (p[0] != '0' || (p[1] != 'x' && p[1] != 'X') || sscanf(p + 2, "%X", &id) != 1)
continue;
ImVec2 p0 = CalcTextSize(line_begin, p);
ImVec2 p1 = CalcTextSize(p, p + 10);
g.LastItemData.Rect = ImRect(text_rect.Min + ImVec2(p0.x, 0.0f), text_rect.Min + ImVec2(p0.x + p1.x, p1.y));
if (IsMouseHoveringRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, true))
DebugLocateItemOnHover(id);
p += 10;
}
}
//-----------------------------------------------------------------------------
// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, ID STACK TOOL)
//-----------------------------------------------------------------------------