Lift common functionality to prop

This commit is contained in:
Gabriel Tofvesson 2024-10-09 06:17:23 +02:00
parent a96102dc48
commit 3bb7a69577
3 changed files with 102 additions and 166 deletions

View File

@ -4,30 +4,6 @@ local Element = require("gfx.element")
local Container = Prop.attach(Element:new(), Children) local Container = Prop.attach(Element:new(), Children)
function Container:draw()
local dirty = Element.draw(self)
if dirty then
self:_getWindow().clear()
for _,child in self:_iterateChildren() do
child:draw()
end
end
return dirty
end
function Container:_isDirty()
if Element._isDirty(self) then
return true
end
for _,child in self:_iterateChildren() do
if child:_isDirty() then
return true
end
end
return false
end
function Container:_reload() function Container:_reload()
Element._reload(self) Element._reload(self)

View File

@ -1,102 +1,44 @@
local Event = require("gfx.event") local Event = require("gfx.event")
local Element = require("gfx.element") local Element = require("gfx.element")
local List = Element:new{ local Prop = require("gfx.prop")
children = {}, local Orientation = require("gfx.prop.orientation")
vertical = false local Children = require("gfx.prop.children")
} local List = Prop.attach(Prop.attach(Element:new(), Orientation), Children)
local function adjustPositions(elements, vertical, from) function List:adjustPositions(from)
from = from or 1
local vertical = self:isVertical()
local newDims = 1 local newDims = 1
local getDim = vertical and function(e) return e:getHeight() end or function(e) return e:getWidth() end local getDim = vertical and function(e) return e:getHeight() end or function(e) return e:getWidth() end
for i=1,from-1 do for _,element in self:_iterateChildren{ to = from } do
newDims = newDims + getDim(elements[i]) newDims = newDims + getDim(element)
end end
local setDim = vertical and function(e, dim) e:setY(dim) end or function(e, dim) e:setX(dim) end local setDim = vertical and function(e, dim) e:setY(dim) end or function(e, dim) e:setX(dim) end
for i=from,#elements do for _, element in self:_iterateChildren{ from = from } do
setDim(elements[i], newDims) setDim(element, newDims)
newDims = newDims + getDim(elements[i]) newDims = newDims + getDim(element)
end end
end end
function List:insertChild(child, atIndex) function List:insertChild(child, atIndex)
local index = math.min(math.max(1, atIndex or #self.children), #self.children) self:_addChild(child, atIndex)
table.insert(self.children, index, child)
-- Update window references
self:_reload()
end end
function List:removeChild(child) function List:removeChild(child)
local index return self:_removeChild(child)
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)
self:_reload()
return true, removed
end end
function List:isVertical() local function maxOrSum(shouldSum, iter, getValue)
return self.vertical
end
function List:isHorizontal()
return not self:isVertical()
end
function List:setDirty(fullInvalidate)
Element.setDirty(self, fullInvalidate)
if fullInvalidate then
for _,child in self.children do
child:setDirty(fullInvalidate)
end
end
end
function List:draw()
local dirty = Element.draw(self)
if dirty then
self:_getWindow().clear()
for _,child in ipairs(self.children) do
child:draw()
end
end
return dirty
end
local function maxOrSum(shouldSum, values, getValue)
if shouldSum then if shouldSum then
local sum = 0 local sum = 0
for _,v in ipairs(values) do for _,v in iter() do
sum = sum + getValue(v) sum = sum + getValue(v)
end end
return sum return sum
else else
local max = 0 local max = 0
for _,v in ipairs(values) do for _,v in iter() do
max = math.max(max, getValue(v)) max = math.max(max, getValue(v))
end end
return max return max
@ -104,68 +46,13 @@ local function maxOrSum(shouldSum, values, getValue)
end end
function List:getHeight() function List:getHeight()
return maxOrSum(self:isVertical(), self.children, function(e) return e:getHeight() end) local lSelf = self
return maxOrSum(self:isVertical(), function() return lSelf:_iterateChildren() end, function(e) return e:getHeight() end)
end end
function List:getWidth() function List:getWidth()
return maxOrSum(self:isHorizontal(), self.children, function(e) return e:getWidth() end) local lSelf = self
end return maxOrSum(self:isHorizontal(), function() return lSelf:_iterateChildren() end, function(e) return e:getWidth() 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
function List:handleEvent(evt)
if Element.handleEvent(self, evt) then
return true
end
local evtLocalCoords = Event.toElementLocalPosition(evt, self)
if Event.isClickEvent(evt) then
-- If click is not inside list bounds, we can safely ignore it
if not Event.containsClick(self, evt) then
return false
end
for _,child in ipairs(self.children) do
if child:handleEvent(evtLocalCoords) then
return true
end
end
return false
else
for _,child in ipairs(self.children) do
if child:handleEvent(evtLocalCoords) then
return true
end
end
return false
end
end
function List:_isDirty()
if Element._isDirty(self) then
return true
end
for _,child in ipairs(self.children) do
if child:_isDirty() then
return true
end
end
return false
end end
function List:_reload() function List:_reload()
@ -173,13 +60,13 @@ function List:_reload()
-- Reload child windows -- Reload child windows
local win = self:_getWindow() local win = self:_getWindow()
for _,child in ipairs(self.children) do for _,child in self:_iterateChildren() do
if child:_getWindow() ~= win then if child:_getWindow() ~= win then
child:setParent(win) child:setParent(win)
end end
end end
adjustPositions(self.children, self:isVertical(), 1) self:adjustPositions()
end end
return List return List

View File

@ -1,4 +1,6 @@
local Prop = require("gfx.prop") local Prop = require("gfx.prop")
local Element = require("gfx.element")
local Event = require("gfx.event")
local Children = Prop:new{ defaultState = {} } local Children = Prop:new{ defaultState = {} }
function Children:with(elementType) function Children:with(elementType)
@ -69,6 +71,48 @@ function Children:with(elementType)
return true, result return true, result
end end
function elementType:setDirty(fullInvalidate)
Element.setDirty(self, fullInvalidate)
if fullInvalidate then
for _,child in self:_iterateChildren() do
child:setDirty(fullInvalidate)
end
end
end
function elementType:_isDirty()
if Element._isDirty(self) then
return true
end
for _,child in self:_iterateChildren() do
if child:_isDirty() then
return true
end
end
return false
end
function elementType:draw()
local dirty = Element.draw(self)
if dirty then
self:_getWindow().clear()
for _,child in self:_iterateChildren() do
child:draw()
end
end
return dirty
end
function elementType:findById(id)
local find = Element.findById(self, id)
if find then
return find
end
return self:findChildById(id)
end
function elementType:findChildById(id) function elementType:findChildById(id)
for _,child in self:_iterateChildren() do for _,child in self:_iterateChildren() do
local result = child:findById(id) local result = child:findById(id)
@ -79,6 +123,35 @@ function Children:with(elementType)
return nil return nil
end end
function elementType:handleEvent(evt)
if Element.handleEvent(self, evt) then
return true
end
local evtLocalCoords = Event.toElementLocalPosition(evt, self)
if Event.isClickEvent(evt) then
-- If click is not inside list bounds, we can safely ignore it
if not Event.containsClick(self, evt) then
return false
end
for _,child in self:_iterateChildren() do
if child:handleEvent(evtLocalCoords) then
return true
end
end
return false
else
for _,child in self:_iterateChildren() do
if child:handleEvent(evtLocalCoords) then
return true
end
end
return false
end
end
return elementType return elementType
end end