Implement basic graphical elements

This commit is contained in:
Gabriel Tofvesson 2024-10-01 14:34:56 +00:00
commit da6325e080
5 changed files with 384 additions and 0 deletions

170
gfx/element.lua Normal file
View File

@ -0,0 +1,170 @@
local Event = require("event")
local Element = {
x = 0,
y = 0,
width = 1,
height = 1,
color = {
bg = colors.black,
fg = colors.white
},
render = {
window = nil,
parent = nil
},
visible = true,
dirty = true,
id = "",
onClick = nil
}
local function createWindow(element)
return window.create(element.render.parent, element:getX(), element:getY(), element:getWidth(), element:getHeight(), element:isVisible())
end
function Element:new(o)
local obj = o or {}
setmetatable(obj, self)
obj.__index = self
return obj
end
function Element:draw()
self.dirty = false
end
function Element:getX()
return self.x
end
function Element:getY()
return self.y
end
function Element:setPos(x, y)
if (x ~= nil and self.x ~= x) or (y ~= nil and self.y ~= y) then
self:setDirty()
self.x = x or self.x
self.y = y or self.y
self.render.window = createWindow(self)
end
end
function Element:setX(x)
if self.x ~= x then
self:setDirty()
self.x = x
self.render.window = createWindow(self)
end
end
function Element:setY(y)
if self.y ~= y then
self:setDirty()
self.y = y
self.render.window = createWindow(self)
end
end
function Element:setParent(parent)
if self.parent ~= parent then
self:setDirty()
self.parent = parent
end
end
function Element:setFgColor(color)
if color ~= self.color.fg then
self:setDirty()
self.color.fg = color
self.render.window.setTextColor(color)
end
end
function Element:setBgColor(color)
if color ~= self.color.bg then
self:setDirty()
self.color.bg = color
self.render.window.setBackgroundColor(color)
end
end
function Element:setVisible(visible)
self.render.window.setVisible(visible)
end
function Element:resize(opts)
if (opts.width ~= nil and self.x ~= opts.width) or (opts.height ~= nil and self.y ~= opts.height) then
self:setDirty()
self.width = opts.width or self.width
self.height = opts.height or self.height
self.render.window = createWindow(self)
end
end
function Element:setWidth(width)
if width ~= self.width then
self:setDirty()
self.width = width
self.render.window = createWindow(self)
end
end
function Element:setHeight(height)
if height ~= self.height then
self:setDirty()
self.height = height
self.render.window = createWindow(self)
end
end
function Element:getWidth()
return self.width
end
function Element:getHeight()
return self.height
end
function Element:getPos()
return self.x, self.y
end
function Element:isVisible()
return self.visible
end
function Element:setDirty()
self.dirty = true
end
function Element:findById(id)
if self:getId() == id then
return self
else
return nil
end
end
function Element:getId()
return self.id
end
function Element:redraw()
self.render.window.redraw()
end
function Element:handleEvent(evt)
if Event.isClickEvent(evt) and self.onClick ~= nil then
local x, y, source = Event.getClickParams(evt)
return not not self.onClick(self, x, y, source)
end
return false
end
return Element

27
gfx/event.lua Normal file
View File

@ -0,0 +1,27 @@
local Event = {}
function Event.isClickEvent(evt)
return evt[1] == "monitor_touch" or evt[1] == "mouse_click"
end
function Event.getClickParams(evt)
return evt[3], evt[4], evt[2]
end
function Event.repositionEvent(evt, dX, dY)
if Event.isClickEvent(evt) then
return evt[1], evt[2], evt[3] + dX, evt[4] + dY
else
return evt
end
end
function Event.containsClick(element, evt, dX, dY)
local x, y = Event.getClickParams(evt)
x = x + dX
y = y + dY
local eX, eY = element:getPos()
return x >= eX and x < (eX + element:getWidth()) and y >= eY and y < (eY + element:getHeight())
end
return Event

108
gfx/list.lua Normal file
View File

