mirror of
				https://github.com/ocornut/imgui.git
				synced 2025-11-04 01:34:32 +00:00 
			
		
		
		
	Internals: Refactor: Moved ItemAdd(), ItemSize(), BeginGroup(), EndGroup(), SameLine(), Indent(), Unindent() to Layout section.
This commit is contained in:
		
							
								
								
									
										425
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										425
									
								
								imgui.cpp
									
									
									
									
									
								
							@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user