- Created Plugin loading system
- Added lazy loading system for elements (optional feature) - Improved rendering performance - Added ID system which is separated from Eement Names - Added Focussystem for container - Improved container performance by only rendering and handling events from visible childrens instead of all - Added label and input - Added animation and xml
This commit is contained in:
297
src/elements/Flexbox.lua
Normal file
297
src/elements/Flexbox.lua
Normal file
@@ -0,0 +1,297 @@
|
||||
local elementManager = require("elementManager")
|
||||
local Container = elementManager.getElement("Container")
|
||||
|
||||
---@class Flexbox : Container
|
||||
local Flexbox = setmetatable({}, Container)
|
||||
Flexbox.__index = Flexbox
|
||||
|
||||
Flexbox.defineProperty(Flexbox, "flexDirection", {default = "row", type = "string"})
|
||||
Flexbox.defineProperty(Flexbox, "flexSpacing", {default = 1, type = "number"})
|
||||
Flexbox.defineProperty(Flexbox, "flexJustifyContent", {
|
||||
default = "flex-start",
|
||||
type = "string",
|
||||
setter = function(self, value)
|
||||
if not value:match("^flex%-") then
|
||||
value = "flex-" .. value
|
||||
end
|
||||
return value
|
||||
end
|
||||
})
|
||||
Flexbox.defineProperty(Flexbox, "flexWrap", {default = false, type = "boolean"})
|
||||
Flexbox.defineProperty(Flexbox, "flexUpdateLayout", {default = false, type = "boolean"})
|
||||
|
||||
local lineBreakElement = {
|
||||
getHeight = function(self) return 0 end,
|
||||
getWidth = function(self) return 0 end,
|
||||
getZ = function(self) return 1 end,
|
||||
getPosition = function(self) return 0, 0 end,
|
||||
getSize = function(self) return 0, 0 end,
|
||||
isType = function(self) return false end,
|
||||
getType = function(self) return "lineBreak" end,
|
||||
getName = function(self) return "lineBreak" end,
|
||||
setPosition = function(self) end,
|
||||
setParent = function(self) end,
|
||||
setSize = function(self) end,
|
||||
getFlexGrow = function(self) return 0 end,
|
||||
getFlexShrink = function(self) return 0 end,
|
||||
getFlexBasis = function(self) return 0 end,
|
||||
init = function(self) end,
|
||||
getVisible = function(self) return true end,
|
||||
}
|
||||
|
||||
|
||||
local function sortElements(self, direction, spacing, wrap)
|
||||
local elements = self.get("children")
|
||||
local sortedElements = {}
|
||||
if not(wrap)then
|
||||
local index = 1
|
||||
local lineSize = 1
|
||||
local lineOffset = 1
|
||||
for _,v in pairs(elements)do
|
||||
if(sortedElements[index]==nil)then sortedElements[index]={offset=1} end
|
||||
|
||||
local childHeight = direction == "row" and v.get("height") or v.get("width")
|
||||
if childHeight > lineSize then
|
||||
lineSize = childHeight
|
||||
end
|
||||
if(v == lineBreakElement)then
|
||||
lineOffset = lineOffset + lineSize + spacing
|
||||
lineSize = 1
|
||||
index = index + 1
|
||||
sortedElements[index] = {offset=lineOffset}
|
||||
else
|
||||
table.insert(sortedElements[index], v)
|
||||
end
|
||||
end
|
||||
elseif(wrap)then
|
||||
local lineSize = 1
|
||||
local lineOffset = 1
|
||||
|
||||
local maxSize = direction == "row" and self.get("width") or self.get("height")
|
||||
local usedSize = 0
|
||||
local index = 1
|
||||
|
||||
for _,v in pairs(elements) do
|
||||
if(sortedElements[index]==nil) then sortedElements[index]={offset=1} end
|
||||
|
||||
if v:getType() == "lineBreak" then
|
||||
lineOffset = lineOffset + lineSize + spacing
|
||||
usedSize = 0
|
||||
lineSize = 1
|
||||
index = index + 1
|
||||
sortedElements[index] = {offset=lineOffset}
|
||||
else
|
||||
local objSize = direction == "row" and v.get("width") or v.get("height")
|
||||
if(objSize+usedSize<=maxSize) then
|
||||
table.insert(sortedElements[index], v)
|
||||
usedSize = usedSize + objSize + spacing
|
||||
else
|
||||
lineOffset = lineOffset + lineSize + spacing
|
||||
lineSize = direction == "row" and v.get("height") or v.get("width")
|
||||
index = index + 1
|
||||
usedSize = objSize + spacing
|
||||
sortedElements[index] = {offset=lineOffset, v}
|
||||
end
|
||||
|
||||
local childHeight = direction == "row" and v.get("height") or v.get("width")
|
||||
if childHeight > lineSize then
|
||||
lineSize = childHeight
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return sortedElements
|
||||
end
|
||||
|
||||
local function calculateRow(self, children, spacing, justifyContent)
|
||||
local containerWidth = self.get("width")
|
||||
|
||||
local usedSpace = spacing * (#children - 1)
|
||||
local totalFlexGrow = 0
|
||||
|
||||
for _, child in ipairs(children) do
|
||||
if child ~= lineBreakElement then
|
||||
usedSpace = usedSpace + child.get("width")
|
||||
totalFlexGrow = totalFlexGrow + child.get("flexGrow")
|
||||
end
|
||||
end
|
||||
|
||||
local remainingSpace = containerWidth - usedSpace
|
||||
local extraSpacePerUnit = totalFlexGrow > 0 and (remainingSpace / totalFlexGrow) or 0
|
||||
local distributedSpace = 0
|
||||
|
||||
local currentX = 1
|
||||
for i, child in ipairs(children) do
|
||||
if child ~= lineBreakElement then
|
||||
local childWidth = child.get("width")
|
||||
|
||||
if child.get("flexGrow") > 0 then
|
||||
|
||||
if i == #children then
|
||||
local extraSpace = remainingSpace - distributedSpace
|
||||
childWidth = childWidth + extraSpace
|
||||
else
|
||||
local extraSpace = math.floor(extraSpacePerUnit * child.get("flexGrow"))
|
||||
childWidth = childWidth + extraSpace
|
||||
distributedSpace = distributedSpace + extraSpace
|
||||
end
|
||||
end
|
||||
|
||||
child.set("x", currentX)
|
||||
child.set("y", children.offset or 1)
|
||||
child.set("width", childWidth)
|
||||
currentX = currentX + childWidth + spacing
|
||||
end
|
||||
end
|
||||
|
||||
if justifyContent == "flex-end" then
|
||||
local offset = containerWidth - (currentX - spacing - 1)
|
||||
for _, child in ipairs(children) do
|
||||
child.set("x", child.get("x") + offset)
|
||||
end
|
||||
elseif justifyContent == "flex-center" or justifyContent == "center" then -- Akzeptiere beide Formate
|
||||
local offset = math.floor((containerWidth - (currentX - spacing - 1)) / 2)
|
||||
for _, child in ipairs(children) do
|
||||
child.set("x", child.get("x") + offset)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function calculateColumn(self, children, spacing, justifyContent)
|
||||
local containerHeight = self.get("height")
|
||||
|
||||
local usedSpace = spacing * (#children - 1)
|
||||
local totalFlexGrow = 0
|
||||
|
||||
for _, child in ipairs(children) do
|
||||
if child ~= lineBreakElement then
|
||||
usedSpace = usedSpace + child.get("height")
|
||||
totalFlexGrow = totalFlexGrow + child.get("flexGrow")
|
||||
end
|
||||
end
|
||||
|
||||
local remainingSpace = containerHeight - usedSpace
|
||||
local extraSpacePerUnit = totalFlexGrow > 0 and (remainingSpace / totalFlexGrow) or 0
|
||||
local distributedSpace = 0
|
||||
|
||||
local currentY = 1
|
||||
for i, child in ipairs(children) do
|
||||
if child ~= lineBreakElement then
|
||||
local childHeight = child.get("height")
|
||||
|
||||
if child.get("flexGrow") > 0 then
|
||||
|
||||
if i == #children then
|
||||
local extraSpace = remainingSpace - distributedSpace
|
||||
childHeight = childHeight + extraSpace
|
||||
else
|
||||
local extraSpace = math.floor(extraSpacePerUnit * child.get("flexGrow"))
|
||||
childHeight = childHeight + extraSpace
|
||||
distributedSpace = distributedSpace + extraSpace
|
||||
end
|
||||
end
|
||||
|
||||
child.set("x", children.offset or 1)
|
||||
child.set("y", currentY)
|
||||
child.set("height", childHeight)
|
||||
currentY = currentY + childHeight + spacing
|
||||
end
|
||||
end
|
||||
|
||||
if justifyContent == "flex-end" then
|
||||
local offset = containerHeight - (currentY - spacing - 1)
|
||||
for _, child in ipairs(children) do
|
||||
child.set("y", child.get("y") + offset)
|
||||
end
|
||||
elseif justifyContent == "flex-center" or justifyContent == "center" then -- Akzeptiere beide Formate
|
||||
local offset = math.floor((containerHeight - (currentY - spacing - 1)) / 2)
|
||||
for _, child in ipairs(children) do
|
||||
child.set("y", child.get("y") + offset)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function updateLayout(self, direction, spacing, justifyContent, wrap)
|
||||
local elements = sortElements(self, direction, spacing, wrap)
|
||||
if direction == "row" then
|
||||
for _,v in pairs(elements)do
|
||||
calculateRow(self, v, spacing, justifyContent)
|
||||
end
|
||||
else
|
||||
for _,v in pairs(elements)do
|
||||
calculateColumn(self, v, spacing, justifyContent)
|
||||
end
|
||||
end
|
||||
self.set("flexUpdateLayout", false)
|
||||
end
|
||||
|
||||
--- Creates a new Flexbox instance
|
||||
--- @param props table The properties to initialize the element with
|
||||
--- @param basalt table The basalt instance
|
||||
--- @return Flexbox object The newly created Flexbox instance
|
||||
--- @usage local element = Flexbox.new("myId", basalt)
|
||||
function Flexbox.new(props, basalt)
|
||||
local self = setmetatable({}, Flexbox):__init()
|
||||
self:init(props, basalt)
|
||||
self.set("width", 12)
|
||||
self.set("height", 6)
|
||||
self.set("background", colors.blue)
|
||||
self.set("z", 10)
|
||||
self:observe("width", function() self.set("flexUpdateLayout", true) end)
|
||||
self:observe("height", function() self.set("flexUpdateLayout", true) end)
|
||||
return self
|
||||
end
|
||||
|
||||
function Flexbox:init(props, basalt)
|
||||
Container.init(self, props, basalt)
|
||||
self.set("type", "Flexbox")
|
||||
end
|
||||
|
||||
function Flexbox:addChild(element)
|
||||
Container.addChild(self, element)
|
||||
|
||||
if(element~=lineBreakElement)then
|
||||
element:instanceProperty("flexGrow", {default = 0, type = "number"})
|
||||
element:instanceProperty("flexShrink", {default = 0, type = "number"})
|
||||
element:instanceProperty("flexBasis", {default = 0, type = "number"})
|
||||
end
|
||||
|
||||
self.set("flexUpdateLayout", true)
|
||||
return self
|
||||
end
|
||||
|
||||
function Flexbox:removeChild(element)
|
||||
Container.removeChild(self, element)
|
||||
|
||||
if(element~=lineBreakElement)then
|
||||
element.setFlexGrow = nil
|
||||
element.setFlexShrink = nil
|
||||
element.setFlexBasis = nil
|
||||
element.getFlexGrow = nil
|
||||
element.getFlexShrink = nil
|
||||
element.getFlexBasis = nil
|
||||
element.set("flexGrow", nil)
|
||||
element.set("flexShrink", nil)
|
||||
element.set("flexBasis", nil)
|
||||
end
|
||||
|
||||
self.set("flexUpdateLayout", true)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Adds a new line break to the flexbox.
|
||||
---@param self Flexbox The element itself
|
||||
---@return Flexbox
|
||||
function Flexbox:addLineBreak()
|
||||
self:addChild(lineBreakElement)
|
||||
return self
|
||||
end
|
||||
|
||||
function Flexbox:render()
|
||||
if(self.get("flexUpdateLayout"))then
|
||||
updateLayout(self, self.get("flexDirection"), self.get("flexSpacing"), self.get("flexJustifyContent"), self.get("flexWrap"))
|
||||
end
|
||||
Container.render(self)
|
||||
end
|
||||
|
||||
return Flexbox
|
||||
Reference in New Issue
Block a user