You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1550 lines
52 KiB
1550 lines
52 KiB
--========================================================--
|
|
-- Scorpio Secure Action Button --
|
|
-- --
|
|
-- Author : kurapica125@outlook.com --
|
|
-- Create Date : 2020/11/16 --
|
|
--========================================================--
|
|
|
|
--========================================================--
|
|
Scorpio "Scorpio.Secure.SecureActionButton" "1.0.0"
|
|
--========================================================--
|
|
|
|
export { GetProxyUI = UI.GetProxyUI }
|
|
|
|
_ManagerFrame = SecureFrame("Scorpio_SecureActionButton_Manager", UIParent, "SecureHandlerStateTemplate")
|
|
_ManagerFrame:Hide()
|
|
|
|
_IFActionTypeHandler = {}
|
|
|
|
_ActionTypeMap = {}
|
|
_ActionTargetMap = {}
|
|
_ActionTargetDetail = {}
|
|
_ReceiveMap = {}
|
|
|
|
_ActionButtonGroupList = {}
|
|
|
|
_AutoAttackButtons = {}
|
|
_AutoRepeatButtons = {}
|
|
_RangeCheckButtons = {}
|
|
_Spell4Buttons = {}
|
|
|
|
local _GridCounter = 0
|
|
local _PetGridCounter = 0
|
|
local _OnTooltipButton
|
|
local _KeyBindingMap = {}
|
|
local _Locale = _Locale
|
|
|
|
local _KeyBindingMode = false
|
|
|
|
IsSpellOverlayed = _G.IsSpellOverlayed or Toolset.fakefunc
|
|
|
|
------------------------------------------------------
|
|
-- Module Event Handler --
|
|
------------------------------------------------------
|
|
function OnLoad()
|
|
_SVData.Char:SetDefault {
|
|
SecureActionButtonNoDragGroup = {},
|
|
SecureActionButtonMouseDownGroup= {},
|
|
}
|
|
|
|
_NoDragGroup = _SVData.Char.SecureActionButtonNoDragGroup
|
|
_MouseDownGroup = _SVData.Char.SecureActionButtonMouseDownGroup
|
|
|
|
for group, val in pairs(_NoDragGroup) do
|
|
if val then DisableDrag(group) end
|
|
end
|
|
end
|
|
|
|
__Service__(true)
|
|
function RangeCheckerService()
|
|
while true do
|
|
for i = 1, 99999 do
|
|
local button = _RangeCheckButtons[i]
|
|
if not button then
|
|
if i == 1 then NextEvent("SCORPIO_SAB_RANGE_CHECK") end
|
|
break
|
|
end
|
|
|
|
_IFActionTypeHandler[button.ActionType]:RefreshRange(button)
|
|
if i % 20 == 0 then Continue() end
|
|
end
|
|
|
|
Wait(0.2, "PLAYER_TARGET_CHANGED")
|
|
end
|
|
end
|
|
|
|
__SystemEvent__()
|
|
function ACTIONBAR_SHOWGRID()
|
|
_GridCounter = _GridCounter + 1
|
|
if _GridCounter == 1 then
|
|
for kind, handler in pairs(_IFActionTypeHandler) do
|
|
if handler.IsPlayerAction and handler.ReceiveStyle ~= "Block" then
|
|
handler:RefershGrid()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
__SystemEvent__()
|
|
function ACTIONBAR_HIDEGRID()
|
|
if _GridCounter > 0 then
|
|
_GridCounter = _GridCounter - 1
|
|
if _GridCounter == 0 then
|
|
for kind, handler in pairs(_IFActionTypeHandler) do
|
|
if handler.IsPlayerAction and handler.ReceiveStyle ~= "Block" then
|
|
handler:RefershGrid()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
__SystemEvent__()
|
|
function PET_BAR_SHOWGRID()
|
|
_PetGridCounter = _PetGridCounter + 1
|
|
if _PetGridCounter == 1 then
|
|
for kind, handler in pairs(_IFActionTypeHandler) do
|
|
if handler.IsPetAction and handler.ReceiveStyle ~= "Block" then
|
|
handler:RefershGrid()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
__SystemEvent__()
|
|
function PET_BAR_HIDEGRID()
|
|
if _PetGridCounter > 0 then
|
|
_PetGridCounter = _PetGridCounter - 1
|
|
if _PetGridCounter == 0 then
|
|
for kind, handler in pairs(_IFActionTypeHandler) do
|
|
if handler.IsPetAction and handler.ReceiveStyle ~= "Block" then
|
|
handler:RefershGrid()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
__SystemEvent__()
|
|
function PLAYER_ENTER_COMBAT()
|
|
for button in pairs(_AutoAttackButtons) do
|
|
button.IsAutoAttacking = true
|
|
end
|
|
end
|
|
|
|
__SystemEvent__()
|
|
function PLAYER_LEAVE_COMBAT()
|
|
for button in pairs(_AutoAttackButtons) do
|
|
button.IsAutoAttacking = false
|
|
end
|
|
end
|
|
|
|
__SystemEvent__()
|
|
function SPELL_ACTIVATION_OVERLAY_GLOW_SHOW(spellId)
|
|
local buttons = _Spell4Buttons[spellId]
|
|
if not buttons then return end
|
|
|
|
if getmetatable(buttons) then
|
|
buttons.OverlayGlow = true
|
|
else
|
|
for button in pairs(buttons) do
|
|
button.OverlayGlow = true
|
|
end
|
|
end
|
|
end
|
|
|
|
__SystemEvent__()
|
|
function SPELL_ACTIVATION_OVERLAY_GLOW_HIDE(spellId)
|
|
local buttons = _Spell4Buttons[spellId]
|
|
if not buttons then return end
|
|
|
|
if getmetatable(buttons) then
|
|
buttons.OverlayGlow = false
|
|
else
|
|
for button in pairs(buttons) do
|
|
button.OverlayGlow = false
|
|
end
|
|
end
|
|
end
|
|
|
|
__SystemEvent__()
|
|
function SPELL_UPDATE_CHARGES()
|
|
for kind, handler in pairs(_IFActionTypeHandler) do
|
|
handler:RefreshCount()
|
|
end
|
|
end
|
|
|
|
__SystemEvent__()
|
|
function START_AUTOREPEAT_SPELL()
|
|
for button in pairs(_AutoRepeatButtons) do
|
|
if not _AutoAttackButtons[button] then
|
|
button.IsAutoAttacking = true
|
|
end
|
|
end
|
|
end
|
|
|
|
__SystemEvent__()
|
|
function STOP_AUTOREPEAT_SPELL()
|
|
for button in pairs(_AutoRepeatButtons) do
|
|
if button.IsAutoAttacking and not _AutoAttackButtons[button] then
|
|
button.IsAutoAttacking = false
|
|
end
|
|
end
|
|
end
|
|
|
|
__SystemEvent__ "ARCHAEOLOGY_CLOSED" "TRADE_SKILL_SHOW" "TRADE_SKILL_CLOSE"
|
|
function TRADE_SKILL_SHOW()
|
|
for kind, handler in pairs(_IFActionTypeHandler) do
|
|
handler:RefreshButtonState()
|
|
end
|
|
end
|
|
|
|
__SystemEvent__"UNIT_ENTERED_VEHICLE" "UNIT_EXITED_VEHICLE"
|
|
function UNIT_ENTERED_VEHICLE(unit)
|
|
if unit == "player" then
|
|
for kind, handler in pairs(_IFActionTypeHandler) do
|
|
handler:RefreshButtonState()
|
|
end
|
|
end
|
|
end
|
|
|
|
__SystemEvent__"UNIT_INVENTORY_CHANGED" "LEARNED_SPELL_IN_TAB" "ACTIONBAR_UPDATE_COOLDOWN"
|
|
function UNIT_INVENTORY_CHANGED(unit)
|
|
return (not unit or unit == "player") and _OnTooltipButton and _OnTooltipButton:UpdateTooltip()
|
|
end
|
|
|
|
__SystemEvent__() __Async__()
|
|
function PET_BATTLE_OPENING_START()
|
|
for i = 1, 6 do
|
|
local key = tostring(i)
|
|
local button = _KeyBindingMap[key]
|
|
if button then ClearOverrideBindings(GetRawUI(button)) end
|
|
end
|
|
|
|
NextEvent("PET_BATTLE_CLOSE") NoCombat()
|
|
|
|
for i = 1, 6 do
|
|
local key = tostring(i)
|
|
local button = _KeyBindingMap[key]
|
|
if button then SetOverrideBindingClick(GetRawUI(button), false, key, button:GetName(), "LeftButton") end
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------
|
|
-- Action Type Handler --
|
|
------------------------------------------------------
|
|
__Sealed__()
|
|
enum "ActionTypeHandleStyle" { "Keep", "Clear", "Block" }
|
|
|
|
-- The handler for action types
|
|
__Sealed__() __AnonymousClass__()
|
|
interface "ActionTypeHandler" (function(_ENV)
|
|
extend "IList"
|
|
|
|
_RegisterSnippetTemplate = "%s[%q] = %q"
|
|
|
|
_ActionButtonMap = Toolset.newtable(true, true)
|
|
|
|
local function refreshButton(self, button)
|
|
_AutoAttackButtons[button] = self.IsAttackAction(button) or nil
|
|
_AutoRepeatButtons[button] = self.IsAutoRepeatAction(button) or nil
|
|
|
|
button.HasAction = self.HasAction(button)
|
|
button.IsAutoAttack = _AutoAttackButtons[button] or _AutoRepeatButtons[button]
|
|
|
|
local spell = self.GetSpellId(button)
|
|
local ospell = _Spell4Buttons[button]
|
|
|
|
if ospell ~= spell then
|
|
if ospell then
|
|
local buttons = _Spell4Buttons[ospell]
|
|
if getmetatable(buttons) == nil then
|
|
buttons[button] = nil
|
|
elseif buttons == button then
|
|
_Spell4Buttons[ospell] = nil
|
|
end
|
|
end
|
|
|
|
if spell then
|
|
local buttons = _Spell4Buttons[spell]
|
|
if buttons == nil then
|
|
_Spell4Buttons[spell] = button
|
|
elseif getmetatable(buttons) == nil then
|
|
buttons[button] = true
|
|
else
|
|
buttons = { [buttons] = true }
|
|
buttons[button] = true
|
|
|
|
_Spell4Buttons[spell] = buttons
|
|
end
|
|
end
|
|
|
|
_Spell4Buttons[button] = spell
|
|
end
|
|
|
|
if self.IsRangeSpell(button) then
|
|
if not _RangeCheckButtons[button] then
|
|
local index = #_RangeCheckButtons + 1
|
|
_RangeCheckButtons[button] = true
|
|
_RangeCheckButtons[index] = button
|
|
|
|
if index == 1 then FireSystemEvent("SCORPIO_SAB_RANGE_CHECK") end
|
|
end
|
|
else
|
|
if _RangeCheckButtons[button] then
|
|
for i = 1, #_RangeCheckButtons do
|
|
if _RangeCheckButtons[i] == button then
|
|
tremove(_RangeCheckButtons, i)
|
|
break
|
|
end
|
|
end
|
|
_RangeCheckButtons[button] = nil
|
|
end
|
|
end
|
|
|
|
if self.ReceiveStyle ~= "Block" then
|
|
self:RefershGrid(button)
|
|
end
|
|
|
|
self:RefreshButtonState(button)
|
|
self:RefreshUsable(button)
|
|
self:RefreshCooldown(button)
|
|
self:RefreshFlyout(button)
|
|
self:RefreshAutoCastable(button)
|
|
self:RefreshAutoCasting(button)
|
|
self:RefreshEquipItem(button)
|
|
self:RefreshText(button)
|
|
self:RefreshIcon(button)
|
|
self:RefreshCount(button)
|
|
self:RefreshOverlayGlow(button)
|
|
self:RefreshShowSearchOverlay(button)
|
|
self:RefreshIconLocked(button)
|
|
self.Refresh(button)
|
|
|
|
button:Refresh()
|
|
|
|
if _OnTooltipButton == button then
|
|
return button:UpdateTooltip()
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------
|
|
-- Event
|
|
------------------------------------------------------
|
|
-- Fired when the handler is enabled or disabled
|
|
event "OnEnableChanged"
|
|
|
|
------------------------------------------------------
|
|
-- Refresh Method
|
|
------------------------------------------------------
|
|
function RefershGrid(self, button)
|
|
local force = (self.IsPlayerAction and _GridCounter or _PetGridCounter) > 0
|
|
local HasAction = self.HasAction
|
|
|
|
if button then
|
|
button.GridVisible = force or HasAction(button)
|
|
else
|
|
for _, button in self:GetIterator() do
|
|
button.GridVisible = force or HasAction(button)
|
|
end
|
|
end
|
|
end
|
|
|
|
function RefreshButtonState(self, button)
|
|
local IsActivedAction = self.IsActivedAction
|
|
local IsAutoRepeatAction= self.IsAutoRepeatAction
|
|
|
|
if button then
|
|
button:SetChecked(IsActivedAction(button) or IsAutoRepeatAction(button))
|
|
else
|
|
for _, button in self:GetIterator() do
|
|
button:SetChecked(IsActivedAction(button) or IsAutoRepeatAction(button))
|
|
end
|
|
end
|
|
end
|
|
|
|
function RefreshUsable(self, button)
|
|
local IsUsableAction = self.IsUsableAction
|
|
|
|
if button then
|
|
button.IsUsable = IsUsableAction(button)
|
|
else
|
|
for _, button in self:GetIterator() do
|
|
button.IsUsable= IsUsableAction(button)
|
|
end
|
|
end
|
|
end
|
|
|
|
function RefreshCount(self, button)
|
|
local IsConsumableAction= self.IsConsumableAction
|
|
local GetActionCount = self.GetActionCount
|
|
local GetActionCharges = self.GetActionCharges
|
|
|
|
if button then
|
|
if IsConsumableAction(button) then
|
|
button.Count = GetActionCount(button)
|
|
else
|
|
local cha, max = GetActionCharges(button)
|
|
if max and max > 1 then
|
|
button.Count= cha
|
|
else
|
|
button.Count= nil
|
|
end
|
|
end
|
|
else
|
|
for _, button in self:GetIterator() do
|
|
if IsConsumableAction(button) then
|
|
button.Count = GetActionCount(button)
|
|
else
|
|
local cha, max = GetActionCharges(button)
|
|
if max and max > 1 then
|
|
button.Count= cha
|
|
else
|
|
button.Count= nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local shareCooldown = { start = 0, duration = 0 }
|
|
function RefreshCooldown(self, button)
|
|
local GetActionCooldown = self.GetActionCooldown
|
|
|
|
if button then
|
|
local s, d = GetActionCooldown(button)
|
|
shareCooldown.start = s or 0
|
|
shareCooldown.duration = d or 0
|
|
button.Cooldown = shareCooldown
|
|
else
|
|
for _, button in self:GetIterator() do
|
|
local s, d = GetActionCooldown(button)
|
|
shareCooldown.start = s or 0
|
|
shareCooldown.duration = d or 0
|
|
button.Cooldown = shareCooldown
|
|
end
|
|
end
|
|
end
|
|
|
|
function RefreshFlash(self, button)
|
|
local IsAttackAction = self.IsAttackAction
|
|
local IsActivedAction = self.IsActivedAction
|
|
local IsAutoRepeatAction= self.IsAutoRepeatAction
|
|
|
|
if button then
|
|
button.IsAutoAttacking = (IsAttackAction(button) and IsActivedAction(button)) or IsAutoRepeatAction(button)
|
|
else
|
|
for _, button in self:GetIterator() do
|
|
button.IsAutoAttacking = (IsAttackAction(button) and IsActivedAction(button)) or IsAutoRepeatAction(button)
|
|
end
|
|
end
|
|
end
|
|
|
|
function RefreshOverlayGlow(self, button)
|
|
local GetSpellId = self.GetSpellId
|
|
|
|
if button then
|
|
local spellId = GetSpellId(button)
|
|
self.OverlayGlow = spellId and IsSpellOverlayed(spellId)
|
|
else
|
|
for _, button in self:GetIterator() do
|
|
local spellId = GetSpellId(button)
|
|
self.OverlayGlow= spellId and IsSpellOverlayed(spellId)
|
|
end
|
|
end
|
|
end
|
|
|
|
function RefreshRange(self, button)
|
|
local IsInRange = self.IsInRange
|
|
|
|
if button then
|
|
button.InRange = IsInRange(button)
|
|
else
|
|
for _, button in self:GetIterator() do
|
|
button.InRange = IsInRange(button)
|
|
end
|
|
end
|
|
end
|
|
|
|
function RefreshFlyout(self, button)
|
|
local IsFlyout = self.IsFlyout
|
|
|
|
if button then
|
|
if button.IsCustomFlyout then return end
|
|
button.IsFlyout = IsFlyout(button)
|
|
else
|
|
for _, button in self:GetIterator() do
|
|
if not button.IsCustomFlyout then
|
|
button.IsFlyout = IsFlyout(button)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function RefreshAutoCastable(self, button)
|
|
local IsAutoCastAction = self.IsAutoCastAction
|
|
|
|
if button then
|
|
button.IsAutoCastable= IsAutoCastAction(button)
|
|
else
|
|
for _, button in self:GetIterator() do
|
|
button.IsAutoCastable = IsAutoCastAction(button)
|
|
end
|
|
end
|
|
end
|
|
|
|
function RefreshAutoCasting(self, button)
|
|
local IsAutoCasting = self.IsAutoCasting
|
|
|
|
if button then
|
|
button.IsAutoCasting= IsAutoCasting(button)
|
|
else
|
|
for _, button in self:GetIterator() do
|
|
button.IsAutoCasting = IsAutoCasting(button)
|
|
end
|
|
end
|
|
end
|
|
|
|
function RefreshIcon(self, button)
|
|
local GetActionTexture = self.GetActionTexture
|
|
|
|
if button then
|
|
button.Icon = GetActionTexture(button)
|
|
else
|
|
for _, button in self:GetIterator() do
|
|
button.Icon = GetActionTexture(button)
|
|
end
|
|
end
|
|
end
|
|
|
|
function RefreshEquipItem(self, button)
|
|
local IsEquippedItem = self.IsEquippedItem
|
|
|
|
if button then
|
|
button.IsEquippedItem = IsEquippedItem(button)
|
|
else
|
|
for _, button in self:GetIterator() do
|
|
button.IsEquippedItem = IsEquippedItem(button)
|
|
end
|
|
end
|
|
end
|
|
|
|
function RefreshText(self, button)
|
|
local IsConsumableAction= self.IsConsumableAction
|
|
local GetActionText = self.GetActionText
|
|
|
|
if button then
|
|
button.Text = IsConsumableAction(button) and "" or GetActionText(button)
|
|
else
|
|
for _, button in self:GetIterator() do
|
|
button.Text = IsConsumableAction(button) and "" or GetActionText(button)
|
|
end
|
|
end
|
|
end
|
|
|
|
function RefreshShowSearchOverlay(self, button)
|
|
local IsSearchOverlayShow = self.IsSearchOverlayShow
|
|
|
|
if button then
|
|
button.ShowSearchOverlay = IsSearchOverlayShow(button)
|
|
else
|
|
for _, button in self:GetIterator() do
|
|
button.ShowSearchOverlay = IsSearchOverlayShow(button)
|
|
end
|
|
end
|
|
end
|
|
|
|
function RefreshIconLocked(self, button)
|
|
local IsIconLocked = self.IsIconLocked
|
|
|
|
if button then
|
|
button.IconLocked = IsIconLocked(button)
|
|
else
|
|
for _, button in self:GetIterator() do
|
|
button.IconLocked = IsIconLocked(button)
|
|
end
|
|
end
|
|
end
|
|
|
|
__Delegate__(Continue)
|
|
function RefreshActionButtons(self, button)
|
|
local refresh = refreshButton
|
|
|
|
if button then
|
|
-- The button may change its action type when waiting
|
|
return button.ActionType == self.Type and refresh(self, button)
|
|
else
|
|
for _, button in self:GetIterator() do
|
|
refresh(self, button)
|
|
Continue()
|
|
end
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------
|
|
-- Method
|
|
------------------------------------------------------
|
|
GetIterator = ipairs
|
|
|
|
function Insert(self, button)
|
|
local oldHandler = _ActionButtonMap[button]
|
|
|
|
if oldHandler then
|
|
if oldHandler == self then return end
|
|
oldHandler:Remove(button)
|
|
end
|
|
|
|
_ActionButtonMap[button]= self
|
|
tinsert(self, button)
|
|
|
|
self.Enabled = true
|
|
end
|
|
|
|
function Remove(self, button)
|
|
if _ActionButtonMap[button] ~= self then return end
|
|
_ActionButtonMap[button]= nil
|
|
|
|
for i, v in ipairs(self) do if v == button then tremove(self, i) break end end
|
|
|
|
self.Enabled = self[1] and true or false
|
|
end
|
|
|
|
-- Run the snippet in the global environment
|
|
__NoCombat__()
|
|
function RunSnippet(self, code)
|
|
return self.Manager:Execute(code)
|
|
end
|
|
|
|
------------------------------------------------------
|
|
-- Overridable Method For Action Buttons
|
|
------------------------------------------------------
|
|
-- Get the actions's kind, target, detail
|
|
function GetActionDetail(self)
|
|
local name = self:GetAttribute("actiontype")
|
|
return self:GetAttribute(_ActionTargetMap[name]), _ActionTargetDetail[name] and self:GetAttribute(_ActionTargetDetail[name])
|
|
end
|
|
|
|
-- Map the action
|
|
function Map(self, ...) return ... end
|
|
|
|
-- The refresh logic
|
|
function Refresh(self) end
|
|
|
|
-- Custom pick up action
|
|
function PickupAction(self, target, detail) end
|
|
|
|
-- Custom receive action
|
|
function ReceiveAction(self, target, detail) end
|
|
|
|
-- Whether the action button has an action
|
|
function HasAction(self) return true end
|
|
|
|
-- Get the action's text
|
|
function GetActionText(self) return "" end
|
|
|
|
-- Get the action's texture
|
|
function GetActionTexture(self) end
|
|
|
|
-- Get the action's charges
|
|
function GetActionCharges(self) end
|
|
|
|
-- Get the action's count
|
|
function GetActionCount(self) return 0 end
|
|
|
|
-- Get the action's cooldown
|
|
function GetActionCooldown(self) return 0, 0, 0 end
|
|
|
|
-- Whether the action is attackable
|
|
function IsAttackAction(self) return false end
|
|
|
|
-- Whether the action is an item and can be equipped
|
|
function IsEquippedItem(self) return false end
|
|
|
|
-- Whether the action is actived
|
|
function IsActivedAction(self) return false end
|
|
|
|
-- Whether the action is auto-repeat
|
|
function IsAutoRepeatAction(self) return false end
|
|
|
|
-- Whether the action is usable
|
|
function IsUsableAction(self) return true end
|
|
|
|
-- Whether the action is consumable
|
|
function IsConsumableAction(self) return false end
|
|
|
|
-- Whether the action is in range of the target
|
|
function IsInRange(self) return end
|
|
|
|
-- Whether the action is auto-castable
|
|
function IsAutoCastAction(self) return false end
|
|
|
|
-- Whether the action is auto-casting now
|
|
function IsAutoCasting(self) return false end
|
|
|
|
-- Whether need show the search overlay
|
|
function IsSearchOverlayShow(self) return false end
|
|
|
|
-- Whether the icon is locked
|
|
function IsIconLocked(self) return false end
|
|
|
|
-- Show the tooltip for the action
|
|
function SetTooltip(self, tip) end
|
|
|
|
-- Get the spell id of the action
|
|
function GetSpellId(self) end
|
|
|
|
-- Whether the action is a flyout spell
|
|
function IsFlyout(self) return false end
|
|
|
|
-- Whether the action has range spell
|
|
function IsRangeSpell(self) return false end
|
|
|
|
------------------------------------------------------
|
|
-- Property
|
|
------------------------------------------------------
|
|
-- The manager of the action system
|
|
property "Manager" { default = _ManagerFrame, set = false }
|
|
|
|
-- Whether the handler is enabled(has buttons)
|
|
property "Enabled" { type = Boolean, event = "OnEnableChanged" }
|
|
|
|
-- The action's name
|
|
property "Name" { type = String }
|
|
|
|
-- The action type's type
|
|
property "Type" { type = String }
|
|
|
|
-- The target attribute name
|
|
property "Target" { type = String }
|
|
|
|
-- The detail attribute name
|
|
property "Detail" { type = String }
|
|
|
|
-- Whether the action is player action
|
|
property "IsPlayerAction" { type = Boolean, default = true }
|
|
|
|
-- Whether the action is pet action
|
|
property "IsPetAction" { type = Boolean, default = false }
|
|
|
|
-- The drag style of the action type
|
|
property "DragStyle" { type = ActionTypeHandleStyle, default = ActionTypeHandleStyle.Clear }
|
|
|
|
-- The receive style of the action type
|
|
property "ReceiveStyle" { type = ActionTypeHandleStyle, default = ActionTypeHandleStyle.Clear }
|
|
|
|
-- The receive map
|
|
property "ReceiveMap" { type = String }
|
|
|
|
-- The pickup map
|
|
property "PickupMap" { type = String }
|
|
|
|
-- The snippet to setup environment for the action type
|
|
property "InitSnippet" { type = String }
|
|
|
|
-- The snippet used when pick up action
|
|
property "PickupSnippet" { type = String }
|
|
|
|
-- The snippet used to update for new action settings
|
|
property "UpdateSnippet" { type = String }
|
|
|
|
-- The snippet used to receive action
|
|
property "ReceiveSnippet" { type = String }
|
|
|
|
-- The snippet used to clear action
|
|
property "ClearSnippet" { type = String }
|
|
|
|
-- The snippet used for pre click
|
|
property "PreClickSnippet" { type = String }
|
|
|
|
-- The snippet used for post click
|
|
property "PostClickSnippet" { type = String }
|
|
|
|
------------------------------------------------------
|
|
-- Initialize
|
|
------------------------------------------------------
|
|
function __init(self)
|
|
-- No repeat definition for action types
|
|
if _IFActionTypeHandler[self.Name] then return end
|
|
|
|
-- Register the action type handler
|
|
_IFActionTypeHandler[self.Name] = self
|
|
|
|
-- Default map
|
|
if self.Type == nil then self.Type = self.Name end
|
|
if self.Target == nil then self.Target = self.Type end
|
|
if self.PickupMap == nil then self.PickupMap = self.Type end
|
|
if self.ReceiveMap == nil and self.ReceiveStyle == "Clear" then self.ReceiveMap = self.Type end
|
|
|
|
-- Register action type map
|
|
_ActionTypeMap[self.Name] = self.Type
|
|
_ActionTargetMap[self.Name] = self.Target
|
|
_ActionTargetDetail[self.Name] = self.Detail
|
|
|
|
self:RunSnippet( _RegisterSnippetTemplate:format("_ActionTypeMap", self.Name, self.Type) )
|
|
self:RunSnippet( _RegisterSnippetTemplate:format("_ActionTargetMap", self.Name, self.Target) )
|
|
if self.Detail then self:RunSnippet( _RegisterSnippetTemplate:format("_ActionTargetDetail", self.Name, self.Detail) ) end
|
|
|
|
-- Init the environment
|
|
if self.InitSnippet then self:RunSnippet( self.InitSnippet ) end
|
|
|
|
-- Register PickupSnippet
|
|
if self.PickupSnippet then self:RunSnippet( _RegisterSnippetTemplate:format("_PickupSnippet", self.Name, self.PickupSnippet) ) end
|
|
|
|
-- Register UpdateSnippet
|
|
if self.UpdateSnippet then self:RunSnippet( _RegisterSnippetTemplate:format("_UpdateSnippet", self.Name, self.UpdateSnippet) ) end
|
|
|
|
-- Register ReceiveSnippet
|
|
if self.ReceiveSnippet then self:RunSnippet( _RegisterSnippetTemplate:format("_ReceiveSnippet", self.Name, self.ReceiveSnippet) ) end
|
|
|
|
-- Register ClearSnippet
|
|
if self.ClearSnippet then self:RunSnippet( _RegisterSnippetTemplate:format("_ClearSnippet", self.Name, self.ClearSnippet) ) end
|
|
|
|
-- Register DragStyle
|
|
self:RunSnippet( _RegisterSnippetTemplate:format("_DragStyle", self.Name, self.DragStyle) )
|
|
|
|
-- Register ReceiveStyle
|
|
self:RunSnippet( _RegisterSnippetTemplate:format("_ReceiveStyle", self.Name, self.ReceiveStyle) )
|
|
|
|
-- Register ReceiveMap
|
|
if self.ReceiveMap then
|
|
self:RunSnippet( _RegisterSnippetTemplate:format("_ReceiveMap", self.ReceiveMap, self.Name) )
|
|
_ReceiveMap[self.ReceiveMap] = self
|
|
end
|
|
|
|
-- Register PickupMap
|
|
if self.PickupMap then self:RunSnippet( _RegisterSnippetTemplate:format("_PickupMap", self.Name, self.PickupMap) ) end
|
|
|
|
-- Register PreClickMap
|
|
if self.PreClickSnippet then self:RunSnippet( _RegisterSnippetTemplate:format("_PreClickSnippet", self.Name, self.PreClickSnippet) ) end
|
|
|
|
-- Register PostClickMap
|
|
if self.PostClickSnippet then self:RunSnippet( _RegisterSnippetTemplate:format("_PostClickSnippet", self.Name, self.PostClickSnippet) ) end
|
|
|
|
-- Clear
|
|
self.InitSnippet = nil
|
|
self.PickupSnippet = nil
|
|
self.UpdateSnippet = nil
|
|
self.ReceiveSnippet = nil
|
|
self.ClearSnippet = nil
|
|
self.PreClickSnippet = nil
|
|
self.PostClickSnippet = nil
|
|
end
|
|
end)
|
|
|
|
------------------------------------------------------
|
|
-- Action Button Manager --
|
|
------------------------------------------------------
|
|
__SecureMethod__()
|
|
function _ManagerFrame:OnPickUp(kind, target, detail)
|
|
return not InCombatLockdown() and PickupAny("clear", kind, target, detail)
|
|
end
|
|
|
|
__SecureMethod__()
|
|
function _ManagerFrame:OnReceive(kind, target, detail)
|
|
return not InCombatLockdown() and _IFActionTypeHandler[kind] and _IFActionTypeHandler[kind]:ReceiveAction(target, detail)
|
|
end
|
|
|
|
__SecureMethod__()
|
|
function _ManagerFrame:UpdateActionButton(name)
|
|
self = GetProxyUI(_G[name])
|
|
|
|
local name = self:GetAttribute("actiontype")
|
|
local handler = _IFActionTypeHandler[name]
|
|
local target, detail = handler.GetActionDetail(self)
|
|
|
|
if self.__IFActionHandler_Kind ~= name
|
|
or self.__IFActionHandler_Target ~= target
|
|
or self.__IFActionHandler_Detail ~= detail then
|
|
|
|
if self.__IFActionHandler_Kind and self.__IFActionHandler_Kind ~= name then
|
|
_IFActionTypeHandler[self.__IFActionHandler_Kind]:Remove(self)
|
|
end
|
|
|
|
self.__IFActionHandler_Kind = name
|
|
self.__IFActionHandler_Target = target
|
|
self.__IFActionHandler_Detail = detail
|
|
|
|
handler:Insert(self)
|
|
return handler:RefreshActionButtons(self)
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------
|
|
-- Secure Snippet --
|
|
------------------------------------------------------
|
|
do
|
|
-- Init manger frame's enviroment
|
|
_ManagerFrame:Execute[[
|
|
-- to fix blz error, use Manager not control
|
|
Manager = self
|
|
|
|
_NoDraggable = newtable()
|
|
|
|
_ActionTypeMap = newtable()
|
|
_ActionTargetMap = newtable()
|
|
_ActionTargetDetail = newtable()
|
|
|
|
_ReceiveMap = newtable()
|
|
_PickupMap = newtable()
|
|
|
|
_ClearSnippet = newtable()
|
|
_UpdateSnippet = newtable()
|
|
_PickupSnippet = newtable()
|
|
_ReceiveSnippet = newtable()
|
|
_PreClickSnippet = newtable()
|
|
_PostClickSnippet = newtable()
|
|
|
|
_DragStyle = newtable()
|
|
_ReceiveStyle = newtable()
|
|
|
|
UpdateAction = [=[
|
|
local name = self:GetAttribute("actiontype")
|
|
|
|
-- Custom update
|
|
if _UpdateSnippet[name] then
|
|
Manager:RunFor(
|
|
self, _UpdateSnippet[name],
|
|
self:GetAttribute(_ActionTargetMap[name]),
|
|
_ActionTargetDetail[name] and self:GetAttribute(_ActionTargetDetail[name])
|
|
)
|
|
end
|
|
|
|
return Manager:CallMethod("UpdateActionButton", self:GetName())
|
|
]=]
|
|
|
|
ClearAction = [=[
|
|
local name = self:GetAttribute("actiontype")
|
|
|
|
if name and name ~= "empty" then
|
|
self:SetAttribute("actiontype", "empty")
|
|
|
|
self:SetAttribute("type", nil)
|
|
self:SetAttribute(_ActionTargetMap[name], nil)
|
|
if _ActionTargetDetail[name] then
|
|
self:SetAttribute(_ActionTargetDetail[name], nil)
|
|
end
|
|
|
|
-- Custom clear
|
|
if _ClearSnippet[name] then
|
|
Manager:RunFor(self, _ClearSnippet[name])
|
|
end
|
|
end
|
|
]=]
|
|
|
|
GetAction = [=[
|
|
return self:GetAttribute("actiontype"), self:GetAttribute(_ActionTargetMap[name]), _ActionTargetDetail[name] and self:GetAttribute(_ActionTargetDetail[name])
|
|
]=]
|
|
|
|
SetAction = [=[
|
|
local name, target, detail = ...
|
|
|
|
Manager:RunFor(self, ClearAction)
|
|
|
|
if name and _ActionTypeMap[name] and target then
|
|
self:SetAttribute("actiontype", name)
|
|
|
|
self:SetAttribute("type", _ActionTypeMap[name])
|
|
self:SetAttribute(_ActionTargetMap[name], target)
|
|
|
|
if detail ~= nil and _ActionTargetDetail[name] then
|
|
self:SetAttribute(_ActionTargetDetail[name], detail)
|
|
end
|
|
end
|
|
|
|
return Manager:RunFor(self, UpdateAction)
|
|
]=]
|
|
|
|
DragStart = [=[
|
|
local name = self:GetAttribute("actiontype")
|
|
|
|
if _DragStyle[name] == "Block" then return false end
|
|
|
|
local target = self:GetAttribute(_ActionTargetMap[name])
|
|
local detail = _ActionTargetDetail[name] and self:GetAttribute(_ActionTargetDetail[name])
|
|
|
|
-- Clear and refresh
|
|
if _DragStyle[name] == "Clear" then
|
|
Manager:RunFor(self, ClearAction)
|
|
Manager:RunFor(self, UpdateAction)
|
|
end
|
|
|
|
-- Pickup the target
|
|
if _PickupSnippet[name] == "Custom" then
|
|
Manager:CallMethod("OnPickUp", name, target, detail)
|
|
return false
|
|
elseif _PickupSnippet[name] then
|
|
return Manager:RunFor(self, _PickupSnippet[name], target, detail)
|
|
else
|
|
return "clear", _PickupMap[name], target, detail
|
|
end
|
|
]=]
|
|
|
|
ReceiveDrag = [=[
|
|
local kind, value, extra, extra2 = ...
|
|
if not kind or not value then return false end
|
|
|
|
local oldName = self:GetAttribute("actiontype")
|
|
if _ReceiveStyle[oldName] == "Block" then return false end
|
|
|
|
local oldTarget = oldName and self:GetAttribute(_ActionTargetMap[oldName])
|
|
local oldDetail = oldName and _ActionTargetDetail[oldName] and self:GetAttribute(_ActionTargetDetail[oldName])
|
|
|
|
if _ReceiveStyle[oldName] == "Clear" then
|
|
Manager:RunFor(self, ClearAction)
|
|
|
|
local name, target, detail = _ReceiveMap[kind]
|
|
|
|
if name then
|
|
if _ReceiveSnippet[name] and _ReceiveSnippet[name] ~= "Custom" then
|
|
target, detail = Manager:RunFor(self, _ReceiveSnippet[name], value, extra, extra2)
|
|
else
|
|
target, detail = value, extra
|
|
end
|
|
|
|
if target then
|
|
self:SetAttribute("actiontype", name)
|
|
|
|
self:SetAttribute("type", _ActionTypeMap[name])
|
|
self:SetAttribute(_ActionTargetMap[name], target)
|
|
|
|
if detail ~= nil and _ActionTargetDetail[name] then
|
|
self:SetAttribute(_ActionTargetDetail[name], detail)
|
|
end
|
|
end
|
|
end
|
|
|
|
Manager:RunFor(self, UpdateAction)
|
|
end
|
|
|
|
if _ReceiveStyle[oldName] == "Keep" and _ReceiveSnippet[oldName] == "Custom" then
|
|
Manager:CallMethod("OnReceive", oldName, oldTarget, oldDetail)
|
|
return Manager:RunFor(self, UpdateAction) or false
|
|
end
|
|
|
|
-- Pickup the target
|
|
if _PickupSnippet[oldName] == "Custom" then
|
|
Manager:CallMethod("OnPickUp", oldName, oldTarget, oldDetail)
|
|
return false
|
|
elseif _PickupSnippet[oldName] then
|
|
return Manager:RunFor(self, _PickupSnippet[oldName], oldTarget, oldDetail)
|
|
else
|
|
return "clear", _PickupMap[oldName], oldTarget, oldDetail
|
|
end
|
|
]=]
|
|
]]
|
|
|
|
_OnDragStartSnippet = [[
|
|
if (IsModifierKeyDown() or _NoDraggable[self:GetAttribute("IFActionHandlerGroup")]) and not IsModifiedClick("PICKUPACTION") then return false end
|
|
return Manager:RunFor(self, DragStart)
|
|
]]
|
|
|
|
_OnReceiveDragSnippet = [[
|
|
return Manager:RunFor(self, ReceiveDrag, kind, value, ...)
|
|
]]
|
|
|
|
_PostReceiveSnippet = [[
|
|
return Manager:RunFor(Manager:GetFrameRef("UpdatingButton"), ReceiveDrag, %s, %s, %s, %s)
|
|
]]
|
|
|
|
_SetActionSnippet = [[
|
|
return Manager:RunFor(Manager:GetFrameRef("UpdatingButton"), SetAction, %s, %s, %s)
|
|
]]
|
|
|
|
_WrapClickPrev = [[
|
|
local name = self:GetAttribute("actiontype")
|
|
|
|
if _PreClickSnippet[name] then
|
|
return Manager:RunFor(self, _PreClickSnippet[name], button, down)
|
|
end
|
|
]]
|
|
|
|
_WrapClickPost = [[
|
|
local name = self:GetAttribute("actiontype")
|
|
|
|
if _PostClickSnippet[name] then
|
|
return Manager:RunFor(self, _PostClickSnippet[name], message, button, down)
|
|
end
|
|
]]
|
|
|
|
_WrapDragPrev = [[ return "message", "update" ]]
|
|
|
|
_WrapDragPost = [[ Manager:RunFor(self, UpdateAction) ]]
|
|
|
|
_OnShowSnippet = [[ if self:GetAttribute("autoKeyBinding") and self:GetAttribute("hotKey") then self:SetBindingClick(true, self:GetAttribute("hotKey"), self:GetName(), "LeftButton") end ]]
|
|
|
|
_OnHideSnippet = [[ if self:GetAttribute("autoKeyBinding") then self:ClearBindings() end ]]
|
|
end
|
|
|
|
------------------------------------------------------
|
|
-- Action Script Hanlder --
|
|
------------------------------------------------------
|
|
do
|
|
_GlobalGroup = "GLOBAL"
|
|
|
|
function GetGroup(group)
|
|
group = type(group) == "string" and strtrim(group)
|
|
return group and group ~= "" and group:upper() or _GlobalGroup
|
|
end
|
|
|
|
function GetFormatString(param)
|
|
return type(param) == "string" and ("%q"):format(param) or tostring(param)
|
|
end
|
|
|
|
function PickupAny(kind, target, detail, ...)
|
|
if (kind == "clear") then
|
|
ClearCursor()
|
|
kind, target, detail= target, detail, ...
|
|
end
|
|
|
|
local handler = _IFActionTypeHandler[kind]
|
|
return handler and handler:PickupAction(target, detail)
|
|
end
|
|
|
|
function PreClick(self)
|
|
local oldKind = self:GetAttribute("actiontype")
|
|
if InCombatLockdown() or (oldKind and _IFActionTypeHandler[oldKind].ReceiveStyle ~= "Clear") then return end
|
|
|
|
local kind, value = GetCursorInfo()
|
|
if not (kind and value) then return end
|
|
|
|
self.__IFActionHandler_PreType = self:GetAttribute("type")
|
|
self.__IFActionHandler_PreMsg = true
|
|
|
|
-- Make sure no action used
|
|
self:SetAttribute("type", nil)
|
|
end
|
|
|
|
function PostClick(self)
|
|
_IFActionTypeHandler[self.ActionType]:RefreshButtonState(self)
|
|
|
|
-- Restore the action
|
|
if self.__IFActionHandler_PreMsg then
|
|
if not InCombatLockdown() then
|
|
if self.__IFActionHandler_PreType then
|
|
self:SetAttribute("type", self.__IFActionHandler_PreType)
|
|
end
|
|
|
|
local kind, value, subtype, detail = GetCursorInfo()
|
|
|
|
if kind and value and _ReceiveMap[kind] then
|
|
local oldName = self.__IFActionHandler_Kind
|
|
local oldTarget = self.__IFActionHandler_Target
|
|
local oldDetail = self.__IFActionHandler_Detail
|
|
|
|
_ManagerFrame:SetFrameRef("UpdatingButton", self)
|
|
_ManagerFrame:Execute(_PostReceiveSnippet:format(GetFormatString(kind), GetFormatString(value), GetFormatString(subtype), GetFormatString(detail)))
|
|
|
|
PickupAny("clear", oldName, oldTarget, oldDetail)
|
|
end
|
|
elseif self.__IFActionHandler_PreType then
|
|
-- Keep safe
|
|
NoCombat(self.SetAttribute, self, "type", self.__IFActionHandler_PreType)
|
|
end
|
|
|
|
self.__IFActionHandler_PreType = false
|
|
self.__IFActionHandler_PreMsg = false
|
|
end
|
|
end
|
|
|
|
function OnEnter(self)
|
|
if _KeyBindingMode then return true end
|
|
|
|
_OnTooltipButton = self
|
|
return self:UpdateTooltip()
|
|
end
|
|
|
|
function OnLeave(self)
|
|
_OnTooltipButton = nil
|
|
GameTooltip:Hide()
|
|
end
|
|
|
|
function OnShow(self)
|
|
_IFActionTypeHandler[self.ActionType]:RefershGrid(self)
|
|
end
|
|
|
|
__NoCombat__()
|
|
function DisableDrag(group, value)
|
|
group = GetGroup(group)
|
|
|
|
_NoDragGroup[group] = value or nil
|
|
_ManagerFrame:Execute( ("_NoDraggable[%q] = %s"):format(group, tostring(value or nil)) )
|
|
end
|
|
|
|
function IsDragEnabled(group)
|
|
return not _NoDragGroup[GetGroup(group)]
|
|
end
|
|
|
|
__NoCombat__()
|
|
function EnableButtonDown(group, value)
|
|
group = GetGroup(group)
|
|
|
|
if not _MouseDownGroup[group] then
|
|
_MouseDownGroup[group] = value or nil
|
|
|
|
if _ActionButtonGroupList[group] then
|
|
local reg = value and "AnyDown" or "AnyUp"
|
|
|
|
for btn in pairs(_ActionButtonGroupList[group]) do
|
|
btn:RegisterForClicks(reg)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function IsButtonDownEnabled(group)
|
|
return _MouseDownGroup[GetGroup(group)]
|
|
end
|
|
|
|
function SetActionButtonGroup(self, group, old)
|
|
group = GetGroup(group)
|
|
old = old and GetGroup(old)
|
|
|
|
if old and _ActionButtonGroupList[old] then
|
|
_ActionButtonGroupList[old][self] = nil
|
|
end
|
|
_ActionButtonGroupList[group] = _ActionButtonGroupList[group] or {}
|
|
_ActionButtonGroupList[group][self] = true
|
|
|
|
self:SetAttribute("IFActionHandlerGroup", group)
|
|
self:RegisterForClicks(_MouseDownGroup[group] and "AnyDown" or "AnyUp")
|
|
end
|
|
|
|
function SetupActionButton(self)
|
|
SetActionButtonGroup(self, self.ActionButtonGroup)
|
|
|
|
self:RegisterForDrag("LeftButton", "RightButton")
|
|
|
|
|
|
_ManagerFrame:WrapScript(self, "OnShow", _OnShowSnippet)
|
|
_ManagerFrame:WrapScript(self, "OnHide", _OnHideSnippet)
|
|
|
|
_ManagerFrame:WrapScript(self, "OnDragStart", _OnDragStartSnippet)
|
|
_ManagerFrame:WrapScript(self, "OnReceiveDrag", _OnReceiveDragSnippet)
|
|
|
|
_ManagerFrame:WrapScript(self, "OnClick", _WrapClickPrev, _WrapClickPost)
|
|
_ManagerFrame:WrapScript(self, "OnDragStart", _WrapDragPrev, _WrapDragPost)
|
|
_ManagerFrame:WrapScript(self, "OnReceiveDrag", _WrapDragPrev, _WrapDragPost)
|
|
|
|
-- Register useful attribute snippets to be used in other addons
|
|
self:SetFrameRef("_Manager", _ManagerFrame)
|
|
self:SetAttribute("SetAction", [[ return self:GetFrameRef("_Manager"):RunFor(self, "Manager:RunFor(self, SetAction, ...)", ...) ]])
|
|
self:SetAttribute("ClearAction",[[ return self:GetFrameRef("_Manager"):RunFor(self, "Manager:RunFor(self, ClearAction)") ]])
|
|
self:SetAttribute("GetAction", [[ return self:GetFrameRef("_Manager"):RunFor(self, "return Manager:RunFor(self, GetAction)") ]])
|
|
|
|
if not self:GetAttribute("actiontype") then
|
|
self:SetAttribute("actiontype", "empty")
|
|
end
|
|
|
|
self.PreClick = self.PreClick + PreClick
|
|
self.PostClick = self.PostClick+ PostClick
|
|
self.OnShow = self.OnShow + OnShow
|
|
self.OnEnter = self.OnEnter + OnEnter
|
|
self.OnLeave = self.OnLeave + OnLeave
|
|
end
|
|
|
|
function SaveAction(self, kind, target, detail)
|
|
_ManagerFrame:SetFrameRef("UpdatingButton", self)
|
|
_ManagerFrame:Execute(_SetActionSnippet:format(GetFormatString(kind), GetFormatString(target), GetFormatString(detail)))
|
|
end
|
|
end
|
|
|
|
class "SecureActionButton" (function(_ENV)
|
|
inherit "SecureCheckButton"
|
|
|
|
import "System.Reactive"
|
|
|
|
export {
|
|
GetRawUI = UI.GetRawUI,
|
|
IsObjectType = Class.IsObjectType,
|
|
}
|
|
|
|
local _KeyBindingMask = Mask("Scorpio_SecureActionButton_KeyBindingMask")
|
|
|
|
_KeyBindingMask:Hide()
|
|
_KeyBindingMask.EnableKeyBinding = true
|
|
|
|
function _KeyBindingMask:OnKeySet(key, old)
|
|
local parent = self:GetParent()
|
|
if IsObjectType(parent, SecureActionButton) then
|
|
parent.HotKey = key
|
|
end
|
|
end
|
|
|
|
function _KeyBindingMask:OnKeyClear()
|
|
local parent = self:GetParent()
|
|
if IsObjectType(parent, SecureActionButton) then
|
|
parent.HotKey = nil
|
|
end
|
|
end
|
|
|
|
local function handleKeyBinding(self)
|
|
if self.HotKey and (not self.AutoKeyBinding or self:IsVisible()) then
|
|
SetOverrideBindingClick(GetRawUI(self), self.AutoKeyBinding, self.HotKey, self:GetName(), "LeftButton")
|
|
else
|
|
ClearOverrideBindings(GetRawUI(self))
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------
|
|
-- Static Property --
|
|
------------------------------------------------------
|
|
--- Whether the action button group is draggable
|
|
__Static__() __Indexer__(String)
|
|
property "Draggable" {
|
|
type = Boolean,
|
|
get = function(self, group) return IsDragEnabled(group) end,
|
|
set = function(self, group, value) DisableDrag(group, not value) end,
|
|
}
|
|
|
|
--- Whether the action button group use mouse down to trigger
|
|
__Static__() __Indexer__(String)
|
|
property "UseMouseDown" {
|
|
type = Boolean,
|
|
get = function(self, group) return IsButtonDownEnabled(group) end,
|
|
set = function(self, group, value) EnableButtonDown(group, value) end,
|
|
}
|
|
|
|
------------------------------------------------------
|
|
-- Property --
|
|
------------------------------------------------------
|
|
--- The action button group
|
|
property "ActionButtonGroup"{ default = _GlobalGroup, handler = SetActionButtonGroup }
|
|
|
|
--- The action type
|
|
property "ActionType" { set = false, field = "__IFActionHandler_Kind", default = "empty" }
|
|
|
|
--- the action content
|
|
property "ActionTarget" { set = false, field = "__IFActionHandler_Target" }
|
|
|
|
--- The action detail
|
|
property "ActionDetail" { set = false, field = "__IFActionHandler_Detail" }
|
|
|
|
--- The gametool tip anchor
|
|
property "GameTooltipAnchor"{ type = AnchorType }
|
|
|
|
--- Whether use custom flyout logic
|
|
property "IsCustomFlyout" { type = Boolean }
|
|
|
|
------------------------------------------------------
|
|
-- Observable Property --
|
|
------------------------------------------------------
|
|
--- Whether show the button grid
|
|
__Observable__()
|
|
property "GridVisible" { type = Boolean }
|
|
|
|
--- Whether always show the button grid
|
|
__Observable__()
|
|
property "GridAlwaysShow" { type = Boolean }
|
|
|
|
--- Whether the button is usable
|
|
__Observable__()
|
|
property "IsUsable" { type = Boolean }
|
|
|
|
--- Whether the button has action
|
|
__Observable__()
|
|
property "HasAction" { type = Boolean }
|
|
|
|
--- The count/charge of the action
|
|
__Observable__()
|
|
property "Count" { type = Number }
|
|
|
|
--- The cooldown of the action
|
|
__Observable__()
|
|
property "Cooldown" { type = CooldownStatus, set = Toolset.fakefunc }
|
|
|
|
--- Whether the action is auto attack or auto repeat
|
|
__Observable__()
|
|
property "IsAutoAttack" { type = Boolean }
|
|
|
|
--- Whether show the IsAutoAttacking
|
|
__Observable__()
|
|
property "IsAutoAttacking" { type = Boolean }
|
|
|
|
--- Whether show the overlay glow
|
|
__Observable__()
|
|
property "OverlayGlow" { type = Boolean }
|
|
|
|
--- Whether the target is in range
|
|
__Observable__()
|
|
property "InRange" { type = Any }
|
|
|
|
--- The action button's flyout direction: UP, DOWN, LEFT, RIGHT
|
|
__Observable__()
|
|
property "FlyoutDirection" { type = FlyoutDirection, default = "UP", handler = function(self, val) self:SetAttribute("flyoutDirection", val) end }
|
|
|
|
--- Whether the action is flyout
|
|
__Observable__()
|
|
property "IsFlyout" { type = Boolean }
|
|
|
|
--- whether the flyout action bar is shown
|
|
__Observable__()
|
|
property "Flyouting" { type = Boolean }
|
|
|
|
--- Whether the action is auto castable
|
|
__Observable__()
|
|
property "IsAutoCastable" { type = Boolean }
|
|
|
|
--- Whether the action is auto casting
|
|
__Observable__()
|
|
property "IsAutoCasting" { type = Boolean }
|
|
|
|
--- The icon of the action
|
|
__Observable__()
|
|
property "Icon" { type = Any }
|
|
|
|
--- Whether the action is an equipped item
|
|
__Observable__()
|
|
property "IsEquippedItem" { type = Boolean }
|
|
|
|
--- The action text
|
|
__Observable__()
|
|
property "Text" { type = String }
|
|
|
|
--- Whether the icon should be locked
|
|
__Observable__()
|
|
property "IconLocked" { type = Boolean }
|
|
|
|
__Observable__()
|
|
property "ShowSearchOverlay"{ type = Boolean }
|
|
|
|
--- The short key of the action
|
|
__Observable__()
|
|
property "HotKey" { type = String, handler = function(self, key, old)
|
|
if old and _KeyBindingMap[old] == self then
|
|
_KeyBindingMap[old] = nil
|
|
end
|
|
|
|
if key and key:upper() ~= key then
|
|
self.HotKey = key:upper()
|
|
return
|
|
end
|
|
|
|
self:SetAttribute("hotKey", key)
|
|
|
|
if key and not self.AutoKeyBinding and _KeyBindingMap[key] ~= self then
|
|
if _KeyBindingMap[key] then _KeyBindingMap[key].HotKey = nil end
|
|
_KeyBindingMap[key] = self
|
|
end
|
|
|
|
return handleKeyBinding(self)
|
|
end
|
|
}
|
|
|
|
------------------------------------------------------
|
|
-- Property --
|
|
------------------------------------------------------
|
|
--- Whether only bind keys when the button is shown
|
|
property "AutoKeyBinding" { type = Boolean, handler = function(self, flag)
|
|
self:SetAttribute("autoKeyBinding", flag and true or nil)
|
|
|
|
if self.HotKey then
|
|
if flag then
|
|
if _KeyBindingMap[self.HotKey] == self then
|
|
_KeyBindingMap[self.HotKey] = nil
|
|
end
|
|
elseif _KeyBindingMap[self.HotKey] and _KeyBindingMap[self.HotKey] ~= self then
|
|
self.HotKey = nil
|
|
return
|
|
end
|
|
end
|
|
|
|
return handleKeyBinding(self)
|
|
end
|
|
}
|
|
|
|
|
|
------------------------------------------------------
|
|
-- Static Method --
|
|
------------------------------------------------------
|
|
--- Start the key binding for all secure action buttons
|
|
__Static__() __Async__()
|
|
function StartKeyBinding()
|
|
_KeyBindingMode = true
|
|
|
|
Next(function()
|
|
local current
|
|
|
|
while _KeyBindingMode do
|
|
local button = GetMouseFocus()
|
|
|
|
if button then
|
|
button = GetProxyUI(button)
|
|
|
|
if IsObjectType(button, SecureActionButton) then
|
|
_KeyBindingMask:SetParent(button)
|
|
_KeyBindingMask:SetBindingKey(button.HotKey)
|
|
_KeyBindingMask:Show()
|
|
|
|
while button:IsMouseOver() and _KeyBindingMode do
|
|
Next()
|
|
end
|
|
|
|
_KeyBindingMask:Hide()
|
|
_KeyBindingMask:SetParent(_ManagerFrame)
|
|
end
|
|
end
|
|
|
|
Next()
|
|
end
|
|
end)
|
|
|
|
Alert(_Locale["Confirm when you finished the key binding"])
|
|
_KeyBindingMode = false
|
|
|
|
_KeyBindingMask:Hide()
|
|
_KeyBindingMask:SetParent(_ManagerFrame)
|
|
end
|
|
|
|
|
|
------------------------------------------------------
|
|
-- Method --
|
|
------------------------------------------------------
|
|
--- Set action for the actionbutton
|
|
function SetAction(self, kind, target, detail)
|
|
if kind and not _IFActionTypeHandler[kind] then
|
|
error("SecureActionButton:SetAction(kind, target, detail) - no such action kind", 2)
|
|
end
|
|
|
|
if not kind or not target then
|
|
kind, target, detail= nil, nil, nil
|
|
else
|
|
target, detail = _IFActionTypeHandler[kind].Map(self, target, detail)
|
|
end
|
|
|
|
NoCombat(SaveAction, self, kind, target, detail)
|
|
end
|
|
|
|
--- Get action for the actionbutton
|
|
function GetAction(self)
|
|
return self.ActionType, self.ActionTarget, self.ActionDetail
|
|
end
|
|
|
|
--- Be called when the action content is changed
|
|
function Refresh(self)
|
|
end
|
|
|
|
__SecureMethod__()
|
|
function UpdateTooltip(self)
|
|
if not self.ActionType then return end
|
|
|
|
local anchor = self.GameTooltipAnchor
|
|
|
|
if anchor then
|
|
GameTooltip:SetOwner(self, anchor)
|
|
else
|
|
if (GetCVar("UberTooltips") == "1") then
|
|
GameTooltip_SetDefaultAnchor(GameTooltip, self)
|
|
else
|
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
|
end
|
|
end
|
|
|
|
_IFActionTypeHandler[self.ActionType].SetTooltip(self, GameTooltip)
|
|
GameTooltip:Show()
|
|
end
|
|
|
|
__Sealed__()
|
|
ISecureActionButton = interface { __init = SetupActionButton }
|
|
|
|
extend(ISecureActionButton)
|
|
end)
|
|
|