|
@@ -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
|