implemented the rest of the state callbacks
redid layout luadoc + emmylua annotations everywhere grid layout started
This commit is contained in:
parent
ea7d0c2da0
commit
5309f35dfc
@ -80,8 +80,17 @@ function atlases:unassignAll()
|
||||
self.atlases[2].taken_area = 0
|
||||
end
|
||||
|
||||
function atlases.onscreenchange(newW, newH)
|
||||
function atlases:onscreenchange(newW, newH)
|
||||
for i, e in ipairs(self.atlases[1].users) do
|
||||
e:reassignCanvas()
|
||||
end
|
||||
|
||||
for i, e in ipairs(self.atlases[2].users) do
|
||||
e:reassignCanvas()
|
||||
end
|
||||
|
||||
self.atlases[1] = atlas.new(newW, newH)
|
||||
self.atlases[2] = atlas.new(newW, newH)
|
||||
end
|
||||
|
||||
function atlas.new(w, h)
|
||||
|
||||
@ -11,9 +11,8 @@ element.__index = element
|
||||
|
||||
local type,pcall = type,pcall
|
||||
setmetatable(element, {
|
||||
__call = function(cls, ...)
|
||||
__call = function(cls, func, param, w, h, flags)
|
||||
local self
|
||||
local func, param, w, h = ...
|
||||
|
||||
--Make the object inherit class
|
||||
self = setmetatable({}, element)
|
||||
@ -22,6 +21,7 @@ setmetatable(element, {
|
||||
self:new(param,nil, w, h)
|
||||
self:createProxies()
|
||||
|
||||
---@type Element
|
||||
return self
|
||||
end
|
||||
})
|
||||
@ -32,6 +32,9 @@ function element:new(param, immediate, w, h)
|
||||
self.parameters = {}
|
||||
self.baseParams = param
|
||||
|
||||
--Internal state callbacks
|
||||
self.callbacks = {}
|
||||
|
||||
--Internal settings
|
||||
self.settings = {
|
||||
isSetup = false,
|
||||
@ -73,6 +76,18 @@ function element:new(param, immediate, w, h)
|
||||
self.view = self.baseView
|
||||
end
|
||||
|
||||
function element:reassignCanvas()
|
||||
self.settings.failedCanvas = false
|
||||
self.settings.hasCanvas = false
|
||||
|
||||
self.canvas = nil
|
||||
self.quad = nil
|
||||
self.interQuad = nil
|
||||
self.deferResize = nil
|
||||
|
||||
self.context:bubbleUpdate()
|
||||
end
|
||||
|
||||
function element:sizeChange(i, v)
|
||||
local increase = self.baseView[i] < v
|
||||
|
||||
@ -90,6 +105,12 @@ function element:sizeChange(i, v)
|
||||
else
|
||||
self.deferResize = { increased = increase }
|
||||
end
|
||||
|
||||
if self.callbacks.onSizeChange then
|
||||
for i, cb in ipairs(self.callbacks.onSizeChange) do
|
||||
cb(self.view.w, self.view.h)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function element:posChange(i, v)
|
||||
@ -99,22 +120,37 @@ function element:posChange(i, v)
|
||||
if not self.deferRepos then
|
||||
self.deferRepos = true
|
||||
end
|
||||
|
||||
|
||||
if self.callbacks.onPosChange then
|
||||
for i, cb in ipairs(self.callbacks.onPosChange) do
|
||||
cb(self.view.x, self.view.y)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function element:onUpdate()
|
||||
|
||||
if self.callbacks.onUpdate then
|
||||
for i, cb in ipairs(self.callbacks.onUpdate) do
|
||||
cb()
|
||||
end
|
||||
end
|
||||
|
||||
function element:onDraw()
|
||||
|
||||
end
|
||||
|
||||
function element:onLoad()
|
||||
|
||||
if self.callbacks.onLoad then
|
||||
for i, cb in ipairs(self.callbacks.onLoad) do
|
||||
cb()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function element:onDestroy()
|
||||
|
||||
if self.callbacks.onDestroy then
|
||||
for i, cb in ipairs(self.callbacks.onDestroy) do
|
||||
cb()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function element:createProxies()
|
||||
@ -204,6 +240,7 @@ function element:setup()
|
||||
self.context:unset()
|
||||
|
||||
self.settings.isSetup = true
|
||||
self:onLoad()
|
||||
end
|
||||
|
||||
local setColor, rectangle, setFont, printf = love.graphics.setColor, love.graphics.rectangle, love.graphics.setFont, love.graphics.printf
|
||||
@ -294,6 +331,7 @@ function element:externalUpdate()
|
||||
end
|
||||
|
||||
if self.settings.pendingUpdate then
|
||||
self:onUpdate()
|
||||
self.settings.needsRendering = true
|
||||
self.settings.pendingUpdate = false
|
||||
end
|
||||
@ -321,8 +359,8 @@ end
|
||||
|
||||
local insert = table.insert
|
||||
|
||||
--External functions
|
||||
--Acts as the entrypoint for beginning rendering
|
||||
---External functions
|
||||
---Acts as the entrypoint for beginning rendering
|
||||
---@param x number
|
||||
---@param y number
|
||||
function element:draw(x, y, w, h)
|
||||
@ -355,10 +393,12 @@ function element:getSize()
|
||||
return self.view.w, self.view.h
|
||||
end
|
||||
|
||||
---Destroys this element
|
||||
function element:destroy()
|
||||
self.settings.remove = true
|
||||
self.settings.firstDraw = true
|
||||
self.settings.isSetup = false
|
||||
self:onDestroy()
|
||||
self.context:destroy()
|
||||
end
|
||||
|
||||
|
||||
@ -174,14 +174,18 @@ function subscription:checkOutside(x, y)
|
||||
return not (x>self.x and x<self.x+self.w and y>self.y and y<self.y+self.h)
|
||||
end
|
||||
|
||||
---@alias InputMouseClickSubscriptionCallback fun(x:number, y:number, mouseButton:string)
|
||||
---@alias InputMouseClickComplexSubscriptionCallback fun(x:number, y:number, mouseButton:string):fun(x:number, y:number)|nil
|
||||
---@alias InputMouseMoveComplexSubscriptionCallback fun(x:number, y:number, dx:number, dy:number):fun(x:number, y:number)|nil
|
||||
---@alias InputKeyPressSubscriptionCallback fun(key:KeyConstant|string, scancode:Scancode|string)
|
||||
---@alias InputTextInputSubscriptionCallback fun(text:string)
|
||||
|
||||
input.subscribe = subscription.create
|
||||
---@param eventType string
|
||||
---@param callback function
|
||||
---@param cbOff boolean
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param w number
|
||||
---@param h number
|
||||
---@overload fun(self:any, eventType: "'mousepressed'"|"'mousereleased'"|"'mousepressed_outside'"|"'mousereleased_outside'", callback: InputMouseClickSubscriptionCallback, cbOff: boolean, x: number|nil, y:number|nil, w: number|nil, h:number|nil)
|
||||
---@overload fun(self:any, eventType: "'clicked'", callback: InputMouseClickComplexSubscriptionCallback, cbOff: boolean, x:number|nil, y:number|nil, w:number|nil, h:number|nil)
|
||||
---@overload fun(self:any, eventType: "'hover'"|"'dragged'", callback: InputMouseMoveComplexSubscriptionCallback, cbOff: boolean, x:number|nil, y:number|nil, w:number|nil, h:number|nil)
|
||||
---@overload fun(self:any, eventType: "'keypressed'"|"'keyreleased'", callback: InputKeyPressSubscriptionCallback, cbOff: boolean)
|
||||
---@overload fun(self:any, eventType: "'textinput'", callback: InputTextInputSubscriptionCallback, cbOff: boolean)
|
||||
input.__call = function(self, eventType, callback, cbOff, x, y, w, h)
|
||||
x = x or 0
|
||||
y = y or 0
|
||||
|
||||
@ -4,12 +4,17 @@ local atlas = require(path..'.core.atlas')
|
||||
local helium = require(path..'.dummy')
|
||||
local input = require(path..'.core.input')
|
||||
|
||||
---@class scene
|
||||
local scene = {
|
||||
activeScene = nil
|
||||
}
|
||||
scene.__index = scene
|
||||
|
||||
---comment
|
||||
---@param cached boolean @whether to enable caching on this scene
|
||||
---@return scene
|
||||
function scene.new(cached)
|
||||
---@type scene
|
||||
local self = {
|
||||
atlas = cached and atlas.create() or nil,
|
||||
cached = cached or false,
|
||||
@ -34,30 +39,32 @@ function scene.bench()
|
||||
end
|
||||
end
|
||||
|
||||
---Activates this scene
|
||||
function scene:activate()
|
||||
scene.activeScene = self
|
||||
end
|
||||
|
||||
--Keeps the scene in memory with potentially the atlas
|
||||
---Keeps the scene in memory with potentially the atlas
|
||||
function scene:deactivate()
|
||||
scene.activeScene = nil
|
||||
end
|
||||
|
||||
|
||||
---Recreates this scene
|
||||
function scene:reload()
|
||||
self.atlas = self.cached and atlas.create() or nil
|
||||
self.ioSubscriptions = {}
|
||||
self.buffer = {}
|
||||
end
|
||||
|
||||
--Nukes the scene and it's elements and atlases and subscriptions from memory
|
||||
--To achieve same state as after creation, use reload
|
||||
---Nukes the scene and it's elements and atlases and subscriptions from memory
|
||||
---To achieve same state as after creation, use reload
|
||||
function scene:unload()
|
||||
self.atlas = nil
|
||||
self.buffer = nil
|
||||
self.ioSubscriptions = nil
|
||||
end
|
||||
|
||||
---Draws this scene and it's elements
|
||||
function scene:draw()
|
||||
helium.stack.newFrame()
|
||||
if not helium.benchNum then
|
||||
@ -73,6 +80,8 @@ function scene:draw()
|
||||
|
||||
end
|
||||
|
||||
---Updates this scene and it's elements
|
||||
---@param dt number
|
||||
function scene:update(dt)
|
||||
for i = 1, #self.buffer do
|
||||
if self.buffer[i]:externalUpdate(i) then
|
||||
|
||||
@ -1 +1,16 @@
|
||||
--Allows to expose a function to outside the element simply
|
||||
local path = string.sub(..., 1, string.len(...) - string.len(".hooks.onDestroy"))
|
||||
local context = require(path.. ".core.stack")
|
||||
|
||||
---Creates a callback on the 'name' field for the current element
|
||||
---@param name string
|
||||
---@param callback function
|
||||
return function (name, callback)
|
||||
local activeContext = context.getContext()
|
||||
|
||||
if context.element[name] then
|
||||
error('callback with name '..name..' would interfere with internal fields')
|
||||
end
|
||||
|
||||
context.element[name] = callback
|
||||
end
|
||||
@ -3,6 +3,10 @@ local context = require(path.. ".core.stack")
|
||||
|
||||
local c = {}
|
||||
|
||||
---Creates a context, that will be available to ALL nodes below this element
|
||||
---@param name string the name of this context to be referenced later
|
||||
---@param base table the table to be used as the base of this new context
|
||||
---@return table
|
||||
function c.use(name, base)
|
||||
base = base or {}
|
||||
local fakeBase = {}
|
||||
@ -39,6 +43,9 @@ function c.use(name, base)
|
||||
return ctx
|
||||
end
|
||||
|
||||
---Gets the context with 'name', if it was initialized
|
||||
---@param name string
|
||||
---@return table|nil
|
||||
function c.get(name)
|
||||
local activeContext = context.getContext()
|
||||
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
local path = string.sub(..., 1, string.len(...) - string.len(".hooks.onDestroy"))
|
||||
local context = require(path.. ".core.stack")
|
||||
|
||||
---Sets a callback on a destructionevent for the current element (can have multiple)
|
||||
---@param callback function
|
||||
return function (callback)
|
||||
local activeContext = context.getContext()
|
||||
|
||||
if not activeContext.element.callbacks['onDestroy'] then
|
||||
activeContext.element.callbacks.onDestroy = {}
|
||||
end
|
||||
|
||||
activeContext.element.callbacks.onDestroy[#activeContext.element.callbacks.onDestroy+1] = callback
|
||||
end
|
||||
@ -0,0 +1,14 @@
|
||||
local path = string.sub(..., 1, string.len(...) - string.len(".hooks.onLoad"))
|
||||
local context = require(path.. ".core.stack")
|
||||
|
||||
---Sets a callback on a load event for the current element (can have multiple)
|
||||
---@param callback function
|
||||
return function (callback)
|
||||
local activeContext = context.getContext()
|
||||
|
||||
if not activeContext.element.callbacks['onLoad'] then
|
||||
activeContext.element.callbacks.onLoad = {}
|
||||
end
|
||||
|
||||
activeContext.element.callbacks.onLoad[#activeContext.element.callbacks.onLoad+1] = callback
|
||||
end
|
||||
@ -0,0 +1,16 @@
|
||||
local path = string.sub(..., 1, string.len(...) - string.len(".hooks.onPosChange"))
|
||||
local context = require(path.. ".core.stack")
|
||||
|
||||
---@alias PosChangeCallback fun(x: number, y:number)
|
||||
|
||||
---Sets a callback on a position change event for the current element (can have multiple)
|
||||
---@param callback PosChangeCallback
|
||||
return function (callback)
|
||||
local activeContext = context.getContext()
|
||||
|
||||
if not activeContext.element.callbacks['onPosChange'] then
|
||||
activeContext.element.callbacks.onPosChange = {}
|
||||
end
|
||||
|
||||
activeContext.element.callbacks.onPosChange[#activeContext.element.callbacks.onPosChange+1] = callback
|
||||
end
|
||||
@ -0,0 +1,16 @@
|
||||
local path = string.sub(..., 1, string.len(...) - string.len(".hooks.onSizeChange"))
|
||||
local context = require(path.. ".core.stack")
|
||||
|
||||
---@alias SizeChangeCallback fun(w: number, h:number)
|
||||
|
||||
---Sets a callback on a size change event for the current element (can have multiple)
|
||||
---@param callback SizeChangeCallback
|
||||
return function (callback)
|
||||
local activeContext = context.getContext()
|
||||
|
||||
if not activeContext.element.callbacks['onSizeChange'] then
|
||||
activeContext.element.callbacks.onSizeChange = {}
|
||||
end
|
||||
|
||||
activeContext.element.callbacks.onSizeChange[#activeContext.element.callbacks.onSizeChange+1] = callback
|
||||
end
|
||||
@ -0,0 +1,15 @@
|
||||
local path = string.sub(..., 1, string.len(...) - string.len(".hooks.onUpdate"))
|
||||
local context = require(path.. ".core.stack")
|
||||
|
||||
---Sets a callback on any updatefor the current element (can have multiple)
|
||||
---Use this to get logic outside of rendering function
|
||||
---@param callback function
|
||||
return function (callback)
|
||||
local activeContext = context.getContext()
|
||||
|
||||
if not activeContext.element.callbacks['onUpdate'] then
|
||||
activeContext.element.callbacks.onUpdate = {}
|
||||
end
|
||||
|
||||
activeContext.element.callbacks.onUpdate[activeContext.element.callbacks.onUpdate+1] = callback
|
||||
end
|
||||
@ -1,6 +1,10 @@
|
||||
local path = string.sub(..., 1, string.len(...) - string.len(".hooks.state"))
|
||||
local context = require(path.. ".core.stack")
|
||||
|
||||
---Creates a new 'state' object that will update the current element whenever a field is changed
|
||||
---@generic T : table
|
||||
---@param base T
|
||||
---@return T
|
||||
return function (base)
|
||||
base = base or {}
|
||||
local fakeBase = {}
|
||||
|
||||
@ -1,4 +1,17 @@
|
||||
return function(x, y, width, height, children, hpad, vpad, alignX)
|
||||
local path = string.sub(..., 1, string.len(...) - string.len(".column"))
|
||||
local layout = require(path..'.init')
|
||||
---@class Column
|
||||
local column = {}
|
||||
column.__index = column
|
||||
|
||||
---@return layout
|
||||
function column.new()
|
||||
local self = setmetatable({}, column)
|
||||
|
||||
return layout(self.draw)
|
||||
end
|
||||
|
||||
function column:draw(x, y, width, height, children, hpad, vpad, alignX)
|
||||
local carriagePos = 0
|
||||
if children then
|
||||
for i, e in ipairs(children) do
|
||||
@ -8,3 +21,5 @@ return function(x, y, width, height, children, hpad, vpad, alignX)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return column
|
||||
277
layout/grid.lua
Normal file
277
layout/grid.lua
Normal file
@ -0,0 +1,277 @@
|
||||
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..'.init')
|
||||
|
||||
---@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 = 3,
|
||||
rowSpacing = 3,
|
||||
verticalStretchMode = 'normal',
|
||||
horizontalStretchMode = 'normal',
|
||||
verticalAlignMode = 'center',
|
||||
horizontalAlignMode = 'center',
|
||||
--rows = {1, 1, 1, 1},
|
||||
columns = {1, 1, 1, 1},
|
||||
--[[layout = {
|
||||
{'header', 'header', 'header'},
|
||||
{'sidebar','content','content'},
|
||||
{'sidebar','content','content'},
|
||||
}]]
|
||||
}
|
||||
|
||||
---@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, hpad, vpad)
|
||||
-- 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 finalLayout = {}
|
||||
|
||||
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
|
||||
total = total + col
|
||||
end
|
||||
|
||||
vertValueToPixels = (height-(self.gridLayout.rowSpacing*total))/total
|
||||
else
|
||||
vertValueToPixels = (height-(self.gridLayout.rowSpacing*self.gridLayout.rows))/self.gridLayout.rows
|
||||
equalRows = true
|
||||
end
|
||||
end
|
||||
if type(self.gridLayout.columns)=="table" then
|
||||
local total = 0
|
||||
|
||||
for i, col in ipairs(self.gridLayout.columns) do
|
||||
total = total + col
|
||||
end
|
||||
|
||||
horValueToPixels = width/total
|
||||
else
|
||||
horValueToPixels = width/self.gridLayout.columns
|
||||
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-(self.gridLayout.rowSpacing*total))/total
|
||||
else
|
||||
vertValueToPixels = (height-(self.gridLayout.rowSpacing*self.gridLayout.rows))/self.gridLayout.rows
|
||||
equalRows = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
print(horValueToPixels, width)
|
||||
|
||||
if (not autoRows) and (not autoCols) then
|
||||
|
||||
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
|
||||
else
|
||||
x = alignHandlerX(self.gridLayout.horizontalAlignMode, xRoot, width, w)
|
||||
end
|
||||
|
||||
if self.gridLayout.verticalStretchMode =='stretch' then
|
||||
h = rowSize
|
||||
else
|
||||
y = alignHandlerY(self.gridLayout.verticalAlignMode, carriagePos, rowSize, h)
|
||||
end
|
||||
|
||||
e:draw(x, y, 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
|
||||
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
|
||||
@ -1,92 +1,109 @@
|
||||
local path = string.sub(..., 1, string.len(...) - string.len(".layout"))
|
||||
local path = string.sub(..., 1, string.len(...) - string.len(".layout.init"))
|
||||
|
||||
---@class layout
|
||||
---@field protected vars table
|
||||
---@field protected type function
|
||||
local layout = {}
|
||||
local layouts = {}
|
||||
layouts.column = require(path..'.layout.column')
|
||||
layouts.row = require(path..'.layout.row')
|
||||
layout.__index = layout
|
||||
local element = require(path..'.core.element')
|
||||
local stack = require(path..'.core.stack')
|
||||
|
||||
--Start prep phase
|
||||
function layout.type(type)
|
||||
function layout.type(binder, callback)
|
||||
local curStack = stack.getContext()
|
||||
curStack:startDeferingChildren()
|
||||
|
||||
local self = {
|
||||
vars = {
|
||||
type = type or 'column',
|
||||
offLeft = 0,
|
||||
offTop = 0,
|
||||
width = 1,
|
||||
hpad = 3,
|
||||
vpad = 3,
|
||||
height = 1,
|
||||
alignX = 'left', --options: left, center, right
|
||||
alignY = 'top', --options: top, center, bottom
|
||||
--flowDir = 'rtl', --options: rtl/ttb
|
||||
},
|
||||
stack = curStack
|
||||
stack = curStack,
|
||||
binder = binder,
|
||||
callback = callback,
|
||||
}
|
||||
|
||||
return setmetatable(self, layout)
|
||||
end
|
||||
|
||||
---Aligns the container vertically
|
||||
---@param pos 'left'|'center'|'right'
|
||||
function layout:alignVert(pos)
|
||||
self.vars.alignY = pos
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
---Aligns the container horizontally
|
||||
---@param pos 'top'|'center'|'bottom'
|
||||
function layout:alignHoriz(pos)
|
||||
self.vars.alignX = pos
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--Sets up the box of the layout
|
||||
---Sets up the width of the box of the layout
|
||||
---@param w number width in pixels or absolute 0-1
|
||||
function layout:width(w)
|
||||
self.vars.width = w
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
---Sets up the height of the box of the layout
|
||||
---@param h number width in pixels or absolute 0-1
|
||||
function layout:height(h)
|
||||
self.vars.height = h
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
---Offset from the left
|
||||
---@param x number offset in pixels or absolute 0-1
|
||||
function layout:left(x)
|
||||
self.vars.offLeft = x
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
---Offset from the right
|
||||
---@param x number offset in pixels or absolute 0-1
|
||||
function layout:right(x)
|
||||
self.vars.offRight = x
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
---Offset from the top
|
||||
---@param y number offset in pixels or absolute 0-1
|
||||
function layout:top(y)
|
||||
self.vars.offTop = y
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
---Offset from the bottom
|
||||
---@param y number offset in pixels or absolute 0-1
|
||||
function layout:bottom(y)
|
||||
self.vars.offBot = y
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
---Padding for the elements vertically
|
||||
---@param px number offset in pixels
|
||||
function layout:vPadding(px)
|
||||
self.vars.vpad = px
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
---Padding for the elements horizontally
|
||||
---@param px number offset in pixels
|
||||
function layout:hPadding(px)
|
||||
self.vars.hpad = px
|
||||
|
||||
@ -97,6 +114,8 @@ end
|
||||
--top + bottom = height ignored
|
||||
--top px + bottom relative works
|
||||
--left relative + bottom px works
|
||||
|
||||
|
||||
function layout:draw()
|
||||
local stack = self.stack
|
||||
local children = stack:stopDeferingChildren()
|
||||
@ -127,19 +146,9 @@ function layout:draw()
|
||||
x = 0
|
||||
end
|
||||
|
||||
layouts[self.vars.type](
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
children,
|
||||
self.vars.hpad,
|
||||
self.vars.vpad,
|
||||
self.vars.alignX,
|
||||
self.vars.alignY
|
||||
)
|
||||
self.callback(self.binder, x, y, width, height, children, self.vars.hpad, self.vars.vpad)
|
||||
end
|
||||
|
||||
|
||||
setmetatable(layout, {__call = function(s, type) return layout.type(type) end })
|
||||
setmetatable(layout, {__call = function(s, callback, binder) return layout.type(callback, binder) end })
|
||||
return layout
|
||||
@ -1,4 +1,18 @@
|
||||
return function(x, y, width, height, children, hpad, vpad, alignX)
|
||||
local path = string.sub(..., 1, string.len(...) - string.len(".row"))
|
||||
local layout = require(path..'.init')
|
||||
|
||||
---@class Row
|
||||
local row = {}
|
||||
row.__index = row
|
||||
|
||||
---@return layout
|
||||
function row.new()
|
||||
local self = setmetatable({}, row)
|
||||
|
||||
return layout(self.draw)
|
||||
end
|
||||
|
||||
function row:draw(x, y, width, height, children, hpad, vpad, alignX)
|
||||
local carriagePos = 0
|
||||
if children then
|
||||
for i, e in ipairs(children) do
|
||||
@ -8,3 +22,5 @@ return function(x, y, width, height, children, hpad, vpad, alignX)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return row
|
||||
@ -2,6 +2,20 @@ local path = string.sub(..., 1, string.len(...) - string.len(".shell.button"))
|
||||
local state = require(path.. ".hooks.state")
|
||||
local input = require(path.. ".core.input")
|
||||
|
||||
---@class buttonState
|
||||
---@param down boolean @indicates whether this element is currently being pressed
|
||||
---@param over boolean @indicates whether the mouse is over this button
|
||||
|
||||
---Creates a simple button wrapper, sets up all the callbacks and state for you
|
||||
---@param onClick function|nil
|
||||
---@param onRelease function|nil
|
||||
---@param onEnter function|nil
|
||||
---@param onExit function|nil
|
||||
---@param x number|nil
|
||||
---@param y number|nil
|
||||
---@param w number|nil
|
||||
---@param h number|nil
|
||||
---@return buttonState
|
||||
return function(onClick, onRelease, onEnter, onExit, x, y, w, h)
|
||||
local button = state {
|
||||
down = false,
|
||||
|
||||
@ -2,6 +2,22 @@ local path = string.sub(..., 1, string.len(...) - string.len(".shell.button"))
|
||||
local state = require(path.. ".hooks.state")
|
||||
local input = require(path.. ".core.input")
|
||||
|
||||
---@class checkboxState
|
||||
---@param down boolean @indicates whether this element is currently held down
|
||||
---@param toggled boolean @current state of the checkbox
|
||||
---@param over boolean @indicates whether the mouse is over this field
|
||||
|
||||
---A wrapper for state and subscriptions for a checkbox
|
||||
---@param onClick function|nil
|
||||
---@param onRelease function|nil
|
||||
---@param onEnter function|nil
|
||||
---@param onExit function|nil
|
||||
---@param startOn boolean|nil
|
||||
---@param x number|nil
|
||||
---@param y number|nil
|
||||
---@param w number|nil
|
||||
---@param h number|nil
|
||||
---@return checkboxState
|
||||
return function(onClick, onRelease, onEnter, onExit, startOn, x, y, w, h)
|
||||
local checkbox = state {
|
||||
down = false,
|
||||
|
||||
@ -3,6 +3,22 @@ local state = require(path.. ".hooks.state")
|
||||
local input = require(path.. ".core.input")
|
||||
local utf8 = require("utf8")
|
||||
|
||||
---@class textState
|
||||
---@param focused boolean @indicates whether this element is currently focused
|
||||
---@param text string @current state of the input string
|
||||
---@param over boolean @indicates whether the mouse is over this field
|
||||
|
||||
---Textinput element wrapper
|
||||
---@param onChange function|nil
|
||||
---@param onFinish function|nil
|
||||
---@param startStr function|nil
|
||||
---@param onEnter function|nil
|
||||
---@param onExit function|nil
|
||||
---@param x number|nil
|
||||
---@param y number|nil
|
||||
---@param w number|nil
|
||||
---@param h number|nil
|
||||
---@return textState
|
||||
return function(onChange, onFinish, startStr, onEnter, onExit, x, y, w, h)
|
||||
local textState = state {
|
||||
focused = false,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user