bezier-string-art/GUI-Framework.lua
2023-05-11 21:28:37 +03:00

166 lines
3.9 KiB
Lua

local GUI = {}
local EMPTY = {}
local Vector2 = require("Vector2")
local templates = {}
GUI.__index = GUI
local function clone(data)
if type(data) ~= "table" then
return data
else
local new = {}
for k, v in pairs(data) do
new[k] = clone(v)
end
return setmetatable(new, getmetatable(data))
end
end
function revipairs(t)
return function(t, i) i = i - 1 if i > 0 then return i, t[i] end end, t, #t+1
end
function GUI.sortByDepth(a, b)
return a.depth < b.depth
end
function getPos(self)
if self._parent then
local x0, y0 = self._parent:getPos()
return self.pos.x + x0, self.pos.y + y0
else
return self.pos.x, self.pos.y
end
end
function getSize(self)
return self.size.x, self.size.y
end
function getBounds(self)
local x, y = getPos(self)
return x, y, self.size.x, self.size.y
end
function inBounds(self, x, y)
local Ex, Ey, width, height = getBounds(self)
return (x > Ex and x < Ex + width and y > Ey and y < Ey + height)
end
function GUI.createElement(elementType, data)
assert(templates[elementType], "Element type \""..elementType.."\" dosen't exist")
local elem = data or {}
for k, v in pairs(templates[elementType]) do
if not (type(k) == "string" and k:find("^__")) and type(elem[k]) == "nil" then
elem[k] = clone(v)
end
end
setmetatable(elem, template)
-- Ensure that the mandatory varaibles are declered
elem.depth = elem.depth or 0
elem.pos = elem.pos or Vector2()
elem.size = elem.size or Vector2()
if type(elem.visible) ~= "boolean" then
elem.visible = true
end
if elem.load then elem:load() end
return elem
end
function GUI.new(class, width, height)
assert(width and height, "Width and height are undefined")
local self = setmetatable({}, class)
self.pos = Vector2()
self.size = Vector2(width, height)
self.getPos = getPos
self.getSize = getSize
self.getBounds = getBounds
self.inBounds = inBounds
self._elements = {}
return self
end
function GUI:removeElement(element)
for i, elem in ipairs(self._elements) do
if elem == element then
table.remove(self._elements, i)
break
end
end
end
function GUI:addElement(elementType, data)
local elem = GUI.createElement(elementType, data)
elem._parent = self
-- Add it to the list
table.insert(self._elements, elem)
table.sort(self._elements, GUI.sortByDepth)
return elem
end
function GUI.newTemplate(name)
local template = {}
template.__index = template
template.getPos = getPos
template.getSize = getSize
template.getBounds = getBounds
template.inBounds = inBounds
templates[name] = template
return template
end
function GUI:resize(...)
for _, element in ipairs(self._elements) do
if element.resize then
element:resize(...)
end
end
end
function GUI.callMethod(parent, name, ...)
local useFallback = false
for _, element in revipairs(parent._elements) do
if element.visible then
if type(element._elements) == "table" then
if GUI.callMethod(element, name, ...) then break end
end
if useFallback and element[name.."Fallback"] then
element[name.."Fallback"](element, ...)
elseif element[name] then
if element[name](element, ...) then useFallback = true end
end
end
end
return useFallback
end
function GUI:draw(...)
local useFallback = false
for _, element in ipairs(self._elements) do
if element.visible then
if useFallback and element["drawFallback"] then
element["drawFallback"](element, ...)
elseif element["draw"] then
if element["draw"](element, ...) then useFallback = true end
end
if type(element._elements) == "table" then
GUI.draw(element, "draw", ...)
end
end
end
return useFallback
end
for i, name in pairs{"keypressed", "keyreleased", "mousemoved", "mousepressed", "mousereleased", "textinput"} do
GUI[name] = function(self, ...)
GUI.callMethod(self, name, ...)
end
end
return GUI