Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add row resizing for tables #50

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
3 changes: 3 additions & 0 deletions lib/Internal.lua
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ return function(Iris: Types.Iris): Types.Internal
ZIndex = 0,
}
Internal._lastWidget = Internal._rootWidget -- widget which was most recently rendered
Internal._windowUpdatedThisCycle = false -- if a window was updated this cycle

-- Config
Internal._rootConfig = {} -- root style which all widgets derive from
Expand Down Expand Up @@ -266,6 +267,8 @@ return function(Iris: Types.Iris): Types.Internal
error("Callback has too few calls to Iris.End()", 0)
end

Internal._windowUpdatedThisCycle = false

--debug.profileend()
end

Expand Down
3 changes: 3 additions & 0 deletions lib/Types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,14 @@ export type Widget = {
usesScreenGUI: boolean,
ButtonColors: { [string]: Color3 | number },
ComboChildrenHeight: number,
postCycleCallbackIDs: { number },

-- Table properties
RowColumnIndex: number,
InitialNumColumns: number,
ColumnInstances: { Frame },
CellInstances: { Frame },
CellSizeUpdateNeeded: boolean,

-- Event Props
isHoveredEvent: boolean,
Expand Down Expand Up @@ -287,6 +289,7 @@ export type Internal = {
SelectionImageObject: Frame,
parentInstance: BasePlayerGui,
_utility: WidgetUtility,
_windowUpdatedThisCycle: boolean,

-- Config
_rootConfig: Config,
Expand Down
25 changes: 25 additions & 0 deletions lib/demoWindow.lua
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,31 @@ return function(Iris: Types.Iris)

Iris.Text({ "" })

Iris.SameLine()
Iris.Text({ "Table with varying sized components:" })
helpMarker("if you have elements with varying sizes, the table will automatically adjust the size of the rows")
Iris.End()

Iris.Table({ 2 })
for i = 1, 4 do
Iris.NextRow()
Iris.NextColumn()
if i % 2 == 0 then
Iris.Text({ `Row: {i}, Column: 1\nExtra Line`, true })
else
Iris.Text({ `Row: {i}, Column: 1`, true })
end
Iris.NextColumn()
if i % 3 == 1 then
Iris.Text({ `Row: {i}, Column: 2\nExtra Line`, true })
else
Iris.Text({ `Row: {i}, Column: 2`, true })
end
end
Iris.End()

Iris.Text({ "" })

Iris.SameLine()
Iris.Text({ "Table using NextColumn only syntax:" })
helpMarker("only calling Iris.NextColumn() in the inner loop, the result is identical")
Expand Down
92 changes: 92 additions & 0 deletions lib/widgets/Table.lua
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ return function(Iris: Types.Internal, widgets: Types.WidgetUtility)
-- reference to these is stored as an optimization
thisWidget.ColumnInstances = {}
thisWidget.CellInstances = {}
thisWidget.postCycleCallbackIDs = {}
thisWidget.CellSizeUpdateNeeded = false

local Table: Frame = Instance.new("Frame")
Table.Name = "Iris_Table"
Expand Down Expand Up @@ -82,6 +84,91 @@ return function(Iris: Types.Internal, widgets: Types.WidgetUtility)
thisWidget.ColumnInstances[index] = Column
Column.Parent = Table
end

-- Resize the table cells to match the largest cell in the row
local function UpdateCellSizes()
if not thisWidget.CellSizeUpdateNeeded and not Iris._windowUpdatedThisCycle then
return
end

thisWidget.CellSizeUpdateNeeded = false

debug.profilebegin("Iris/UpdateCellSizes")

local columnCells = {}
local mostRowsColumn, mostRowsCount = nil, 0
for _, Column in thisWidget.ColumnInstances do
columnCells[Column] = {}
for i, Cell in Column:GetChildren() do
if Cell:IsA("Frame") then
-- Reset the size of the cell to normal so it can size down if needed
Cell.Size = UDim2.new(1, 0, 0, 0)
table.insert(columnCells[Column], {
Cell = Cell,
LayoutOrder = Cell.LayoutOrder,
})

-- table.maxn is 15x faster than table.getn (#table)
if table.maxn(columnCells[Column]) > mostRowsCount then
mostRowsColumn = Column
mostRowsCount = table.maxn(columnCells[Column])
end
end
end
end

for _, cells in columnCells do
table.sort(cells, function(a, b)
return a.LayoutOrder < b.LayoutOrder
end)
end

for row, cellData in columnCells[mostRowsColumn] do
-- Compare other cells in this row
local cell = cellData.Cell
local largestYSize = cell.AbsoluteSize.Y

-- Find the largest cell in the row
for _, otherColumn in columnCells do
if otherColumn == mostRowsColumn then
continue
end

-- edge case for when the other column has less cells than the column
-- with the most rows
if not otherColumn[row] then
continue
end

if otherColumn[row].Cell.AbsoluteSize.Y > largestYSize then
largestYSize = otherColumn[row].Cell.AbsoluteSize.Y
end
end

-- Set the size of all cells in this row to the largest cell in the row
for _, otherColumn in columnCells do
if otherColumn == mostRowsColumn then
continue
end

-- edge case for when the other column has less cells than the column
-- with the most rows
if not otherColumn[row] then
continue
end

otherColumn[row].Cell.Size = UDim2.new(1, 0, 0, largestYSize)
end
end

debug.profileend()
end

task.defer(UpdateCellSizes)

local id = #Iris._postCycleCallbacks + 1
table.insert(thisWidget.postCycleCallbackIDs, id)
Iris._postCycleCallbacks[id] = UpdateCellSizes
elseif thisWidget.arguments.NumColumns ~= thisWidget.InitialNumColumns then
-- its possible to make it so that the NumColumns can increase,
-- but decreasing it would interfere with child widget instances
Expand Down Expand Up @@ -114,8 +201,13 @@ return function(Iris: Types.Internal, widgets: Types.WidgetUtility)
Discard = function(thisWidget: Types.Widget)
tableWidgets[thisWidget.ID] = nil
thisWidget.Instance:Destroy()

for _, id in thisWidget.postCycleCallbackIDs do
Iris._postCycleCallbacks[id] = nil
end
end,
ChildAdded = function(thisWidget: Types.Widget)
thisWidget.CellSizeUpdateNeeded = true
if thisWidget.RowColumnIndex == 0 then
thisWidget.RowColumnIndex = 1
end
Expand Down
17 changes: 17 additions & 0 deletions lib/widgets/Window.lua
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ return function(Iris: Types.Internal, widgets: Types.WidgetUtility)

thisWidget.usesScreenGUI = Iris._config.UseScreenGUIs
windowWidgets[thisWidget.ID] = thisWidget
thisWidget.postCycleCallbackIDs = {}

local Window
if thisWidget.usesScreenGUI then
Expand Down Expand Up @@ -780,6 +781,11 @@ return function(Iris: Types.Internal, widgets: Types.WidgetUtility)
resizeWindow = nil
isResizing = false
end

for _, callbackID in thisWidget.postCycleCallbackIDs do
Iris._postCycleCallbacks[callbackID] = nil
end

windowWidgets[thisWidget.ID] = nil
thisWidget.Instance:Destroy()
widgets.discardState(thisWidget)
Expand Down Expand Up @@ -899,6 +905,17 @@ return function(Iris: Types.Internal, widgets: Types.WidgetUtility)
if thisWidget.state.scrollDistance == nil then
thisWidget.state.scrollDistance = Iris._widgetState(thisWidget, "scrollDistance", 0)
end

-- this.state.size:OnChange() wasn't working so I'm doing this instead
local id = #Iris._postCycleCallbacks + 1
table.insert(thisWidget.postCycleCallbackIDs, id)
local lastSizeValue = thisWidget.state.size.value
Iris._postCycleCallbacks[id] = function()
if lastSizeValue ~= thisWidget.state.size.value then
lastSizeValue = thisWidget.state.size.value
Iris._windowUpdatedThisCycle = true
end
end
end,
} :: Types.WidgetClass)
end