Hotswapping+new index
This commit is contained in:
parent
004e6cb34a
commit
07dbbb06e9
5
conf.lua
Normal file
5
conf.lua
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
return {
|
||||||
|
HOTSWAP = true,
|
||||||
|
AUTO_RUN = true,
|
||||||
|
DEBUG = true,
|
||||||
|
}
|
||||||
154
core/element.lua
154
core/element.lua
@ -1,4 +1,5 @@
|
|||||||
--[[ Element superclass ]]
|
--[[ Element superclass ]]
|
||||||
|
--[[ Love is currently a hard dependency, although not in many places ]]
|
||||||
local path = string.sub(..., 1, string.len(...) - string.len(".core.element"))
|
local path = string.sub(..., 1, string.len(...) - string.len(".core.element"))
|
||||||
local helium = require(path .. ".dummy")
|
local helium = require(path .. ".dummy")
|
||||||
|
|
||||||
@ -58,11 +59,8 @@ setmetatable(element,{
|
|||||||
local func, loader = ...
|
local func, loader = ...
|
||||||
if type(func)=='function' then
|
if type(func)=='function' then
|
||||||
self = setmetatable({}, element)
|
self = setmetatable({}, element)
|
||||||
self.renderer = ...
|
self.parentFunc = func
|
||||||
self.classless = true
|
self.classless = true
|
||||||
elseif type(cls)=='table' then
|
|
||||||
self = setmetatable({}, cls)
|
|
||||||
self.classless = false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if loader then
|
if loader then
|
||||||
@ -105,32 +103,79 @@ function element:new()
|
|||||||
inserted = false
|
inserted = false
|
||||||
}
|
}
|
||||||
|
|
||||||
self.view = {
|
self.baseState = {}
|
||||||
|
|
||||||
|
self.baseView = {
|
||||||
x = 0,
|
x = 0,
|
||||||
y = 0,
|
y = 0,
|
||||||
w = 10,
|
w = 10,
|
||||||
h = 10,
|
h = 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.view = setmetatable({},{
|
||||||
|
__index = function(t, index)
|
||||||
|
return self.baseView[index]
|
||||||
|
end,
|
||||||
|
__newindex = function(t, index, val)
|
||||||
|
if self.baseView[index] ~= val then
|
||||||
|
self.baseView[index] = val
|
||||||
|
self.context:bubbleUpdate()
|
||||||
|
self:updateInputCtx()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
--Context makes sure element internals don't have to worry about absolute coordinates
|
||||||
|
self.inputContext = helium.input.newContext(self)
|
||||||
|
self.context = context.new(self)
|
||||||
|
|
||||||
if self.classless then
|
if self.classless then
|
||||||
self.classlessState = {}
|
self.classlessFuncs = {}
|
||||||
self.classlessData = {}
|
|
||||||
|
--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
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function element:updateInputCtx()
|
||||||
|
self.inputContext:update()
|
||||||
|
if self.settings.canvasW then
|
||||||
|
if self.settings.canvasW < self.view.w or self.settings.canvasH < self.view.h then
|
||||||
|
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)
|
||||||
|
end
|
||||||
|
|
||||||
|
self.quad = love.graphics.newQuad(0, 0, self.view.w, self.view.h, self.settings.canvasW, self.settings.canvasH)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--Hotswapping code
|
--Hotswapping code
|
||||||
|
|
||||||
function element:reLoader(newFunc)
|
function element:reLoader(newFunc)
|
||||||
self.renderer = newFunc
|
self.inputContext:set()
|
||||||
|
self.inputContext:destroy()
|
||||||
|
|
||||||
|
self.parentFunc = newFunc
|
||||||
|
self.renderer = self.parentFunc(self.parameters,self.state,self.view)
|
||||||
self.context:bubbleUpdate()
|
self.context:bubbleUpdate()
|
||||||
|
|
||||||
|
self.inputContext:unset()
|
||||||
end
|
end
|
||||||
|
|
||||||
--Called once dimensions are validated
|
--Called once dimensions are validated
|
||||||
function element:setup()
|
function element:setup()
|
||||||
self.state =
|
self.state = setmetatable({},{
|
||||||
setmetatable(
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
__index = function(t, index)
|
__index = function(t, index)
|
||||||
return self.baseState[index]
|
return self.baseState[index]
|
||||||
end,
|
end,
|
||||||
@ -140,15 +185,11 @@ function element:setup()
|
|||||||
self.context:bubbleUpdate()
|
self.context:bubbleUpdate()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
self.parameters =
|
self.parameters = setmetatable({},{
|
||||||
setmetatable(
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
__index = function(t, index)
|
__index = function(t, index)
|
||||||
return self.baseParams[index] or nil
|
return self.baseParams[index]
|
||||||
end,
|
end,
|
||||||
__newindex = function(t, index, val)
|
__newindex = function(t, index, val)
|
||||||
if self.baseParams[index] ~= val then
|
if self.baseParams[index] ~= val then
|
||||||
@ -156,68 +197,32 @@ function element:setup()
|
|||||||
self.context:bubbleUpdate()
|
self.context:bubbleUpdate()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
self.canvas = love.graphics.newCanvas(self.view.w, self.view.h)
|
|
||||||
|
|
||||||
self.quad = love.graphics.newQuad(0, 0, self.view.w, self.view.h, self.view.w, self.view.h)
|
self.settings.canvasW = self.view.w*1.25
|
||||||
|
self.settings.canvasH = self.view.h*1.25
|
||||||
|
|
||||||
--Context makes sure element internals don't have to worry about absolute coordinates
|
self.canvas = love.graphics.newCanvas(self.view.w*1.25, self.view.h*1.25)
|
||||||
self.inputContext = helium.input.newContext(self)
|
|
||||||
self.context = context.new(self)
|
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.settings.isSetup = true
|
self.settings.isSetup = true
|
||||||
|
|
||||||
--Classless rendering
|
|
||||||
if self.classless then
|
|
||||||
self.classlessData.loadEffect = function (func)
|
|
||||||
if self.classlessData.loaded and self.classlessData.loadCaptured then
|
|
||||||
return self.classlessData.loadCaptured
|
|
||||||
elseif not self.classlessData.loaded then
|
|
||||||
self.classlessData.loadCaptured = func()
|
|
||||||
self.classlessData.loaded = true
|
|
||||||
if self.classlessData.loadCaptured then
|
|
||||||
return self.classlessData.loadCaptured
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
---@param initial any
|
|
||||||
---@return any
|
|
||||||
---@return function
|
|
||||||
self.classlessData.useState = function (initial)
|
|
||||||
self.settings.indice = self.settings.indice + 1
|
|
||||||
local indice = self.settings.indice
|
|
||||||
|
|
||||||
if self.classlessState[indice] and self.classlessState[indice].state then
|
|
||||||
return self.classlessState[indice].state, self.classlessState[indice].setState
|
|
||||||
else
|
|
||||||
self.classlessState[indice] = {}
|
|
||||||
self.classlessState[indice].state = initial
|
|
||||||
|
|
||||||
self.classlessState[indice].setState = function(set)
|
|
||||||
self.classlessState[indice].state = set
|
|
||||||
self.context:bubbleUpdate()
|
|
||||||
end
|
|
||||||
|
|
||||||
self.classlessState[indice].getState = function()
|
|
||||||
return self.classlessState[indice].state
|
|
||||||
end
|
|
||||||
return self.classlessState[indice].state, self.classlessState[indice].setState, self.classlessState[indice].getState
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function element:classlessRender()
|
function element:classlessRender()
|
||||||
self.inputContext:set()
|
|
||||||
self.settings.indice = 0
|
|
||||||
if type(self.renderer)=='function' then
|
|
||||||
local denv = getfenv(self.renderer)
|
|
||||||
denv['useState'] = self.classlessData.useState
|
|
||||||
denv['loadEffect'] = self.classlessData.loadEffect
|
|
||||||
|
|
||||||
local status,err = pcall(self.renderer,self.parameters, self.view.w, self.view.h)
|
self.inputContext:set()
|
||||||
|
if type(self.renderer)=='function' then
|
||||||
|
local status, err = pcall(self.renderer)
|
||||||
|
|
||||||
if not status then
|
if not status then
|
||||||
love.graphics.setColor(1,0,0)
|
love.graphics.setColor(1,0,0)
|
||||||
@ -226,8 +231,6 @@ function element:classlessRender()
|
|||||||
love.graphics.printf("Error: "..err,0,0,self.view.w)
|
love.graphics.printf("Error: "..err,0,0,self.view.w)
|
||||||
end
|
end
|
||||||
|
|
||||||
denv['useState'] = nil
|
|
||||||
denv['loadEffect'] = nil
|
|
||||||
elseif type(self.renderer)=='string' then
|
elseif type(self.renderer)=='string' then
|
||||||
love.graphics.setColor(1,0,0)
|
love.graphics.setColor(1,0,0)
|
||||||
love.graphics.rectangle('line',0,0,self.view.w,self.view.h)
|
love.graphics.rectangle('line',0,0,self.view.w,self.view.h)
|
||||||
@ -235,6 +238,7 @@ function element:classlessRender()
|
|||||||
love.graphics.printf("Error: "..self.renderer,0,0,self.view.w)
|
love.graphics.printf("Error: "..self.renderer,0,0,self.view.w)
|
||||||
end
|
end
|
||||||
self.inputContext:unset()
|
self.inputContext:unset()
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function element:renderWrapper()
|
function element:renderWrapper()
|
||||||
@ -286,10 +290,12 @@ end
|
|||||||
---@param w number
|
---@param w number
|
||||||
---@param h number
|
---@param h number
|
||||||
function element:draw(params, x, y, w, h)
|
function element:draw(params, x, y, w, h)
|
||||||
|
if not self.view.lock then
|
||||||
self.view.x = x or self.view.x
|
self.view.x = x or self.view.x
|
||||||
self.view.y = y or self.view.y
|
self.view.y = y or self.view.y
|
||||||
self.view.w = w or self.view.w
|
self.view.w = w or self.view.w
|
||||||
self.view.h = h or self.view.h
|
self.view.h = h or self.view.h
|
||||||
|
end
|
||||||
|
|
||||||
if params then
|
if params then
|
||||||
if type(params)=='table' and self.baseParams then
|
if type(params)=='table' and self.baseParams then
|
||||||
|
|||||||
@ -36,7 +36,7 @@ local activeContext
|
|||||||
|
|
||||||
]]
|
]]
|
||||||
function input.newContext(element)
|
function input.newContext(element)
|
||||||
local ctx = setmetatable({view = element.view, subs = {}}, context)
|
local ctx = setmetatable({elem = element, subs = {}}, context)
|
||||||
|
|
||||||
return ctx
|
return ctx
|
||||||
end
|
end
|
||||||
@ -44,16 +44,22 @@ end
|
|||||||
function context:set()
|
function context:set()
|
||||||
if activeContext then
|
if activeContext then
|
||||||
self.parentCtx = activeContext
|
self.parentCtx = activeContext
|
||||||
self.absX = self.parentCtx.absX + self.view.x
|
self.absX = self.parentCtx.absX + self.elem.view.x
|
||||||
self.absY = self.parentCtx.absY + self.view.y
|
self.absY = self.parentCtx.absY + self.elem.view.y
|
||||||
activeContext = self
|
activeContext = self
|
||||||
else
|
else
|
||||||
self.absX = self.view.x
|
self.absX = self.elem.view.x
|
||||||
self.absY = self.view.y
|
self.absY = self.elem.view.y
|
||||||
activeContext = self
|
activeContext = self
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function context:update()
|
||||||
|
for i, sub in ipairs(self.subs) do
|
||||||
|
sub:contextUpdate(self.absX,self.absY)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function context:unset()
|
function context:unset()
|
||||||
if self.parentCtx then
|
if self.parentCtx then
|
||||||
activeContext = self.parentCtx
|
activeContext = self.parentCtx
|
||||||
@ -64,7 +70,7 @@ end
|
|||||||
|
|
||||||
function context:destroy()
|
function context:destroy()
|
||||||
for i, e in ipairs(self.subs) do
|
for i, e in ipairs(self.subs) do
|
||||||
self.subs:destroy()
|
e:destroy()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -84,10 +90,14 @@ function subscription.create(x, y, w, h, eventType, callback, doff)
|
|||||||
y = activeContext.absY + y,
|
y = activeContext.absY + y,
|
||||||
w = w,
|
w = w,
|
||||||
h = h,
|
h = h,
|
||||||
|
ix = x,
|
||||||
|
iy = y,
|
||||||
eventType = eventType,
|
eventType = eventType,
|
||||||
active = doff or true,
|
active = doff or true,
|
||||||
callback = callback
|
callback = callback
|
||||||
},subscription)
|
},subscription)
|
||||||
|
|
||||||
|
activeContext.subs[#activeContext.subs+1] = sub
|
||||||
else
|
else
|
||||||
sub = setmetatable({
|
sub = setmetatable({
|
||||||
x = x,
|
x = x,
|
||||||
@ -118,10 +128,15 @@ function subscription:on()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function subscription:destroy()
|
function subscription:destroy()
|
||||||
self.destroy = true
|
self.destroyStat = true
|
||||||
self.active = false
|
self.active = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function subscription:contextUpdate(absX, absY)
|
||||||
|
self.x = absX + self.ix
|
||||||
|
self.y = absY + self.iy
|
||||||
|
end
|
||||||
|
|
||||||
function subscription:update(x, y, w, h)
|
function subscription:update(x, y, w, h)
|
||||||
self.x = x or self.x
|
self.x = x or self.x
|
||||||
self.y = y or self.y
|
self.y = y or self.y
|
||||||
@ -191,10 +206,23 @@ function input.eventHandlers.mousereleased(x, y, btn)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if input.subscriptions.dragged then
|
||||||
|
for index, sub in ipairs(input.subscriptions.dragged) do
|
||||||
|
if sub.currentEvent then
|
||||||
|
sub.currentEvent = false
|
||||||
|
captured = true
|
||||||
|
if sub.cleanUp then
|
||||||
|
sub.cleanUp(x, y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return captured
|
return captured
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function input.eventHandlers.mousepressed(x, y, btn)
|
function input.eventHandlers.mousepressed(x, y, btn)
|
||||||
local captured = false
|
local captured = false
|
||||||
if input.subscriptions.mousepressed then
|
if input.subscriptions.mousepressed then
|
||||||
@ -232,6 +260,18 @@ function input.eventHandlers.mousepressed(x, y, btn)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if input.subscriptions.dragged then
|
||||||
|
for index, sub in ipairs(input.subscriptions.dragged) do
|
||||||
|
local succ = sub:checkInside(x, y)
|
||||||
|
|
||||||
|
if succ and sub.active then
|
||||||
|
sub.currentEvent = true
|
||||||
|
captured = true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return captured
|
return captured
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -264,7 +304,7 @@ function input.eventHandlers.keyreleased(btn)
|
|||||||
return captured
|
return captured
|
||||||
end
|
end
|
||||||
|
|
||||||
function input.eventHandlers.mousemoved(x, y)
|
function input.eventHandlers.mousemoved(x, y, dx, dy)
|
||||||
local captured = false
|
local captured = false
|
||||||
|
|
||||||
if input.subscriptions.hover then
|
if input.subscriptions.hover then
|
||||||
@ -285,6 +325,22 @@ function input.eventHandlers.mousemoved(x, y)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if input.subscriptions.dragged then
|
||||||
|
for index, sub in ipairs(input.subscriptions.dragged) do
|
||||||
|
if sub.active and sub.currentEvent then
|
||||||
|
if not sub.cleanUp then
|
||||||
|
sub.cleanUp = sub:emit(x, y, dx, dy)
|
||||||
|
else
|
||||||
|
sub:emit(x, y, dx, dy)
|
||||||
|
end
|
||||||
|
sub.currentEvent = true
|
||||||
|
captured = true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return captured
|
return captured
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
17
init.lua
17
init.lua
@ -5,10 +5,11 @@
|
|||||||
----------------------------------------------------]]
|
----------------------------------------------------]]
|
||||||
local path = ...
|
local path = ...
|
||||||
local helium = require(path..".dummy")
|
local helium = require(path..".dummy")
|
||||||
|
helium.conf = require(path..".conf")
|
||||||
helium.utils = require(path..".utils")
|
helium.utils = require(path..".utils")
|
||||||
helium.element = require(path..".core.element")
|
helium.element = require(path..".core.element")
|
||||||
helium.input = require(path..".core.input")
|
helium.input = require(path..".core.input")
|
||||||
helium.debugLoader = require(path..".debugLoader")
|
helium.loader = require(path..".loader")
|
||||||
helium.elementBuffer = {}
|
helium.elementBuffer = {}
|
||||||
|
|
||||||
function helium.render()
|
function helium.render()
|
||||||
@ -17,7 +18,11 @@ function helium.render()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function helium.update()
|
function helium.update(dt)
|
||||||
|
if helium.conf.HOTSWAP then
|
||||||
|
helium.loader.update(dt)
|
||||||
|
end
|
||||||
|
|
||||||
local remove = false
|
local remove = false
|
||||||
|
|
||||||
for i, e in ipairs(helium.elementBuffer) do
|
for i, e in ipairs(helium.elementBuffer) do
|
||||||
@ -60,7 +65,8 @@ end
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
]]
|
]]
|
||||||
function love.run()
|
if helium.conf.AUTO_RUN then
|
||||||
|
function love.run()
|
||||||
|
|
||||||
if love.math then
|
if love.math then
|
||||||
love.math.setRandomSeed(os.time())
|
love.math.setRandomSeed(os.time())
|
||||||
@ -101,20 +107,19 @@ function love.run()
|
|||||||
-- Call update and draw
|
-- Call update and draw
|
||||||
if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled
|
if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled
|
||||||
helium.update(dt)
|
helium.update(dt)
|
||||||
helium.debugLoader.update(dt)
|
|
||||||
|
|
||||||
if love.graphics and love.graphics.isActive() then
|
if love.graphics and love.graphics.isActive() then
|
||||||
love.graphics.clear(love.graphics.getBackgroundColor())
|
love.graphics.clear(love.graphics.getBackgroundColor())
|
||||||
love.graphics.origin()
|
love.graphics.origin()
|
||||||
|
|
||||||
if love.draw then love.draw() end
|
if love.draw then love.draw() end
|
||||||
helium.render()
|
helium.render()
|
||||||
love.graphics.present()
|
love.graphics.present()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
if love.timer then love.timer.sleep(0.00001) end
|
if love.timer then love.timer.sleep(0.00001) end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return helium
|
return helium
|
||||||
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
local path = string.sub(..., 1, string.len(...) - string.len(".debugLoader"))
|
local path = string.sub(..., 1, string.len(...) - string.len(".loader"))
|
||||||
local helium = require(path..'.dummy')
|
local helium = require(path..'.dummy')
|
||||||
local elements = {}
|
local elements = {}
|
||||||
local debugLoader = {}
|
local debugLoader = {}
|
||||||
Loading…
x
Reference in New Issue
Block a user