Skip to content

Commit

Permalink
Error check: clarified that carriage returns are emitted by our code.…
Browse files Browse the repository at this point in the history
… Added helper default callback. Comments. (#1651)

(doesn't affect test engine hook for it as trailing \n are trimmed anyhow)
  • Loading branch information
ocornut committed Sep 20, 2024
1 parent 0af2c4e commit d0750ee
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 19 deletions.
52 changes: 35 additions & 17 deletions imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ CODE
// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
// [SECTION] ID STACK
// [SECTION] INPUTS
// [SECTION] ERROR CHECKING
// [SECTION] ERROR CHECKING, STATE RECOVERY
// [SECTION] ITEM SUBMISSION
// [SECTION] LAYOUT
// [SECTION] SCROLLING
Expand Down Expand Up @@ -7734,7 +7734,8 @@ void ImGui::PopItemFlag()
// - 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.
// - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions.
// (as a micro-optimisation if you can avoid calling BeginDisabled(false)/EndDisabled() tens of thousands of times by doing a local check, it won't hurt)
// - Optimized shortcuts instead of PushStyleVar() + PushItemFlag()
// - Note: mixing up BeginDisabled() and PushItemFlag(ImGuiItemFlags_Disabled) is currently NOT SUPPORTED.
void ImGui::BeginDisabled(bool disabled)
Expand Down Expand Up @@ -10069,7 +10070,15 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags, ImGuiID own


//-----------------------------------------------------------------------------
// [SECTION] ERROR CHECKING
// [SECTION] ERROR CHECKING, STATE RECOVERY
//-----------------------------------------------------------------------------
// - DebugCheckVersionAndDataLayout() (called via IMGUI_CHECKVERSION() macros)
// - ErrorCheckUsingSetCursorPosToExtendParentBoundaries()
// - ErrorCheckNewFrameSanityChecks()
// - ErrorCheckEndFrameSanityChecks()
// - ErrorCheckEndFrameRecover()
// - ErrorCheckEndWindowRecover()
// - ImGuiStackSizes
//-----------------------------------------------------------------------------

// Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues.
Expand Down Expand Up @@ -10215,6 +10224,15 @@ static void ImGui::ErrorCheckEndFrameSanityChecks()
IM_ASSERT_USER_ERROR(g.GroupStack.Size == 0, "Missing EndGroup call!");
}

// Default implementation of ImGuiErrorLogCallback that pipe errors to DebugLog: appears in tty + Tools->DebugLog
void ImGui::ErrorLogCallbackToDebugLog(void*, const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
ImGui::DebugLogV(fmt, args);
va_end(args);
}

// Experimental recovery from incorrect usage of BeginXXX/EndXXX/PushXXX/PopXXX calls.
// Must be called during or before EndFrame().
// This is generally flawed as we are not necessarily End/Popping things in the right order.
Expand All @@ -10235,12 +10253,12 @@ void ImGui::ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, voi
}
if (window->Flags & ImGuiWindowFlags_ChildWindow)
{
if (log_callback) log_callback(user_data, "Recovered from missing EndChild() for '%s'", window->Name);
if (log_callback) log_callback(user_data, "Recovered from missing EndChild() for '%s'\n", window->Name);
EndChild();
}
else
{
if (log_callback) log_callback(user_data, "Recovered from missing End() for '%s'", window->Name);
if (log_callback) log_callback(user_data, "Recovered from missing End() for '%s'\n", window->Name);
End();
}
}
Expand All @@ -10252,7 +10270,7 @@ void ImGui::ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, vo
ImGuiContext& g = *GImGui;
while (g.CurrentTable && (g.CurrentTable->OuterWindow == g.CurrentWindow || g.CurrentTable->InnerWindow == g.CurrentWindow))
{
if (log_callback) log_callback(user_data, "Recovered from missing EndTable() in '%s'", g.CurrentTable->OuterWindow->Name);
if (log_callback) log_callback(user_data, "Recovered from missing EndTable() in '%s'\n", g.CurrentTable->OuterWindow->Name);
EndTable();
}

