Hello friends-in-Codea !
I have progressed in my understanding.
@toffer example is missing the ability to have several register to the same event, so it is not really usable. I tried to extend it, but the code is so compact i am not able to modify it without errors.
So i looked back to tnlogy code and found it really corresponds to my needs. And i understand it! Sorry for puting you down in my last comment, @tnlogy, my understanding was just wrong. So i have modified you code to extend it a little bit.
I am not using @Toadkick code for the momnt, because it is so long i havent even tried to understand it…
Can you guys have a look at my code and tell me if it looks ok, or i have completely misunderstood how to use events?
-- @tnlogy >> @JMV38 modifications
-- ############## START of EVENT MANAGER ##################
-- example of usage:
-- evMngr = EventMngr() -- create the event manager
-- evMngr:on("touch",func) -- register func() to fire on "touch" event
-- evMngr:on("touch", obj.func, obj) -- register obj:func() to fire on "touch" event
-- evMngr:trigger("touch",10,50) -- fires func(10,50) and obj:func(10,50)
-- evMngr:off("touch", func) -- unregister func()
-- evMngr:off("touch", obj.func, obj) -- unregister obj:func()
-- evMngr:off("touch") -- unregister all "touch" listeners
-- evMngr:off(obj.func) -- unregister all listeners with obj.func
-- evMngr:off(obj) -- unregister events with obj listening
-- evMngr:reset() -- unregister everything
EventMngr = class()
function EventMngr:init() end
function EventMngr:on(names, fn, obj)
for name in string.gmatch(names, "%S+") do
if not self.events then self.events = {} end
if not self.events[name] then self.events[name] = {} end
local new = true -- confirm it is a new request
for i,fa in ipairs(self.events[name]) do
if fa.func == fn and fa.obj == obj then new = false end
end
if new then table.insert(self.events[name], {func = fn, obj = obj }) end
end
return self
end
function EventMngr:reset()
self.events = {}
end
function EventMngr:off(nameOrFnOrObj, fn, obj)
local name
local fn,obj = fn,obj -- manage the case when they are nil
local firstType = type(nameOrFnOrObj)
local request
if firstType == "string" then
name = nameOrFnOrObj
if fn == nil then request = "remove all instances of this event"
else request = "remove this event" end
elseif firstType == "function" then
fn = nameOrFnOrObj
request = "remove all events with this function"
else
obj = nameOrFnOrObj
request = "remove all events with this object"
end
if request == "remove all suscriptions to this event" then
self.events[name] = nil
else
local evs = self.events -- go through all events ...
if name then evs = {evs[name]} end -- ... or through 1 event only
for k,fns in pairs(evs) do
local n = #fns
for i=0,n-1 do
local j = n-i -- go backward because of remove, ipairs not suitable
local f = fns[j]
local match
if request == "remove this event"
then match=(f.func==fn and f.obj==obj)
elseif request == "remove all events with this function"
then match=(f.func==fn)
elseif request == "remove all events with this object"
then match=(f.obj==obj)
end
if match then table.remove(fns,j) end
end
end
end
return self
end
function EventMngr:trigger(name, ...)
self.lastTrigger = name
local evs = (self.events and self.events[name]) or {}
for i,fa in ipairs(evs) do
local func,obj = fa.func, fa.obj
if obj then func(obj,...)
else func(...) end
end
end
-- ############## END of EVENT MANAGER ##################
local function func(x,y)
print("touch at",x,y)
end
-- fake class for the tests
local Obj = class()
function Obj:init(name)
self.name = name
end
function Obj:echo(x,y)
print(self.name .. " touch at ".. tostring(x) .. " , " .. tostring(y) )
end
function setup()
evMngr = EventMngr()
-- test on a standalone function
print("-------------------")
print("one touch should be triggered:")
evMngr:on("touch",func)
evMngr:trigger("touch",10,50)
print("-------------------")
print("here nothing should happen:") print("")
evMngr:off("touch")
evMngr:trigger("touch",10,50)
-- test on a class member
obj1 = Obj("object 1")
obj2 = Obj("object 2")
print("-------------------")
print("2 objects should echo a touch event:")
evMngr:on("touch", obj1.echo, obj1)
evMngr:on("touch", obj2.echo, obj2)
evMngr:trigger("touch",10,50)
print("touch object 2 is off:")
evMngr:off("touch", obj2.echo, obj2)
evMngr:trigger("touch",10,50)
print("-------------------")
print("re-arm the 2 events:")
evMngr:on("touch", obj1.echo, obj1)
evMngr:on("touch", obj2.echo, obj2)
evMngr:trigger("touch",10,50)
print("echo removed :nothing should happen:") print("")
evMngr:off(obj1.echo)
evMngr:trigger("touch",10,50)
print("-------------------")
print("re-arm the 2 events:")
evMngr:on("touch", obj1.echo, obj1)
evMngr:on("touch", obj2.echo, obj2)
evMngr:trigger("touch",10,50)
print("object 1 removed :")
evMngr:off(obj1)
evMngr:trigger("touch",10,50)
print("-------------------")
print("re-arm the 2 events:")
evMngr:on("touch", obj1.echo, obj1)
evMngr:on("touch", obj2.echo, obj2)
evMngr:trigger("touch",10,50)
print("trigger removed :nothing should happen:") print("")
evMngr:off("touch")
evMngr:trigger("touch",10,50)
print("-------------------")
print("re-arm the 2 events:")
evMngr:on("touch", obj1.echo, obj1)
evMngr:on("touch", obj2.echo, obj2)
evMngr:trigger("touch",10,50)
evMngr:reset()
print("reset :nothing should happen:") print("")
evMngr:trigger("touch",10,50)
end
function draw()
background(20)
end
function touched(t)
evMngr:trigger("touch",t.x,t.y)
end