-
Posted by galvin on Thu, 10 Jun 2010 06:44:24
This part has me confused.
/run SABTest:SetAttribute("type", "spell") /run SABTest:SetAttribute("spell", "Lesser Heal") /run SABTest:SetAttribute("unit", "player") /run SABTest:SetAttribute("shift-type1", "spell") /run SABTest:SetAttribute("shift-spell1", "Power Word: Fortitude")
Your setting a predefined attribute to "spell" or creating a new attribute called "spell"? Then you're taking the new attribute "spell" that was created and setting it to a real spell called "Lesser Heal". So basically type = "lesser heal". But couldn't the 4th line be "shift-type1", "Lesser Heal"?
Also the last line if spell is already defined as Lesser Heal how can it be redefined to do power word instead?
-
Posted by jnwhiteh on Thu, 10 Jun 2010 09:18:07
This part has me confused.
/run SABTest:SetAttribute("type", "spell")
/run SABTest:SetAttribute("spell", "Lesser Heal")
/run SABTest:SetAttribute("unit", "player")
/run SABTest:SetAttribute("shift-type1", "spell")
/run SABTest:SetAttribute("shift-spell1", "Power Word: Fortitude")
Your setting a predefined attribute to "spell" or creating a new attribute called "spell"? Then you're taking the new attribute "spell" that was created and setting it to a real spell called "Lesser Heal". So basically type = "lesser heal". But couldn't the 4th line be "shift-type1", "Lesser Heal"?
Also the last line if spell is already defined as Lesser Heal how can it be redefined to do power word instead?
Attributes are just a mapping from a key (the first argument) to a value (the second argument). Here is what is happening:
-- Set the type attribute (this is a default value) to spell. -- This will cause the button to cast a spell when clicked SABTest:SetAttribute("type", "spell") -- Set the default spell to be cast to 'Lesser Heal'. SABTest:SetAttribute("spell", "Lesser Heal") -- Set the default unit (the unit on which to cast the spell) to the player unit SABTest:SetAttribute("unit", "player") -- Set up shift-leftclick to cast a spell SABTest:SetAttribute("shift-type1", "spell") -- Set the spell that is cast on shift-leftclick to 'Power Word: Fortitude' SABTest:SetAttribute("shift-spell1", "Power Word: Fortitude")
There's no redefining anything. There's also no concept of 'predefined' attributes, or 'new' attributes. An attribute can be set on a frame, or obtained from a frame by name. There's a bit more going on behind the scenes, but the code is all available to read in the secure templates.
Let me know if that doesn't make any sense.
-
Posted by galvin on Thu, 10 Jun 2010 17:36:45
This part has me confused.
/run SABTest:SetAttribute("type", "spell")
/run SABTest:SetAttribute("spell", "Lesser Heal")
/run SABTest:SetAttribute("unit", "player")
/run SABTest:SetAttribute("shift-type1", "spell")
/run SABTest:SetAttribute("shift-spell1", "Power Word: Fortitude")
Your setting a predefined attribute to "spell" or creating a new attribute called "spell"? Then you're taking the new attribute "spell" that was created and setting it to a real spell called "Lesser Heal". So basically type = "lesser heal". But couldn't the 4th line be "shift-type1", "Lesser Heal"?
Also the last line if spell is already defined as Lesser Heal how can it be redefined to do power word instead?
Attributes are just a mapping from a key (the first argument) to a value (the second argument). Here is what is happening:
-- Set the type attribute (this is a default value) to spell. -- This will cause the button to cast a spell when clicked SABTest:SetAttribute("type", "spell") -- Set the default spell to be cast to 'Lesser Heal'. SABTest:SetAttribute("spell", "Lesser Heal") -- Set the default unit (the unit on which to cast the spell) to the player unit SABTest:SetAttribute("unit", "player") -- Set up shift-leftclick to cast a spell SABTest:SetAttribute("shift-type1", "spell") -- Set the spell that is cast on shift-leftclick to 'Power Word: Fortitude' SABTest:SetAttribute("shift-spell1", "Power Word: Fortitude")
There's no redefining anything. There's also no concept of 'predefined' attributes, or 'new' attributes. An attribute can be set on a frame, or obtained from a frame by name. There's a bit more going on behind the scenes, but the code is all available to read in the secure templates.
Let me know if that doesn't make any sense.
I guess what's throwing me off is shift-type1. Why bother setting type and spell? couldn't you just do SABTest:SetAttribute("shift-type1", "Lesser Heal") and the "type" in this line is related at all to the "type" set above. In the book it says there are predefined attributes like unit, type, and some others.
Also is "spell" made up or is that something predefined that has a special meaning? Could "spell" be called "berries" and still work the same?
-
Posted by jnwhiteh on Thu, 10 Jun 2010 17:45:10
type
is there to tell the SecureActionButtonTemplate what action is being taken. There are a number of actions, and it needs to know which one. Consider the following example:When
type
isitem
, the following code is run:SECURE_ACTIONS.item = function (self, unit, button) local item = SecureButton_GetModifiedAttribute(self, "item", button); if ( not item ) then -- Backwards compatibility code, deprecated but still handled for now. local bag = SecureButton_GetModifiedAttribute(self, "bag", button); local slot = SecureButton_GetModifiedAttribute(self, "slot", button); if ( bag and slot ) then item = bag.." "..slot; else item = slot; end end if ( item ) then local name, bag, slot = SecureCmdItemParse(item); if ( IsEquippableItem(name) and not IsEquippedItem(name) ) then EquipItemByName(name); else SecureCmdUseItem(name, bag, slot, unit); end end end;
It needs to look up what item you want to use, and it needs to distinguish this from spells. Now a completely different example, cancelling an aura:
SECURE_ACTIONS.cancelaura = function (self, unit, button) local index = SecureButton_GetModifiedAttribute(self, "index", button); if ( index ) then CancelUnitBuff(unit, index); else local spell = SecureButton_GetModifiedAttribute(self, "spell", button); local rank = SecureButton_GetModifiedAttribute(self, "rank", button); CancelUnitBuff(unit, spell, rank); end end;
The type is just telling the button what TYPE of action it's going to take, and then it knows where to look for more information about what to actually do.
-
Posted by galvin on Thu, 10 Jun 2010 20:45:02
So when setting buttons to do an action directly. so would these be valid?
/run SABTest:SetAttribute("shift-unit1", "Some spell here")
/run SABTest:SetAttribute("alt-type1", "another spell here")
but with those set you could still do?
/run SABTest:SetAttribute("type", "spell")
/run SABTest:SetAttribute("spell", "Lesser Heal")
Then do
/run SABTest:SetAttribute("ctrl-spell1", "spell")
Can "spell" be called something else or does it always have to be "spell" ?
-
Posted by jnwhiteh on Thu, 10 Jun 2010 21:09:03
So when setting buttons to do an action directly. so would these be valid?
/run SABTest:SetAttribute("shift-unit1", "Some spell here")
/run SABTest:SetAttribute("alt-type1", "another spell here")
No. In order to set a button to cast a spell, the following attributes must be set: *
unit
- Tells the system what unit to act on (set to "player" or such) *type
- Tells the system that you want to cast a spell (set to "spell") *spell
- Tells the system what spell to cast (set to "Lesser Heal")but with those set you could still do?
/run SABTest:SetAttribute("type", "spell")
/run SABTest:SetAttribute("spell", "Lesser Heal")
This sets the 'default' type to spell, and the 'default' spell to Lesser Heal. You probably don't mean this.
Then do
/run SABTest:SetAttribute("ctrl-spell1", "spell")
Can "spell" be called something else or does it always have to be "spell" ?
I'm not really sure I understand this question. You really shouldn't be doing things like this. Setting a button to cast a spell is very simple, and I suspect you've overcomplicating the issue.
if not SpellTestButton then -- Create and setup a spell button (run this once) CreateFrame("Button", "SpellTestButton", UIParent, "SecureActionButtonTemplate") SpellTestButton:SetSize(100, 100) SpellTestButton:SetPoint("CENTER", 0, 0) SpellTestButton:SetNormalTexture([[Interface\Icons\Spell_Holy_ImprovedResistanceAuras]]) SpellTestButton:RegisterForClicks("AnyDown") end -- Now set up some attributes on this button -- Set the unit for the button to be the 'focus' unit, so any actions -- that you take will be on that unit SpellTestButton:SetAttribute("unit", "focus") -- Set the button up so that an UNMODIFIED left-click will target the unit -- This means you can left-click on the button and the focus unit will be -- targeted. SpellTestButton:SetAttribute("type1", "target") -- Now set it up so you can cast spells, specifically set it so control-right-click -- casts Rejuvenation. SpellTestButton:SetAttribute("ctrl-type2", "spell") SpellTestButton:SetAttribute("ctrl-spell2", "Rejuvenation") -- Set a second spell, so shift-left-click casts Regrowth SpellTestButton:SetAttribute("shift-type1", "spell") SpellTestButton:SetAttribute("shift-spell1", "Regrowth")
The button will obviously do nothing if don't have a focus unit, so you'll need to type
/focus
to set a focus unit first. Then you'll be able to:- left-click to target your focus
- shift-left-click to cast regrowth on your focus
- ctrl-right-click to cast rejuvenation on your focus
Let's try to discuss and understand this example before we move on from it.
-
Posted by galvin on Thu, 10 Jun 2010 22:28:12
So when setting buttons to do an action directly. so would these be valid?
I'm not really sure I understand this question. You really shouldn't be doing things like this. Setting a button to cast a spell is very simple, and I suspect you've overcomplicating the issue.
if not SpellTestButton then -- Create and setup a spell button (run this once) CreateFrame("Button", "SpellTestButton", UIParent, "SecureActionButtonTemplate") SpellTestButton:SetSize(100, 100) SpellTestButton:SetPoint("CENTER", 0, 0) SpellTestButton:SetNormalTexture(<a href="/Interface_Icons_Spell_Holy_ImprovedResistanceAuras.html">Interface\Icons\Spell_Holy_ImprovedResistanceAuras</a>) SpellTestButton:RegisterForClicks("AnyDown") end
This is setting up the button yoy use on the screen. RegisterForClicks anydown means the button will respond on a downclick but not on an upclick.
-- Now set up some attributes on this button -- Set the unit for the button to be the 'focus' unit, so any actions -- that you take will be on that unit SpellTestButton:SetAttribute("unit", "focus")
Set the predefined attribute unit to the focus.
-- Set the button up so that an UNMODIFIED left-click will target the unit -- This means you can left-click on the button and the focus unit will be -- targeted. SpellTestButton:SetAttribute("type1", "target")
I guess this is where I got confused earlier. Cause I didn't think you could use type to bind it to a mouse click. So type and spell can be used in binding clicks to values I take it? these the only 2 predefined attributes that can be used like this?
-- Now set it up so you can cast spells, specifically set it so control-right-click -- casts Rejuvenation. SpellTestButton:SetAttribute("ctrl-type2", "spell") SpellTestButton:SetAttribute("ctrl-spell2", "Rejuvenation")
Would ("ctrl-type2", "Rejuvenation") work too? What i'm seeing is in some examples two lines of code to do a spell and in other examples one line of code that does the same thing. Why use "spell" if you can just put the actual spell in the bind to button instead? Anyway yeah I understand what it's doing.
-- Set a second spell, so shift-left-click casts Regrowth SpellTestButton:SetAttribute("shift-type1", "spell") SpellTestButton:SetAttribute("shift-spell1", "Regrowth")
The button will obviously do nothing if don't have a focus unit, so you'll need to type
/focus
to set a focus unit first. Then you'll be able to:- left-click to target your focus
- shift-left-click to cast regrowth on your focus
- ctrl-right-click to cast rejuvenation on your focus
Let's try to discuss and understand this example before we move on from it.
I may not be able to respond for a while raiding soon.
-
Posted by jnwhiteh on Thu, 10 Jun 2010 23:35:23
This is setting up the button yoy use on the screen. RegisterForClicks anydown means the button will respond on a downclick but not on an upclick.
Not quite. There are any number of buttons on a mouse, and any click has two directions. All of the following are valid:
- Button1Up
- Button1Down
- Button9Up
- Button13Down
Depending on how many mouse buttons you have (I have 15). You could register them individually passing multiple arguments in, as detailed on Button:RegisterForClicks()
This is register fro ALL buttons, and is saying to trigger on the down portion of the click, rather than waiting for the up portion of the click.
-- Now set up some attributes on this button -- Set the unit for the button to be the 'focus' unit, so any actions -- that you take will be on that unit SpellTestButton:SetAttribute("unit", "focus")
Set the predefined attribute unit to the focus.
There is no 'predefined'. All this code does is set the 'unit' attribute to the string 'focus'. In the context of the SecureActionButtonTemplate this mean something, but there's nothing 'special' about it, it's just an attribute.
-- Set the button up so that an UNMODIFIED left-click will target the unit -- This means you can left-click on the button and the focus unit will be -- targeted. SpellTestButton:SetAttribute("type1", "target")
I guess this is where I got confused earlier. Cause I didn't think you could use type to bind it to a mouse click. So type and spell can be used in binding clicks to values I take it? these the only 2 predefined attributes that can be used like this?
There ARE no predefined attributes. Chapter 15 goes through all of this stuff fairly well, I would suggest going back and reading the TEXT of that chapter again.
A SecureActionButton needs to know, first of anything, what type of action to take. There are a few predefined action types that the template is able to handle, such as casting a spell, targeting a unit or cancelling an aura. Anything that must be done in 'secure' code has a corresponding type.
Attributes in the SecureActionButton template can be prefixed by modifiers (ctrl, alt, etc.) and suffixed by a button. This is, when you right-click on a secure action button with no modifiers, it looks for the following attributes, in some order:
type2
*-type2
type*
*type*
Whichever one it finds first it will use to determine what action to take. When you set the type2 attribute, that means the
type
attribute for when the user right-clicks. In the same waytype1
would be for left-clicks andtype7
be a click with mouse button 7, whatever that is.-- Now set it up so you can cast spells, specifically set it so control-right-click -- casts Rejuvenation. SpellTestButton:SetAttribute("ctrl-type2", "spell") SpellTestButton:SetAttribute("ctrl-spell2", "Rejuvenation")
Would ("ctrl-type2", "Rejuvenation") work too? What i'm seeing is in some examples two lines of code to do a spell and in other examples one line of code that does the same thing. Why use "spell" if you can just put the actual spell in the bind to button instead? Anyway yeah I understand what it's doing.
No, absolutely not. You must specify the type, and then specify any additional information. It always requires two attributes to cast a spell with a secure button. Now, in some of the examples in the chapter, we use wildcards which can work for ANY modifier or ANY button, depending on how they're set up. Just because you don't see the lines together doesn't mean that it doesn't take two attributes. It always requires two attributes.
This is the explicit way of doing things. It's always clear, and it always works. It's unfortunate that some examples snuck through that use wildcards, thus making things a bit confusing, but what I'm showing you is always correct. It just may not be the 'shortest' way to do something, but the clarity is important.
-- Set a second spell, so shift-left-click casts Regrowth SpellTestButton:SetAttribute("shift-type1", "spell") SpellTestButton:SetAttribute("shift-spell1", "Regrowth")
The button will obviously do nothing if don't have a focus unit, so you'll need to type
/focus
to set a focus unit first. Then you'll be able to:- left-click to target your focus
- shift-left-click to cast regrowth on your focus
- ctrl-right-click to cast rejuvenation on your focus
Let's try to discuss and understand this example before we move on from it.
I may not be able to respond for a while raiding soon.
Well I'm off to bed so you've got plenty of time. I'll respond sometime tomorrow if you respond.
-
Posted by galvin on Fri, 11 Jun 2010 04:01:02
So if I understand this correctly these two examples would do the same thing
SABTest:SetAttribute("type", "spell")
SABTest:SetAttribute("spell", "attack")
SABTest:SetAttribute("shift-type1", "spell")
And doing it this way
SABTest:SetAttribute("type", "spell")
SABTest:SetAttribute("shift-spell1", "attack")
So the second line is setting the spell to attack and also making it so left click does the "attack".
And I take it spell could be called "myspell" or something, or does the button code look for "spell" specifically.
-
Posted by jnwhiteh on Fri, 11 Jun 2010 07:58:15
So if I understand this correctly these two examples would do the same thing
SABTest:SetAttribute("type", "spell")
SABTest:SetAttribute("spell", "attack")
SABTest:SetAttribute("shift-type1", "spell")
And doing it this way
SABTest:SetAttribute("type", "spell")
SABTest:SetAttribute("shift-spell1", "attack")
No, not really. I'm not sure what you're trying to do here.
So the second line is setting the spell to attack and also making it so left click does the "attack".
And I take it spell could be called "myspell" or something, or does the button code look for "spell" specifically.
The base attribute has to be spell. To cast a spell using the secure templates, you must have a type, a unit and a spell.
I am not sure why you are so interested in short examples. I also don't know why you're using something like 'attack' instead of a real spell name. Can we go back to my example rather than coming up with contrived ones. What you've done here doesn't really make any sense you'd never do this.
-
Posted by jnwhiteh on Fri, 11 Jun 2010 08:10:57
I suspect what you were attempting to do was explain the 'shorter' examples that you've seen. This is one such example:
-- Set the frame to always cast on 'focus', and to always cast spells frame:SetAttribute("unit", "focus") frame:SetAttribute("type", "spell") -- Set unmodified left-click to target the unit frame:SetAttribute("type1", "target") -- Regrowth on shift-leftclick and Rejuv on ctrl-rightclick frame:SetAttribute("shift-spell1", "Regrowth") frame:SetAttribute("ctrl-spell2", "Rejuvenation")
You could set as many mod-spellX attributes you want to define extra spells without having to specify the 'type' attribute each time, because of the default you gave at the start.
-
Posted by galvin on Fri, 11 Jun 2010 17:34:27
I suspect what you were attempting to do was explain the 'shorter' examples that you've seen. This is one such example:
-- Set the frame to always cast on 'focus', and to always cast spells frame:SetAttribute("unit", "focus") frame:SetAttribute("type", "spell") -- Set unmodified left-click to target the unit frame:SetAttribute("type1", "target") -- Regrowth on shift-leftclick and Rejuv on ctrl-rightclick frame:SetAttribute("shift-spell1", "Regrowth") frame:SetAttribute("ctrl-spell2", "Rejuvenation")
You could set as many mod-spellX attributes you want to define extra spells without having to specify the 'type' attribute each time, because of the default you gave at the start.
Yeah I realized that last night that you can use spell or type more than once for buttons. It made sense when I saw spell1 or spell2 cause those are for spells. But when I saw type being used the same way type1 or type2 it threw me off cause type says what type of action the button is going to be doing. Type could be macro or spell, but no specific spell. That's what the spell attribute is for.
So I thought only spell could be used in spell2 or spell1 etc for casting stuff. Then later I read that type1 or type2 can be used exactly the same way spell1 or spell2. Then though why bother doing this
frame:SetAttribute("type", "spell")
frame:SetAttribute("spell", "heal")
frame:SetAttribute("type1", "spell")
when you can do
frame:SetAttribute("type", "spell")
frame:SetAttribute("type1, "heal")
I got "attack" from the book it used it in some examples.
-
Posted by jnwhiteh on Fri, 11 Jun 2010 17:53:32
Yeah I realized that last night that you can use spell or type more than once for buttons. It made sense when I saw spell1 or spell2 cause those are for spells. But when I saw type being used the same way type1 or type2 it threw me off cause type says what type of action the button is going to be doing. Type could be macro or spell, but no specific spell. That's what the spell attribute is for.
So I thought only spell could be used in spell2 or spell1 etc for casting stuff. Then later I read that type1 or type2 can be used exactly the same way spell1 or spell2. Then though why bother doing this
frame:SetAttribute("type", "spell")
frame:SetAttribute("spell", "heal")
frame:SetAttribute("type1", "spell")
I wouldn't. I would just do:
frame:SetAttribute("spell", "heal") frame:SetAttribute("type1", "spell")
when you can do
frame:SetAttribute("type", "spell")
frame:SetAttribute("type1, "heal")
And the reason you don't just do
frame:SetAttribute("type", "spell")
is because you may be doing more than just casting spells. For example, the average button has:
- a way to target a unit
- a way to open a menu for the unit (right-click normally)
- ways to cast spells or take other actions
That's the 'target', 'menu' and 'spell' types. So rather than just specifying a
type
attribute, you be incredibly specific about what you're doing. -
Posted by galvin on Sun, 13 Jun 2010 06:13:42
So was reading a lot. I think I understand this a little more.
frame:SetAttribute("type", "spell")
frame:SetAttribute("spell", "heal")
frame:SetAttribute("type1", "spell")
So the 3rd line sets the value "spell" to type when the left button is clicked. Which would be doing the same thing line 1 did right?
So what would happen if the 3rd line did this?
frame:SetAttribute("type1" "greater heal")
Would this erase the original value "spell" that was set to type from line 1 when the left button is clicked?
Wish this stuff wasn't so hard to understand. a few years ago when i first saw this stuff it totally didn't make sense, and still having a hard time wrapping my head around it still.
And how come I need to add a blank line so text doesn't get all put on one line.
-
Posted by jnwhiteh on Sun, 13 Jun 2010 08:17:12
So was reading a lot. I think I understand this a little more.
frame:SetAttribute("type", "spell")
frame:SetAttribute("spell", "heal")
frame:SetAttribute("type1", "spell")
So the 3rd line sets the value "spell" to type when the left button is clicked. Which would be doing the same thing line 1 did right?
Yes, it would be pointless in this particular case.
So what would happen if the 3rd line did this?
frame:SetAttribute("type1" "greater heal")
Nothing. A
type
attribute HAS to be set to one of the type and a random spell name is not one of them. As I have said about 15 times in this thread, you need THREE attributes to cast a spell with a SecureActionButton. Atype
attribute, aspell
attribute and either an explicitunit
attribute, or an implicit one.Would this erase the original value "spell" that was set to type from line 1 when the left button is clicked?
No. You cannot overwrite anything other than by setting the same attribute. You can however mask it in configuration, but what you've written is not valid.
Wish this stuff wasn't so hard to understand. a few years ago when i first saw this stuff it totally didn't make sense, and still having a hard time wrapping my head around it still.
It is really very simple to understand, but you seem to keep jumping way ahead and trying to make connections where there are none.
To make a button cast a spell, you need three attribute. That's it, and that's always.
And how come I need to add a blank line so text doesn't get all put on one line.
That's markdown, it's just the way it works. If you turned the code into code lines it would be better.
-
Posted by galvin on Sun, 13 Jun 2010 17:14:47
Yet in examples I see type being used two times. Once to set the type for the button and again for a button click. But I also see examples where unit is also being used as a button click. But I think in that example it's the only time unit it used. Which makes me think any attribute can be used for button clicks? so far seen type, unit, and spell used for clicks.
What gets confusing is when you see the same attribute used in two different ways.
Can't move on till I fully understand this stuff. Even read a different book on the same thing, but didn't really clear things up.
Attribute("type1", "greater heal")
Said this wouldn't work, but I did an example where type1 did bandages and it worked. So if it works for bandages it should work for a spell too.
Don't know how to do code lines. When I press the code button I get ``. And I tried placing those around my text but doesn't do anything.
-
Posted by jnwhiteh on Sun, 13 Jun 2010 21:15:21
Attribute("type1", "greater heal")
Said this wouldn't work, but I did an example where type1 did bandages and it worked. So if it works for bandages it should work for a spell too.
This doesn't work. It just doesn't. It didn't for bandages, and it won't for spells. If you believe it did, you are almost certainly mistaken and were activating some previously set attribute. This will not work. I can't make that any clearer.
Don't know how to do code lines. When I press the code button I get ``. And I tried placing those around my text but doesn't do anything.
Highlight the line of code in your editor and click the code button. The entire line.
-
Posted by galvin on Sun, 13 Jun 2010 21:48:35
Attribute("type1", "greater heal")
Said this wouldn't work, but I did an example where type1 did bandages and it worked. So if it works for bandages it should work for a spell too.
This doesn't work. It just doesn't. It didn't for bandages, and it won't for spells. If you believe it did, you are almost certainly mistaken and were activating some previously set attribute. This will not work. I can't make that any clearer.
Don't know how to do code lines. When I press the code button I get ``. And I tried placing those around my text but doesn't do anything.
Highlight the line of code in your editor and click the code button. The entire line.
Page 296 at the bottom. This line /run SABTest:SetAttribute("shift-type1", "spell")
Only difference is it using the value of spell that was set to "Lesser Heal" instead of just using "Lesser heal" it's self on line 5.
in the example type and spell are being used two times. Once to set values to them and again to set a click to them.
-
Posted by jnwhiteh on Sun, 13 Jun 2010 21:55:38
Please just wait. I'm working on a mega post to explain this to you, but you're completely mixing things up.
Nowhere in that entire example is a
type
attribute set to a spell or an item name. That's just false and as I've explained over and over again it will not work.I'm working on a huge explanation, check back in 5 minutes.
-
Posted by jnwhiteh on Sun, 13 Jun 2010 21:57:43
I am going to explain, once more, and likely for the last time, how the SecureActionButton template works. You can ask questions, but I'm afraid I just don't have time to commit to rewriting the material that is already in the book. The amount of support I can provide is limited.
DO NOT READ THIS SECTION AND THINK ABOUT THE CODE YOU'VE SEEN OR THE CODE YOU WANT TO WRITE. JUST READ THE CONTENT AND UNDERSTAND THE EXAMPLES AS THEY ARE GIVEN. WE CAN GET TO COMPARING THINGS AS WE MOVE FORWARD, BUT IT WOULD BE USELESS RIGHT NOW TO CONFUSE THINGS. PLEASE TRY TO NOT USE YOUR SPECIAL TERMINOLOGY WHEN DISCUSSING THESE THINGS, IT JUST CONFUSES MATTERS BECAUSE IT IS NOT ACCURATE.
SecureActionButton template
The
SecureActionButton
is an XML template that exists in Blizzard's FrameXML code. This template is specially designed to allow the user to pre-program a button to take certain protected actions. For the purposes of our discussion, we will limit this to:- Targeting a unit
- Casting a spell on a unit
- Using an item (possibly on a unit)
Attributes
This is accomplished using a series of attributes. Attributes can be set on a frame in a way that is very similar to a dictionary. There are two things that can be done with attributes:
- Set an attribute (it may be set to nil to clear it)
- Get an attribute
Really think of this as a dictionary. You are given a word, let's call it 'monkey' and you ask the dictionary for the definition of that word. The dictionary tells you (by you looking at it) that a monkey is defined as "Any of various long-tailed, medium-sized members of the order Primates, including the macaques, baboons, guenons, capuchins, marmosets, and tamarins...". Furthermore you can look up a work such as 'frabloygai' and will see that it does not have a definition; it is not set. This is precisely how attributes work.
Hopefully you understand that. The following are always true:
-- Set the attribute 'foo' on the button to the string "bar" frame:SetAttribute("foo", "bar") -- Check the value of the attribute print(frame:GetAttribute("foo") == "bar") -- This will print true to the chat frame.
That is once you've set an attribute it will persist until someone again tries to set the attribute WITH PRECISELY THE SAME NAME. I can set the attribute 'foo2' and it will in no way affect the attribute 'foo', they're completely different.
How does the SecureActionButton work?
Now that we hopefully understand how attributes work, we can look at the way the secure action buttons function. For the purposes of our discussion we will only consider a portion of the template since it can do lots of magical things. I want you to ONLY focus on what we're talking about here. Once you understand this, and understand it fully we can answer any other questions that you have, but this much is absolutely imperative.. and should not be difficult to understand.
This is a simplified overview, just read it and then move onto the next section. It should all be self explanatory.
There is a script set on all buttons that inherit from
SecureActionButton
that does the following:- Look up the
type
attribute set on the frame - Check to see if the attribute is set to an action we know how to take, for
example:
- Cast a spell when the
type
attribute is the string "spell" - Target a unit when the
type
attribute is the string "target" - Use an item when the
type
attribute is the string "item"
- Cast a spell when the
- Look up any additional attributes that are needed to actually take the
action:
- For the "spell" type, we need to look up the
spell
attribute and theunit
attribute. If theunit
attribute is not set but auto-self-casting is enabled, the spell will be cast on the player (eventually). - For the "target" type, we need to look up the
unit
attribute so we know which unit we need to target. This is how we distinguish between targeting two different party members, for example. - For the "item" type, we need to look up the name of the item in the
item
attribute. Failing that, we can look up thebag
attribute and theslot
attribute that allow us to specify a slot in a given bag, the item in which will be used.
- For the "spell" type, we need to look up the
- Using super-Blizzard-secure magic (since Blizzard code can take protected actions in combat and we cannot), take the action that was specified.
Without this template, there would be no way to create a simple unit frame that allows us to click on it to target a unit. Addon code can no longer call the
TargetUnit
function directly, so we need Blizzard template support in order to do even these simple protected tasks.Up until this point...
So at this point we have a picture of how you can program a button to take a specific action, but there are no details about how to take more than one action for a given button. Up until this point we've only looked at the base attributes, like
type
andspell
. These can always be set and then will allow the button to take a SINGLE action. If you want to do different things, such as targeting a unit when left-click while casting a spell when right-clicked, you'll need to use modified attributes.Modified Attributes with Different Buttons
Modified attributes are used by the secure template system in order to allow different actions to be taken under different conditions. The simplest example of this is changing behavior based on which mouse button was used to click the frame.
When an in-game button is clicked, the game sends a string that indicates which mouse button was used to click the frame. This could be any of the following:
- "LeftButton"
- "RightButton"
- "MiddleButton"
- "Button4"
- "Button5"
- ...
- "Button31"
These buttons are then converted using the
SecureButton_GetButtonSuffix
function from their names to a simpler string. For example, the buttons above would become:- "1"
- "2"
- "3"
- "4"
- "5"
- ...
- "31"
So let's elaborate on what actually happens in the
SecureActionButton
'sOnClick
handler. I did not lie when I said if we're looking for thetype
attribute that it looks for whatever was set with the specific keytype
. In reality what it does it a bit more complicated.The handler actually tries to look up the
type
attribute, with the button number added to the end. So if you left-click on the button, it looks up thetype1
attribute. If you right-click on the button, it looks up thetype2
attribute, and so on. If you have 14 buttons and you click using yourButton14
, then it will look up thetype14
attribute.The template, however, is smart enough to know that it may not find a value set for that given attribute. Therefore it knows enough to "fall back" on the base attribute, which is
type
. This lets us do the following on a unit frame. Do not try to set these attributes right now, especially on an existing unit frame. The attributes that are already set on the frame make things more complicated and that is not useful to us right now. This is about understanding and you don't need to type to do that.frame:SetAttribute("unit", "player") frame:SetAttribute("type", "spell") frame:SetAttribute("spell", "Greater Heal") frame:SetAttribute("type1", "target")
DO NOT READ AHEAD. DO NOT TRY TO EXTEND THIS. DO NOT TRY TO CHANGE IT. JUST CONTINUE READING. THIS IS SIMPLY AN EXAMPLE..
Assume these are the ONLY attributes that are set on the frame. Now ask yourself what happens in the following situations:
- What happens when the user left-clicks on the button?
- What happens if the user right-clicks on the button?
- What happens if the user clicks on the button with
Button14
?
In the first case, the template tries to look up the
type1
attribute, since the left mouse button is button "1". It finds this set and sees the value "target". It needs to know which unit to target, so it looks up theunit1
attribute (again, because it checks the more specific attribute first) and sees that it is not set. It then looks up the base attributeunit
, and finds the value "player". Thus, when this button is left-click it will change the player's target to the player itself.In the second case, when the button is right-clicked, the template will look up the
type2
attribute, since the right mouse button is button "2". It sees that this attribute is not set, so it looks up the base valuetype
. It finds this set to the value "spell". The template now knows it needs to look up spell and unit information, so it queries thespell2
attribute first. Not finding it, it then looks for the base attributespell
. It finds this set to "Greater Heal". Finally the template looks up theunit2
attribute, and then falls back to theunit
attribute when it's not found. Thus, when right-clicked, this button will cast Greater Heal on the player.Precisely the same sequence of events happens when click on the frame with any button that is not the left-button, other than the attribute that is first queried. In the example of
Button14
, it queries thetype14
,spell14
and possibly theunit14
attribute. The same applies to the different buttons.Another way of doing it...
The above example could have been written differently:
frame:SetAttribute("unit", "player") frame:SetAttribute("type2", "spell") frame:SetAttribute("spell2", "Greater Heal") frame:SetAttribute("type1", "target")
However, this button does something quite different. Although the functionality is the same for left-click and right-click, the button is no longer programmed to do anything for any other button click. The
type
attribute is not set, which means the template does not know what to do.Since the template only checks the specific button that was clicked and then the base template, clicking with
Button14
will query thetype14
attribute, then thetype
attribute, neither of which is set. Thus the button will do nothing when clicked with the other buttons.Summary
That's step #1. If we can get you past that we can move onto using the Control, Alt and Shift keys to modify clicks as well, although they function is almost the same way as the button modifiers.
-
Posted by galvin on Sun, 13 Jun 2010 22:55:08
Yeah that explained some things I didn't know. The main thing was when say a left button is clicked it looks for a type1 first then type if it doesn't find it. So knowing how it looks things up on clicks helps remove a lot of confusion. Thanks for that post was most helpful.
-
Posted by jnwhiteh on Sun, 13 Jun 2010 22:57:53
I'm glad it could help. You should note that the same happens with modifiers, but it's a but more complicated since they're overly specific.
The attribute
alt-type1
will be found when someone clicks on the button with the left mouse button and they are holding down the alt-key. If the user, however, is holding down more keys than that (for example alt-shift) then it will not be found, because it doesn't match alt-shift-type1 or type1.Wildcards are another messy business, but most of the problem really comes from when you're trying to alter buttons that already have attributes set. Attributes don't really go away, and you'd have to have the SPECIFIC name of the attribute you want to overwrite, if you want to, for example, clear it.
Thanks for reporting back.