mirror of
				https://github.com/Reuh/ubiquitousse.git
				synced 2025-10-27 17:19:31 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			167 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
| --- Signal management.
 | |
| --
 | |
| -- No dependency.
 | |
| -- @module signal
 | |
| 
 | |
| --- Signal registry.
 | |
| --
 | |
| -- A SignalRegistry is a separate ubiquitousse.signal instance: its signals will be independant from other registries.
 | |
| -- @type SignalRegistry
 | |
| let registry_mt = {
 | |
| 	--- Map of signals to list of listeners.
 | |
| 	signals = {},
 | |
| 
 | |
| 	--- Bind one or several functions to a signal name.
 | |
| 	bind = :(name, fn, ...)
 | |
| 		if not @signals[name] then
 | |
| 			@signals[name] = {}
 | |
| 		end
 | |
| 		table.insert(@signals[name], fn)
 | |
| 		if ... then
 | |
| 			return @bind(name, ...)
 | |
| 		end
 | |
| 	end,
 | |
| 
 | |
| 	--- Unbind one or several functions to a signal name.
 | |
| 	unbind = :(name, fn, ...)
 | |
| 		if not @signals[name] then
 | |
| 			return
 | |
| 		end
 | |
| 		for i=#@signals[name], 1, -1 do
 | |
| 			if @signals[name] == fn then
 | |
| 				table.remove(@signals[name], i)
 | |
| 			end
 | |
| 		end
 | |
| 		if ... then
 | |
| 			return @unbind(name, ...)
 | |
| 		end
 | |
| 	end,
 | |
| 
 | |
| 	--- Remove every bound function to a signal name.
 | |
| 	unbindAll = :(name)
 | |
| 		@signals[name] = nil
 | |
| 	end,
 | |
| 
 | |
| 	--- Replace a bound function with another function.
 | |
| 	replace = :(name, sourceFn, destFn)
 | |
| 		if not @signals[name] then
 | |
| 			@signals[name] = {}
 | |
| 		end
 | |
| 		for i, fn in ipairs(@signals[name]) do
 | |
| 			if fn == sourceFn then
 | |
| 				@signals[name][i] = destFn
 | |
| 				break
 | |
| 			end
 | |
| 		end
 | |
| 	end,
 | |
| 
 | |
| 	--- Remove every bound function to every signal.
 | |
| 	clear = :()
 | |
| 		@signals = {}
 | |
| 	end,
 | |
| 
 | |
| 	--- Emit a signal, i.e. call every function bound to it, with the given arguments.
 | |
| 	emit = :(name, ...)
 | |
| 		if @signals[name] then
 | |
| 			for _, fn in ipairs(@signals[name]) do
 | |
| 				fn(...)
 | |
| 			end
 | |
| 		end
 | |
| 	end
 | |
| }
 | |
| registry_mt.__index = registry_mt
 | |
| 
 | |
| --- Module.
 | |
| --
 | |
| -- This module also acts as a global `SignalRegistry`, so you can call the `:bind`, `:emit`, etc. methods directly on the module
 | |
| -- if you don't need to isolate your signals in separate registries.
 | |
| -- @section module
 | |
| 
 | |
| let signal = {
 | |
| 	--- Creates and return a new SignalRegistry.
 | |
| 	-- @treturn SignalRegistry
 | |
| 	new = ()
 | |
| 		return setmetatable({ signals = {} }, registry_mt)
 | |
| 	end,
 | |
| 
 | |
| 	-- Global SignalRegistry.
 | |
| 	signals = {},
 | |
| 	bind = (...)
 | |
| 		return registry_mt.bind(signal, ...)
 | |
| 	end,
 | |
| 	unbind = (...)
 | |
| 		return registry_mt.unbind(signal, ...)
 | |
| 	end,
 | |
| 	unbindAll = (...)
 | |
| 		return registry_mt.unbindAll(signal, ...)
 | |
| 	end,
 | |
| 	replace = (...)
 | |
| 		return registry_mt.replace(signal, ...)
 | |
| 	end,
 | |
| 	clear = (...)
 | |
| 		return registry_mt.clear(signal, ...)
 | |
| 	end,
 | |
| 	emit = (...)
 | |
| 		return registry_mt.emit(signal, ...)
 | |
| 	end,
 | |
| 
 | |
| 	--- SignalRegistry which will be used to bind signals that need to be called on game engine event; other ubiquitousse modules may bind to this registry
 | |
| 	-- if avaible.
 | |
| 	--
 | |
| 	-- For example, every ubiquitousse module with a "update" function will bind it to the "update" signal in the registry;
 | |
| 	-- you can then call this signal on each game update to update every ubiquitousse module easily.
 | |
| 	--
 | |
| 	-- Provided signals:
 | |
| 	--
 | |
| 	-- * `update(dt)`, should be called on every game update
 | |
| 	-- * `draw()`, should be called on every game draw
 | |
| 	-- * for LÖVE, there are callbacks for every LÖVE callback function that need to be called on their corresponding LÖVE callback
 | |
| 	event = nil,
 | |
| 
 | |
| 	--- Call this function to hook `signal.event` signals to LÖVE events.
 | |
| 	-- This means overriding every existing LÖVE callback. If a callback is already defined, the new one will call the old function along with the signal:emit.
 | |
| 	-- @require love
 | |
| 	registerEvents = ()
 | |
| 		local callbacks = { -- everything except run, errorhandler, threaderror
 | |
| 			"displayrotated", "draw", "load", "lowmemory", "quit", "update",
 | |
| 			"directorydropped", "filedropped", "focus", "mousefocus", "resize", "visible",
 | |
| 			"keypressed", "keyreleased", "textedited", "textinput",
 | |
| 			"mousemoved", "mousepressed", "mousereleased", "wheelmoved",
 | |
| 			"gamepadaxis", "gamepadpressed", "gamepadreleased",
 | |
| 			"joystickadded", "joystickaxis", "joystickhat", "joystickpressed", "joystickreleased", "joystickremoved",
 | |
| 			"touchmoved", "touchpressed", "touchreleased"
 | |
| 		}
 | |
| 		local event = signal.event
 | |
| 		for _, callback in ipairs(callbacks) do
 | |
| 			if callback == "update" then
 | |
| 				if love[callback] then
 | |
| 					local old = love[callback]
 | |
| 					love[callback] = function(dt)
 | |
| 						old(dt)
 | |
| 						event:emit(callback, dt)
 | |
| 					end
 | |
| 				else
 | |
| 					love[callback] = function(dt)
 | |
| 						event:emit(callback, dt)
 | |
| 					end
 | |
| 				end
 | |
| 			else
 | |
| 				if love[callback] then
 | |
| 					local old = love[callback]
 | |
| 					love[callback] = function(...)
 | |
| 						old(...)
 | |
| 						event:emit(callback, ...)
 | |
| 					end
 | |
| 				else
 | |
| 					love[callback] = function(...)
 | |
| 						event:emit(callback, ...)
 | |
| 					end
 | |
| 				end
 | |
| 			end
 | |
| 		end
 | |
| 	end
 | |
| }
 | |
| 
 | |
| signal.event = signal.new()
 | |
| 
 | |
| return signal
 |