|
@@ -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
|
|
@@ -3101,102 +3102,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
|
|
@@ -6923,88 +6828,6 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind
|
|
|
FocusWindow(NULL);
|
|
|
}
|
|
|
|
|
|
-void ImGui::SetNextItemWidth(float item_width)
|
|
|
-{
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
- g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth;
|
|
|
- g.NextItemData.Width = item_width;
|
|
|
-}
|
|
|
-
|
|
|
-void ImGui::PushItemWidth(float item_width)
|
|
|
-{
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
- ImGuiWindow* window = g.CurrentWindow;
|
|
|
- window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
|
|
|
- window->DC.ItemWidthStack.push_back(window->DC.ItemWidth);
|
|
|
- g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
|
|
|
-}
|
|
|
-
|
|
|
-void ImGui::PushMultiItemsWidths(int components, float w_full)
|
|
|
-{
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
- ImGuiWindow* window = g.CurrentWindow;
|
|
|
- const ImGuiStyle& style = g.Style;
|
|
|
- const float w_item_one = ImMax(1.0f, IM_FLOOR((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
|
|
|
- const float w_item_last = ImMax(1.0f, IM_FLOOR(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
|
|
|
- window->DC.ItemWidthStack.push_back(w_item_last);
|
|
|
- for (int i = 0; i < components-1; i++)
|
|
|
- window->DC.ItemWidthStack.push_back(w_item_one);
|
|
|
- window->DC.ItemWidth = window->DC.ItemWidthStack.back();
|
|
|
- g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
|
|
|
-}
|
|
|
-
|
|
|
-void ImGui::PopItemWidth()
|
|
|
-{
|
|
|
- ImGuiWindow* window = GetCurrentWindow();
|
|
|
- window->DC.ItemWidthStack.pop_back();
|
|
|
- window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back();
|
|
|
-}
|
|
|
-
|
|
|
-// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth().
|
|
|
-// The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags()
|
|
|
-float ImGui::CalcItemWidth()
|
|
|
-{
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
- ImGuiWindow* window = g.CurrentWindow;
|
|
|
- float w;
|
|
|
- if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth)
|
|
|
- w = g.NextItemData.Width;
|
|
|
- else
|
|
|
- w = window->DC.ItemWidth;
|
|
|
- if (w < 0.0f)
|
|
|
- {
|
|
|
- float region_max_x = GetContentRegionMaxAbs().x;
|
|
|
- w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w);
|
|
|
- }
|
|
|
- w = IM_FLOOR(w);
|
|
|
- return w;
|
|
|
-}
|
|
|
-
|
|
|
-// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth().
|
|
|
-// Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical.
|
|
|
-// Note that only CalcItemWidth() is publicly exposed.
|
|
|
-// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable)
|
|
|
-ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h)
|
|
|
-{
|
|
|
- ImGuiWindow* window = GImGui->CurrentWindow;
|
|
|
-
|
|
|
- ImVec2 region_max;
|
|
|
- if (size.x < 0.0f || size.y < 0.0f)
|
|
|
- region_max = GetContentRegionMaxAbs();
|
|
|
-
|
|
|
- if (size.x == 0.0f)
|
|
|
- size.x = default_w;
|
|
|
- else if (size.x < 0.0f)
|
|
|
- size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x);
|
|
|
-
|
|
|
- if (size.y == 0.0f)
|
|
|
- size.y = default_h;
|
|
|
- else if (size.y < 0.0f)
|
|
|
- size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y);
|
|
|
-
|
|
|
- return size;
|
|
|
-}
|
|
|
-
|
|
|
void ImGui::SetCurrentFont(ImFont* font)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
@@ -7426,77 +7249,6 @@ void ImGui::SetNextWindowClass(const ImGuiWindowClass* window_class)
|
|
|
g.NextWindowData.WindowClass = *window_class;
|
|
|
}
|
|
|
|
|
|
-// FIXME: This is in window space (not screen space!). We should try to obsolete all those functions.
|
|
|
-ImVec2 ImGui::GetContentRegionMax()
|
|
|
-{
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
- ImGuiWindow* window = g.CurrentWindow;
|
|
|
- ImVec2 mx = window->ContentRegionRect.Max - window->Pos;
|
|
|
- if (window->DC.CurrentColumns)
|
|
|
- mx.x = window->WorkRect.Max.x - window->Pos.x;
|
|
|
- return mx;
|
|
|
-}
|
|
|
-
|
|
|
-// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features.
|
|
|
-ImVec2 ImGui::GetContentRegionMaxAbs()
|
|
|
-{
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
- ImGuiWindow* window = g.CurrentWindow;
|
|
|
- ImVec2 mx = window->ContentRegionRect.Max;
|
|
|
- if (window->DC.CurrentColumns)
|
|
|
- mx.x = window->WorkRect.Max.x;
|
|
|
- return mx;
|
|
|
-}
|
|
|
-
|
|
|
-ImVec2 ImGui::GetContentRegionAvail()
|
|
|
-{
|
|
|
- ImGuiWindow* window = GImGui->CurrentWindow;
|
|
|
- return GetContentRegionMaxAbs() - window->DC.CursorPos;
|
|
|
-}
|
|
|
-
|
|
|
-// In window space (not screen space!)
|
|
|
-ImVec2 ImGui::GetWindowContentRegionMin()
|
|
|
-{
|
|
|
- ImGuiWindow* window = GImGui->CurrentWindow;
|
|
|
- return window->ContentRegionRect.Min - window->Pos;
|
|
|
-}
|
|
|
-
|
|
|
-ImVec2 ImGui::GetWindowContentRegionMax()
|
|
|
-{
|
|
|
- ImGuiWindow* window = GImGui->CurrentWindow;
|
|
|
- return window->ContentRegionRect.Max - window->Pos;
|
|
|
-}
|
|
|
-
|
|
|
-float ImGui::GetWindowContentRegionWidth()
|
|
|
-{
|
|
|
- ImGuiWindow* window = GImGui->CurrentWindow;
|
|
|
- return window->ContentRegionRect.GetWidth();
|
|
|
-}
|
|
|
-
|
|
|
-float ImGui::GetTextLineHeight()
|
|
|
-{
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
- return g.FontSize;
|
|
|
-}
|
|
|
-
|
|
|
-float ImGui::GetTextLineHeightWithSpacing()
|
|
|
-{
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
- return g.FontSize + g.Style.ItemSpacing.y;
|
|
|
-}
|
|
|
-
|
|
|
-float ImGui::GetFrameHeight()
|
|
|
-{
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
- return g.FontSize + g.Style.FramePadding.y * 2.0f;
|
|
|
-}
|
|
|
-
|
|
|
-float ImGui::GetFrameHeightWithSpacing()
|
|
|
-{
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
- return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y;
|
|
|
-}
|
|
|
-
|
|
|
ImDrawList* ImGui::GetWindowDrawList()
|
|
|
{
|
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
@@ -7539,70 +7291,10 @@ void ImGui::SetWindowFontScale(float scale)
|
|
|
g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
|
|
|
}
|
|
|
|
|
|
-// User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient.
|
|
|
-// Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'.
|
|
|
-ImVec2 ImGui::GetCursorPos()
|
|
|
+void ImGui::ActivateItem(ImGuiID id)
|
|
|
{
|
|
|
- ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
- return window->DC.CursorPos - window->Pos + window->Scroll;
|
|
|
-}
|
|
|
-
|
|
|
-float ImGui::GetCursorPosX()
|
|
|
-{
|
|
|
- ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
- return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
|
|
|
-}
|
|
|
-
|
|
|
-float ImGui::GetCursorPosY()
|
|
|
-{
|
|
|
- ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
- return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;
|
|
|
-}
|
|
|
-
|
|
|
-void ImGui::SetCursorPos(const ImVec2& local_pos)
|
|
|
-{
|
|
|
- ImGuiWindow* window = GetCurrentWindow();
|
|
|
- window->DC.CursorPos = window->Pos - window->Scroll + local_pos;
|
|
|
- window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
|
|
|
-}
|
|
|
-
|
|
|
-void ImGui::SetCursorPosX(float x)
|
|
|
-{
|
|
|
- ImGuiWindow* window = GetCurrentWindow();
|
|
|
- window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;
|
|
|
- window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);
|
|
|
-}
|
|
|
-
|
|
|
-void ImGui::SetCursorPosY(float y)
|
|
|
-{
|
|
|
- ImGuiWindow* window = GetCurrentWindow();
|
|
|
- window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;
|
|
|
- window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
|
|
|
-}
|
|
|
-
|
|
|
-ImVec2 ImGui::GetCursorStartPos()
|
|
|
-{
|
|
|
- ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
- return window->DC.CursorStartPos - window->Pos;
|
|
|
-}
|
|
|
-
|
|
|
-ImVec2 ImGui::GetCursorScreenPos()
|
|
|
-{
|
|
|
- ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
- return window->DC.CursorPos;
|
|
|
-}
|
|
|
-
|
|
|
-void ImGui::SetCursorScreenPos(const ImVec2& pos)
|
|
|
-{
|
|
|
- ImGuiWindow* window = GetCurrentWindow();
|
|
|
- window->DC.CursorPos = pos;
|
|
|
- window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
|
|
|
-}
|
|
|
-
|
|
|
-void ImGui::ActivateItem(ImGuiID id)
|
|
|
-{
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
- g.NavNextActivateId = id;
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ g.NavNextActivateId = id;
|
|
|
}
|
|
|
|
|
|
void ImGui::PushFocusScope(ImGuiID id)
|
|
@@ -7727,129 +7419,6 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
|
|
|
return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
|
|
|
}
|
|
|
|
|
|
-// 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()
|
|
|
-{
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
- ImGuiWindow* window = GetCurrentWindow();
|
|
|
-
|
|
|
- window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1);
|
|
|
- ImGuiGroupData& group_data = window->DC.GroupStack.back();
|
|
|
- group_data.BackupCursorPos = window->DC.CursorPos;
|
|
|
- group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
|
|
|
- group_data.BackupIndent = window->DC.Indent;
|
|
|
- group_data.BackupGroupOffset = window->DC.GroupOffset;
|
|
|
- group_data.BackupCurrLineSize = window->DC.CurrLineSize;
|
|
|
- group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset;
|
|
|
- group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive;
|
|
|
- group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive;
|
|
|
- group_data.EmitItem = true;
|
|
|
-
|
|
|
- window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x;
|
|
|
- window->DC.Indent = window->DC.GroupOffset;
|
|
|
- window->DC.CursorMaxPos = window->DC.CursorPos;
|
|
|
- window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
|
|
|
- if (g.LogEnabled)
|
|
|
- g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return
|
|
|
-}
|
|
|
-
|
|
|
-void ImGui::EndGroup()
|
|
|
-{
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
- ImGuiWindow* window = GetCurrentWindow();
|
|
|
- IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls
|
|
|
-
|
|
|
- ImGuiGroupData& group_data = window->DC.GroupStack.back();
|
|
|
-
|
|
|
- ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos));
|
|
|
-
|
|
|
- window->DC.CursorPos = group_data.BackupCursorPos;
|
|
|
- window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
|
|
|
- window->DC.Indent = group_data.BackupIndent;
|
|
|
- window->DC.GroupOffset = group_data.BackupGroupOffset;
|
|
|
- window->DC.CurrLineSize = group_data.BackupCurrLineSize;
|
|
|
- window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset;
|
|
|
- if (g.LogEnabled)
|
|
|
- g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return
|
|
|
-
|
|
|
- if (!group_data.EmitItem)
|
|
|
- {
|
|
|
- window->DC.GroupStack.pop_back();
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
|
|
|
- ItemSize(group_bb.GetSize());
|
|
|
- ItemAdd(group_bb, 0);
|
|
|
-
|
|
|
- // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group.
|
|
|
- // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets.
|
|
|
- // Also if you grep for LastItemId you'll notice it is only used in that context.
|
|
|
- // (The tests not symmetrical because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.)
|
|
|
- const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId;
|
|
|
- const bool group_contains_prev_active_id = !group_data.BackupActiveIdPreviousFrameIsAlive && g.ActiveIdPreviousFrameIsAlive;
|
|
|
- if (group_contains_curr_active_id)
|
|
|
- window->DC.LastItemId = g.ActiveId;
|
|
|
- else if (group_contains_prev_active_id)
|
|
|
- window->DC.LastItemId = g.ActiveIdPreviousFrame;
|
|
|
- window->DC.LastItemRect = group_bb;
|
|
|
-
|
|
|
- // Forward Edited flag
|
|
|
- if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame)
|
|
|
- window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
|
|
|
-
|
|
|
- // Forward Deactivated flag
|
|
|
- window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated;
|
|
|
- if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame)
|
|
|
- window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated;
|
|
|
-
|
|
|
- window->DC.GroupStack.pop_back();
|
|
|
- //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
|
|
@@ -7863,13 +7432,13 @@ void ImGui::Unindent(float indent_w)
|
|
|
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!"); }
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
@@ -7891,7 +7460,6 @@ static void ImGui::ErrorCheckEndFrame()
|
|
|
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
|
|
@@ -7916,6 +7484,477 @@ static void ImGui::ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool
|
|
|
IM_ASSERT(p == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup));
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+// [SECTION] LAYOUT
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+// - ItemSize()
|
|
|
+// - ItemAdd()
|
|
|
+// - SameLine()
|
|
|
+// - GetCursorScreenPos()
|
|
|
+// - SetCursorScreenPos()
|
|
|
+// - GetCursorPos(), GetCursorPosX(), GetCursorPosY()
|
|
|
+// - SetCursorPos(), SetCursorPosX(), SetCursorPosY()
|
|
|
+// - GetCursorStartPos()
|
|
|
+// - Indent()
|
|
|
+// - Unindent()
|
|
|
+// - SetNextItemWidth()
|
|
|
+// - PushItemWidth()
|
|
|
+// - PushMultiItemsWidths()
|
|
|
+// - PopItemWidth()
|
|
|
+// - CalcItemWidth()
|
|
|
+// - CalcItemSize()
|
|
|
+// - GetTextLineHeight()
|
|
|
+// - GetTextLineHeightWithSpacing()
|
|
|
+// - GetFrameHeight()
|
|
|
+// - GetFrameHeightWithSpacing()
|
|
|
+// - GetContentRegionMax()
|
|
|
+// - GetContentRegionMaxAbs() [Internal]
|
|
|
+// - GetContentRegionAvail(),
|
|
|
+// - GetWindowContentRegionMin(), GetWindowContentRegionMax()
|
|
|
+// - GetWindowContentRegionWidth()
|
|
|
+// - 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;
|
|
|
+}
|
|
|
+
|
|
|
+ImVec2 ImGui::GetCursorScreenPos()
|
|
|
+{
|
|
|
+ ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
+ return window->DC.CursorPos;
|
|
|
+}
|
|
|
+
|
|
|
+void ImGui::SetCursorScreenPos(const ImVec2& pos)
|
|
|
+{
|
|
|
+ ImGuiWindow* window = GetCurrentWindow();
|
|
|
+ window->DC.CursorPos = pos;
|
|
|
+ window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
|
|
|
+}
|
|
|
+
|
|
|
+// User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient.
|
|
|
+// Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'.
|
|
|
+ImVec2 ImGui::GetCursorPos()
|
|
|
+{
|
|
|
+ ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
+ return window->DC.CursorPos - window->Pos + window->Scroll;
|
|
|
+}
|
|
|
+
|
|
|
+float ImGui::GetCursorPosX()
|
|
|
+{
|
|
|
+ ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
+ return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
|
|
|
+}
|
|
|
+
|
|
|
+float ImGui::GetCursorPosY()
|
|
|
+{
|
|
|
+ ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
+ return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;
|
|
|
+}
|
|
|
+
|
|
|
+void ImGui::SetCursorPos(const ImVec2& local_pos)
|
|
|
+{
|
|
|
+ ImGuiWindow* window = GetCurrentWindow();
|
|
|
+ window->DC.CursorPos = window->Pos - window->Scroll + local_pos;
|
|
|
+ window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
|
|
|
+}
|
|
|
+
|
|
|
+void ImGui::SetCursorPosX(float x)
|
|
|
+{
|
|
|
+ ImGuiWindow* window = GetCurrentWindow();
|
|
|
+ window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;
|
|
|
+ window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);
|
|
|
+}
|
|
|
+
|
|
|
+void ImGui::SetCursorPosY(float y)
|
|
|
+{
|
|
|
+ ImGuiWindow* window = GetCurrentWindow();
|
|
|
+ window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;
|
|
|
+ window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
|
|
|
+}
|
|
|
+
|
|
|
+ImVec2 ImGui::GetCursorStartPos()
|
|
|
+{
|
|
|
+ ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
+ return window->DC.CursorStartPos - window->Pos;
|
|
|
+}
|
|
|
+
|
|
|
+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;
|
|
|
+}
|
|
|
+
|
|
|
+// Affect large frame+labels widgets only.
|
|
|
+void ImGui::SetNextItemWidth(float item_width)
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth;
|
|
|
+ g.NextItemData.Width = item_width;
|
|
|
+}
|
|
|
+
|
|
|
+void ImGui::PushItemWidth(float item_width)
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ ImGuiWindow* window = g.CurrentWindow;
|
|
|
+ window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
|
|
|
+ window->DC.ItemWidthStack.push_back(window->DC.ItemWidth);
|
|
|
+ g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
|
|
|
+}
|
|
|
+
|
|
|
+void ImGui::PushMultiItemsWidths(int components, float w_full)
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ ImGuiWindow* window = g.CurrentWindow;
|
|
|
+ const ImGuiStyle& style = g.Style;
|
|
|
+ const float w_item_one = ImMax(1.0f, IM_FLOOR((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
|
|
|
+ const float w_item_last = ImMax(1.0f, IM_FLOOR(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
|
|
|
+ window->DC.ItemWidthStack.push_back(w_item_last);
|
|
|
+ for (int i = 0; i < components-1; i++)
|
|
|
+ window->DC.ItemWidthStack.push_back(w_item_one);
|
|
|
+ window->DC.ItemWidth = window->DC.ItemWidthStack.back();
|
|
|
+ g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
|
|
|
+}
|
|
|
+
|
|
|
+void ImGui::PopItemWidth()
|
|
|
+{
|
|
|
+ ImGuiWindow* window = GetCurrentWindow();
|
|
|
+ window->DC.ItemWidthStack.pop_back();
|
|
|
+ window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back();
|
|
|
+}
|
|
|
+
|
|
|
+// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth().
|
|
|
+// The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags()
|
|
|
+float ImGui::CalcItemWidth()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ ImGuiWindow* window = g.CurrentWindow;
|
|
|
+ float w;
|
|
|
+ if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth)
|
|
|
+ w = g.NextItemData.Width;
|
|
|
+ else
|
|
|
+ w = window->DC.ItemWidth;
|
|
|
+ if (w < 0.0f)
|
|
|
+ {
|
|
|
+ float region_max_x = GetContentRegionMaxAbs().x;
|
|
|
+ w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w);
|
|
|
+ }
|
|
|
+ w = IM_FLOOR(w);
|
|
|
+ return w;
|
|
|
+}
|
|
|
+
|
|
|
+// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth().
|
|
|
+// Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical.
|
|
|
+// Note that only CalcItemWidth() is publicly exposed.
|
|
|
+// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable)
|
|
|
+ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h)
|
|
|
+{
|
|
|
+ ImGuiWindow* window = GImGui->CurrentWindow;
|
|
|
+
|
|
|
+ ImVec2 region_max;
|
|
|
+ if (size.x < 0.0f || size.y < 0.0f)
|
|
|
+ region_max = GetContentRegionMaxAbs();
|
|
|
+
|
|
|
+ if (size.x == 0.0f)
|
|
|
+ size.x = default_w;
|
|
|
+ else if (size.x < 0.0f)
|
|
|
+ size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x);
|
|
|
+
|
|
|
+ if (size.y == 0.0f)
|
|
|
+ size.y = default_h;
|
|
|
+ else if (size.y < 0.0f)
|
|
|
+ size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y);
|
|
|
+
|
|
|
+ return size;
|
|
|
+}
|
|
|
+
|
|
|
+float ImGui::GetTextLineHeight()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ return g.FontSize;
|
|
|
+}
|
|
|
+
|
|
|
+float ImGui::GetTextLineHeightWithSpacing()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ return g.FontSize + g.Style.ItemSpacing.y;
|
|
|
+}
|
|
|
+
|
|
|
+float ImGui::GetFrameHeight()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ return g.FontSize + g.Style.FramePadding.y * 2.0f;
|
|
|
+}
|
|
|
+
|
|
|
+float ImGui::GetFrameHeightWithSpacing()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y;
|
|
|
+}
|
|
|
+
|
|
|
+// FIXME: All the Contents Region function are messy or misleading. WE WILL AIM TO OBSOLETE ALL OF THEM WITH A NEW "WORK RECT" API. Thanks for your patience!
|
|
|
+
|
|
|
+// FIXME: This is in window space (not screen space!).
|
|
|
+ImVec2 ImGui::GetContentRegionMax()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ ImGuiWindow* window = g.CurrentWindow;
|
|
|
+ ImVec2 mx = window->ContentRegionRect.Max - window->Pos;
|
|
|
+ if (window->DC.CurrentColumns)
|
|
|
+ mx.x = window->WorkRect.Max.x - window->Pos.x;
|
|
|
+ return mx;
|
|
|
+}
|
|
|
+
|
|
|
+// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features.
|
|
|
+ImVec2 ImGui::GetContentRegionMaxAbs()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ ImGuiWindow* window = g.CurrentWindow;
|
|
|
+ ImVec2 mx = window->ContentRegionRect.Max;
|
|
|
+ if (window->DC.CurrentColumns)
|
|
|
+ mx.x = window->WorkRect.Max.x;
|
|
|
+ return mx;
|
|
|
+}
|
|
|
+
|
|
|
+ImVec2 ImGui::GetContentRegionAvail()
|
|
|
+{
|
|
|
+ ImGuiWindow* window = GImGui->CurrentWindow;
|
|
|
+ return GetContentRegionMaxAbs() - window->DC.CursorPos;
|
|
|
+}
|
|
|
+
|
|
|
+// In window space (not screen space!)
|
|
|
+ImVec2 ImGui::GetWindowContentRegionMin()
|
|
|
+{
|
|
|
+ ImGuiWindow* window = GImGui->CurrentWindow;
|
|
|
+ return window->ContentRegionRect.Min - window->Pos;
|
|
|
+}
|
|
|
+
|
|
|
+ImVec2 ImGui::GetWindowContentRegionMax()
|
|
|
+{
|
|
|
+ ImGuiWindow* window = GImGui->CurrentWindow;
|
|
|
+ return window->ContentRegionRect.Max - window->Pos;
|
|
|
+}
|
|
|
+
|
|
|
+float ImGui::GetWindowContentRegionWidth()
|
|
|
+{
|
|
|
+ ImGuiWindow* window = GImGui->CurrentWindow;
|
|
|
+ return window->ContentRegionRect.GetWidth();
|
|
|
+}
|
|
|
+
|
|
|
+// 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()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ ImGuiWindow* window = GetCurrentWindow();
|
|
|
+
|
|
|
+ window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1);
|
|
|
+ ImGuiGroupData& group_data = window->DC.GroupStack.back();
|
|
|
+ group_data.BackupCursorPos = window->DC.CursorPos;
|
|
|
+ group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
|
|
|
+ group_data.BackupIndent = window->DC.Indent;
|
|
|
+ group_data.BackupGroupOffset = window->DC.GroupOffset;
|
|
|
+ group_data.BackupCurrLineSize = window->DC.CurrLineSize;
|
|
|
+ group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset;
|
|
|
+ group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive;
|
|
|
+ group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive;
|
|
|
+ group_data.EmitItem = true;
|
|
|
+
|
|
|
+ window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x;
|
|
|
+ window->DC.Indent = window->DC.GroupOffset;
|
|
|
+ window->DC.CursorMaxPos = window->DC.CursorPos;
|
|
|
+ window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
|
|
|
+ if (g.LogEnabled)
|
|
|
+ g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return
|
|
|
+}
|
|
|
+
|
|
|
+void ImGui::EndGroup()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ ImGuiWindow* window = GetCurrentWindow();
|
|
|
+ IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls
|
|
|
+
|
|
|
+ ImGuiGroupData& group_data = window->DC.GroupStack.back();
|
|
|
+
|
|
|
+ ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos));
|
|
|
+
|
|
|
+ window->DC.CursorPos = group_data.BackupCursorPos;
|
|
|
+ window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
|
|
|
+ window->DC.Indent = group_data.BackupIndent;
|
|
|
+ window->DC.GroupOffset = group_data.BackupGroupOffset;
|
|
|
+ window->DC.CurrLineSize = group_data.BackupCurrLineSize;
|
|
|
+ window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset;
|
|
|
+ if (g.LogEnabled)
|
|
|
+ g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return
|
|
|
+
|
|
|
+ if (!group_data.EmitItem)
|
|
|
+ {
|
|
|
+ window->DC.GroupStack.pop_back();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
|
|
|
+ ItemSize(group_bb.GetSize());
|
|
|
+ ItemAdd(group_bb, 0);
|
|
|
+
|
|
|
+ // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group.
|
|
|
+ // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets.
|
|
|
+ // Also if you grep for LastItemId you'll notice it is only used in that context.
|
|
|
+ // (The tests not symmetrical because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.)
|
|
|
+ const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId;
|
|
|
+ const bool group_contains_prev_active_id = !group_data.BackupActiveIdPreviousFrameIsAlive && g.ActiveIdPreviousFrameIsAlive;
|
|
|
+ if (group_contains_curr_active_id)
|
|
|
+ window->DC.LastItemId = g.ActiveId;
|
|
|
+ else if (group_contains_prev_active_id)
|
|
|
+ window->DC.LastItemId = g.ActiveIdPreviousFrame;
|
|
|
+ window->DC.LastItemRect = group_bb;
|
|
|
+
|
|
|
+ // Forward Edited flag
|
|
|
+ if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame)
|
|
|
+ window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
|
|
|
+
|
|
|
+ // Forward Deactivated flag
|
|
|
+ window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated;
|
|
|
+ if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame)
|
|
|
+ window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated;
|
|
|
+
|
|
|
+ window->DC.GroupStack.pop_back();
|
|
|
+ //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug]
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
//-----------------------------------------------------------------------------
|
|
|
// [SECTION] SCROLLING
|
|
|
//-----------------------------------------------------------------------------
|