Add MultiTrigger to combine multiple triggers into one

MultiTrigger will pass on the data from the highest priority child
trigger.

Fix MultiTrigger

MultiTrigger didn't properly inherit from Trigger and reimplemented some
methods. This happened because it started out as a copy of Trigger
This commit is contained in:
2023-04-09 16:39:54 +02:00
parent 22dee8b536
commit 0436f8a0e0
2 changed files with 123 additions and 0 deletions

View File

@@ -12,6 +12,7 @@ types/object.lua
types/triggers/trigger.lua types/triggers/trigger.lua
types/triggers/auratrigger.lua types/triggers/auratrigger.lua
types/triggers/statustrigger.lua types/triggers/statustrigger.lua
types/triggers/multitrigger.lua
types/statusbar.lua types/statusbar.lua
types/auralist.lua types/auralist.lua
types/indicators/indicator.lua types/indicators/indicator.lua

View File

@@ -0,0 +1,122 @@
-- Copyright 2023 <omicron.me@protonmail.com>
--
-- This file is part of Omicron Frames
--
-- Omicron Frames is free software: you can redistribute it and/or modify it
-- under the terms of the GNU General Public License as published by the Free
-- Software Foundation, either version 3 of the License, or (at your option)
-- any later version.
--
-- Omicron Frames is distributed in the hope that it will be useful, but
-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-- more details.
--
-- You should have received a copy of the GNU General Public License along with
-- Omicron Frames. If not, see <https://www.gnu.org/licenses/>.
local omi = select(2, ...)
local types = omi.GetModule("types")
---@class Trigger
local Trigger = types.Trigger
---MultiTrigger is a trigger that collects other triggers as children. The first
---child added has the highest priority. When several triggers are active at the
---same time, the data from the highest priority trigger will be passed to the
---indicator.
---@class MultiTrigger: Trigger
---@field active boolean
---@field invert boolean
local MultiTrigger = types.CreateClass("MultiTrigger", Trigger)
types.MultiTrigger = MultiTrigger
--- Initialize a new Trigger object
---@param invert boolean|nil
function MultiTrigger:Init(invert)
Trigger.Init(self, invert, nil)
invert = invert or false
self.invert = invert
self.active = invert
self.children = {}
self.activeChildren = {}
self.childrenData = {}
end
---Add a child trigger. Each newly added trigger has lower priority than the previous triggers
---@param trigger Trigger
function MultiTrigger:AddTrigger(trigger)
local children = self.children
local idx = #children + 1
children[idx] = trigger
-- Create a fake Indicator as the target of our children. This is honestly
-- a bit sus. Possibly redesign Trigger to have more than just Indicator targets.
trigger:SetTarget({
Show = function(_, data)
self:OnChildActivate(idx, trigger, data)
end,
Update = function(_, data)
self:OnChildUpdate(idx, trigger, data)
end,
Hide = function(_, data)
self:OnChildDeactivate(idx, trigger, data)
end
})
end
---@param idx number
---@param trigger Trigger
---@param data table
function MultiTrigger:OnChildActivate(idx, trigger, data)
-- TODO: Measure the impact of this. Since we are sorting active triggers
-- this scales at least O(n log(n)) with active triggers. However, this is
-- is likely for very low n
local childrenData = self.childrenData
local activeChildren = self.activeChildren
local activeChild = activeChildren[1]
childrenData[idx] = data
table.insert(activeChildren, idx)
table.sort(activeChildren)
-- The highest priority active trigger has changed
if activeChild ~= activeChildren[1] then
self:SetState(true, data)
end
end
---@param idx number
---@param trigger Trigger
---@param data table
function MultiTrigger:OnChildDeactivate(idx, trigger, data)
local childrenData = self.childrenData
local activeChildren = self.activeChildren
local activeChild = activeChildren[1]
childrenData[idx] = data
local found = nil
for i, loopIdx in ipairs(activeChildren) do
if loopIdx == idx then
found = i
break
end
end
table.remove(activeChildren, found)
if activeChild ~= activeChildren[1] then
self:SetState(activeChildren[1] ~= nil, childrenData[1], true)
end
end
---@param idx number
---@param trigger Trigger
---@param data table
function MultiTrigger:OnChildUpdate(idx, trigger, data)
self.childrenData[idx] = data
if idx == self.activeChildren[1] and self.active then
self.indicator:Update(data)
end
end
-- Reset the trigger to the default state. If this changes the activation of the
-- trigger then the target will be notified.
function MultiTrigger:Reset()
self:SetState(false)
end