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:
122
src/types/triggers/multitrigger.lua
Normal file
122
src/types/triggers/multitrigger.lua
Normal 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
|
||||
|
Reference in New Issue
Block a user