@ -65,6 +65,7 @@ CODE
// [SECTION] RENDER HELPERS
// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
// [SECTION] ERROR CHECKING
// [SECTION] LAYOUT
// [SECTION] SCROLLING
// [SECTION] TOOLTIPS
// [SECTION] POPUPS
@ -3042,102 +3043,6 @@ static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFla
return true ;
}
// Advance cursor given item size for layout.
void ImGui : : ItemSize ( const ImVec2 & size , float text_baseline_y )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
if ( window - > SkipItems )
return ;
// We increase the height in this function to accommodate for baseline offset.
// In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor,
// but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect.
const float offset_to_match_baseline_y = ( text_baseline_y > = 0 ) ? ImMax ( 0.0f , window - > DC . CurrLineTextBaseOffset - text_baseline_y ) : 0.0f ;
const float line_height = ImMax ( window - > DC . CurrLineSize . y , size . y + offset_to_match_baseline_y ) ;
// Always align ourselves on pixel boundaries
//if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG]
window - > DC . CursorPosPrevLine . x = window - > DC . CursorPos . x + size . x ;
window - > DC . CursorPosPrevLine . y = window - > DC . CursorPos . y ;
window - > DC . CursorPos . x = IM_FLOOR ( window - > Pos . x + window - > DC . Indent . x + window - > DC . ColumnsOffset . x ) ; // Next line
window - > DC . CursorPos . y = IM_FLOOR ( window - > DC . CursorPos . y + line_height + g . Style . ItemSpacing . y ) ; // Next line
window - > DC . CursorMaxPos . x = ImMax ( window - > DC . CursorMaxPos . x , window - > DC . CursorPosPrevLine . x ) ;
window - > DC . CursorMaxPos . y = ImMax ( window - > DC . CursorMaxPos . y , window - > DC . CursorPos . y - g . Style . ItemSpacing . y ) ;
//if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
window - > DC . PrevLineSize . y = line_height ;
window - > DC . CurrLineSize . y = 0.0f ;
window - > DC . PrevLineTextBaseOffset = ImMax ( window - > DC . CurrLineTextBaseOffset , text_baseline_y ) ;
window - > DC . CurrLineTextBaseOffset = 0.0f ;
// Horizontal layout mode
if ( window - > DC . LayoutType = = ImGuiLayoutType_Horizontal )
SameLine ( ) ;
}
void ImGui : : ItemSize ( const ImRect & bb , float text_baseline_y )
{
ItemSize ( bb . GetSize ( ) , text_baseline_y ) ;
}
// Declare item bounding box for clipping and interaction.
// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
// declare their minimum size requirement to ItemSize() and then use a larger region for drawing/interaction, which is passed to ItemAdd().
bool ImGui : : ItemAdd ( const ImRect & bb , ImGuiID id , const ImRect * nav_bb_arg )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
if ( id ! = 0 )
{
// Navigation processing runs prior to clipping early-out
// (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
// (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
// unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
// thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
// We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able
// to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).
// We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null.
// If we crash on a NULL g.NavWindow we need to fix the bug elsewhere.
window - > DC . NavLayerActiveMaskNext | = window - > DC . NavLayerCurrentMask ;
if ( g . NavId = = id | | g . NavAnyRequest )
if ( g . NavWindow - > RootWindowForNav = = window - > RootWindowForNav )
if ( window = = g . NavWindow | | ( ( window - > Flags | g . NavWindow - > Flags ) & ImGuiWindowFlags_NavFlattened ) )
NavProcessItem ( window , nav_bb_arg ? * nav_bb_arg : bb , id ) ;
// [DEBUG] Item Picker tool, when enabling the "extended" version we perform the check in ItemAdd()
# ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
if ( id = = g . DebugItemPickerBreakId )
{
IM_DEBUG_BREAK ( ) ;
g . DebugItemPickerBreakId = 0 ;
}
# endif
}
window - > DC . LastItemId = id ;
window - > DC . LastItemRect = bb ;
window - > DC . LastItemStatusFlags = ImGuiItemStatusFlags_None ;
g . NextItemData . Flags = ImGuiNextItemDataFlags_None ;
# ifdef IMGUI_ENABLE_TEST_ENGINE
if ( id ! = 0 )
IMGUI_TEST_ENGINE_ITEM_ADD ( nav_bb_arg ? * nav_bb_arg : bb , id ) ;
# endif
// Clipping test
const bool is_clipped = IsClippedEx ( bb , id , false ) ;
if ( is_clipped )
return false ;
//if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
// We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
if ( IsMouseHoveringRect ( bb . Min , bb . Max ) )
window - > DC . LastItemStatusFlags | = ImGuiItemStatusFlags_HoveredRect ;
return true ;
}
// This is roughly matching the behavior of internal-facing ItemHoverable()
// - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered()
// - this should work even for non-interactive items that have no ID, so we cannot use LastItemId
@ -6988,6 +6893,226 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
return window - > ClipRect . Overlaps ( ImRect ( rect_min , rect_max ) ) ;
}
//-----------------------------------------------------------------------------
// [SECTION] ERROR CHECKING
//-----------------------------------------------------------------------------
// Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui.
// Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit
// If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. your user code
// may see different structures than what imgui.cpp sees, which is problematic.
// We usually require settings to be in imconfig.h to make sure that they are accessible to all compilation units involved with Dear ImGui.
bool ImGui : : DebugCheckVersionAndDataLayout ( const char * version , size_t sz_io , size_t sz_style , size_t sz_vec2 , size_t sz_vec4 , size_t sz_vert , size_t sz_idx )
{
bool error = false ;
if ( strcmp ( version , IMGUI_VERSION ) ! = 0 ) { error = true ; IM_ASSERT ( strcmp ( version , IMGUI_VERSION ) = = 0 & & " Mismatched version string! " ) ; }
if ( sz_io ! = sizeof ( ImGuiIO ) ) { error = true ; IM_ASSERT ( sz_io = = sizeof ( ImGuiIO ) & & " Mismatched struct layout! " ) ; }
if ( sz_style ! = sizeof ( ImGuiStyle ) ) { error = true ; IM_ASSERT ( sz_style = = sizeof ( ImGuiStyle ) & & " Mismatched struct layout! " ) ; }
if ( sz_vec2 ! = sizeof ( ImVec2 ) ) { error = true ; IM_ASSERT ( sz_vec2 = = sizeof ( ImVec2 ) & & " Mismatched struct layout! " ) ; }
if ( sz_vec4 ! = sizeof ( ImVec4 ) ) { error = true ; IM_ASSERT ( sz_vec4 = = sizeof ( ImVec4 ) & & " Mismatched struct layout! " ) ; }
if ( sz_vert ! = sizeof ( ImDrawVert ) ) { error = true ; IM_ASSERT ( sz_vert = = sizeof ( ImDrawVert ) & & " Mismatched struct layout! " ) ; }
if ( sz_idx ! = sizeof ( ImDrawIdx ) ) { error = true ; IM_ASSERT ( sz_idx = = sizeof ( ImDrawIdx ) & & " Mismatched struct layout! " ) ; }
return ! error ;
}
static void ImGui : : ErrorCheckEndFrame ( )
{
// Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you
// to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API).
ImGuiContext & g = * GImGui ;
if ( g . CurrentWindowStack . Size ! = 1 )
{
if ( g . CurrentWindowStack . Size > 1 )
{
IM_ASSERT_USER_ERROR ( g . CurrentWindowStack . Size = = 1 , " Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild? " ) ;
while ( g . CurrentWindowStack . Size > 1 )
End ( ) ;
}
else
{
IM_ASSERT_USER_ERROR ( g . CurrentWindowStack . Size = = 1 , " Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much? " ) ;
}
}
}
// Save and compare stack sizes on Begin()/End() to detect usage errors
// Begin() calls this with write=true
// End() calls this with write=false
static void ImGui : : ErrorCheckBeginEndCompareStacksSize ( ImGuiWindow * window , bool write )
{
ImGuiContext & g = * GImGui ;
short * p = & window - > DC . StackSizesBackup [ 0 ] ;
// Window stacks
// NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin)
{ int n = window - > IDStack . Size ; if ( write ) * p = ( short ) n ; else IM_ASSERT ( * p = = n & & " PushID/PopID or TreeNode/TreePop Mismatch! " ) ; p + + ; } // Too few or too many PopID()/TreePop()
{ int n = window - > DC . GroupStack . Size ; if ( write ) * p = ( short ) n ; else IM_ASSERT ( * p = = n & & " BeginGroup/EndGroup Mismatch! " ) ; p + + ; } // Too few or too many EndGroup()
// Global stacks
// For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them.
{ int n = g . BeginPopupStack . Size ; if ( write ) * p = ( short ) n ; else IM_ASSERT ( * p = = n & & " BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch! " ) ; p + + ; } // Too few or too many EndMenu()/EndPopup()
{ int n = g . ColorModifiers . Size ; if ( write ) * p = ( short ) n ; else IM_ASSERT ( * p > = n & & " PushStyleColor/PopStyleColor Mismatch! " ) ; p + + ; } // Too few or too many PopStyleColor()
{ int n = g . StyleModifiers . Size ; if ( write ) * p = ( short ) n ; else IM_ASSERT ( * p > = n & & " PushStyleVar/PopStyleVar Mismatch! " ) ; p + + ; } // Too few or too many PopStyleVar()
{ int n = g . FontStack . Size ; if ( write ) * p = ( short ) n ; else IM_ASSERT ( * p > = n & & " PushFont/PopFont Mismatch! " ) ; p + + ; } // Too few or too many PopFont()
IM_ASSERT ( p = = window - > DC . StackSizesBackup + IM_ARRAYSIZE ( window - > DC . StackSizesBackup ) ) ;
}
//-----------------------------------------------------------------------------
// [SECTION] LAYOUT
//-----------------------------------------------------------------------------
// - ItemSize()
// - ItemAdd()
// - SameLine()
// - Indent()
// - Unindent()
// - BeginGroup()
// - EndGroup()
// Also see in imgui_widgets: tab bars, columns.
//-----------------------------------------------------------------------------
// Advance cursor given item size for layout.
void ImGui : : ItemSize ( const ImVec2 & size , float text_baseline_y )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
if ( window - > SkipItems )
return ;
// We increase the height in this function to accommodate for baseline offset.
// In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor,
// but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect.
const float offset_to_match_baseline_y = ( text_baseline_y > = 0 ) ? ImMax ( 0.0f , window - > DC . CurrLineTextBaseOffset - text_baseline_y ) : 0.0f ;
const float line_height = ImMax ( window - > DC . CurrLineSize . y , size . y + offset_to_match_baseline_y ) ;
// Always align ourselves on pixel boundaries
//if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG]
window - > DC . CursorPosPrevLine . x = window - > DC . CursorPos . x + size . x ;
window - > DC . CursorPosPrevLine . y = window - > DC . CursorPos . y ;
window - > DC . CursorPos . x = IM_FLOOR ( window - > Pos . x + window - > DC . Indent . x + window - > DC . ColumnsOffset . x ) ; // Next line
window - > DC . CursorPos . y = IM_FLOOR ( window - > DC . CursorPos . y + line_height + g . Style . ItemSpacing . y ) ; // Next line
window - > DC . CursorMaxPos . x = ImMax ( window - > DC . CursorMaxPos . x , window - > DC . CursorPosPrevLine . x ) ;
window - > DC . CursorMaxPos . y = ImMax ( window - > DC . CursorMaxPos . y , window - > DC . CursorPos . y - g . Style . ItemSpacing . y ) ;
//if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
window - > DC . PrevLineSize . y = line_height ;
window - > DC . CurrLineSize . y = 0.0f ;
window - > DC . PrevLineTextBaseOffset = ImMax ( window - > DC . CurrLineTextBaseOffset , text_baseline_y ) ;
window - > DC . CurrLineTextBaseOffset = 0.0f ;
// Horizontal layout mode
if ( window - > DC . LayoutType = = ImGuiLayoutType_Horizontal )
SameLine ( ) ;
}
void ImGui : : ItemSize ( const ImRect & bb , float text_baseline_y )
{
ItemSize ( bb . GetSize ( ) , text_baseline_y ) ;
}
// Declare item bounding box for clipping and interaction.
// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
// declare their minimum size requirement to ItemSize() and then use a larger region for drawing/interaction, which is passed to ItemAdd().
bool ImGui : : ItemAdd ( const ImRect & bb , ImGuiID id , const ImRect * nav_bb_arg )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
if ( id ! = 0 )
{
// Navigation processing runs prior to clipping early-out
// (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
// (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
// unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
// thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
// We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able
// to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).
// We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null.
// If we crash on a NULL g.NavWindow we need to fix the bug elsewhere.
window - > DC . NavLayerActiveMaskNext | = window - > DC . NavLayerCurrentMask ;
if ( g . NavId = = id | | g . NavAnyRequest )
if ( g . NavWindow - > RootWindowForNav = = window - > RootWindowForNav )
if ( window = = g . NavWindow | | ( ( window - > Flags | g . NavWindow - > Flags ) & ImGuiWindowFlags_NavFlattened ) )
NavProcessItem ( window , nav_bb_arg ? * nav_bb_arg : bb , id ) ;
// [DEBUG] Item Picker tool, when enabling the "extended" version we perform the check in ItemAdd()
# ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
if ( id = = g . DebugItemPickerBreakId )
{
IM_DEBUG_BREAK ( ) ;
g . DebugItemPickerBreakId = 0 ;
}
# endif
}
window - > DC . LastItemId = id ;
window - > DC . LastItemRect = bb ;
window - > DC . LastItemStatusFlags = ImGuiItemStatusFlags_None ;
g . NextItemData . Flags = ImGuiNextItemDataFlags_None ;
# ifdef IMGUI_ENABLE_TEST_ENGINE
if ( id ! = 0 )
IMGUI_TEST_ENGINE_ITEM_ADD ( nav_bb_arg ? * nav_bb_arg : bb , id ) ;
# endif
// Clipping test
const bool is_clipped = IsClippedEx ( bb , id , false ) ;
if ( is_clipped )
return false ;
//if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
// We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
if ( IsMouseHoveringRect ( bb . Min , bb . Max ) )
window - > DC . LastItemStatusFlags | = ImGuiItemStatusFlags_HoveredRect ;
return true ;
}
// Gets back to previous line and continue with horizontal layout
// offset_from_start_x == 0 : follow right after previous item
// offset_from_start_x != 0 : align to specified x position (relative to window/group left)
// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0
// spacing_w >= 0 : enforce spacing amount
void ImGui : : SameLine ( float offset_from_start_x , float spacing_w )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
if ( window - > SkipItems )
return ;
ImGuiContext & g = * GImGui ;
if ( offset_from_start_x ! = 0.0f )
{
if ( spacing_w < 0.0f ) spacing_w = 0.0f ;
window - > DC . CursorPos . x = window - > Pos . x - window - > Scroll . x + offset_from_start_x + spacing_w + window - > DC . GroupOffset . x + window - > DC . ColumnsOffset . x ;
window - > DC . CursorPos . y = window - > DC . CursorPosPrevLine . y ;
}
else
{
if ( spacing_w < 0.0f ) spacing_w = g . Style . ItemSpacing . x ;
window - > DC . CursorPos . x = window - > DC . CursorPosPrevLine . x + spacing_w ;
window - > DC . CursorPos . y = window - > DC . CursorPosPrevLine . y ;
}
window - > DC . CurrLineSize = window - > DC . PrevLineSize ;
window - > DC . CurrLineTextBaseOffset = window - > DC . PrevLineTextBaseOffset ;
}
void ImGui : : Indent ( float indent_w )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . Indent . x + = ( indent_w ! = 0.0f ) ? indent_w : g . Style . IndentSpacing ;
window - > DC . CursorPos . x = window - > Pos . x + window - > DC . Indent . x + window - > DC . ColumnsOffset . x ;
}
void ImGui : : Unindent ( float indent_w )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . Indent . x - = ( indent_w ! = 0.0f ) ? indent_w : g . Style . IndentSpacing ;
window - > DC . CursorPos . x = window - > Pos . x + window - > DC . Indent . x + window - > DC . ColumnsOffset . x ;
}
// 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.)
void ImGui : : BeginGroup ( )
{
@ -7068,114 +7193,6 @@ void ImGui::EndGroup()
//window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug]
}
// Gets back to previous line and continue with horizontal layout
// offset_from_start_x == 0 : follow right after previous item
// offset_from_start_x != 0 : align to specified x position (relative to window/group left)
// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0
// spacing_w >= 0 : enforce spacing amount
void ImGui : : SameLine ( float offset_from_start_x , float spacing_w )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
if ( window - > SkipItems )
return ;
ImGuiContext & g = * GImGui ;
if ( offset_from_start_x ! = 0.0f )
{
if ( spacing_w < 0.0f ) spacing_w = 0.0f ;
window - > DC . CursorPos . x = window - > Pos . x - window - > Scroll . x + offset_from_start_x + spacing_w + window - > DC . GroupOffset . x + window - > DC . ColumnsOffset . x ;
window - > DC . CursorPos . y = window - > DC . CursorPosPrevLine . y ;
}
else
{
if ( spacing_w < 0.0f ) spacing_w = g . Style . ItemSpacing . x ;
window - > DC . CursorPos . x = window - > DC . CursorPosPrevLine . x + spacing_w ;
window - > DC . CursorPos . y = window - > DC . CursorPosPrevLine . y ;
}
window - > DC . CurrLineSize = window - > DC . PrevLineSize ;
window - > DC . CurrLineTextBaseOffset = window - > DC . PrevLineTextBaseOffset ;
}
void ImGui : : Indent ( float indent_w )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . Indent . x + = ( indent_w ! = 0.0f ) ? indent_w : g . Style . IndentSpacing ;
window - > DC . CursorPos . x = window - > Pos . x + window - > DC . Indent . x + window - > DC . ColumnsOffset . x ;
}
void ImGui : : Unindent ( float indent_w )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . Indent . x - = ( indent_w ! = 0.0f ) ? indent_w : g . Style . IndentSpacing ;
window - > DC . CursorPos . x = window - > Pos . x + window - > DC . Indent . x + window - > DC . ColumnsOffset . x ;
}
//-----------------------------------------------------------------------------
// [SECTION] ERROR CHECKING
//-----------------------------------------------------------------------------
// Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui.
// Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit
// If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. your user code
// may see different structures than what imgui.cpp sees, which is problematic.
// We usually require settings to be in imconfig.h to make sure that they are accessible to all compilation units involved with Dear ImGui.
bool ImGui : : DebugCheckVersionAndDataLayout ( const char * version , size_t sz_io , size_t sz_style , size_t sz_vec2 , size_t sz_vec4 , size_t sz_vert , size_t sz_idx )
{
bool error = false ;
if ( strcmp ( version , IMGUI_VERSION ) ! = 0 ) { error = true ; IM_ASSERT ( strcmp ( version , IMGUI_VERSION ) = = 0 & & " Mismatched version string! " ) ; }
if ( sz_io ! = sizeof ( ImGuiIO ) ) { error = true ; IM_ASSERT ( sz_io = = sizeof ( ImGuiIO ) & & " Mismatched struct layout! " ) ; }
if ( sz_style ! = sizeof ( ImGuiStyle ) ) { error = true ; IM_ASSERT ( sz_style = = sizeof ( ImGuiStyle ) & & " Mismatched struct layout! " ) ; }
if ( sz_vec2 ! = sizeof ( ImVec2 ) ) { error = true ; IM_ASSERT ( sz_vec2 = = sizeof ( ImVec2 ) & & " Mismatched struct layout! " ) ; }
if ( sz_vec4 ! = sizeof ( ImVec4 ) ) { error = true ; IM_ASSERT ( sz_vec4 = = sizeof ( ImVec4 ) & & " Mismatched struct layout! " ) ; }
if ( sz_vert ! = sizeof ( ImDrawVert ) ) { error = true ; IM_ASSERT ( sz_vert = = sizeof ( ImDrawVert ) & & " Mismatched struct layout! " ) ; }
if ( sz_idx ! = sizeof ( ImDrawIdx ) ) { error = true ; IM_ASSERT ( sz_idx = = sizeof ( ImDrawIdx ) & & " Mismatched struct layout! " ) ; }
return ! error ;
}
static void ImGui : : ErrorCheckEndFrame ( )
{
// Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you
// to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API).
ImGuiContext & g = * GImGui ;
if ( g . CurrentWindowStack . Size ! = 1 )
{
if ( g . CurrentWindowStack . Size > 1 )
{
IM_ASSERT_USER_ERROR ( g . CurrentWindowStack . Size = = 1 , " Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild? " ) ;
while ( g . CurrentWindowStack . Size > 1 )
End ( ) ;
}
else
{
IM_ASSERT_USER_ERROR ( g . CurrentWindowStack . Size = = 1 , " Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much? " ) ;
}
}
}
// Save and compare stack sizes on Begin()/End() to detect usage errors
// Begin() calls this with write=true
// End() calls this with write=false
static void ImGui : : ErrorCheckBeginEndCompareStacksSize ( ImGuiWindow * window , bool write )
{
ImGuiContext & g = * GImGui ;
short * p = & window - > DC . StackSizesBackup [ 0 ] ;
// Window stacks
// NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin)
{ int n = window - > IDStack . Size ; if ( write ) * p = ( short ) n ; else IM_ASSERT ( * p = = n & & " PushID/PopID or TreeNode/TreePop Mismatch! " ) ; p + + ; } // Too few or too many PopID()/TreePop()
{ int n = window - > DC . GroupStack . Size ; if ( write ) * p = ( short ) n ; else IM_ASSERT ( * p = = n & & " BeginGroup/EndGroup Mismatch! " ) ; p + + ; } // Too few or too many EndGroup()
// Global stacks
// For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them.
{ int n = g . BeginPopupStack . Size ; if ( write ) * p = ( short ) n ; else IM_ASSERT ( * p = = n & & " BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch! " ) ; p + + ; } // Too few or too many EndMenu()/EndPopup()
{ int n = g . ColorModifiers . Size ; if ( write ) * p = ( short ) n ; else IM_ASSERT ( * p > = n & & " PushStyleColor/PopStyleColor Mismatch! " ) ; p + + ; } // Too few or too many PopStyleColor()
{ int n = g . StyleModifiers . Size ; if ( write ) * p = ( short ) n ; else IM_ASSERT ( * p > = n & & " PushStyleVar/PopStyleVar Mismatch! " ) ; p + + ; } // Too few or too many PopStyleVar()
{ int n = g . FontStack . Size ; if ( write ) * p = ( short ) n ; else IM_ASSERT ( * p > = n & & " PushFont/PopFont Mismatch! " ) ; p + + ; } // Too few or too many PopFont()
IM_ASSERT ( p = = window - > DC . StackSizesBackup + IM_ARRAYSIZE ( window - > DC . StackSizesBackup ) ) ;
}
//-----------------------------------------------------------------------------
// [SECTION] SCROLLING