@ -0,0 +1,108 @@
local Element = require("element")
local List = Element:new{
children = {},
vertical = false
}
local function adjustPositions(elements, vertical, from)
local newDims = 0
local getDim = vertical and function(e) return e:getHeight() end or function(e) return e:getWidth() end
for i=1,from-1 do
newDims = newDims + getDim(elements[i])
end
local setDim = vertical and function(e, dim) e:setPos(0, dim) end or function(e, dim) e:setPos(dim, 0) end
for i=from,#elements do
setDim(elements[i])
newDims = newDims + getDim(elements[i])
end
end
function List:insertChild(child, atIndex)
local index = math.min(math.max(1, atIndex or #self.children), #self.children)
table.insert(self.children, index, child)
adjustPositions(self.children, self:isVertical(), index)
end
function List:removeChild(child)
local index
local searchType = type(child)
if searchType == "string" then
for i,v in ipairs(self.children) do
if v:getId() == child then
index = i
break
end
end
return false, nil
elseif searchType == "table" then
for i,v in ipairs(self.children) do
if v == child then
index = i
end
end
return false, nil
else
index = child
end
if index <= 0 or index > #self.children then
return false, nil
end
local removed = table.remove(self.children, index)
if index <= #self.children then
adjustPositions(self.children, self:isVertical(), index)
end
return true, removed
end
function List:isVertical()
return self.vertical
end
function List:isHorizontal()
return not self:isVertical()
end
function List:draw()
Element.draw(self)
self.render.window.clear()
for _,v in ipairs(self.children) do
v:draw()
end
end
function List:getHeight()
local h = 0
for _,v in ipairs(self.children) do
h = h + v:getHeight()
end
return h
end
function List:getWidth()
local h = 0
for _,v in ipairs(self.children) do
h = h + v:getHeight()
end
return h
end
function List:findById(id)
local find = Element.findById(self, id)
if find then
return find
end
for _,v in ipairs(self.children) do
local result = v:findById(id)
if result then
return result
end
end
return nil
end
return List

70
gfx/padding.lua Normal file
View File

@ -0,0 +1,70 @@
local Event = require("event")
local Element = require("element")
local Padding = Element:new{
left = 0,
right = 0,
top = 0,
bottom = 0,
element = nil
}
function Padding:resize(opts)
-- Un-pad dimensions and pass to child element
return self.element:resize{
width = (opts.width and opts.width - self:getPaddingLeft() - self:getPaddingRight()) or self:getWidth(),
height = (opts.height and opts.height - self:getPaddingTop() - self:getPaddingBottom()) or self:getHeight()
}
end
function Padding:getPaddingLeft()
return self.left
end
function Padding:getPaddingRight()
return self.right
end
function Padding:getPaddingTop()
return self.top
end
function Padding:getPaddingBottom()
return self.bottom
end
function Padding:getInnerWidth()
return self.element:getWidth()
end
function Padding:getInnerHeight()
return self.element:getHeight()
end
function Padding:getWidth()
return self:getInnerWidth() + self:getPaddingLeft() + self:getPaddingRight()
end
function Padding:getHeight()
return self:getInnerHeight() + self:getPaddingTop() + self:getPaddingBottom()
end
function Padding:findById(id)
return Element.findById(self, id) or self.element:findById(id)
end
function Padding:handleEvent(evt)
if Element.handleEvent(self, evt) then
return true
end
if Event.isClickEvent(evt) then
if Event.containsClick(self.element, evt, -self:getPaddingLeft(), -self:getPaddingTop()) then
self.element:handleEvent({Event.repositionEvent(evt, -self:getPaddingLeft(), -self:getPaddingTop())})
end
else
return self.element:handleEvent(evt)
end
return false
end
return Padding

9
gfx/text.lua Normal file
View File

@ -0,0 +1,9 @@
local Element = require("element")
local Text = Element:new{ text = "" }
function Text:draw()
Element.draw(self)
self.render.window.write(self.text)
end
return Text