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 ]]
|
||||
--[[ Love is currently a hard dependency, although not in many places ]]
|
||||
local path = string.sub(..., 1, string.len(...) - string.len(".core.element"))
|
||||
local helium = require(path .. ".dummy")
|
||||
|
||||
@ -58,11 +59,8 @@ setmetatable(element,{
|
||||
local func, loader = ...
|
||||
if type(func)=='function' then
|
||||
self = setmetatable({}, element)
|
||||
self.renderer = ...
|
||||
self.parentFunc = func
|
||||
self.classless = true
|
||||
elseif type(cls)=='table' then
|
||||
self = setmetatable({}, cls)
|
||||
self.classless = false
|
||||
end
|
||||
|
||||
if loader then
|
||||
@ -105,32 +103,79 @@ function element:new()
|
||||
inserted = false
|
||||
}
|
||||
|
||||
self.view = {
|
||||
self.baseState = {}
|
||||
|
||||
self.baseView = {
|
||||
x = 0,
|
||||
y = 0,
|
||||
w = 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
|
||||
self.classlessState = {}
|
||||
self.classlessData = {}
|
||||
self.classlessFuncs = {}
|
||||
|
||||
--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
|
||||
|
||||
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
|
||||
|
||||
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.inputContext:unset()
|
||||
end
|
||||
|
||||
--Called once dimensions are validated
|
||||
function element:setup()
|
||||
self.state =
|
||||
setmetatable(
|
||||
{},
|
||||
{
|
||||
self.state = setmetatable({},{
|
||||
__index = function(t, index)
|
||||
return self.baseState[index]
|
||||
end,
|
||||
@ -140,15 +185,11 @@ function element:setup()
|
||||
self.context:bubbleUpdate()
|
||||
end
|
||||
end
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
self.parameters =
|
||||
setmetatable(
|
||||
{},
|
||||
{
|
||||
self.parameters = setmetatable({},{
|
||||
__index = function(t, index)
|
||||
return self.baseParams[index] or nil
|
||||
return self.baseParams[index]
|
||||
end,
|
||||
__newindex = function(t, index, val)
|
||||
if self.baseParams[index] ~= val then
|
||||
@ -156,68 +197,32 @@ function element:setup()
|
||||
self.context:bubbleUpdate()
|
||||
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.inputContext = helium.input.newContext(self)
|
||||
self.context = context.new(self)
|
||||
self.canvas = love.graphics.newCanvas(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.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
|
||||
|
||||
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
|
||||
love.graphics.setColor(1,0,0)
|
||||
@ -226,8 +231,6 @@ function element:classlessRender()
|
||||
love.graphics.printf("Error: "..err,0,0,self.view.w)
|
||||
end
|
||||
|
||||
denv['useState'] = nil
|
||||
denv['loadEffect'] = nil
|
||||
elseif type(self.renderer)=='string' then
|
||||
love.graphics.setColor(1,0,0)
|
||||
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)
|
||||
end
|
||||
self.inputContext:unset()
|
||||
|
||||
end
|
||||
|
||||
function element:renderWrapper()
|
||||
@ -286,10 +290,12 @@ end
|
||||
---@param w number
|
||||
---@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
|
||||
end
|
||||
|
||||
if params then
|
||||
if type(params)=='table' and self.baseParams then
|
||||
|
||||
@ -36,7 +36,7 @@ local activeContext
|
||||
|
||||
]]
|
||||
function input.newContext(element)
|
||||
local ctx = setmetatable({view = element.view, subs = {}}, context)
|
||||
local ctx = setmetatable({elem = element, subs = {}}, context)
|
||||
|
||||
return ctx
|
||||
end
|
||||
@ -44,16 +44,22 @@ end
|
||||
function context:set()
|
||||
if activeContext then
|
||||
self.parentCtx = activeContext
|
||||
self.absX = self.parentCtx.absX + self.view.x
|
||||
self.absY = self.parentCtx.absY + self.view.y
|
||||
self.absX = self.parentCtx.absX + self.elem.view.x
|
||||
self.absY = self.parentCtx.absY + self.elem.view.y
|
||||
activeContext = self
|
||||
else
|
||||
self.absX = self.view.x
|
||||
self.absY = self.view.y
|
||||
self.absX = self.elem.view.x
|
||||
self.absY = self.elem.view.y
|
||||
activeContext = self
|
||||
end
|
||||
end
|
||||
|
||||
function context:update()
|
||||
for i, sub in ipairs(self.subs) do
|
||||
sub:contextUpdate(self.absX,self.absY)
|
||||
end
|
||||
end
|
||||
|
||||
function context:unset()
|
||||
if self.parentCtx then
|
||||
activeContext = self.parentCtx
|
||||
@ -64,7 +70,7 @@ end
|
||||
|
||||
function context:destroy()
|
||||
for i, e in ipairs(self.subs) do
|
||||
self.subs:destroy()
|
||||
e:destroy()
|
||||
end
|
||||
end
|
||||
|
||||
@ -84,10 +90,14 @@ function subscription.create(x, y, w, h, eventType, callback, doff)
|
||||
y = activeContext.absY + y,
|
||||
w = w,
|
||||
h = h,
|
||||
ix = x,
|
||||
iy = y,
|
||||
eventType = eventType,
|
||||
active = doff or true,
|
||||
callback = callback
|
||||
},subscription)
|
||||
|
||||
activeContext.subs[#activeContext.subs+1] = sub
|
||||
else
|
||||
sub = setmetatable({
|
||||
x = x,
|
||||
@ -118,10 +128,15 @@ function subscription:on()
|
||||
end
|
||||
|
||||
function subscription:destroy()
|
||||
self.destroy = true
|
||||
self.destroyStat = true
|
||||
self.active = false
|
||||
end
|
||||
|
||||
function subscription:contextUpdate(absX, absY)
|
||||
self.x = absX + self.ix
|
||||
self.y = absY + self.iy
|
||||
end
|
||||
|
||||
function subscription:update(x, y, w, h)
|
||||
self.x = x or self.x
|
||||
self.y = y or self.y
|
||||
@ -191,10 +206,23 @@ function input.eventHandlers.mousereleased(x, y, btn)
|
||||
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
|
||||
end
|
||||
|
||||
|
||||
|
||||
function input.eventHandlers.mousepressed(x, y, btn)
|
||||
local captured = false
|
||||
if input.subscriptions.mousepressed then
|
||||
@ -232,6 +260,18 @@ function input.eventHandlers.mousepressed(x, y, btn)
|
||||
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
|
||||
end
|
||||
|
||||
@ -264,7 +304,7 @@ function input.eventHandlers.keyreleased(btn)
|
||||
return captured
|
||||
end
|
||||
|
||||
function input.eventHandlers.mousemoved(x, y)
|
||||
function input.eventHandlers.mousemoved(x, y, dx, dy)
|
||||
local captured = false
|
||||
|
||||
if input.subscriptions.hover then
|
||||
@ -285,6 +325,22 @@ function input.eventHandlers.mousemoved(x, y)
|
||||
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
|
||||
end
|
||||
|
||||
|
||||
17
init.lua
17
init.lua
@ -5,10 +5,11 @@
|
||||
----------------------------------------------------]]
|
||||
local path = ...
|
||||
local helium = require(path..".dummy")
|
||||
helium.conf = require(path..".conf")
|
||||
helium.utils = require(path..".utils")
|
||||
helium.element = require(path..".core.element")
|
||||
helium.input = require(path..".core.input")
|
||||
helium.debugLoader = require(path..".debugLoader")
|
||||
helium.loader = require(path..".loader")
|
||||
helium.elementBuffer = {}
|
||||
|
||||
function helium.render()
|
||||
@ -17,7 +18,11 @@ function helium.render()
|
||||
end
|
||||
end
|
||||
|
||||
function helium.update()
|
||||
function helium.update(dt)
|
||||
if helium.conf.HOTSWAP then
|
||||
helium.loader.update(dt)
|
||||
end
|
||||
|
||||
local remove = false
|
||||
|
||||
for i, e in ipairs(helium.elementBuffer) do
|
||||
@ -60,7 +65,8 @@ end
|
||||
end
|
||||
end
|
||||
]]
|
||||
function love.run()
|
||||
if helium.conf.AUTO_RUN then
|
||||
function love.run()
|
||||
|
||||
if love.math then
|
||||
love.math.setRandomSeed(os.time())
|
||||
@ -101,20 +107,19 @@ function love.run()
|
||||
-- Call update and draw
|
||||
if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled
|
||||
helium.update(dt)
|
||||
helium.debugLoader.update(dt)
|
||||
|
||||
if love.graphics and love.graphics.isActive() then
|
||||
love.graphics.clear(love.graphics.getBackgroundColor())
|
||||
love.graphics.origin()
|
||||
|
||||
if love.draw then love.draw() end
|
||||
helium.render()
|
||||
love.graphics.present()
|
||||
end
|
||||
|
||||
|
||||
if love.timer then love.timer.sleep(0.00001) end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
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 elements = {}
|
||||
local debugLoader = {}
|
||||
Loading…
x
Reference in New Issue
Block a user