Library perf (draw-data identical): layout core (no ImVec2 __index in ItemSize, inlined ID/style/clip stacks, scalar ItemAdd/IsClippedEx/CalcItemSize/GetColorU32), text + widgets (scalar TextEx/ButtonEx/Checkbox/Slider/Drag/Selectable/TreeNode, word-wrap memo), tables (in-place clip rects, no per-row/cell temporaries, @native cell functions, scalar ClipWith), draw list (PrimRectXY, scalar AddRect/AddRectFilled/AddLine/PathRect/arcs)

This commit is contained in:
4DBug
2026-10-14 23:27:23 -05:00
parent b71e29ee35
commit ed53d0683e
9 changed files with 2213 additions and 1255 deletions
+185 -121
View File
@@ -200,6 +200,7 @@ end
local bit32 = bit32
local band, bor, bnot, lshift, rshift = bit32.band, bit32.bor, bit32.bnot, bit32.lshift, bit32.rshift
local mathMax, mathMin = math.max, math.min -- [Luau] scalar ImMax()/ImMin() in table code are written as mathMax()/mathMin() (no call through the vector-aware helper)
IM_COL32_DISABLE = IM_COL32(0, 0, 0, 1) -- Special sentinel code which cannot be used as a regular color.
IMGUI_TABLE_MAX_COLUMNS = 512 -- Arbitrary "safety" maximum, may be lifted in the future if needed. Must fit in ImGuiTableColumnIdx/ImGuiTableDrawChannelIdx.
@@ -482,7 +483,7 @@ function ImGui.BeginTableEx(name, id, columns_count, flags, outer_size, inner_wi
-- - always performing the GetOrAddByKey() O(log N) query in g.Tables.Map[].
local use_child_window = band(flags, bor(ImGuiTableFlags.ScrollX, ImGuiTableFlags.ScrollY)) ~= 0
local avail_size = ImGui.GetContentRegionAvail()
local actual_outer_size = ImTrunc(ImGui.CalcItemSize(outer_size, ImMax(avail_size.x, IMGUI_WINDOW_HARD_MIN_SIZE), use_child_window and ImMax(avail_size.y, IMGUI_WINDOW_HARD_MIN_SIZE) or 0.0))
local actual_outer_size = ImTrunc(ImGui.CalcItemSize(outer_size, mathMax(avail_size.x, IMGUI_WINDOW_HARD_MIN_SIZE), use_child_window and mathMax(avail_size.y, IMGUI_WINDOW_HARD_MIN_SIZE) or 0.0))
local outer_rect = ImRect(outer_window.DC.CursorPos, outer_window.DC.CursorPos + actual_outer_size)
local outer_window_is_measuring_size = (outer_window.AutoFitFramesX > 0) or (outer_window.AutoFitFramesY > 0) -- Doesn't apply to AlwaysAutoResize windows!
if use_child_window and ImGui.IsClippedEx(outer_rect, 0) and not outer_window_is_measuring_size then
@@ -638,15 +639,15 @@ function ImGui.BeginTableEx(name, id, columns_count, flags, outer_size, inner_wi
-- different x/y values to BeginChild().
local border_size = TABLE_BORDER_SIZE
if band(flags, ImGuiTableFlags.BordersOuterV) ~= 0 then
table_.HostClipRect.Min.x = ImMin(table_.HostClipRect.Min.x + border_size, table_.HostClipRect.Max.x)
table_.HostClipRect.Min.x = mathMin(table_.HostClipRect.Min.x + border_size, table_.HostClipRect.Max.x)
if inner_window.DecoOuterSizeX2 == 0.0 then
table_.HostClipRect.Max.x = ImMax(table_.HostClipRect.Max.x - border_size, table_.HostClipRect.Min.x)
table_.HostClipRect.Max.x = mathMax(table_.HostClipRect.Max.x - border_size, table_.HostClipRect.Min.x)
end
end
if band(flags, ImGuiTableFlags.BordersOuterH) ~= 0 then
table_.HostClipRect.Min.y = ImMin(table_.HostClipRect.Min.y + border_size, table_.HostClipRect.Max.y)
table_.HostClipRect.Min.y = mathMin(table_.HostClipRect.Min.y + border_size, table_.HostClipRect.Max.y)
if inner_window.DecoOuterSizeY2 == 0.0 then
table_.HostClipRect.Max.y = ImMax(table_.HostClipRect.Max.y - border_size, table_.HostClipRect.Min.y)
table_.HostClipRect.Max.y = mathMax(table_.HostClipRect.Max.y - border_size, table_.HostClipRect.Min.y)
end
end
end
@@ -679,7 +680,7 @@ function ImGui.BeginTableEx(name, id, columns_count, flags, outer_size, inner_wi
ImRect_Copy(table_.InnerClipRect, (inner_window == outer_window) and table_.WorkRect or inner_window.ClipRect)
table_.InnerClipRect:ClipWith(table_.WorkRect) -- We need this to honor inner_width
table_.InnerClipRect:ClipWithFull(table_.HostClipRect)
table_.InnerClipRect.Max.y = (band(flags, ImGuiTableFlags.NoHostExtendY) ~= 0) and ImMin(table_.InnerClipRect.Max.y, inner_window.WorkRect.Max.y) or table_.HostClipRect.Max.y
table_.InnerClipRect.Max.y = (band(flags, ImGuiTableFlags.NoHostExtendY) ~= 0) and mathMin(table_.InnerClipRect.Max.y, inner_window.WorkRect.Max.y) or table_.HostClipRect.Max.y
table_.RowPosY1 = table_.WorkRect.Min.y -- This is needed somehow
table_.RowPosY2 = table_.WorkRect.Min.y
@@ -1050,7 +1051,7 @@ function ImGui.TableUpdateLayout(table_)
BitArrayClearAll(table_.EnabledMaskByIndex)
BitArrayClearAll(table_.EnabledMaskByDisplayOrder)
table_.LeftMostEnabledColumn = -1
table_.MinColumnWidth = ImMax(1.0, g.Style.FramePadding.x * 1.0) -- g.Style.ColumnsMinSpacing -- FIXME-TABLE
table_.MinColumnWidth = mathMax(1.0, g.Style.FramePadding.x * 1.0) -- g.Style.ColumnsMinSpacing -- FIXME-TABLE
-- [Part 1] Apply/lock Enabled and Order states. Calculate auto/ideal width for columns. Count fixed/stretch columns.
-- Process columns in their visible orders as we are building the Prev/Next indices.
@@ -1152,7 +1153,7 @@ function ImGui.TableUpdateLayout(table_)
stretch_sum_width_auto = stretch_sum_width_auto + column.WidthAuto
count_stretch = count_stretch + 1
else
fixed_max_width_auto = ImMax(fixed_max_width_auto, column.WidthAuto)
fixed_max_width_auto = mathMax(fixed_max_width_auto, column.WidthAuto)
count_fixed = count_fixed + 1
end
end
@@ -1204,7 +1205,7 @@ function ImGui.TableUpdateLayout(table_)
-- FIXME: Move this to .WidthGiven to avoid temporary lossyness?
-- FIXME: This break IsPreserveWidthAuto from not flickering if the stored WidthAuto was smaller.
if column.AutoFitQueue > 0x01 and table_.IsInitializing and not column.IsPreserveWidthAuto then
column.WidthRequest = ImMax(column.WidthRequest, table_.MinColumnWidth * 4.0) -- FIXME-TABLE: Another constant/scale?
column.WidthRequest = mathMax(column.WidthRequest, table_.MinColumnWidth * 4.0) -- FIXME-TABLE: Another constant/scale?
end
sum_width_requests = sum_width_requests + column.WidthRequest
else
@@ -1238,7 +1239,7 @@ function ImGui.TableUpdateLayout(table_)
local work_rect = Rect(table_.WorkRect)
local width_spacings = (table_.OuterPaddingX * 2.0) + (table_.CellSpacingX1 + table_.CellSpacingX2) * (table_.ColumnsEnabledCount - 1)
local width_removed = (table_.HasScrollbarYPrev and not table_.InnerWindow.ScrollbarY) and g.Style.ScrollbarSize or 0.0 -- To synchronize decoration width of synced tables with mismatching scrollbar state (#5920)
local width_avail = ImMax(1.0, ((band(table_.Flags, ImGuiTableFlags.ScrollX) ~= 0 and table_.InnerWidth == 0.0) and table_.InnerClipRect:GetWidth() or work_rect:GetWidth()) - width_removed)
local width_avail = mathMax(1.0, ((band(table_.Flags, ImGuiTableFlags.ScrollX) ~= 0 and table_.InnerWidth == 0.0) and table_.InnerClipRect:GetWidth() or work_rect:GetWidth()) - width_removed)
local width_avail_for_stretched_columns = width_avail - width_spacings - sum_width_requests
local width_remaining_for_stretched_columns = width_avail_for_stretched_columns
table_.ColumnsGivenWidth = width_spacings + (table_.CellPaddingX * 2.0) * table_.ColumnsEnabledCount
@@ -1249,7 +1250,7 @@ function ImGui.TableUpdateLayout(table_)
-- Allocate width for stretched/weighted columns (StretchWeight gets converted into WidthRequest)
if band(column.Flags, ImGuiTableColumnFlags.WidthStretch) ~= 0 then
local weight_ratio = column.StretchWeight / stretch_sum_weights
column.WidthRequest = IM_TRUNC(ImMax(width_avail_for_stretched_columns * weight_ratio, table_.MinColumnWidth) + 0.01)
column.WidthRequest = IM_TRUNC(mathMax(width_avail_for_stretched_columns * weight_ratio, table_.MinColumnWidth) + 0.01)
width_remaining_for_stretched_columns = width_remaining_for_stretched_columns - column.WidthRequest
end
@@ -1260,7 +1261,7 @@ function ImGui.TableUpdateLayout(table_)
end
-- Assign final width, record width in case we will need to shrink
column.WidthGiven = ImTrunc(ImMax(column.WidthRequest, table_.MinColumnWidth))
column.WidthGiven = ImTrunc(mathMax(column.WidthRequest, table_.MinColumnWidth))
table_.ColumnsGivenWidth = table_.ColumnsGivenWidth + column.WidthGiven
end
end
@@ -1291,7 +1292,7 @@ function ImGui.TableUpdateLayout(table_)
table_instance.HoveredRowLast = table_instance.HoveredRowNext
table_instance.HoveredRowNext = -1
table_.HoveredColumnBody = -1; table_.HoveredColumnBorder = -1
local mouse_hit_rect = ImRect(table_.OuterRect.Min.x, table_.OuterRect.Min.y, table_.OuterRect.Max.x, ImMax(table_.OuterRect.Max.y, table_.OuterRect.Min.y + table_instance.LastOuterHeight))
local mouse_hit_rect = ImRect(table_.OuterRect.Min.x, table_.OuterRect.Min.y, table_.OuterRect.Max.x, mathMax(table_.OuterRect.Max.y, table_.OuterRect.Min.y + table_instance.LastOuterHeight))
local backup_active_id = g.ActiveId
g.ActiveId = 0
local is_hovering_table = ImGui.ItemHoverable(mouse_hit_rect, 0, ImGuiItemFlags.None)
@@ -1346,8 +1347,8 @@ function ImGui.TableUpdateLayout(table_)
-- Lock width based on start position and minimum/maximum width for this position
column.WidthMax = ImGui.TableCalcMaxColumnWidth(table_, column_n)
column.WidthGiven = ImMin(column.WidthGiven, column.WidthMax)
column.WidthGiven = ImMax(column.WidthGiven, ImMin(column.WidthRequest, table_.MinColumnWidth))
column.WidthGiven = mathMin(column.WidthGiven, column.WidthMax)
column.WidthGiven = mathMax(column.WidthGiven, mathMin(column.WidthRequest, table_.MinColumnWidth))
column.MaxX = offset_x + column.WidthGiven + table_.CellSpacingX1 + table_.CellSpacingX2 + table_.CellPaddingX * 2.0
-- Lock other positions
@@ -1455,7 +1456,7 @@ function ImGui.TableUpdateLayout(table_)
-- [Part 7] Detect/store when we are hovering the unused space after the right-most column (so e.g. context menus can react on it)
-- Clear Resizable flag if none of our column are actually resizable (either via an explicit _NoResize flag, either
-- because of using _WidthAuto/_WidthStretch). This will hide the resizing option from the context menu.
local unused_x1 = ImMax(table_.WorkRect.Min.x, table_.Columns[table_.RightMostEnabledColumn].ClipRect.Max.x)
local unused_x1 = mathMax(table_.WorkRect.Min.x, table_.Columns[table_.RightMostEnabledColumn].ClipRect.Max.x)
if is_hovering_table and table_.HoveredColumnBody == -1 then
if mouse_skewed_x >= unused_x1 then
table_.HoveredColumnBody = columns_count
@@ -1475,7 +1476,7 @@ function ImGui.TableUpdateLayout(table_)
end
if band(table_.Flags, ImGuiTableFlags.NoHostExtendX) ~= 0 then
table_.OuterRect.Max.x = unused_x1; table_.WorkRect.Max.x = unused_x1
table_.InnerClipRect.Max.x = ImMin(table_.InnerClipRect.Max.x, unused_x1)
table_.InnerClipRect.Max.x = mathMin(table_.InnerClipRect.Max.x, unused_x1)
end
ImRect_Copy(table_.InnerWindow.ParentWorkRect, table_.WorkRect)
table_.BorderX1 = table_.InnerClipRect.Min.x
@@ -1486,7 +1487,7 @@ function ImGui.TableUpdateLayout(table_)
if band(table_.Flags, ImGuiTableFlags.NoHostExtendY) ~= 0 then
window_content_max_y = table_.OuterRect.Max.y
else
window_content_max_y = ImMax(table_.InnerWindow.ContentRegionRect.Max.y, (band(table_.Flags, ImGuiTableFlags.ScrollY) ~= 0) and 0.0 or table_.OuterRect.Max.y)
window_content_max_y = mathMax(table_.InnerWindow.ContentRegionRect.Max.y, (band(table_.Flags, ImGuiTableFlags.ScrollY) ~= 0) and 0.0 or table_.OuterRect.Max.y)
end
table_.InnerWindow.WorkRect.Max.y = ImClamp(window_content_max_y - g.Style.CellPadding.y, table_.InnerWindow.WorkRect.Min.y, table_.InnerWindow.WorkRect.Max.y)
@@ -1578,7 +1579,7 @@ function ImGui.TableUpdateBorders(table_)
local table_instance = ImGui.TableGetInstanceData(table_, table_.InstanceCurrent)
local hit_half_width = ImTrunc(TABLE_RESIZE_SEPARATOR_HALF_THICKNESS * g.CurrentDpiScale)
local hit_y1 = ((table_.FreezeRowsCount >= 1) and table_.OuterRect.Min.y or table_.WorkRect.Min.y) + table_.AngledHeadersHeight
local hit_y2_body = ImMax(table_.OuterRect.Max.y, hit_y1 + table_instance.LastOuterHeight - table_.AngledHeadersHeight)
local hit_y2_body = mathMax(table_.OuterRect.Max.y, hit_y1 + table_instance.LastOuterHeight - table_.AngledHeadersHeight)
local hit_y2_head = hit_y1 + table_instance.LastTopHeadersRowHeight
for order_n = 0, table_.ColumnsCount - 1 do
@@ -1672,10 +1673,10 @@ function ImGui.EndTable()
if inner_window ~= outer_window then
inner_window.DC.CursorMaxPos.y = inner_content_max_y
elseif band(flags, ImGuiTableFlags.NoHostExtendY) == 0 then
local v = ImMax(table_.OuterRect.Max.y, inner_content_max_y) -- Patch OuterRect/InnerRect height
local v = mathMax(table_.OuterRect.Max.y, inner_content_max_y) -- Patch OuterRect/InnerRect height
table_.OuterRect.Max.y = v; table_.InnerRect.Max.y = v
end
table_.WorkRect.Max.y = ImMax(table_.WorkRect.Max.y, table_.OuterRect.Max.y)
table_.WorkRect.Max.y = mathMax(table_.WorkRect.Max.y, table_.OuterRect.Max.y)
table_instance.LastOuterHeight = table_.OuterRect:GetHeight()
-- Setup inner scrolling range
@@ -1685,10 +1686,10 @@ function ImGui.EndTable()
local outer_padding_for_border = (band(table_.Flags, ImGuiTableFlags.BordersOuterV) ~= 0) and TABLE_BORDER_SIZE or 0.0
local max_pos_x = inner_window.DC.CursorMaxPos.x
if table_.RightMostEnabledColumn ~= -1 then
max_pos_x = ImMax(max_pos_x, table_.Columns[table_.RightMostEnabledColumn].WorkMaxX + table_.CellPaddingX + table_.OuterPaddingX - outer_padding_for_border)
max_pos_x = mathMax(max_pos_x, table_.Columns[table_.RightMostEnabledColumn].WorkMaxX + table_.CellPaddingX + table_.OuterPaddingX - outer_padding_for_border)
end
if table_.ResizedColumn ~= -1 then
max_pos_x = ImMax(max_pos_x, table_.ResizeLockMinContentsX2)
max_pos_x = mathMax(max_pos_x, table_.ResizeLockMinContentsX2)
end
inner_window.DC.CursorMaxPos.x = max_pos_x + table_.TempData.AngledHeadersExtraWidth
end
@@ -1731,12 +1732,12 @@ function ImGui.EndTable()
auto_fit_width_for_stretched = auto_fit_width_for_stretched + column_width_request
end
if band(column.Flags, ImGuiTableColumnFlags.WidthStretch) ~= 0 and band(column.Flags, ImGuiTableColumnFlags.NoResize) ~= 0 then
auto_fit_width_for_stretched_min = ImMax(auto_fit_width_for_stretched_min, column_width_request / (column.StretchWeight / table_.ColumnsStretchSumWeights))
auto_fit_width_for_stretched_min = mathMax(auto_fit_width_for_stretched_min, column_width_request / (column.StretchWeight / table_.ColumnsStretchSumWeights))
end
end
end
local width_spacings = (table_.OuterPaddingX * 2.0) + (table_.CellSpacingX1 + table_.CellSpacingX2) * (table_.ColumnsEnabledCount - 1)
table_.ColumnsAutoFitWidth = width_spacings + (table_.CellPaddingX * 2.0) * table_.ColumnsEnabledCount + auto_fit_width_for_fixed + ImMax(auto_fit_width_for_stretched, auto_fit_width_for_stretched_min)
table_.ColumnsAutoFitWidth = width_spacings + (table_.CellPaddingX * 2.0) * table_.ColumnsEnabledCount + auto_fit_width_for_fixed + mathMax(auto_fit_width_for_stretched, auto_fit_width_for_stretched_min)
-- Update scroll
if band(table_.Flags, ImGuiTableFlags.ScrollX) == 0 and inner_window ~= outer_window then
@@ -1801,27 +1802,27 @@ function ImGui.EndTable()
-- FIXME-TABLE: Could we remove this section?
-- ColumnsAutoFitWidth may be one frame ahead here since for Fixed+NoResize is calculated from latest contents
IM_ASSERT(band(table_.Flags, ImGuiTableFlags.ScrollX) == 0)
outer_window.DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, table_.OuterRect.Min.x + table_.ColumnsAutoFitWidth)
outer_window.DC.CursorMaxPos.x = mathMax(backup_outer_max_pos.x, table_.OuterRect.Min.x + table_.ColumnsAutoFitWidth)
elseif temp_data.UserOuterSize.x <= 0.0 then
-- Some references for this: #7651 + tests "table_reported_size", "table_reported_size_outer" equivalent Y block, #9352
-- - FIXME-TABLE: Would make sense to pre-compute expected scrollbar visibility/sizes to generally save a frame of feedback? See broken test in 'table_reported_size_outer'
local outer_content_max_x = table_.OuterRect.Min.x + table_.ColumnsAutoFitWidth
local decoration_size = table_.TempData.AngledHeadersExtraWidth + ((inner_window ~= outer_window) and inner_window.ScrollbarSizes.x or 0.0)
outer_window.DC.IdealMaxPos.x = ImMax(outer_window.DC.IdealMaxPos.x, outer_content_max_x + decoration_size - temp_data.UserOuterSize.x)
outer_window.DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table_.OuterRect.Max.x, outer_content_max_x + decoration_size))
outer_window.DC.IdealMaxPos.x = mathMax(outer_window.DC.IdealMaxPos.x, outer_content_max_x + decoration_size - temp_data.UserOuterSize.x)
outer_window.DC.CursorMaxPos.x = mathMax(backup_outer_max_pos.x, mathMin(table_.OuterRect.Max.x, outer_content_max_x + decoration_size))
else
outer_window.DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, table_.OuterRect.Max.x)
outer_window.DC.CursorMaxPos.x = mathMax(backup_outer_max_pos.x, table_.OuterRect.Max.x)
end
if temp_data.UserOuterSize.y <= 0.0 then
-- (same comment as above)
local outer_content_size_y = (inner_window == outer_window) and (inner_content_max_y - table_.InnerRect.Min.y) or (inner_content_max_y - inner_window.DC.CursorStartPos.y)
local outer_content_max_y = table_.OuterRect.Min.y + outer_content_size_y
local decoration_size = (inner_window ~= outer_window) and inner_window.ScrollbarSizes.y or 0.0
outer_window.DC.IdealMaxPos.y = ImMax(outer_window.DC.IdealMaxPos.y, outer_content_max_y + decoration_size - temp_data.UserOuterSize.y)
outer_window.DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, ImMin(table_.OuterRect.Max.y, outer_content_max_y + decoration_size))
outer_window.DC.IdealMaxPos.y = mathMax(outer_window.DC.IdealMaxPos.y, outer_content_max_y + decoration_size - temp_data.UserOuterSize.y)
outer_window.DC.CursorMaxPos.y = mathMax(backup_outer_max_pos.y, mathMin(table_.OuterRect.Max.y, outer_content_max_y + decoration_size))
else
-- OuterRect.Max.y may already have been pushed downward from the initial value (unless ImGuiTableFlags.NoHostExtendY is set)
outer_window.DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, table_.OuterRect.Max.y)
outer_window.DC.CursorMaxPos.y = mathMax(backup_outer_max_pos.y, table_.OuterRect.Max.y)
end
-- Save settings
@@ -2039,7 +2040,7 @@ function ImGui.TableSetupScrollFreeze(columns, rows)
IM_ASSERT(columns >= 0 and columns < IMGUI_TABLE_MAX_COLUMNS)
IM_ASSERT(rows >= 0 and rows < 128) -- Arbitrary limit
table_.FreezeColumnsRequest = (band(table_.Flags, ImGuiTableFlags.ScrollX) ~= 0) and ImMin(columns, table_.ColumnsCount) or 0
table_.FreezeColumnsRequest = (band(table_.Flags, ImGuiTableFlags.ScrollX) ~= 0) and mathMin(columns, table_.ColumnsCount) or 0
table_.FreezeColumnsCount = (table_.InnerWindow.Scroll.x ~= 0.0) and table_.FreezeColumnsRequest or 0
table_.FreezeRowsRequest = (band(table_.Flags, ImGuiTableFlags.ScrollY) ~= 0) and rows or 0
table_.FreezeRowsCount = (table_.InnerWindow.Scroll.y ~= 0.0) and table_.FreezeRowsRequest or 0
@@ -2065,11 +2066,23 @@ end
-- they would meddle many times with the underlying ImDrawCmd.
-- Instead, we do a preemptive overwrite of clipping rectangle _without_ altering the command-buffer and let
-- the subsequent single call to SetCurrentChannel() does it things once.
@native
function ImGui.SetWindowClipRectBeforeSetChannel(window, clip_rect)
local clip_rect_vec4 = clip_rect:ToVec4()
ImRect_Copy(window.ClipRect, clip_rect)
ImVec4_Copy(window.DrawList._CmdHeader.ClipRect, clip_rect_vec4)
window.DrawList._ClipRectStack.Data[window.DrawList._ClipRectStack.Size] = clip_rect_vec4
-- [Luau] scalar copies, no temporary ImVec4: the clip rect stack top is a uniquely owned ImVec4 (PushClipRect always pushes a fresh one), so overwrite it in place
local min, max = clip_rect.Min, clip_rect.Max
local x1, y1, x2, y2 = min.x, min.y, max.x, max.y
local wcr = window.ClipRect
wcr.Min.x = x1; wcr.Min.y = y1; wcr.Max.x = x2; wcr.Max.y = y2
local draw_list = window.DrawList
local hcr = draw_list._CmdHeader.ClipRect
hcr.x = x1; hcr.y = y1; hcr.z = x2; hcr.w = y2
local stack = draw_list._ClipRectStack
local top = stack.Data[stack.Size]
if top ~= nil then
top.x = x1; top.y = y1; top.z = x2; top.w = y2
else
stack.Data[stack.Size] = ImVec4(x1, y1, x2, y2)
end
end
function ImGui.TableGetColumnCount()
@@ -2154,8 +2167,8 @@ function ImGui.TableGetCellBgRect(table_, column_n)
-- x1 = x1 - table.OuterPaddingX
--if column.NextEnabledColumn == -1 then
-- x2 = x2 + table.OuterPaddingX
x1 = ImMax(x1, table_.WorkRect.Min.x)
x2 = ImMin(x2, table_.WorkRect.Max.x)
x1 = mathMax(x1, table_.WorkRect.Min.x)
x2 = mathMin(x2, table_.WorkRect.Max.x)
return ImRect(x1, table_.RowPosY1, x2, table_.RowPosY2)
end
@@ -2274,8 +2287,7 @@ function ImGui.TableNextRow(row_flags, row_min_height)
-- We honor min_row_height requested by user, but cannot guarantee per-row maximum height,
-- because that would essentially require a unique clipping rectangle per-cell.
table_.RowPosY2 = table_.RowPosY2 + table_.RowCellPaddingY * 2.0
table_.RowPosY2 = ImMax(table_.RowPosY2, table_.RowPosY1 + row_min_height)
table_.RowPosY2 = mathMax(table_.RowPosY2 + table_.RowCellPaddingY * 2.0, table_.RowPosY1 + row_min_height) -- [Luau] inline ImMax
-- Disable output until user calls TableNextColumn()
table_.InnerWindow.SkipItems = true
@@ -2302,15 +2314,16 @@ function ImGui.TableBeginRow(table_)
table_.RowPosY1 = next_y1; table_.RowPosY2 = next_y1
table_.RowTextBaseline = 0.0
table_.RowIndentOffsetX = window.DC.Indent.x - table_.HostIndentX -- Lock indent
local dc = window.DC -- [Luau] cache
table_.RowIndentOffsetX = dc.Indent.x - table_.HostIndentX -- Lock indent
window.DC.PrevLineTextBaseOffset = 0.0
window.DC.CursorPosPrevLine.x = window.DC.CursorPos.x
window.DC.CursorPosPrevLine.y = window.DC.CursorPos.y + table_.RowCellPaddingY -- This allows users to call SameLine() to share LineSize between columns.
window.DC.PrevLineSize.x = 0.0; window.DC.PrevLineSize.y = 0.0 -- This allows users to call SameLine() to share LineSize between columns, and to call it from first column too.
window.DC.CurrLineSize.x = 0.0; window.DC.CurrLineSize.y = 0.0
window.DC.IsSameLine = false; window.DC.IsSetPos = false
window.DC.CursorMaxPos.y = next_y1
dc.PrevLineTextBaseOffset = 0.0
dc.CursorPosPrevLine.x = dc.CursorPos.x
dc.CursorPosPrevLine.y = dc.CursorPos.y + table_.RowCellPaddingY -- This allows users to call SameLine() to share LineSize between columns.
dc.PrevLineSize.x = 0.0; dc.PrevLineSize.y = 0.0 -- This allows users to call SameLine() to share LineSize between columns, and to call it from first column too.
dc.CurrLineSize.x = 0.0; dc.CurrLineSize.y = 0.0
dc.IsSameLine = false; dc.IsSetPos = false
dc.CursorMaxPos.y = next_y1
-- Making the header BG color non-transparent will allow us to overlay it multiple times when handling smooth dragging.
if band(table_.RowFlags, ImGuiTableRowFlags.Headers) ~= 0 then
@@ -2321,6 +2334,9 @@ function ImGui.TableBeginRow(table_)
end
end
-- [Luau] scratch vectors for TableEndRow() row background (never escape)
local TableEndRow_RowMin, TableEndRow_RowMax = ImVec2(), ImVec2()
-- [Internal] Called by TableNextRow()
function ImGui.TableEndRow(table_)
local g = GImGui
@@ -2347,7 +2363,7 @@ function ImGui.TableEndRow(table_)
local bg_y2 = table_.RowPosY2
local unfreeze_rows_actual = (table_.CurrentRow + 1 == table_.FreezeRowsCount)
local unfreeze_rows_request = (table_.CurrentRow + 1 == table_.FreezeRowsRequest)
local table_instance = ImGui.TableGetInstanceData(table_, table_.InstanceCurrent)
local table_instance = (table_.InstanceCurrent == 0) and table_.InstanceDataFirst or ImGui.TableGetInstanceData(table_, table_.InstanceCurrent) -- [Luau] inline common case
if band(table_.RowFlags, ImGuiTableRowFlags.Headers) ~= 0 and (table_.CurrentRow == 0 or band(table_.LastRowFlags, ImGuiTableRowFlags.Headers) ~= 0) then
table_instance.LastTopHeadersRowHeight = table_instance.LastTopHeadersRowHeight + bg_y2 - bg_y1
end
@@ -2384,7 +2400,9 @@ function ImGui.TableEndRow(table_)
-- In theory we could call SetWindowClipRectBeforeSetChannel() but since we know TableEndRow() is
-- always followed by a change of clipping rectangle we perform the smallest overwrite possible here.
if band(table_.Flags, ImGuiTableFlags.NoClip) == 0 then
ImVec4_Copy(window.DrawList._CmdHeader.ClipRect, table_.Bg0ClipRectForDrawCmd:ToVec4())
-- [Luau] scalar copy, no temporary ImVec4
local src, dst = table_.Bg0ClipRectForDrawCmd, window.DrawList._CmdHeader.ClipRect
dst.x = src.Min.x; dst.y = src.Min.y; dst.z = src.Max.x; dst.w = src.Max.y
end
table_.DrawSplitter:SetCurrentChannel(window.DrawList, TABLE_DRAW_CHANNEL_BG0)
end
@@ -2392,13 +2410,16 @@ function ImGui.TableEndRow(table_)
-- Draw row background
-- We soft/cpu clip this so all backgrounds and borders can share the same clipping rectangle
if bg_col0 ~= 0 or bg_col1 ~= 0 then
local row_rect = ImRect(table_.WorkRect.Min.x, bg_y1, table_.WorkRect.Max.x, bg_y2)
row_rect:ClipWith(table_.BgClipRect)
if bg_col0 ~= 0 and row_rect.Min.y < row_rect.Max.y then
window.DrawList:AddRectFilled(row_rect.Min, row_rect.Max, bg_col0)
-- [Luau] row_rect = ImRect(WorkRect.Min.x, bg_y1, WorkRect.Max.x, bg_y2); row_rect:ClipWith(BgClipRect), in scratch vectors (only read by AddRectFilled)
local bg_clip_rect = table_.BgClipRect
local row_min, row_max = TableEndRow_RowMin, TableEndRow_RowMax
row_min.x = mathMax(table_.WorkRect.Min.x, bg_clip_rect.Min.x); row_min.y = mathMax(bg_y1, bg_clip_rect.Min.y)
row_max.x = mathMin(table_.WorkRect.Max.x, bg_clip_rect.Max.x); row_max.y = mathMin(bg_y2, bg_clip_rect.Max.y)
if bg_col0 ~= 0 and row_min.y < row_max.y then
window.DrawList:AddRectFilled(row_min, row_max, bg_col0)
end
if bg_col1 ~= 0 and row_rect.Min.y < row_rect.Max.y then
window.DrawList:AddRectFilled(row_rect.Min, row_rect.Max, bg_col1)
if bg_col1 ~= 0 and row_min.y < row_max.y then
window.DrawList:AddRectFilled(row_min, row_max, bg_col1)
end
end
@@ -2411,8 +2432,8 @@ function ImGui.TableEndRow(table_)
local column = table_.Columns[cell_data.Column]
local cell_bg_rect = ImGui.TableGetCellBgRect(table_, cell_data.Column)
cell_bg_rect:ClipWith(table_.BgClipRect)
cell_bg_rect.Min.x = ImMax(cell_bg_rect.Min.x, column.ClipRect.Min.x) -- So that first column after frozen one gets clipped when scrolling
cell_bg_rect.Max.x = ImMin(cell_bg_rect.Max.x, column.MaxX)
cell_bg_rect.Min.x = mathMax(cell_bg_rect.Min.x, column.ClipRect.Min.x) -- So that first column after frozen one gets clipped when scrolling
cell_bg_rect.Max.x = mathMin(cell_bg_rect.Max.x, column.MaxX)
if cell_bg_rect.Min.y < cell_bg_rect.Max.y then
window.DrawList:AddRectFilled(cell_bg_rect.Min, cell_bg_rect.Max, cell_data.BgColor)
end
@@ -2438,7 +2459,7 @@ function ImGui.TableEndRow(table_)
for column_n = 0, table_.ColumnsCount - 1 do
table_.Columns[column_n].NavLayerCurrent = table_.NavLayer
end
local y0 = ImMax(table_.RowPosY2 + 1, table_.InnerClipRect.Min.y)
local y0 = mathMax(table_.RowPosY2 + 1, table_.InnerClipRect.Min.y)
table_instance.LastFrozenHeight = y0 - table_.OuterRect.Min.y
if unfreeze_rows_actual then
@@ -2446,7 +2467,7 @@ function ImGui.TableEndRow(table_)
table_.IsUnfrozenRows = true
-- BgClipRect starts as table.InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect
local min_y = ImMin(y0, table_.InnerClipRect.Max.y)
local min_y = mathMin(y0, table_.InnerClipRect.Max.y)
table_.BgClipRect.Min.y = min_y; table_.Bg2ClipRectForDrawCmd.Min.y = min_y
table_.BgClipRect.Max.y = table_.InnerClipRect.Max.y; table_.Bg2ClipRectForDrawCmd.Max.y = table_.InnerClipRect.Max.y
table_.Bg2DrawChannelCurrent = table_.Bg2DrawChannelUnfrozen
@@ -2518,6 +2539,7 @@ function ImGui.TableSetColumnIndex(column_n)
end
-- [Public] Append into the next column, wrap and create a new row when already on last column
@native
function ImGui.TableNextColumn()
local g = GImGui
local table_ = g.CurrentTable
@@ -2525,28 +2547,33 @@ function ImGui.TableNextColumn()
return false
end
if table_.IsInsideRow and table_.CurrentColumn + 1 < table_.ColumnsCount then
if table_.CurrentColumn ~= -1 then
local current_column = table_.CurrentColumn
local next_column
if table_.IsInsideRow and current_column + 1 < table_.ColumnsCount then
if current_column ~= -1 then
ImGui.TableEndCell(table_)
end
ImGui.TableBeginCell(table_, table_.CurrentColumn + 1)
next_column = current_column + 1
else
ImGui.TableNextRow()
ImGui.TableBeginCell(table_, 0)
next_column = 0
end
ImGui.TableBeginCell(table_, next_column)
-- Return whether the column is visible. User may choose to skip submitting items based on this return value,
-- however they shouldn't skip submitting for columns that may have the tallest contribution to row height.
return table_.Columns[table_.CurrentColumn].IsRequestOutput
return table_.Columns[next_column].IsRequestOutput
end
-- [Internal] Called by TableSetColumnIndex()/TableNextColumn()
-- This is called very frequently, so we need to be mindful of unnecessary overhead.
-- FIXME-TABLE FIXME-OPT: Could probably shortcut some things for non-active or clipped columns.
@native
function ImGui.TableBeginCell(table_, column_n)
local g = GImGui
local column = table_.Columns[column_n]
local window = table_.InnerWindow
local dc = window.DC -- [Luau] cache
table_.CurrentColumn = column_n
-- Start position is roughly ~~ CellRect.Min + CellPadding + Indent
@@ -2555,35 +2582,45 @@ function ImGui.TableBeginCell(table_, column_n)
start_x = start_x + table_.RowIndentOffsetX -- ~~ += window.DC.Indent.x - table.HostIndentX, except we locked it for the row.
end
window.DC.CursorPos.x = start_x
window.DC.CursorPos.y = table_.RowPosY1 + table_.RowCellPaddingY
window.DC.CursorMaxPos.x = window.DC.CursorPos.x
window.DC.ColumnsOffset.x = start_x - window.Pos.x - window.DC.Indent.x -- FIXME-WORKRECT
window.DC.CursorPosPrevLine.x = window.DC.CursorPos.x -- PrevLine.y is preserved. This allows users to call SameLine() to share LineSize between columns.
window.DC.CurrLineTextBaseOffset = table_.RowTextBaseline
window.DC.NavLayerCurrent = column.NavLayerCurrent
local start_y = table_.RowPosY1 + table_.RowCellPaddingY
dc.CursorPos.x = start_x
dc.CursorPos.y = start_y
dc.CursorMaxPos.x = start_x
dc.ColumnsOffset.x = start_x - window.Pos.x - dc.Indent.x -- FIXME-WORKRECT
dc.CursorPosPrevLine.x = start_x -- PrevLine.y is preserved. This allows users to call SameLine() to share LineSize between columns.
dc.CurrLineTextBaseOffset = table_.RowTextBaseline
dc.NavLayerCurrent = column.NavLayerCurrent
-- Note how WorkRect.Max.y is only set once during layout
window.WorkRect.Min.y = window.DC.CursorPos.y
window.WorkRect.Min.x = column.WorkMinX
window.WorkRect.Max.x = column.WorkMaxX
window.DC.ItemWidth = column.ItemWidth
local work_rect = window.WorkRect
work_rect.Min.y = start_y
work_rect.Min.x = column.WorkMinX
work_rect.Max.x = column.WorkMaxX
dc.ItemWidth = column.ItemWidth
window.SkipItems = column.IsSkipItems
if column.IsSkipItems then
local skip_items = column.IsSkipItems
window.SkipItems = skip_items
if skip_items then
g.LastItemData.ID = 0
g.LastItemData.StatusFlags = 0
end
-- Also see TablePushColumnChannel()
-- [Luau] inline the SetCurrentChannel() early-out (same channel) to skip the method call
local splitter = table_.DrawSplitter
if band(table_.Flags, ImGuiTableFlags.NoClip) ~= 0 then
-- FIXME: if we end up drawing all borders/bg in EndTable, could remove this and just assert that channel hasn't changed.
table_.DrawSplitter:SetCurrentChannel(window.DrawList, TABLE_DRAW_CHANNEL_NOCLIP)
if splitter._Current ~= TABLE_DRAW_CHANNEL_NOCLIP then
splitter:SetCurrentChannel(window.DrawList, TABLE_DRAW_CHANNEL_NOCLIP)
end
--IM_ASSERT(table.DrawSplitter._Current == TABLE_DRAW_CHANNEL_NOCLIP)
else
-- FIXME-TABLE: Could avoid this if draw channel is dummy channel?
ImGui.SetWindowClipRectBeforeSetChannel(window, column.ClipRect)
table_.DrawSplitter:SetCurrentChannel(window.DrawList, column.DrawChannelCurrent)
local channel = column.DrawChannelCurrent
if splitter._Current ~= channel then
splitter:SetCurrentChannel(window.DrawList, channel)
end
end
-- Logging
@@ -2594,31 +2631,34 @@ function ImGui.TableBeginCell(table_, column_n)
end
-- [Internal] Called by TableNextRow()/TableSetColumnIndex()/TableNextColumn()
@native
function ImGui.TableEndCell(table_)
local column = table_.Columns[table_.CurrentColumn]
local window = table_.InnerWindow
local dc = window.DC -- [Luau] cache; mathMax() inlined as math.max below
if window.DC.IsSetPos then
if dc.IsSetPos then
ImGui.ErrorCheckUsingSetCursorPosToExtendParentBoundaries()
end
-- Report maximum position so we can infer content size per column.
local x = window.DC.CursorMaxPos.x
local cursor_max_pos = dc.CursorMaxPos
local x = cursor_max_pos.x
if band(table_.RowFlags, ImGuiTableRowFlags.Headers) ~= 0 then
column.ContentMaxXHeadersUsed = ImMax(column.ContentMaxXHeadersUsed, x) -- Useful in case user submit contents in header row that is not a TableHeader() call
column.ContentMaxXHeadersUsed = mathMax(column.ContentMaxXHeadersUsed, x) -- Useful in case user submit contents in header row that is not a TableHeader() call
elseif table_.IsUnfrozenRows then
column.ContentMaxXUnfrozen = ImMax(column.ContentMaxXUnfrozen, x)
column.ContentMaxXUnfrozen = mathMax(column.ContentMaxXUnfrozen, x)
else
column.ContentMaxXFrozen = ImMax(column.ContentMaxXFrozen, x)
column.ContentMaxXFrozen = mathMax(column.ContentMaxXFrozen, x)
end
if column.IsEnabled then
table_.RowPosY2 = ImMax(table_.RowPosY2, window.DC.CursorMaxPos.y + table_.RowCellPaddingY)
table_.RowPosY2 = mathMax(table_.RowPosY2, cursor_max_pos.y + table_.RowCellPaddingY)
end
column.ItemWidth = window.DC.ItemWidth
column.ItemWidth = dc.ItemWidth
-- Propagate text baseline for the entire row
-- FIXME-TABLE: Here we propagate text baseline from the last line of the cell.. instead of the first one.
table_.RowTextBaseline = ImMax(table_.RowTextBaseline, window.DC.PrevLineTextBaseOffset)
table_.RowTextBaseline = mathMax(table_.RowTextBaseline, dc.PrevLineTextBaseOffset)
end
-------------------------------------------------------------------------------
@@ -2663,11 +2703,11 @@ end
-- Note this is meant to be stored in column.WidthAuto, please generally use the WidthAuto field
function ImGui.TableGetColumnWidthAuto(table_, column)
local content_width_body = ImMax(column.ContentMaxXFrozen, column.ContentMaxXUnfrozen) - column.WorkMinX
local content_width_body = mathMax(column.ContentMaxXFrozen, column.ContentMaxXUnfrozen) - column.WorkMinX
local content_width_headers = column.ContentMaxXHeadersIdeal - column.WorkMinX
local width_auto = content_width_body
if band(column.Flags, ImGuiTableColumnFlags.NoHeaderWidth) == 0 then
width_auto = ImMax(width_auto, content_width_headers)
width_auto = mathMax(width_auto, content_width_headers)
end
-- Non-resizable fixed columns preserve their requested width
@@ -2677,7 +2717,7 @@ function ImGui.TableGetColumnWidthAuto(table_, column)
end
end
return ImMax(width_auto, table_.MinColumnWidth)
return mathMax(width_auto, table_.MinColumnWidth)
end
-- 'width' = inner column width, without padding
@@ -2693,7 +2733,7 @@ function ImGui.TableSetColumnWidth(column_n, width)
-- Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded)
IM_ASSERT(table_.MinColumnWidth > 0.0)
local min_width = table_.MinColumnWidth
local max_width = ImMax(min_width, column_0.WidthMax) -- Don't use TableCalcMaxColumnWidth() here as it would rely on MinX from last instance (#7933)
local max_width = mathMax(min_width, column_0.WidthMax) -- Don't use TableCalcMaxColumnWidth() here as it would rely on MinX from last instance (#7933)
column_0_width = ImClamp(column_0_width, min_width, max_width)
if column_0.WidthGiven == column_0_width or column_0.WidthRequest == column_0_width then
return
@@ -2754,7 +2794,7 @@ function ImGui.TableSetColumnWidth(column_n, width)
-- Resizing from right-side of a Stretch column before a Fixed column forward sizing to left-side of fixed column.
-- (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b)
local column_1_width = ImMax(column_1.WidthRequest - (column_0_width - column_0.WidthRequest), min_width)
local column_1_width = mathMax(column_1.WidthRequest - (column_0_width - column_0.WidthRequest), min_width)
column_0_width = column_0.WidthRequest + column_1.WidthRequest - column_1_width
IM_ASSERT(column_0_width > 0.0 and column_1_width > 0.0)
column_0.WidthRequest = column_0_width
@@ -2970,6 +3010,12 @@ end
--
-- This function is particularly tricky to understand.. take a breath.
-- (Lua: splitter channel n lives in splitter._Channels.Data[n + 1]; bit arrays are Lua sets)
local TableMergeDrawChannels_MergeGroups = {}
for n = 0, 3 do
TableMergeDrawChannels_MergeGroups[n] = { ClipRect = ImRect(), ChannelsCount = 0, ChannelsMask = {} }
end
local TableMergeDrawChannels_RemainingMask = {}
local TableMergeDrawChannels_DstTmp = {}
function ImGui.TableMergeDrawChannels(table_)
local splitter = table_.DrawSplitter
local channels = splitter._Channels.Data
@@ -2979,12 +3025,18 @@ function ImGui.TableMergeDrawChannels(table_)
-- Track which groups we are going to attempt to merge, and which channels goes into each group.
local merge_group_mask = 0x00
local merge_groups = {}
-- [Luau] reuse file-level scratch storage (function is not re-entrant, nothing escapes)
local merge_groups = TableMergeDrawChannels_MergeGroups
for n = 0, 3 do
merge_groups[n] = { ClipRect = ImRect(), ChannelsCount = 0, ChannelsMask = {} }
local merge_group = merge_groups[n]
local cr = merge_group.ClipRect
cr.Min.x = 0.0; cr.Min.y = 0.0; cr.Max.x = 0.0; cr.Max.y = 0.0
merge_group.ChannelsCount = 0
table.clear(merge_group.ChannelsMask)
end
local max_draw_channels = (4 + table_.ColumnsCount * 2)
local remaining_mask = {}
local remaining_mask = TableMergeDrawChannels_RemainingMask
table.clear(remaining_mask)
-- 1. Scan channels and take note of those which can be merged
for column_n = 0, table_.ColumnsCount - 1 do
@@ -3011,9 +3063,9 @@ function ImGui.TableMergeDrawChannels(table_)
if band(column.Flags, ImGuiTableColumnFlags.NoClip) == 0 then
local content_max_x
if not has_freeze_v then
content_max_x = ImMax(column.ContentMaxXUnfrozen, column.ContentMaxXHeadersUsed) -- No row freeze
content_max_x = mathMax(column.ContentMaxXUnfrozen, column.ContentMaxXHeadersUsed) -- No row freeze
elseif merge_group_sub_n == 0 then
content_max_x = ImMax(column.ContentMaxXFrozen, column.ContentMaxXHeadersUsed) -- Row freeze: use width before freeze
content_max_x = mathMax(column.ContentMaxXFrozen, column.ContentMaxXHeadersUsed) -- Row freeze: use width before freeze
else
content_max_x = column.ContentMaxXUnfrozen -- Row freeze: use width after freeze
end
@@ -3026,12 +3078,18 @@ function ImGui.TableMergeDrawChannels(table_)
IM_ASSERT(channel_no < max_draw_channels)
local merge_group = merge_groups[merge_group_n]
if merge_group.ChannelsCount == 0 then
merge_group.ClipRect = ImRect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX)
local gcr = merge_group.ClipRect -- [Luau] in place (merge_groups are local to this call)
gcr.Min.x = FLT_MAX; gcr.Min.y = FLT_MAX; gcr.Max.x = -FLT_MAX; gcr.Max.y = -FLT_MAX
end
merge_group.ChannelsMask[channel_no] = true
merge_group.ChannelsCount = merge_group.ChannelsCount + 1
local cr = cmds.Data[1].ClipRect
merge_group.ClipRect:Add(ImRect(cr.x, cr.y, cr.z, cr.w))
-- [Luau] scalar version of merge_group.ClipRect:Add(ImRect(cr.x, cr.y, cr.z, cr.w))
local gmin, gmax = merge_group.ClipRect.Min, merge_group.ClipRect.Max
if gmin.x > cr.x then gmin.x = cr.x end
if gmin.y > cr.y then gmin.y = cr.y end
if gmax.x < cr.z then gmax.x = cr.z end
if gmax.y < cr.w then gmax.y = cr.w end
merge_group_mask = bor(merge_group_mask, lshift(1, merge_group_n))
until true
end
@@ -3046,7 +3104,8 @@ function ImGui.TableMergeDrawChannels(table_)
if merge_group_mask ~= 0 then
-- We skip channel 0 (Bg0/Bg1) and 1 (Bg2 frozen) from the shuffling since they won't move - see channels allocation in TableSetupDrawChannels().
local LEADING_DRAW_CHANNELS = 2
local dst_tmp = {}
local dst_tmp = TableMergeDrawChannels_DstTmp -- [Luau] scratch
table.clear(dst_tmp)
for n = LEADING_DRAW_CHANNELS, splitter._Count - 1 do
remaining_mask[n] = true
end
@@ -3069,16 +3128,16 @@ function ImGui.TableMergeDrawChannels(table_)
-- FIXME-TABLE FIXME-WORKRECT: We are wasting a merge opportunity on tables without scrolling if column doesn't fit
-- within host clip rect, solely because of the half-padding difference between window.WorkRect and window.InnerClipRect.
if band(merge_group_n, 1) == 0 or not has_freeze_h then
merge_clip_rect.Min.x = ImMin(merge_clip_rect.Min.x, host_rect.Min.x)
merge_clip_rect.Min.x = mathMin(merge_clip_rect.Min.x, host_rect.Min.x)
end
if band(merge_group_n, 2) == 0 or not has_freeze_v then
merge_clip_rect.Min.y = ImMin(merge_clip_rect.Min.y, host_rect.Min.y)
merge_clip_rect.Min.y = mathMin(merge_clip_rect.Min.y, host_rect.Min.y)
end
if band(merge_group_n, 1) ~= 0 then
merge_clip_rect.Max.x = ImMax(merge_clip_rect.Max.x, host_rect.Max.x)
merge_clip_rect.Max.x = mathMax(merge_clip_rect.Max.x, host_rect.Max.x)
end
if band(merge_group_n, 2) ~= 0 and band(table_.Flags, ImGuiTableFlags.NoHostExtendY) == 0 then
merge_clip_rect.Max.y = ImMax(merge_clip_rect.Max.y, host_rect.Max.y)
merge_clip_rect.Max.y = mathMax(merge_clip_rect.Max.y, host_rect.Max.y)
end
--ImGui.GetForegroundDrawList():AddRect(merge_group.ClipRect.Min, merge_group.ClipRect.Max, IM_COL32(255, 0, 0, 200), 0.0, 0, 1.0) -- [DEBUG]
--ImGui.GetForegroundDrawList():AddLine(merge_group.ClipRect.Min, merge_clip_rect.Min, IM_COL32(255, 100, 0, 200))
@@ -3096,7 +3155,8 @@ function ImGui.TableMergeDrawChannels(table_)
local channel = channels[n + 1]
IM_ASSERT(channel._CmdBuffer.Size == 1)
ImVec4_Copy(channel._CmdBuffer.Data[1].ClipRect, merge_clip_rect:ToVec4())
local dst = channel._CmdBuffer.Data[1].ClipRect -- [Luau] scalar copy, no temporary ImVec4
dst.x = merge_clip_rect.Min.x; dst.y = merge_clip_rect.Min.y; dst.z = merge_clip_rect.Max.x; dst.w = merge_clip_rect.Max.y
dst_tmp[#dst_tmp + 1] = channel
end
n = n + 1
@@ -3122,6 +3182,7 @@ function ImGui.TableMergeDrawChannels(table_)
for i = 1, #dst_tmp do
channels[LEADING_DRAW_CHANNELS + i] = dst_tmp[i]
end
table.clear(dst_tmp) -- [Luau] don't keep channel references alive in the scratch
end
end
@@ -3152,9 +3213,9 @@ function ImGui.TableDrawBorders(table_)
-- Draw inner border and resizing feedback
local table_instance = ImGui.TableGetInstanceData(table_, table_.InstanceCurrent)
local border_size = TABLE_BORDER_SIZE
local draw_y1 = ImMax(table_.InnerRect.Min.y, ((table_.FreezeRowsCount >= 1) and table_.InnerRect.Min.y or table_.WorkRect.Min.y) + table_.AngledHeadersHeight) + ((band(table_.Flags, ImGuiTableFlags.BordersOuterH) ~= 0) and border_size or 0.0)
local draw_y1 = mathMax(table_.InnerRect.Min.y, ((table_.FreezeRowsCount >= 1) and table_.InnerRect.Min.y or table_.WorkRect.Min.y) + table_.AngledHeadersHeight) + ((band(table_.Flags, ImGuiTableFlags.BordersOuterH) ~= 0) and border_size or 0.0)
local draw_y2_body = table_.InnerRect.Max.y
local draw_y2_head = table_.IsUsingHeaders and ImMin(table_.InnerRect.Max.y, ((table_.FreezeRowsCount >= 1) and table_.InnerRect.Min.y or table_.WorkRect.Min.y) + table_instance.LastTopHeadersRowHeight) or draw_y1
local draw_y2_head = table_.IsUsingHeaders and mathMin(table_.InnerRect.Max.y, ((table_.FreezeRowsCount >= 1) and table_.InnerRect.Min.y or table_.WorkRect.Min.y) + table_instance.LastTopHeadersRowHeight) or draw_y1
if band(table_.Flags, ImGuiTableFlags.BordersInnerV) ~= 0 then
for order_n = 0, table_.ColumnsCount - 1 do
repeat
@@ -3310,7 +3371,7 @@ function ImGui.TableSetColumnSortDirection(column_n, sort_direction, append_to_s
local sort_order_max = 0
if append_to_sort_specs then
for other_column_n = 0, table_.ColumnsCount - 1 do
sort_order_max = ImMax(sort_order_max, table_.Columns[other_column_n].SortOrder)
sort_order_max = mathMax(sort_order_max, table_.Columns[other_column_n].SortOrder)
end
end
@@ -3468,7 +3529,7 @@ function ImGui.TableGetHeaderRowHeight()
for column_n = 0, table_.ColumnsCount - 1 do
if BitTest(table_.EnabledMaskByIndex, column_n) then
if band(table_.Columns[column_n].Flags, ImGuiTableColumnFlags.NoHeaderLabel) == 0 then
row_height = ImMax(row_height, ImGui.CalcTextSize(ImGui.TableGetColumnName(table_, column_n)).y)
row_height = mathMax(row_height, ImGui.CalcTextSize(ImGui.TableGetColumnName(table_, column_n)).y)
end
end
end
@@ -3482,7 +3543,7 @@ function ImGui.TableGetHeaderAngledMaxLabelWidth()
for column_n = 0, table_.ColumnsCount - 1 do
if BitTest(table_.EnabledMaskByIndex, column_n) then
if band(table_.Columns[column_n].Flags, ImGuiTableColumnFlags.AngledHeader) ~= 0 then
width = ImMax(width, ImGui.CalcTextSize(ImGui.TableGetColumnName(table_, column_n), nil, true).x)
width = mathMax(width, ImGui.CalcTextSize(ImGui.TableGetColumnName(table_, column_n), nil, true).x)
end
end
end
@@ -3561,8 +3622,11 @@ function ImGui.TableHeader(label)
-- If we already got a row height, there's use that.
-- FIXME-TABLE: Padding problem if the correct outer-padding CellBgRect strays off our ClipRect?
local cell_r = ImGui.TableGetCellBgRect(table_, column_n)
local label_height = ImMax(label_size.y, table_.RowMinHeight - table_.RowCellPaddingY * 2.0)
-- [Luau] scalar version of: cell_r = TableGetCellBgRect(table_, column_n) (Min.x/Min.y/Max.x/Max.y -> cell_x1/cell_y1/cell_x2/cell_y2)
local cell_x1 = mathMax(column.MinX, table_.WorkRect.Min.x)
local cell_x2 = mathMin(column.MaxX, table_.WorkRect.Max.x)
local cell_y1, cell_y2 = table_.RowPosY1, table_.RowPosY2
local label_height = mathMax(label_size.y, table_.RowMinHeight - table_.RowCellPaddingY * 2.0)
-- Calculate ideal size for sort order arrow
local w_arrow = 0.0
@@ -3583,12 +3647,12 @@ function ImGui.TableHeader(label)
-- We feed our unclipped width to the column without writing on CursorMaxPos, so that column is still considered for merging.
local max_pos_x = label_pos.x + label_size.x + w_sort_text + w_arrow
column.ContentMaxXHeadersUsed = ImMax(column.ContentMaxXHeadersUsed, sort_arrow and cell_r.Max.x or ImMin(max_pos_x, cell_r.Max.x))
column.ContentMaxXHeadersIdeal = ImMax(column.ContentMaxXHeadersIdeal, max_pos_x)
column.ContentMaxXHeadersUsed = mathMax(column.ContentMaxXHeadersUsed, sort_arrow and cell_x2 or mathMin(max_pos_x, cell_x2))
column.ContentMaxXHeadersIdeal = mathMax(column.ContentMaxXHeadersIdeal, max_pos_x)
-- Keep header highlighted when context menu is open.
local id = window:GetID(label)
local bb = ImRect(cell_r.Min.x, cell_r.Min.y, cell_r.Max.x, ImMax(cell_r.Max.y, cell_r.Min.y + label_height + g.Style.CellPadding.y * 2.0))
local bb = ImRect(cell_x1, cell_y1, cell_x2, mathMax(cell_y2, cell_y1 + label_height + g.Style.CellPadding.y * 2.0))
ImGui.ItemSize(ImVec2(0.0, label_height)) -- Don't declare unclipped width, it'll be fed ContentMaxPosHeadersIdeal
if not ImGui.ItemAdd(bb, id) then
return
@@ -3626,13 +3690,13 @@ function ImGui.TableHeader(label)
-- ... 2 3 4 ... 2 3 4 (Display order)
-- - The other constraints are enforced by TableQueueSetColumnDisplayOrder() which might early out.
table_.InstanceInteracted = table_.InstanceCurrent
if g.IO.MouseDelta.x < 0.0 and g.IO.MousePos.x < cell_r.Min.x then
if g.IO.MouseDelta.x < 0.0 and g.IO.MousePos.x < cell_x1 then
local prev_column = (column.PrevEnabledColumn ~= -1) and table_.Columns[column.PrevEnabledColumn] or nil
if prev_column then
ImGui.TableQueueSetColumnDisplayOrder(table_, column_n, prev_column.DisplayOrder)
end
end
if g.IO.MouseDelta.x > 0.0 and g.IO.MousePos.x > cell_r.Max.x then
if g.IO.MouseDelta.x > 0.0 and g.IO.MousePos.x > cell_x2 then
local next_column = (column.NextEnabledColumn ~= -1) and table_.Columns[column.NextEnabledColumn] or nil
if next_column then
ImGui.TableQueueSetColumnDisplayOrder(table_, column_n, next_column.DisplayOrder)
@@ -3643,10 +3707,10 @@ function ImGui.TableHeader(label)
-- Sort order arrow
-- - Only clip label for a visible arrow. Auto-fit still accounts for a possible arrow, but when
-- manually sized smaller we don't clip the label for the sake of an arrow that isn't displayed.
local ellipsis_max = ImMax(cell_r.Max.x - (sort_arrow and (w_arrow + w_sort_text) or 0.0), label_pos.x)
local ellipsis_max = mathMax(cell_x2 - (sort_arrow and (w_arrow + w_sort_text) or 0.0), label_pos.x)
if band(table_.Flags, ImGuiTableFlags.Sortable) ~= 0 and band(column.Flags, ImGuiTableColumnFlags.NoSort) == 0 then
if column.SortOrder ~= -1 then
local x = ImMax(cell_r.Min.x, cell_r.Max.x - w_arrow - w_sort_text)
local x = mathMax(cell_x1, cell_x2 - w_arrow - w_sort_text)
local y = label_pos.y
if column.SortOrder > 0 then
ImGui.PushStyleColor(ImGuiCol.Text, ImGui.GetColorU32(ImGuiCol.Text, 0.70))