414 lines
10 KiB
Lua
414 lines
10 KiB
Lua
local column = require "helium.layout.column"
|
|
--my copy of the cssssss grids
|
|
local path = string.sub(..., 1, string.len(...) - string.len(".grid"))
|
|
local layout = require(path..'.layout')
|
|
|
|
---@class GridCell
|
|
---@field name string @Will find the element with the relevant flag
|
|
|
|
---@alias GridRow GridCell[]
|
|
|
|
---@class HGridCell
|
|
---@field width number @Determines how wide this column will be
|
|
|
|
---@class WGridCell
|
|
---@field height string @Determines how high this column will be
|
|
|
|
---@alias HGridRow number[]|number|nil @Width of the row in cells
|
|
|
|
---@alias WGridCol number[]|number|nil @Width of the row in cells
|
|
|
|
---@alias GridLayout GridRow[]
|
|
|
|
---@class GridConfig
|
|
---@field layout GridLayout|nil @preconfigured layout table
|
|
---@field rows HGridRow|number|nil @set these instead of layout if you just want a regularly spaced 'table'
|
|
---@field columns WGridCol|number|nil @set these instead of layout if you just want a regularly spaced 'table' leave empty to flow in as many elements as you have
|
|
---@field verticalStretchMode "'stretch'"|"'normal'"
|
|
---@field horizontalStretchMode "'stretch'"|"'normal'"
|
|
---@field horizontalAlignMode "'left'"|"'center'"|"'right'"
|
|
---@field verticalAlignMode "'top'"|"'center'"|"'bottom'"
|
|
---@field rowSpacing number @size in pixels to space the rows
|
|
---@field colSpacing number @size in pixels to space the columns
|
|
---@field rowSizeMode "'relative'"|"'absolute'"
|
|
---@field colSizeMode "'relative'"|"'absolute'"
|
|
|
|
---@type GridConfig
|
|
local preconfiguredGrid = {
|
|
colSpacing = 20,
|
|
rowSpacing = 20,
|
|
verticalStretchMode = 'stretch',
|
|
horizontalStretchMode = 'stretch',
|
|
verticalAlignMode = 'center',
|
|
horizontalAlignMode = 'center',
|
|
rows = {5,5},
|
|
columns = {1,3,1},
|
|
layout = {
|
|
{'sidebar','content','sidebar2'},
|
|
{'sidebar','content','sidebar2'},
|
|
}
|
|
}
|
|
|
|
---@class grid
|
|
---@field gridLayout GridConfig
|
|
local grid = {}
|
|
grid.__index = grid
|
|
|
|
---@param gridLayout GridConfig
|
|
---@return layout
|
|
function grid.new(gridLayout)
|
|
local gridLayout = gridLayout or preconfiguredGrid
|
|
local self = setmetatable({
|
|
gridLayout = gridLayout
|
|
}, grid)
|
|
|
|
return layout(self, self.draw)
|
|
end
|
|
|
|
local function alignLeft(x, wroot, wchild)
|
|
return x
|
|
end
|
|
|
|
local function alignCenter(x, wroot, wchild)
|
|
return x+(wroot/2-wchild/2)
|
|
end
|
|
|
|
local function alignRight(x, wroot, wchild)
|
|
return x+(wroot-wchild)
|
|
end
|
|
|
|
|
|
local function alignHandlerX(mode, x, wr, wc)
|
|
if mode == 'center' then
|
|
return alignCenter(x, wr, wc)
|
|
elseif mode == 'right' then
|
|
return alignRight(x, wr, wc)
|
|
else
|
|
return alignLeft(x)
|
|
end
|
|
end
|
|
|
|
local function alignHandlerY(mode, y, hr, hc)
|
|
if mode == 'center' then
|
|
return alignCenter(y, hr, hc)
|
|
elseif mode == 'bottom' then
|
|
return alignRight(y, hr, hc)
|
|
else
|
|
return alignLeft(y)
|
|
end
|
|
end
|
|
|
|
function grid:draw(xRoot, yRoot, width, height, children)
|
|
-- Either of these means no named layout
|
|
local fullyAutoLayout = false
|
|
local autoCols = false
|
|
local autoRows = false
|
|
local equalRows = false
|
|
local equalCols = false
|
|
|
|
local vertValueToPixels = 0
|
|
local horValueToPixels = 0
|
|
|
|
local XIndexes = {}
|
|
local YIndexes = {}
|
|
|
|
if self.gridLayout.columns then
|
|
if not self.gridLayout.rows then
|
|
autoRows = true
|
|
else
|
|
if type(self.gridLayout.rows)=="table" then
|
|
local total = 0
|
|
|
|
for i, col in ipairs(self.gridLayout.rows) do
|
|
YIndexes[i] = {}
|
|
|
|
YIndexes[i].start = total
|
|
total = total + col
|
|
YIndexes[i].finish = total
|
|
end
|
|
|
|
vertValueToPixels = height/total
|
|
else
|
|
vertValueToPixels = height/self.gridLayout.rows
|
|
|
|
for y = 1, self.gridLayout.rows do
|
|
YIndexes[y] = {}
|
|
YIndexes[y].start = y-1
|
|
YIndexes[y].finish = y
|
|
end
|
|
|
|
equalRows = true
|
|
end
|
|
end
|
|
if type(self.gridLayout.columns)=="table" then
|
|
local total = 0
|
|
|
|
for i, col in ipairs(self.gridLayout.columns) do
|
|
XIndexes[i] = {}
|
|
|
|
XIndexes[i].start = total
|
|
total = total + col
|
|
XIndexes[i].finish = total
|
|
end
|
|
|
|
horValueToPixels = width/total
|
|
else
|
|
horValueToPixels = width/self.gridLayout.columns
|
|
|
|
for x = 1, self.gridLayout.columns do
|
|
XIndexes[x] = {}
|
|
XIndexes[x].start = x-1
|
|
XIndexes[x].finish = x
|
|
end
|
|
|
|
equalCols = true
|
|
end
|
|
else
|
|
if not self.gridLayout.rows then
|
|
fullyAutoLayout = true
|
|
autoRows = true
|
|
else
|
|
autoCols = true
|
|
if type(self.gridLayout.rows)=="table" then
|
|
local total = 0
|
|
|
|
for i, col in ipairs(self.gridLayout.rows) do
|
|
total = total + col
|
|
end
|
|
|
|
vertValueToPixels = (height)/total
|
|
else
|
|
vertValueToPixels = (height)/self.gridLayout.rows
|
|
equalRows = true
|
|
end
|
|
end
|
|
end
|
|
|
|
if (not autoRows) and (not autoCols) then
|
|
|
|
if self.gridLayout.layout then
|
|
local layout = {}
|
|
--flip layout table
|
|
for x = 1, #self.gridLayout.layout[1] do
|
|
layout[x] = {}
|
|
end
|
|
|
|
for x = 1, #self.gridLayout.layout do
|
|
for y = 1, #self.gridLayout.layout[x] do
|
|
layout[y][x] = self.gridLayout.layout[x][y]
|
|
end
|
|
end
|
|
|
|
local layoutDepth, layoutWidth = #self.gridLayout.layout, #layout
|
|
if type(self.gridLayout.rows) == "table" then
|
|
if not #self.gridLayout.rows == layoutDepth then
|
|
error('Layout table doesnt match row number')
|
|
end
|
|
else
|
|
if not self.gridLayout.rows == layoutDepth then
|
|
error('Layout table doesnt match row number')
|
|
end
|
|
end
|
|
if type(self.gridLayout.columns) == "table" then
|
|
if not #self.gridLayout.columns == layoutWidth then
|
|
error('Layout table doesnt match column number')
|
|
end
|
|
else
|
|
if not self.gridLayout.columns == layoutWidth then
|
|
error('Layout table doesnt match column number')
|
|
end
|
|
end
|
|
-- {x, y, width, height}
|
|
local fields = {
|
|
|
|
}
|
|
|
|
for x = 1, #layout do
|
|
for y = 1, #layout[x] do
|
|
if not fields[layout[x][y]] then
|
|
local finishedRow = false
|
|
local finishedCol = false
|
|
local curField = layout[x][y]
|
|
fields[curField] = {}
|
|
|
|
fields[curField].x = XIndexes[x].start
|
|
fields[curField].y = YIndexes[y].start
|
|
fields[curField].finX = XIndexes[x].finish
|
|
fields[curField].finY = YIndexes[y].finish
|
|
|
|
local parseX, parseY = x+1, y+1
|
|
while not finishedRow do
|
|
if layout[x][parseY] and layout[x][parseY] == curField then
|
|
fields[curField].finY = YIndexes[parseY].finish
|
|
else
|
|
finishedRow = true
|
|
end
|
|
parseY = parseY + 1
|
|
end
|
|
|
|
while not finishedCol do
|
|
if layout[parseX] and layout[parseX][y] == curField then
|
|
fields[curField].finX = XIndexes[parseX].finish
|
|
else
|
|
finishedCol = true
|
|
end
|
|
parseX = parseX + 1
|
|
end
|
|
|
|
fields[curField].h = fields[curField].finY - fields[curField].y
|
|
fields[curField].w = fields[curField].finX - fields[curField].x
|
|
end
|
|
end
|
|
end
|
|
|
|
for i, field in pairs(fields) do
|
|
for y, elem in ipairs(children) do
|
|
if elem.flags[i] then
|
|
field.element = elem
|
|
end
|
|
end
|
|
end
|
|
|
|
for i, field in pairs(fields) do
|
|
if field.element then
|
|
local containerWidth = (field.w*horValueToPixels)-(self.gridLayout.colSpacing)
|
|
local containerHeight = (field.h*vertValueToPixels)-(self.gridLayout.rowSpacing)
|
|
|
|
local containerX = ((field.x)*horValueToPixels)+(self.gridLayout.colSpacing/2)
|
|
local containerY = ((field.y)*vertValueToPixels)+(self.gridLayout.rowSpacing/2)
|
|
|
|
local w, h = field.element:getSize()
|
|
local x, y
|
|
|
|
if self.gridLayout.horizontalStretchMode =='stretch' then
|
|
w = containerWidth
|
|
x = containerX
|
|
else
|
|
x = alignHandlerX(self.gridLayout.horizontalAlignMode, containerX, containerWidth, w)
|
|
end
|
|
|
|
if self.gridLayout.verticalStretchMode =='stretch' then
|
|
h = containerHeight
|
|
y = containerY
|
|
else
|
|
y = alignHandlerY(self.gridLayout.verticalAlignMode, containerY, containerHeight, h)
|
|
end
|
|
|
|
field.element:draw(x+xRoot, y+yRoot, w, h)
|
|
end
|
|
end
|
|
else
|
|
error('please provide a layout table')
|
|
end
|
|
elseif fullyAutoLayout then--one element per width, vertically down
|
|
local carriagePos = 0
|
|
if children then
|
|
for i, e in ipairs(children) do
|
|
local w, h = e:getSize()
|
|
|
|
if self.gridLayout.horizontalStretchMode =='stretch' then
|
|
w = width
|
|
e:draw(xRoot, yRoot+carriagePos, w)
|
|
else
|
|
local x = alignHandlerX(self.gridLayout.horizontalAlignMode, xRoot, width, w)
|
|
e:draw(x, yRoot+carriagePos)
|
|
end
|
|
|
|
carriagePos = carriagePos + self.gridLayout.rowSpacing + h
|
|
end
|
|
end
|
|
elseif autoCols then--one element per width, rows spaced
|
|
local carriagePos = 0
|
|
local row = 1
|
|
local lastRowSize = 1
|
|
|
|
if children then
|
|
for i, e in ipairs(children) do
|
|
local w, h = e:getSize()
|
|
local rowSize
|
|
local x, y
|
|
|
|
if equalRows then
|
|
rowSize = 1 * vertValueToPixels
|
|
else
|
|
rowSize = (self.gridLayout.rows[row] or lastRowSize)*vertValueToPixels
|
|
end
|
|
|
|
rowSize = math.max(h, rowSize)
|
|
|
|
if self.gridLayout.horizontalStretchMode =='stretch' then
|
|
w = width
|
|
x = xRoot
|
|
else
|
|
x = alignHandlerX(self.gridLayout.horizontalAlignMode, xRoot, width, w)
|
|
end
|
|
|
|
if self.gridLayout.verticalStretchMode =='stretch' then
|
|
h = rowSize
|
|
y = carriagePos
|
|
else
|
|
y = alignHandlerY(self.gridLayout.verticalAlignMode, carriagePos, rowSize, h)
|
|
end
|
|
|
|
e:draw(x, y + yRoot, w, h)
|
|
|
|
carriagePos = carriagePos + self.gridLayout.rowSpacing + rowSize
|
|
row = row + 1
|
|
end
|
|
end
|
|
elseif autoRows then--flow the elements freely vertically, space columns according to layout
|
|
local carriagePos = 0
|
|
local row = 1
|
|
local colDrawStart = 0
|
|
|
|
local currentRowMax = 1
|
|
|
|
local currentCol = 1
|
|
|
|
local rowWidth
|
|
|
|
if equalCols then
|
|
rowWidth = self.gridLayout.columns
|
|
else
|
|
rowWidth = #self.gridLayout.columns
|
|
end
|
|
|
|
|
|
if children then
|
|
for i, e in ipairs(children) do
|
|
local w, h = e:getSize()
|
|
local colSize
|
|
local x, y
|
|
|
|
if equalCols then
|
|
colSize = 1 * horValueToPixels
|
|
else
|
|
colSize = self.gridLayout.columns[currentCol] * horValueToPixels
|
|
end
|
|
|
|
currentRowMax = math.max(currentRowMax, h)
|
|
|
|
if self.gridLayout.horizontalStretchMode =='stretch' then
|
|
w = colSize
|
|
x = colDrawStart
|
|
else
|
|
x = alignHandlerX(self.gridLayout.horizontalAlignMode, colDrawStart, colSize, w)
|
|
end
|
|
|
|
e:draw(x, yRoot+carriagePos, w, h)
|
|
|
|
colDrawStart = colDrawStart + colSize + self.gridLayout.colSpacing
|
|
|
|
if currentCol == rowWidth then
|
|
carriagePos = carriagePos + self.gridLayout.rowSpacing + currentRowMax
|
|
currentCol = 0
|
|
currentRowMax = 0
|
|
colDrawStart = 0
|
|
end
|
|
currentCol = currentCol + 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return grid |