Refactor + prevent memory leaks
This commit is contained in:
parent
31317ad926
commit
5d707925c6
113
core/element.lua
113
core/element.lua
@ -11,7 +11,7 @@ local activeContext
|
||||
|
||||
---@param elem element
|
||||
function context.new(elem)
|
||||
local ctx = setmetatable({view = elem.view, element = elem}, context)
|
||||
local ctx = setmetatable({view = elem.view, element = elem, childrenContexts={}}, context)
|
||||
|
||||
return ctx
|
||||
end
|
||||
@ -27,7 +27,10 @@ end
|
||||
|
||||
function context:set()
|
||||
if activeContext then
|
||||
self.parentCtx = activeContext
|
||||
if not self.parentCtx then
|
||||
self.parentCtx = activeContext
|
||||
activeContext.childrenContexts[#activeContext.childrenContexts] = self
|
||||
end
|
||||
|
||||
self.absX = self.parentCtx.absX + self.view.x
|
||||
self.absY = self.parentCtx.absY + self.view.y
|
||||
@ -49,10 +52,18 @@ function context:unset()
|
||||
end
|
||||
end
|
||||
|
||||
function context:destroy()
|
||||
self.elem:undraw()
|
||||
for i=1,#self.childrenContexts do
|
||||
self.childrenContexts[i]:destroy()
|
||||
end
|
||||
end
|
||||
|
||||
---@class element
|
||||
local element = {}
|
||||
element.__index = element
|
||||
|
||||
local type,pcall = type,pcall
|
||||
setmetatable(element,{
|
||||
__call = function(cls, ...)
|
||||
local self
|
||||
@ -60,7 +71,6 @@ setmetatable(element,{
|
||||
if type(func)=='function' then
|
||||
self = setmetatable({}, element)
|
||||
self.parentFunc = func
|
||||
self.classless = true
|
||||
end
|
||||
|
||||
if loader then
|
||||
@ -79,11 +89,6 @@ setmetatable(element,{
|
||||
--Dummy functions
|
||||
function element:renderer() print('no renderer') end
|
||||
|
||||
function element:updater() end
|
||||
|
||||
function element:constructor() end
|
||||
|
||||
|
||||
--Control functions
|
||||
--The new function that should be used for element creation
|
||||
function element:new()
|
||||
@ -92,7 +97,7 @@ function element:new()
|
||||
self.parameters = {}
|
||||
|
||||
--The element canvas
|
||||
self.canvas = nil
|
||||
--self.canvas = nil
|
||||
|
||||
--Internal settings
|
||||
self.settings = {
|
||||
@ -129,19 +134,17 @@ function element:new()
|
||||
self.inputContext = helium.input.newContext(self)
|
||||
self.context = context.new(self)
|
||||
|
||||
if self.classless then
|
||||
self.classlessFuncs = {}
|
||||
self.classlessFuncs = {}
|
||||
|
||||
--Allows manipulation of the arbitrary state
|
||||
self.classlessFuncs.getState = function ()
|
||||
return self.state
|
||||
end
|
||||
--Allows manipulation of the arbitrary state
|
||||
self.classlessFuncs.getState = function ()
|
||||
return self.state
|
||||
end
|
||||
|
||||
--Allows manipulation of rendering width height, relative X and relative Y
|
||||
self.classlessFuncs.getView = function ()
|
||||
self.settings.restrictView = true
|
||||
return self.view
|
||||
end
|
||||
--Allows manipulation of rendering width height, relative X and relative Y
|
||||
self.classlessFuncs.getView = function ()
|
||||
self.settings.restrictView = true
|
||||
return self.view
|
||||
end
|
||||
end
|
||||
|
||||
@ -173,6 +176,7 @@ function element:reLoader(newFunc)
|
||||
self.inputContext:unset()
|
||||
end
|
||||
|
||||
local newCanvas,newQuad = love.graphics.newCanvas,love.graphics.newQuad
|
||||
--Called once dimensions are validated
|
||||
function element:setup()
|
||||
self.state = setmetatable({},{
|
||||
@ -203,21 +207,17 @@ function element:setup()
|
||||
self.settings.canvasW = self.view.w*1.25
|
||||
self.settings.canvasH = self.view.h*1.25
|
||||
|
||||
self.canvas = love.graphics.newCanvas(self.view.w*1.25, self.view.h*1.25)
|
||||
self.canvas = newCanvas(self.view.w*1.25, self.view.h*1.25)
|
||||
self.quad = newQuad(0, 0, self.view.w, self.view.h, self.view.w*1.25, self.view.h*1.25)
|
||||
|
||||
self.quad = love.graphics.newQuad(0, 0, self.view.w, self.view.h, self.view.w*1.25, self.view.h*1.25)
|
||||
|
||||
if self.classless then
|
||||
self.inputContext:set()
|
||||
|
||||
self.renderer = self.parentFunc(self.parameters,self.state,self.view)
|
||||
|
||||
self.inputContext:unset()
|
||||
end
|
||||
self.inputContext:set()
|
||||
self.renderer = self.parentFunc(self.parameters,self.state,self.view)
|
||||
self.inputContext:unset()
|
||||
|
||||
self.settings.isSetup = true
|
||||
end
|
||||
|
||||
local setColor,rectangle,setFont,printf = love.graphics.setColor,love.graphics.rectangle,love.graphics.setFont,love.graphics.printf
|
||||
function element:classlessRender()
|
||||
|
||||
self.inputContext:set()
|
||||
@ -225,38 +225,38 @@ function element:classlessRender()
|
||||
local status, err = pcall(self.renderer)
|
||||
|
||||
if not status then
|
||||
love.graphics.setColor(1,0,0)
|
||||
love.graphics.rectangle('line',0,0,self.view.w,self.view.h)
|
||||
love.graphics.setColor(1,1,1)
|
||||
love.graphics.printf("Error: "..err,0,0,self.view.w)
|
||||
setColor(1,0,0)
|
||||
rectangle('line',0,0,self.view.w,self.view.h)
|
||||
setColor(1,1,1)
|
||||
printf("Error: "..err,0,0,self.view.w)
|
||||
end
|
||||
|
||||
elseif type(self.renderer)=='string' then
|
||||
love.graphics.setColor(1,0,0)
|
||||
love.graphics.rectangle('line',0,0,self.view.w,self.view.h)
|
||||
love.graphics.setColor(1,1,1)
|
||||
love.graphics.printf("Error: "..self.renderer,0,0,self.view.w)
|
||||
setColor(1,0,0)
|
||||
rectangle('line',0,0,self.view.w,self.view.h)
|
||||
setColor(1,1,1)
|
||||
printf("Error: "..self.renderer,0,0,self.view.w)
|
||||
end
|
||||
self.inputContext:unset()
|
||||
|
||||
self.inputContext:unset()
|
||||
end
|
||||
|
||||
local getCanvas,setCanvas,clear = love.graphics.getCanvas,love.graphics.setCanvas,love.graphics.clear
|
||||
function element:renderWrapper()
|
||||
local cnvs = love.graphics.getCanvas()
|
||||
love.graphics.setCanvas({self.canvas, stencil = true})
|
||||
local cnvs = getCanvas()
|
||||
setCanvas({self.canvas, stencil = true})
|
||||
|
||||
love.graphics.clear()
|
||||
clear()
|
||||
|
||||
if self.classless and self.parameters then
|
||||
if self.parameters then
|
||||
self:classlessRender()
|
||||
self.settings.pendingUpdate = false
|
||||
else
|
||||
self:renderer()
|
||||
end
|
||||
|
||||
love.graphics.setCanvas(cnvs)
|
||||
setCanvas(cnvs)
|
||||
end
|
||||
|
||||
local draw = love.graphics.draw
|
||||
function element:externalRender()
|
||||
self.context:set()
|
||||
|
||||
@ -265,8 +265,8 @@ function element:externalRender()
|
||||
self.settings.needsRendering = false
|
||||
end
|
||||
|
||||
love.graphics.setColor(1,1,1)
|
||||
love.graphics.draw(self.canvas, self.quad, self.view.x, self.view.y)
|
||||
setColor(1,1,1)
|
||||
draw(self.canvas, self.quad, self.view.x, self.view.y)
|
||||
|
||||
self.context:unset()
|
||||
end
|
||||
@ -282,6 +282,7 @@ function element:externalUpdate()
|
||||
end
|
||||
end
|
||||
|
||||
local insert = table.insert
|
||||
--External functions
|
||||
--Acts as the entrypoint for beginning rendering
|
||||
---@param params any
|
||||
@ -291,10 +292,14 @@ end
|
||||
---@param h number
|
||||
function element:draw(params, x, y, w, h)
|
||||
if not self.view.lock then
|
||||
self.view.x = x or self.view.x
|
||||
self.view.y = y or self.view.y
|
||||
self.view.w = w or self.view.w
|
||||
self.view.h = h or self.view.h
|
||||
--self.view.x = x or self.view.x
|
||||
--self.view.y = y or self.view.y
|
||||
--self.view.w = w or self.view.w
|
||||
--self.view.h = h or self.view.h
|
||||
if x then self.view.x = x end
|
||||
if y then self.view.y = y end
|
||||
if w then self.view.w = w end
|
||||
if h then self.view.h = h end
|
||||
end
|
||||
|
||||
if params then
|
||||
@ -316,13 +321,15 @@ function element:draw(params, x, y, w, h)
|
||||
self:externalRender()
|
||||
elseif not self.settings.inserted then
|
||||
self.settings.inserted = true
|
||||
table.insert(helium.elementBuffer, self)
|
||||
insert(helium.elementBuffer, self)
|
||||
end
|
||||
end
|
||||
|
||||
function element:undraw()
|
||||
self.settings.remove = true
|
||||
self.settings.isSetup = false
|
||||
self.inputContext:set()
|
||||
self.inputContext:destroy()
|
||||
end
|
||||
|
||||
return element
|
||||
|
||||
@ -36,14 +36,17 @@ local activeContext
|
||||
|
||||
]]
|
||||
function input.newContext(element)
|
||||
local ctx = setmetatable({elem = element, subs = {}}, context)
|
||||
local ctx = setmetatable({elem = element, subs = {}, childContexts={}}, context)
|
||||
|
||||
return ctx
|
||||
end
|
||||
|
||||
function context:set()
|
||||
if activeContext then
|
||||
self.parentCtx = activeContext
|
||||
if not self.parentCtx then
|
||||
activeContext.childContexts[#activeContext.childContexts+1] = self
|
||||
self.parentCtx = activeContext
|
||||
end
|
||||
self.absX = self.parentCtx.absX + self.elem.view.x
|
||||
self.absY = self.parentCtx.absY + self.elem.view.y
|
||||
activeContext = self
|
||||
@ -72,6 +75,9 @@ function context:destroy()
|
||||
for i, e in ipairs(self.subs) do
|
||||
e:destroy()
|
||||
end
|
||||
for i, e in ipairs(self.childContexts) do
|
||||
e:destroy()
|
||||
end
|
||||
end
|
||||
|
||||
---@param x number
|
||||
@ -149,33 +155,23 @@ function subscription:emit(...)
|
||||
end
|
||||
|
||||
function subscription:checkInside(x, y)
|
||||
if x>self.x and x<self.x+self.w and y>self.y and y<self.y+self.h then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
return x>self.x and x<self.x+self.w and y>self.y and y<self.y+self.h
|
||||
end
|
||||
|
||||
function subscription:checkOutside(x, y)
|
||||
if x>self.x and x<self.x+self.w and y>self.y and y<self.y+self.h then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
return not (x>self.x and x<self.x+self.w and y>self.y and y<self.y+self.h)
|
||||
end
|
||||
|
||||
input.subscribe = function(...)
|
||||
return subscription.create(...)
|
||||
end
|
||||
input.subscribe = subscription.create
|
||||
|
||||
|
||||
function input.eventHandlers.mousereleased(x, y, btn)
|
||||
local captured = false
|
||||
if input.subscriptions.mousereleased then
|
||||
for index, sub in ipairs(input.subscriptions.mousereleased) do
|
||||
local succ = sub:checkInside(x, y)
|
||||
--local succ = sub:checkInside(x, y)
|
||||
|
||||
if succ and sub.active then
|
||||
if sub.active and sub:checkInside(x, y) then -- succ and sub:check
|
||||
sub:emit(x, y, btn)
|
||||
captured = true
|
||||
end
|
||||
@ -184,9 +180,9 @@ function input.eventHandlers.mousereleased(x, y, btn)
|
||||
end
|
||||
if input.subscriptions.mousereleased_outside then
|
||||
for index, sub in ipairs(input.subscriptions.mousereleased_outside) do
|
||||
local succ = sub:checkOutside(x, y)
|
||||
--local succ = sub:checkOutside(x, y)
|
||||
|
||||
if succ and sub.active then
|
||||
if sub.active and sub:checkOutside(x, y) then -- succ and sub.active then
|
||||
sub:emit(x, y, btn)
|
||||
captured = true
|
||||
end
|
||||
@ -227,9 +223,9 @@ function input.eventHandlers.mousepressed(x, y, btn)
|
||||
local captured = false
|
||||
if input.subscriptions.mousepressed then
|
||||
for index, sub in ipairs(input.subscriptions.mousepressed) do
|
||||
local succ = sub:checkInside(x, y)
|
||||
--local succ = sub:checkInside(x, y)
|
||||
|
||||
if succ and sub.active then
|
||||
if sub.active and sub:checkInside(x, y) then -- succ and sub:check
|
||||
sub:emit(x, y, btn)
|
||||
captured = true
|
||||
end
|
||||
@ -238,9 +234,9 @@ function input.eventHandlers.mousepressed(x, y, btn)
|
||||
end
|
||||
if input.subscriptions.mousepressed_outside then
|
||||
for index, sub in ipairs(input.subscriptions.mousepressed_outside) do
|
||||
local succ = sub:checkOutside(x, y)
|
||||
--local succ = sub:checkOutside(x, y)
|
||||
|
||||
if succ and sub.active then
|
||||
if sub.active and sub:checkOutside(x, y) then -- succ and sub.active then
|
||||
sub:emit(x, y, btn)
|
||||
captured = true
|
||||
end
|
||||
@ -262,9 +258,9 @@ function input.eventHandlers.mousepressed(x, y, btn)
|
||||
|
||||
if input.subscriptions.dragged then
|
||||
for index, sub in ipairs(input.subscriptions.dragged) do
|
||||
local succ = sub:checkInside(x, y)
|
||||
--local succ = sub:checkInside(x, y)
|
||||
|
||||
if succ and sub.active then
|
||||
if sub.active and sub:checkInside(x, y) then -- succ and sub:check
|
||||
sub.currentEvent = true
|
||||
captured = true
|
||||
end
|
||||
@ -279,7 +275,7 @@ function input.eventHandlers.keypressed(btn)
|
||||
local captured = false
|
||||
if input.subscriptions.keypressed then
|
||||
for index, sub in ipairs(input.subscriptions.keypressed) do
|
||||
if sub.active ==true then
|
||||
if sub.active then -- ==true then
|
||||
sub:emit( btn)
|
||||
captured = true
|
||||
end
|
||||
@ -311,11 +307,11 @@ function input.eventHandlers.mousemoved(x, y, dx, dy)
|
||||
for index, sub in ipairs(input.subscriptions.hover) do
|
||||
local succ = sub:checkInside(x, y)
|
||||
|
||||
if succ and sub.active and not sub.currentEvent then
|
||||
if sub.active and not sub.currentEvent and succ then
|
||||
sub.cleanUp = sub:emit(x, y)
|
||||
sub.currentEvent = true
|
||||
captured = true
|
||||
elseif sub.currentEvent and not sub:checkInside(x, y) then
|
||||
elseif sub.currentEvent and not succ then
|
||||
sub.currentEvent = false
|
||||
captured = true
|
||||
if sub.cleanUp then
|
||||
@ -334,7 +330,7 @@ function input.eventHandlers.mousemoved(x, y, dx, dy)
|
||||
else
|
||||
sub:emit(x, y, dx, dy)
|
||||
end
|
||||
sub.currentEvent = true
|
||||
--sub.currentEvent = true -- checked in the condition so must be true
|
||||
captured = true
|
||||
end
|
||||
|
||||
|
||||
40
loader.lua
40
loader.lua
@ -5,23 +5,40 @@ local elements = {}
|
||||
local debugLoader = {}
|
||||
--Return level: 1--string; 2--chunk; 3--return value; default: element factory
|
||||
local function loader(path)
|
||||
local succ = true
|
||||
|
||||
--File string
|
||||
local fileContents, err = love.filesystem.read(path)
|
||||
local lastLoaded, status, func, succ, ret
|
||||
|
||||
if fileContents then
|
||||
lastLoaded = love.filesystem.getInfo(path).modtime
|
||||
status, func = pcall(loadstring,fileContents)
|
||||
if not status then
|
||||
print('Error compiling ',path,':',tostring(err),', will continue watching!')
|
||||
else
|
||||
succ, ret = pcall(func,path)
|
||||
end
|
||||
if fileContents==nil then
|
||||
print('Error loading ',path,':',tostring(err),', will continue watching!')
|
||||
succ = false
|
||||
end
|
||||
|
||||
local t, lastLoaded
|
||||
if succ then
|
||||
t = love.filesystem.getInfo(path)
|
||||
lastLoaded = t['modtime']
|
||||
end
|
||||
|
||||
--Chunk
|
||||
local status, err
|
||||
if succ then
|
||||
status, err = pcall(loadstring,fileContents)
|
||||
end
|
||||
|
||||
if status==false or status==nil then
|
||||
print('Error compiling ',path,':',tostring(err),', will continue watching!')
|
||||
succ = false
|
||||
end
|
||||
|
||||
--Return values
|
||||
local ret
|
||||
if succ then
|
||||
succ, ret = pcall(err,path)
|
||||
if not succ then
|
||||
print('Error calling ',path,':',tostring(ret))
|
||||
end
|
||||
else
|
||||
print('Error loading ',path,':',tostring(err),', will continue watching!')
|
||||
end
|
||||
|
||||
return fileContents, err, ret, lastLoaded
|
||||
@ -60,6 +77,7 @@ function debugLoader.update(dt)
|
||||
--If last save time differs then start reload sequence
|
||||
local _, _, ret, lastLoaded = loader(elem[4])
|
||||
|
||||
|
||||
local setfuncs = {}
|
||||
|
||||
local reloader = function(setFunc)
|
||||
|
||||
18
utils.lua
18
utils.lua
@ -4,25 +4,25 @@ function utils.ArrayRemove(t, fnKeep)
|
||||
local j, n = 1, #t;
|
||||
|
||||
for i=1,n do
|
||||
if (fnKeep(t, i, j)) then
|
||||
if fnKeep(t, i, j) then
|
||||
-- Move i's kept value to j's position, if it's not already there.
|
||||
if (i ~= j) then
|
||||
if i ~= j then
|
||||
t[j] = t[i];
|
||||
t[i] = nil;
|
||||
--t[i] = nil;
|
||||
end
|
||||
j = j + 1; -- Increment position of where we'll place the next kept value.
|
||||
else
|
||||
t[i] = nil;
|
||||
end
|
||||
end --else
|
||||
t[i] = nil; -- in both if cases you nil it sooooo
|
||||
--end
|
||||
end
|
||||
|
||||
return t;
|
||||
end
|
||||
|
||||
function utils.tableMerge(t, bt)
|
||||
for i, e in pairs(t) do
|
||||
if e ~= bt[i] then
|
||||
bt[i] = e
|
||||
for k, v in pairs(t) do
|
||||
if v ~= bt[k] then
|
||||
bt[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user