WoW:SecureActionButtonTemplate
(This is me documenting as I learn, so please clean up and correct as necessary).
Introduction
Secure Frames are Blizzard's new mechanism as of WoW 2.0 to allow for the creation of custom interfaces which may target units, cast spells, use items, and the like while ensuring that such actions are done in a way that Blizzard approves of.
This is documentation for current beta functionality, and is subject to change.
Creating Secure Frames
All secure frames must inherit from one of the secure frame templates. These templates, found in FrameXML/SecureTemplates.xml include (but are not limited to):
- SecureActionButtonTemplate - A button template for click-cast style action buttons
- SecureUnitButtonTemplate - A variant of SecureActionButtonTemplate used for unit buttons
<Button name="myButton" inherits="SecureActionButtonTemplate"> ... </Button>
<Button name="myButton" inherits="SecureUnitButtonTemplate"> ... </Button>
- All secure frames must set a "unit" attribute, even if your intended usage of the button doesn't use a unit. Any secure frame that does not have a UnitId will fail to perform any action.
myButton:SetAttribute("unit", UnitId)
Frame Attribute Types
After creating a frame, you will want to endow it with various attributes that determine how it reacts to user input.
- You will want to set an action type for the button. This determines what action the button takes when acted upon.
myButton:SetAttribute("type", <typeString>)
Where typeString is one of the following base strings, which may then be modified as described below.
actionbar
A button of this type changes your current action bar.
Attributes:
action | May be "increment", "decrement", or an integer which specifies the page to switch to. |
frame:SetAttribute("type1", "actionbar") -- Sets this frame's left click type to "actionbar" frame:SetAttribute("action1", "increment") -- Causes this frame to increment the action bar index when left clicked
action
Executes an action. Calls UseAction(self:GetAttribute("action"), 1, self:GetAttribute("unit"))
Attributes:
action | (integer) The action slot to execute |
frame:SetAttribute("type1", "action") frame:SetAttribute("action1", 3) -- Causes this frame to use the action in your #3 action bar slot when left clicked frame:SetAttribute("shift-action1", 4) -- Causes this frame to use the action in your #4 action bar slot when shift-left clicked
pet
Executes a pet action. Calls CastPetAction(self:GetAttribute("action"), self:GetAttribute("unit"))
Attributes:
action | (integer) The pet action slot to execute |
frame:SetAttribute("type1", "pet") frame:SetAttribute("action1", 3) -- Causes this frame to use the action in your pet's #3 bar slot when left clicked frame:SetAttribute("shift-action1", 4) -- Causes this frame to use the action in your pet's #4 action bar slot when shift-left clicked
spell
Casts a spell.
Attributes:
spell | The name of the spell to cast. For example, "Flash Heal". |
frame:SetAttribute("type1", "spell") frame:SetAttribute("spell1", "Flash Heal") frame:SetAttribute("shift-spell1", "Greater Heal")
item
Uses an item in your inventory (equipped items) or your bags.
Attributes:
slot | Integer specifying the slot the item to be used is in. If "bag" is set, then this will be a bag slot. If "bag" is not set, then it is an Inventory slot. |
bag | Integer specifying the bag the item to be used is in. Requires that "slot" be set. |
item | String specifying the item name. May be used instead of a bag/slot combo. Will not be used if "slot" is set. |
This causes the button to use the item in Slot #1 in your backpack when left clicked:
frame:SetAttribute("type1", "item") frame:SetAttribute("bag1", "1") frame:SetAttribute("slot1", "1")
This causes the button to use your Hearthstone when left clicked:
frame:SetAttribute("type1", "item") frame:SetAttribute("item1", "Hearthstone")
macro
Executes a macro.
Attributes:
macro | (unknown) Identifier specifying the macro to execute. Does this take a macro name or ID (testing needed)? |
Causes this frame to run the macro with ID #1 when left clicked.
frame:SetAttribute("type1", "macro") frame:SetAttribute("macro1", 1)
stop
Cancels a spell if you are targeting a spellcast.
Attributes:
None |
Causes this frame to cancel spell targeting when clicked.
frame:SetAttribute("type", "stop")
target
Perform an action on the target represented by this button's unit property.
- If you are targeting a spell, casts the spell on this button's unit.
- If you are holding an item, attempts to drop the item onto the unit (initiate trade)
- Otherwise, targets the unit.
Attributes:
None |
frame:SetAttribute("type", "target")
focus
Sets your focus to this button's unit attribute.
Attributes:
None |
Clicking this frame will set your focus to this frame's specified unit.
frame:SetAttribute("type", "focus")
assist
Assist the unit specified by this button's unit attribute and attack their target.
Attributes:
None |
Clicking this frame will cause you to target and start attacking the target of this button's unit.
frame:SetAttribute("type", "assist")
click
Clicks another button. Allows this button to act as a proxy to another button.
Attributes:
clickbutton | The button object that this button will proxy its click to when clicked |
Clicking this button will call :Click() on myOtherButton.
frame:SetAttribute("type", "click") frame:SetAttribute("clickbutton", myOtherButton)
Shows a popup menu.
Attributes:
Requires that the button have a "showmenu" property set. This property should be a function that takes a unit as a parameter. |
Clicking this button will call :Click() on myOtherButton.
frame:SetAttribute("type", "menu") frame.showmenu = some_function_that_shows_a_menu
Frame Attribute Modifications
As the examples above have hinted, frame attributes may be modified to refer to allow for extreme flexibility in binding reactions to buttons.
FrameXML/SecureTemplates.lua offers this documentation:
The "modified attribute" takes the form of: modifier-name-button. The modifier is one of "shift-", "ctrl-", "alt-", and the button is a number from 1 through 5.
For example, you could set an action that is used for unmodified left click like this:
self:SetAttribute("action1", value);
You could set an action that is used for shift-right-click like this:
self:SetAttribute("shift-action2", value);
You can also use a wildcard in the place of the modifier or button to denote an attribute that is used for any modifier or any button.
For example, you could set an action that is used for any left click like this:
self:SetAttribute("*action1", value);
You could set an action that is used for shift-click with any button like this:
self:SetAttribute("shift-action*", value);
You can exclude an action by explicitly setting its value to ATTRIBUTE_NOOP
For example, you could set an action that was used for all clicks except ctrl-left-click:
self:SetAttribute("*action*", value); self:SetAttribute("shift-action1", ATTRIBUTE_NOOP);
Setting the attribute by itself is equivalent to *attribute*
SecureActionButtons allow you to map different combinations of modifiers and buttons into actions which are executed when the button is clicked.
For example, you could set up the button to respond to left clicks by targeting the focus:
self:SetAttribute("unit", "focus"); self:SetAttribute("type1", "target");
You could set up all other buttons to bring up a menu like this:
self:SetAttribute("type*", "menu"); self.showmenu = menufunc;
SecureActionButtons are also able to perform different actions depending on whether you can attack the unit or assist the unit associated with the action button. It does so by mapping mouse buttons into "virtual buttons" based on the state of the unit. For example, you can use the following to cast "Mind Blast" on a left click and "Shadow Word: Death" on a right click if the unit can be attacked:
self:SetAttribute("harmbutton1", "nuke1"); self:SetAttribute("type-nuke1", "spell"); self:SetAttribute("spell-nuke1", "Mind Blast"); self:SetAttribute("harmbutton2", "nuke2"); self:SetAttribute("type-nuke2", "spell"); self:SetAttribute("spell-nuke2", "Shadow Word: Death");
In this example, we use the special attribute "harmbutton" which is used to map a virtual button when the unit is attackable. We also have the attribute "helpbutton" which is used when the unit can be assisted.
Although it may not be immediately obvious, we are able to use this new virtual button to set up very complex click behaviors on buttons. For example, we can define a new "heal" virtual button for all friendly left clicks, and then set the button to cast "Flash Heal" on an unmodified left click and "Renew" on a ctrl left click:
self:SetAttribute("*helpbutton1", "heal"); self:SetAttribute("*type-heal", "spell"); self:SetAttribute("spell-heal", "Flash Heal"); self:SetAttribute("ctrl-spell-heal", "Renew");
This system is very powerful, and provides a good layer of abstraction for setting up a button's click behaviors.
The above, step-by-step, does the following:
Creates a virtual button on this button named "nuke1", which will respond to left clicks when this unit's target is attackable.
self:SetAttribute("harmbutton1", "nuke1");
Sets the virtual button "harm1"'s type to "spell"
self:SetAttribute("type-nuke1", "spell");
Sets the virtual button "harm1"'s spell to "Mind Blast"
self:SetAttribute("spell-nuke1", "Mind Blast");
The net result is that when you left-click the button and the button's unit is attackable, you will cast Mind Blast (if you are able).
Creates a virtual button on this button named "nuke2", which will respond to right clicks when this unit's target is attackable.
self:SetAttribute("harmbutton2", "nuke2");
Sets the virtual button "harm1"'s type to "spell"
self:SetAttribute("type-nuke2", "spell");
Sets the virtual button "harm1"'s spell to "Mind Blast"
self:SetAttribute("spell-nuke2", "Shadow Word: Death");
The net result is that when you right-click the button and the button's unit is attackable, you will cast Shadow Word:Death (if you are able).
With both of these set on the button, you will be able to cast Mind Blast and SW:D by left and right clicking, respectively, while the button's unit is set to an attackable unit.
We can then extend our button so that it also casts heal spells if the button's unit is friendly.
self:SetAttribute("helpbutton1", "heal1"); self:SetAttribute("type-heal1", "spell"); self:SetAttribute("spell-heal1", "Flash Heal");
self:SetAttribute("helpbutton2", "heal2"); self:SetAttribute("type-heal2", "spell"); self:SetAttribute("spell-heal2", "Renew");
The net result is a button that:
- Casts Mind Blast when left-clicked if your target is hostile
- Casts Shadow Word: Death when right-clicked if your target is hostile
- Casts Flash Heal when left-clicked if your target is friendly
- Casts Renew when right-clicked if your target is friendly