Expand All @@ -10261,32 +10279,32 @@ void ImGui::ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, vo
IM_ASSERT(window != NULL);
while (g.CurrentTabBar != NULL) //-V1044
{
if (log_callback) log_callback(user_data, "Recovered from missing EndTabBar() in '%s'", window->Name);
if (log_callback) log_callback(user_data, "Recovered from missing EndTabBar() in '%s'\n", window->Name);
EndTabBar();
}
while (g.CurrentMultiSelect != NULL && g.CurrentMultiSelect->Storage->Window == window)
{
if (log_callback) log_callback(user_data, "Recovered from missing EndMultiSelect() in '%s'", window->Name);
if (log_callback) log_callback(user_data, "Recovered from missing EndMultiSelect() in '%s'\n", window->Name);
EndMultiSelect();
}
while (window->DC.TreeDepth > 0)
{
if (log_callback) log_callback(user_data, "Recovered from missing TreePop() in '%s'", window->Name);
if (log_callback) log_callback(user_data, "Recovered from missing TreePop() in '%s'\n", window->Name);
TreePop();
}
while (g.GroupStack.Size > stack_sizes->SizeOfGroupStack) //-V1044
{
if (log_callback) log_callback(user_data, "Recovered from missing EndGroup() in '%s'", window->Name);
if (log_callback) log_callback(user_data, "Recovered from missing EndGroup() in '%s'\n", window->Name);
EndGroup();
}
while (window->IDStack.Size > 1)
{
if (log_callback) log_callback(user_data, "Recovered from missing PopID() in '%s'", window->Name);
if (log_callback) log_callback(user_data, "Recovered from missing PopID() in '%s'\n", window->Name);
PopID();
}
while (g.DisabledStackSize > stack_sizes->SizeOfDisabledStack) //-V1044
{
if (log_callback) log_callback(user_data, "Recovered from missing EndDisabled() in '%s'", window->Name);
if (log_callback) log_callback(user_data, "Recovered from missing EndDisabled() in '%s'\n", window->Name);
if (g.CurrentItemFlags & ImGuiItemFlags_Disabled)
EndDisabled();
else
Expand All @@ -10297,27 +10315,27 @@ void ImGui::ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, vo
}
while (g.ColorStack.Size > stack_sizes->SizeOfColorStack)
{
if (log_callback) log_callback(user_data, "Recovered from missing PopStyleColor() in '%s' for ImGuiCol_%s", window->Name, GetStyleColorName(g.ColorStack.back().Col));
if (log_callback) log_callback(user_data, "Recovered from missing PopStyleColor() in '%s' for ImGuiCol_%s\n", window->Name, GetStyleColorName(g.ColorStack.back().Col));
PopStyleColor();
}
while (g.ItemFlagsStack.Size > stack_sizes->SizeOfItemFlagsStack) //-V1044
{
if (log_callback) log_callback(user_data, "Recovered from missing PopItemFlag() in '%s'", window->Name);
if (log_callback) log_callback(user_data, "Recovered from missing PopItemFlag() in '%s'\n", window->Name);
PopItemFlag();
}
while (g.StyleVarStack.Size > stack_sizes->SizeOfStyleVarStack) //-V1044
{
if (log_callback) log_callback(user_data, "Recovered from missing PopStyleVar() in '%s'", window->Name);
if (log_callback) log_callback(user_data, "Recovered from missing PopStyleVar() in '%s'\n", window->Name);
PopStyleVar();
}
while (g.FontStack.Size > stack_sizes->SizeOfFontStack) //-V1044
{
if (log_callback) log_callback(user_data, "Recovered from missing PopFont() in '%s'", window->Name);
if (log_callback) log_callback(user_data, "Recovered from missing PopFont() in '%s'\n", window->Name);
PopFont();
}
while (g.FocusScopeStack.Size > stack_sizes->SizeOfFocusScopeStack + 1) //-V1044
{
if (log_callback) log_callback(user_data, "Recovered from missing PopFocusScope() in '%s'", window->Name);
if (log_callback) log_callback(user_data, "Recovered from missing PopFocusScope() in '%s'\n", window->Name);
PopFocusScope();
}
}
Expand Down
8 changes: 6 additions & 2 deletions imgui_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1259,6 +1259,7 @@ struct ImGuiTreeNodeStackData
ImRect NavRect; // Used for nav landing
};

// sizeof() = 18
struct IMGUI_API ImGuiStackSizes
{
short SizeOfIDStack;
Expand Down Expand Up @@ -3606,11 +3607,14 @@ namespace ImGui
IMGUI_API void GcCompactTransientWindowBuffers(ImGuiWindow* window);
IMGUI_API void GcAwakeTransientWindowBuffers(ImGuiWindow* window);

// Debug Tools
IMGUI_API void DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr, size_t size); // size >= 0 : alloc, size = -1 : free
// Error Checking, State Recovery
IMGUI_API void ErrorLogCallbackToDebugLog(void* user_data, const char* fmt, ...);
IMGUI_API void ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL);
IMGUI_API void ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL);
IMGUI_API void ErrorCheckUsingSetCursorPosToExtendParentBoundaries();

// Debug Tools
IMGUI_API void DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr, size_t size); // size >= 0 : alloc, size = -1 : free
IMGUI_API void DebugDrawCursorPos(ImU32 col = IM_COL32(255, 0, 0, 255));
IMGUI_API void DebugDrawLineExtents(ImU32 col = IM_COL32(255, 0, 0, 255));
IMGUI_API void DebugDrawItemRect(ImU32 col = IM_COL32(255, 0, 0, 255));
Expand Down

0 comments on commit d0750ee

Please sign in to comment.