diff --git a/gfx/container.lua b/gfx/container.lua index 4124932..14be45a 100644 --- a/gfx/container.lua +++ b/gfx/container.lua @@ -4,30 +4,6 @@ local Element = require("gfx.element") 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() Element._reload(self) diff --git a/gfx/list.lua b/gfx/list.lua index d7fa10f..497b2f4 100644 --- a/gfx/list.lua +++ b/gfx/list.lua @@ -1,102 +1,44 @@ local Event = require("gfx.event") local Element = require("gfx.element") -local List = Element:new{ - children = {}, - vertical = false -} +local Prop = require("gfx.prop") +local Orientation = require("gfx.prop.orientation") +local Children = require("gfx.prop.children") +local List = Prop.attach(Prop.attach(Element:new(), Orientation), Children) -local function adjustPositions(elements, vertical, from) - local newDims = 1 - 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:setY(dim) end or function(e, dim) e:setX(dim) end - for i=from,#elements do - setDim(elements[i], newDims) - newDims = newDims + getDim(elements[i]) - end +function List:adjustPositions(from) + from = from or 1 + local vertical = self:isVertical() + local newDims = 1 + local getDim = vertical and function(e) return e:getHeight() end or function(e) return e:getWidth() end + for _,element in self:_iterateChildren{ to = from } do + newDims = newDims + getDim(element) + end + + local setDim = vertical and function(e, dim) e:setY(dim) end or function(e, dim) e:setX(dim) end + for _, element in self:_iterateChildren{ from = from } do + setDim(element, newDims) + newDims = newDims + getDim(element) + 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) - - -- Update window references - self:_reload() + self:_addChild(child, atIndex) 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) - self:_reload() - - return true, removed + return self:_removeChild(child) end -function List:isVertical() - 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) +local function maxOrSum(shouldSum, iter, getValue) if shouldSum then local sum = 0 - for _,v in ipairs(values) do + for _,v in iter() do sum = sum + getValue(v) end return sum else local max = 0 - for _,v in ipairs(values) do + for _,v in iter() do max = math.max(max, getValue(v)) end return max @@ -104,68 +46,13 @@ local function maxOrSum(shouldSum, values, getValue) end 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 function List:getWidth() - return maxOrSum(self:isHorizontal(), self.children, function(e) return e:getWidth() end) -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 + local lSelf = self + return maxOrSum(self:isHorizontal(), function() return lSelf:_iterateChildren() end, function(e) return e:getWidth() end) end function List:_reload() @@ -173,13 +60,13 @@ function List:_reload() -- Reload child windows local win = self:_getWindow() - for _,child in ipairs(self.children) do + for _,child in self:_iterateChildren() do if child:_getWindow() ~= win then child:setParent(win) end end - adjustPositions(self.children, self:isVertical(), 1) + self:adjustPositions() end return List \ No newline at end of file diff --git a/gfx/prop/children.lua b/gfx/prop/children.lua index 5a2fe49..ce53b27 100644 --- a/gfx/prop/children.lua +++ b/gfx/prop/children.lua @@ -1,4 +1,6 @@ local Prop = require("gfx.prop") +local Element = require("gfx.element") +local Event = require("gfx.event") local Children = Prop:new{ defaultState = {} } function Children:with(elementType) @@ -69,6 +71,48 @@ function Children:with(elementType) return true, result 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) for _,child in self:_iterateChildren() do local result = child:findById(id) @@ -79,6 +123,35 @@ function Children:with(elementType) return nil 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 end