mirror of
https://github.com/Drezil/imgui.git
synced 2024-12-19 06:26:35 +00:00
Merge branch 'master' into docking
# Conflicts: # imgui.cpp
This commit is contained in:
commit
91ac93f9a6
873
imgui.cpp
873
imgui.cpp
@ -65,6 +65,7 @@ CODE
|
|||||||
// [SECTION] RENDER HELPERS
|
// [SECTION] RENDER HELPERS
|
||||||
// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
|
// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
|
||||||
// [SECTION] ERROR CHECKING
|
// [SECTION] ERROR CHECKING
|
||||||
|
// [SECTION] LAYOUT
|
||||||
// [SECTION] SCROLLING
|
// [SECTION] SCROLLING
|
||||||
// [SECTION] TOOLTIPS
|
// [SECTION] TOOLTIPS
|
||||||
// [SECTION] POPUPS
|
// [SECTION] POPUPS
|
||||||
@ -3101,102 +3102,6 @@ static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFla
|
|||||||
return true;
|
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()
|
// 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()
|
// - 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
|
// - 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);
|
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)
|
void ImGui::SetCurrentFont(ImFont* font)
|
||||||
{
|
{
|
||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
@ -7426,77 +7249,6 @@ void ImGui::SetNextWindowClass(const ImGuiWindowClass* window_class)
|
|||||||
g.NextWindowData.WindowClass = *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()
|
ImDrawList* ImGui::GetWindowDrawList()
|
||||||
{
|
{
|
||||||
ImGuiWindow* window = GetCurrentWindow();
|
ImGuiWindow* window = GetCurrentWindow();
|
||||||
@ -7539,66 +7291,6 @@ void ImGui::SetWindowFontScale(float scale)
|
|||||||
g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
|
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()
|
|
||||||
{
|
|
||||||
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)
|
void ImGui::ActivateItem(ImGuiID id)
|
||||||
{
|
{
|
||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
@ -7727,6 +7419,461 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
|
|||||||
return window->ClipRect.Overlaps(ImRect(rect_min, 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()
|
||||||
|
// - 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.)
|
// 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()
|
void ImGui::BeginGroup()
|
||||||
{
|
{
|
||||||
@ -7807,114 +7954,6 @@ void ImGui::EndGroup()
|
|||||||
//window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug]
|
//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
|
// [SECTION] SCROLLING
|
||||||
|
Loading…
Reference in New Issue
Block a user