enUS Localization Update Announcement / localization-update-announcement (push) Canceled after 0s
181 lines
9.2 KiB
Lua
181 lines
9.2 KiB
Lua
-- Bagshui Core: Events
|
|
-- Event registration, raising, queuing, and callbacks.
|
|
-- Raises: BAGSHUI_CORE_EVENT_FUNCTIONS_LOADED
|
|
|
|
Bagshui:LoadComponent(
|
|
function()
|
|
--- Request to receive event notifications of the specified type. Supports both WoW and Bagshui events.
|
|
---@param event string Name of event (ADDON_LOADED, etc.).
|
|
---@param classObject table? Class that will consume the event (must have an `OnEvent()` function if `eventFunctionName` isn't specified).
|
|
---@param classEventFunctionName string? Class function to use instead of `OnEvent`.
|
|
function Bagshui:RegisterEvent(event, classObject, classEventFunctionName)
|
|
assert(type(event) == "string", "Bagshui:RegisterEvent() - event is required and must be a string")
|
|
|
|
-- The Bagshui class internally uses RegisterEvent, so bypass consumer registration when there isn't a classObject.
|
|
if classObject then
|
|
self:RegisterClassForEvents(classObject, classEventFunctionName)
|
|
self.eventConsumers[classObject][event] = true
|
|
end
|
|
|
|
-- Don't try to register internal events with the game (doesn't seem to cause a problem but is also pointless).
|
|
if string.find(event, "^BAGSHUI_") then
|
|
return
|
|
end
|
|
|
|
-- This probably isn't a big deal, but let's avoid registering events multiple times.
|
|
if not self.eventFrame.bagshuiData.registeredEvents[event] then
|
|
self.eventFrame:RegisterEvent(event)
|
|
self.eventFrame.bagshuiData.registeredEvents[event] = true
|
|
end
|
|
end
|
|
|
|
--- Add a class to the `Bagshui.eventConsumers` table, populating the `_eventFunctionName` property.
|
|
---@param classObject table Class that will consume the event (must have an `OnEvent()` function if `eventFunctionName` isn't specified).
|
|
---@param eventFunctionName string? Class function to use instead of `OnEvent`.
|
|
function Bagshui:RegisterClassForEvents(classObject, eventFunctionName)
|
|
-- Already registered.
|
|
if self.eventConsumers[classObject] then
|
|
return
|
|
end
|
|
|
|
eventFunctionName = eventFunctionName or "OnEvent"
|
|
|
|
assert(
|
|
classObject[eventFunctionName],
|
|
"Bagshui:RegisterClassForEvents(): "
|
|
.. tostring(eventFunctionName)
|
|
.. " not found on classObject "
|
|
.. tostring(classObject)
|
|
)
|
|
|
|
self.eventConsumers[classObject] = {
|
|
_eventFunctionName = eventFunctionName,
|
|
}
|
|
end
|
|
|
|
--- Stop receiving notifications for the specified event.
|
|
---@param event string Name of event (ADDON_LOADED, etc.).
|
|
---@param classObject table Class that consumes the event.
|
|
function Bagshui:UnregisterEvent(event, classObject)
|
|
self.eventConsumers[classObject][event] = false
|
|
end
|
|
|
|
--- Add a custom event to the internal queue.
|
|
---@param event string|function Unique event identifier or function to call.
|
|
---@param delaySeconds number? Time after which the event should be triggered (next frame if not specified).
|
|
---@param noReset boolean? `true` if an already-queued event's delay should *not* be reset.
|
|
---@param arg1 any? First argument to pass when the event is raised.
|
|
---@param arg2 any? Second argument to pass when the event is raised.
|
|
---@param arg3 any? Third argument to pass when the event is raised.
|
|
---@param arg4 any? Fourth argument to pass when the event is raised.
|
|
---@return boolean queued Whether the event was queued.
|
|
function Bagshui:QueueEvent(event, delaySeconds, noReset, arg1, arg2, arg3, arg4)
|
|
-- Add to queue if not currently queued or the delay should be reset.
|
|
if not self.queuedEvents.events[event] or (self.queuedEvents.events[event] and not noReset) then
|
|
self.queuedEvents.events[event] = _G.GetTime() + (delaySeconds or 0.00001)
|
|
self.queuedEvents.arg1[event] = arg1
|
|
self.queuedEvents.arg2[event] = arg2
|
|
self.queuedEvents.arg3[event] = arg3
|
|
self.queuedEvents.arg4[event] = arg4
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
--- Call the given class function after a delay.
|
|
---@param classInstance table Class that owns the function.
|
|
---@param classFunction function Function to call.
|
|
---@param delaySeconds number? Parameter for `Bagshui:QueueEvent()`.
|
|
---@param noReset boolean? Parameter for `Bagshui:QueueEvent()`.
|
|
---@param arg1 any? Parameter for `Bagshui:QueueEvent()`.
|
|
---@param arg2 any? Parameter for `Bagshui:QueueEvent()`.
|
|
---@param arg3 any? Parameter for `Bagshui:QueueEvent()`.
|
|
---@param arg4 any? Parameter for `Bagshui:QueueEvent()`.
|
|
function Bagshui:QueueClassCallback(classInstance, classFunction, delaySeconds, noReset, arg1, arg2, arg3, arg4)
|
|
-- Create a unique identifier for this event since it's not a predefined event string.
|
|
local eventId = tostring(classInstance) .. ":" .. tostring(classFunction)
|
|
if self:QueueEvent(eventId, delaySeconds, noReset, arg1, arg2, arg3, arg4) then
|
|
-- When the event is successfully queued, store callback information so RaiseEvent()
|
|
-- knows to handle this as a class callback, not a standard event.
|
|
self.queuedEvents.class[eventId] = classInstance
|
|
self.queuedEvents.classFunction[eventId] = classFunction
|
|
end
|
|
end
|
|
|
|
--- Process the Bagshui event queue.
|
|
--- Declaring variables outside to make the Lua garbage collector happier since this is called from
|
|
--- OnUpdate() [per Blizzard comment in UIPanelTemplates.lua]. Can't really do anything about the
|
|
--- variables in the for loop though.
|
|
local processEventQueue_success, processEventQueue_errorMessage
|
|
function Bagshui:ProcessEventQueue()
|
|
-- Loop through queued events and fire them if enough time has passed.
|
|
for event, raiseAfter in pairs(self.queuedEvents.events) do
|
|
if raiseAfter <= _G.GetTime() then
|
|
-- Fire the event and capture the status
|
|
-- We need to prevent RaiseEvent from erroring so we can remove the event from the queue, so we'll handle errors here
|
|
processEventQueue_success, processEventQueue_errorMessage = self:RaiseEvent(
|
|
event,
|
|
true,
|
|
self.queuedEvents.arg1[event],
|
|
self.queuedEvents.arg2[event],
|
|
self.queuedEvents.arg3[event],
|
|
self.queuedEvents.arg4[event]
|
|
)
|
|
|
|
-- Only remove from queue if the delay hasn't changed (i.e. the event hasn't been re-queued)
|
|
if raiseAfter == self.queuedEvents.events[event] then
|
|
self.queuedEvents.events[event] = nil
|
|
self.queuedEvents.arg1[event] = nil
|
|
self.queuedEvents.arg2[event] = nil
|
|
self.queuedEvents.arg3[event] = nil
|
|
self.queuedEvents.arg4[event] = nil
|
|
self.queuedEvents.class[event] = nil
|
|
self.queuedEvents.classFunction[event] = nil
|
|
end
|
|
|
|
assert(processEventQueue_success, processEventQueue_errorMessage)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Declaring variables for RaiseEvent outside to make the Lua garbage collector happier
|
|
-- since this is called from OnUpdate() [per Blizzard comment in UIPanelTemplates.lua].
|
|
local raiseEvent_success, raiseEvent_errorMessage
|
|
|
|
--- There are several ways an event can be raised:
|
|
--- 1. Calling a class function (event was set up via `Bagshui:QueueClassCallback()`).
|
|
--- 2. Calling a potentially anonymous function (event was set up via `Bagshui:QueueEvent(<function>)`).
|
|
--- 3. Passing off to `Bagshui:OnEvent()`, which can then pass on to registered consumers (event was
|
|
--- registered via `Bagshui:RegisterEvent()` and may have been raised by WoW or a call to `Bagshui:RaiseEvent()`).
|
|
---@param event string|function Name of event (WoW or Bagshui).
|
|
---@param returnStatus boolean? If true, `returnValue` and `errorMessage` from the event call will be returned.
|
|
---@param arg1 any? First event argument, if any.
|
|
---@param arg2 any? Second event argument, if any.
|
|
---@param arg3 any? Third event argument, if any.
|
|
---@param arg4 any? Fourth event argument, if any.
|
|
---@return boolean? returnValue Value returned from the event call, if any, when `returnStatus` is true.
|
|
---@return string? errorMessage Error message returned from the event call, if any, when `returnStatus` is true.
|
|
function Bagshui:RaiseEvent(event, returnStatus, arg1, arg2, arg3, arg4)
|
|
if self.queuedEvents.class[event] then
|
|
assert(self.queuedEvents.classFunction[event], "Class does not have the provided function!")
|
|
-- Call `<ClassInstance>:<Function>()` by calling `<ClassInstance>.<Function>(<ClassInstance>)`.
|
|
raiseEvent_success, raiseEvent_errorMessage =
|
|
pcall(self.queuedEvents.classFunction[event], self.queuedEvents.class[event], arg1, arg2, arg3, arg4)
|
|
elseif type(event) == "function" then
|
|
raiseEvent_success, raiseEvent_errorMessage = pcall(event, arg1, arg2, arg3, arg4)
|
|
else
|
|
raiseEvent_success, raiseEvent_errorMessage = pcall(self.OnEvent, self, event, arg1, arg2, arg3, arg4)
|
|
end
|
|
|
|
-- Error handling.
|
|
if returnStatus then
|
|
return raiseEvent_success, raiseEvent_errorMessage
|
|
elseif not raiseEvent_success then
|
|
assert(false, raiseEvent_errorMessage)
|
|
end
|
|
end
|
|
end,
|
|
-- Event to raise. This will trigger Bagshui:Init().
|
|
"BAGSHUI_CORE_EVENT_FUNCTIONS_LOADED"
|
|
)
|