Thread Tools Display Modes
12-06-17, 10:20 AM   #1
vis781
A Fallenroot Satyr
Join Date: Dec 2017
Posts: 27
Dynamic frame resize, whilst in combat?

Hi there, first post here and a newbie member so thank you for taking the time to read this..

I am an experienced asm/c/c++ programmer that loves wow and am having a go at writing my first addon. I have no problems with events, frames, textures and understanding coding in general.

The problem I have is this.. I am creating a target unit frame ( a simple one ) and all I want it to do right now is dynamically change its width based on the width of the targets name. I have the frame with some text for the name of the target all doing what it should except for combat... now you see my problem, I can't change the width of the frame whilst in combat to match the width of the new targets name, not allowed and I get why.

Thing is I have seen frames dynamically resize whilst in combat.. i.e raid frames, so it must be possible...

Now I think I need to be involved with RegisterStateDriver and secure frame wrapscript etc.. I mean I have a secure frame, that's easy, and I understand setting attributes, however I don't know how to respond to a change of target in the frames secure environment. I do hope this makes sense.. or you get the idea of what i'm trying to do.... should be simple to do I think, but I just can't see it.

Thank you all for reading

Kind regards

v

p.s I have posted this in the wrong forum, I'm very sorry, could a mod please move it for me? Thank you.

Last edited by vis781 : 12-06-17 at 10:23 AM. Reason: typo, posted in wrong forum ( sorry )
  Reply With Quote
12-06-17, 10:52 AM   #2
Kanegasi
A Molten Giant
 
Kanegasi's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2007
Posts: 666
Anything clickable for combat, such as buttons or in this case the target frame, cannot be altered while in combat. The raid frames adding people in combat is Blizzard's secure code, which is why they can change. There is very limited options for custom secure code, and moving/resizing is not included.

If you're okay with making a custom target frame that can't be clicked, then you can do whatever you want to it in combat. It could also be possible for a custom static frame with 0 alpha overlaying a frame that can't be clicked, so you can make it look like the target frame is clickable but can still resize visually, but that's beyond me.
  Reply With Quote
12-06-17, 11:01 AM   #3
vis781
A Fallenroot Satyr
Join Date: Dec 2017
Posts: 27
Oh, so it's not possible. That's a pain! The problem with an overlay frame is that it would have to be anchored to the secure frame, which as I understand it would make the overlay frame implicitly secure too, if I have understood correctly.

It'a a shame it can't be done. I've seen examples of wrapping arbitrary insecure snippets using 'secureFrame:WrapScript' which essentially executes addon insecure code in a secure environment, actually SUF does exactly that, but it would take a long time to pick out how it works. I just can't find enough information on it to know if it's something I can use.

Thank you for your reply.
  Reply With Quote
12-06-17, 11:17 AM   #4
Kanegasi
A Molten Giant
 
Kanegasi's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2007
Posts: 666
You wouldn't need to anchor the overlay. Just make two separate frames with manually set coordinates relative to something like UIParent at the same location. The secure frame on top doesn't resize, has 0 alpha, and accepts the clicks while the unsecure frame underneath acts like a background displaying the target name and resizes width accordingly. I'm just tossing the idea out.
  Reply With Quote
12-06-17, 11:23 AM   #5
vis781
A Fallenroot Satyr
Join Date: Dec 2017
Posts: 27
Yea, it's a good idea, and it's very likely that it would work fine. I haven't tested it yet but I can't think of a reason why it wouldn't work. You know when you start down a path have to have to solve the problem? That's where I got to with this.... as much as I wanted to understand secure frame handling better. It's going to be a bigger and bigger part of wow I would imagine and it seems important to understand it.

I will try your idea, thank you. In the mean time could you help me with understanding secure frames a bit better... with a snippet I can try? Preferably using the WrapScript method so I can start to understand what it would be used for.

Thanks
  Reply With Quote
12-06-17, 11:53 AM   #6
aallkkaa
A Warpwood Thunder Caller
 
aallkkaa's Avatar
AddOn Author - Click to view addons
Join Date: Jun 2017
Posts: 98
Originally Posted by vis781 View Post
I will try your idea, thank you. In the mean time could you help me with understanding secure frames a bit better... with a snippet I can try? Preferably using the WrapScript method so I can start to understand what it would be used for.
I myself can't really help all that much (I don't understand it well enough yet), but a while ago I had a problem to solve for which MunkDev gave me a ready sollution, which showcases the use of securestatedriver() and restricted environment pretty well, I believe.
For context, my purpose was: when in an actionbar page other than 1, after clicking a button on said page, automatically switch back to page 1 (something you can do with a macro, for each button, like /cast <spell> /changeactionbar 1).
This is what I got from MunkDev:
Originally Posted by MunkDev View Post
I tinkered a bit more with this and you can actually do the same thing with just one button that uses a state driver, a wrapped PreClick and a custom identifier passed as the 'button' argument to the click script.

This solution only uses one secure button, does what you want, and the only drawback is that it won't trigger the first time if you're on a swap page when changing key bindings. This method also works when changing key bindings in combat.

Lua Code:
  1. local header = CreateFrame('Button', 'AllInOneActionButton', nil, 'SecureHandlerBaseTemplate, SecureHandlerStateTemplate, SecureActionButtonTemplate')
  2. header:RegisterForClicks('AnyUp', 'AnyDown') -- process both press and release of an arbitrary key
  3. header:SetAttribute('action', 1) -- this attribute will be used in conjunction with 'actionbar' to swap the bar back
  4.  
  5. do  -- generate a state driver condition with generic values to ensure any bar change pushes an update.
  6.     -- the actual bar ID check is done in the _onstate-actionpage function body instead.
  7.     -- this method seems to work regardless of API changes that cause
  8.     -- some of these macro conditions to shift around on certain specs.
  9.     local conditionBase, driver = '[%s] %d; ', ''
  10.     local conditions = {
  11.         ----------------------------------
  12.         'vehicleui', 'possessbar', 'overridebar', 'shapeshift',
  13.         'bar:2', 'bar:3', 'bar:4', 'bar:5', 'bar:6',
  14.         'bonusbar:1', 'bonusbar:2', 'bonusbar:3', 'bonusbar:4'
  15.         ----------------------------------
  16.     }
  17.     -- concatenate conditions into a long macro condition that can be
  18.     -- evaluated by the state driver and send updates to the header.
  19.     -- e.g. "[vehicleui] 1; [possessbar] 2; [overridebar] 3;" etc.
  20.     for i, macroCondition in ipairs(conditions) do
  21.         driver = driver .. conditionBase:format(macroCondition, i)
  22.     end
  23.     ----------------------------------
  24.     -- append the list for the default bar (1) when none of the conditions apply.
  25.     driver = driver .. (#conditions + 1)
  26.  
  27.     -- register the state driver to handle page updates
  28.     RegisterStateDriver(header, 'actionpage', driver)
  29. end
  30.  
  31. -- set up the _onstate-actionpage function body that sets the new actionpage ID.
  32. -- this is a rewrite of the response in ActionBarController_UpdateAll.
  33. -- state drivers use the _onstate-<name> attribute when looking for the function body to run.
  34. -- 'newstate' is the argument passed to all state drivers expressing the outcome
  35. -- of the registered condition, but in this case it's overwritten by the page calculation.
  36. -- note that all code in a restricted environment is written as strings and compiled in
  37. -- real time using loadstring(), to ensure you don't have access to unrestricted API.
  38. header:SetAttribute('_onstate-actionpage', [[
  39.     -- update actionpage
  40.     if HasVehicleActionBar() then
  41.         newstate = GetVehicleBarIndex()
  42.     elseif HasOverrideActionBar() then
  43.         newstate = GetOverrideBarIndex()
  44.     elseif HasTempShapeshiftActionBar() then
  45.         newstate = GetTempShapeshiftBarIndex()
  46.     elseif GetBonusBarOffset() > 0 then
  47.         newstate = GetBonusBarOffset() + 6
  48.     else
  49.         newstate = GetActionBarPage()
  50.     end
  51.     self:SetAttribute('actionpage', newstate)
  52.  
  53.     -- update bindings
  54.     self:ClearBindings()
  55.     for i=1, 12 do
  56.         local key = GetBindingKey('ACTIONBUTTON' .. i)
  57.         if key then
  58.             self:SetBindingClick(false, key, self, tostring(i))
  59.         end
  60.     end
  61. ]])
  62.  
  63. -- wrap the preclick script on the header
  64. -- use the inherent 'button' argument to tell the header
  65. -- which action button you want to simulate.
  66. -- since PreClick runs before OnClick, you're able to change
  67. -- what the button should do while you're pressing it.
  68. header:WrapScript(header, 'PreClick', [[
  69.     if down then
  70.         -- set up the downpress attributes to perform the action first
  71.         self:SetID(tonumber(button)) -- see ActionButton_CalculateAction
  72.         self:SetAttribute('type', 'action')
  73.     else
  74.         -- set the type to actionbar on release, which swaps the bar back
  75.         self:SetAttribute('type', 'actionbar')
  76.     end
  77.     self:CallMethod('OnButtonPressed', down, button)
  78. ]])
  79.  
  80. -- finally, execute the actionpage response on load,
  81. -- to set the correct action page and your override bindings.
  82. -- 'Execute' is included in the SecureHandlerBaseTemplate,
  83. -- and allows you to execute code in a restricted environment.
  84. header:Execute(header:GetAttribute('_onstate-actionpage'))
  85.  
  86. -- this function is called from the preclick script,
  87. -- which visually indicates a button press on your bar.
  88. -- this part isn't functionally necessary,
  89. -- it just makes it look like you're pressing regular buttons,
  90. -- when you're actually pressing your hidden button.
  91. function header:OnButtonPressed(down, id)
  92.     local button = GetActionButtonForID(id)
  93.     if button then
  94.         if down and button:GetButtonState() == 'NORMAL' then
  95.             button:SetButtonState('PUSHED')
  96.         elseif not down and button:GetButtonState() == 'PUSHED' then
  97.             button:SetButtonState('NORMAL')
  98.         end
  99.     end
  100. end
I have done some very minor tweaking to it since (the code above borks OverrideActionBar - easy to fix; I also tried printing to the UIErrorsFrame ( UIErrorsFrame:AddMessage() ) on which page I was on but that didn't work - works fine with print() to the chat frame though - global frames don't seem to "exist" in the restricted environment).
You can see a list of attributes to use in: https://wow.gamepedia.com/SecureActionButtonTemplate
MunkDev also linked a very helpful (albeit not enough for my lack of coding-skills ) free ebook about the restricted environment: Iriel's Field Guide to Secure Handlers

Hope that helps!
  Reply With Quote
12-06-17, 12:13 PM   #7
vis781
A Fallenroot Satyr
Join Date: Dec 2017
Posts: 27
Thanks, and interesting that you posted that link, as it was the very one I was just reading! and it gives me hope... according to the article it is possible to SetWidth and SetHeight of frames during combat. It says so clearly in the article... the restriction is.. as far as I can tell without testing that..

a) It must be a precompiled "snippet" string of lua code.
b) the frame must be first made available to the secure environment ( which now I know is nothing but a sandbox ) by using Header.SetFrameRef(..) and then inside the snippet the frame can be referenced with Header.GetFrameRef(..)

From there the handle returned can ( if i'm correct ) be used to manipulate many of the frames properties..

i.e Width/Height/Show/Hide/Alpha to name just a few... No moving though.. but that makes sense.

I will try to make a test addon tonight and have it changed the width of a frame during combat, and see if it works.. If so I'll post the code here for anyone to use.

Hopefully it'll work!
  Reply With Quote
12-06-17, 12:27 PM   #8
vis781
A Fallenroot Satyr
Join Date: Dec 2017
Posts: 27
Incidentally, I was way off with thinking WrapScript was the answer..... all it does it "wrap" an existing script handler allowing you to place pre and post snippets of code around it. Kinda makes sense I suppose.
  Reply With Quote
12-06-17, 12:41 PM   #9
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
You can change secure attributes in combat, however only in under certain conditions (everything that a macro can do), and you can only access certain functions in the restricted environment, and you can only access your own secure references that you can only set out of combat and while logging into the game, or if your secure reference is a frame you can only access it's sub-methods limited too. UnitName() which would be the handler here for the changes you want to make, is not accessible. So it's not possible.

Last edited by Resike : 12-06-17 at 12:49 PM.
  Reply With Quote
12-06-17, 12:48 PM   #10
aallkkaa
A Warpwood Thunder Caller
 
aallkkaa's Avatar
AddOn Author - Click to view addons
Join Date: Jun 2017
Posts: 98
Interestingly enough, SetWidth/SetHeight, as well as GetWidth/GetHeight do work in the sandboxed (as you very well put it) restricted environment; SetSize/GetSize however do not.

There's a nice listing of what's available in a restricted environment here: https://wow.gamepedia.com/RestrictedEnvironment

Secure handler templates will give you a few more methods: https://wow.gamepedia.com/SecureHandlers (see bottom of page for more info on specific templates).

And... you have the "source" (if I'm not mistaken: the source is actualy in C, I believe, and unavailable; these are the Lua equivalents of the proper source). There is a Blizzard-provided tool for the purpose of extracting the data but I forgot what it is. I do remember it is a lengthy process (lots of data) and some people have kindly posted it on the Internet anyway. For example: https://www.townlong-yak.com/framexml/ptr - RestrictedEnvironment.lua and other Restricted*.lua files should be of interest.
  Reply With Quote
12-06-17, 12:51 PM   #11
vis781
A Fallenroot Satyr
Join Date: Dec 2017
Posts: 27
Oh, so you're saying it's possible to change the frame just fine, but there would be no way for me to get the with of the string in to the secure snippet?

You are absolutely right... there isn't.

Well, glad I didn't sit here all night trying to get that to work..

Thanks for the reply and saving me the time.
  Reply With Quote
12-06-17, 12:55 PM   #12
vis781
A Fallenroot Satyr
Join Date: Dec 2017
Posts: 27
Wait a sec... you're saying that the Blizzard function UnitName is not callable from a secure snippet? But why not, that actually doesn't make sense at all.
  Reply With Quote
12-06-17, 01:51 PM   #13
vis781
A Fallenroot Satyr
Join Date: Dec 2017
Posts: 27
Rightio, for anyone that might be interested in how to accomplish this, here is the quicker and much dirtier answer.....

No need to worry about changing the size of the frame itself. Since texture are not clipped to the frame and they can "live" outside of it, one solution is to have the frame the size of your portrait and then set textures for the fill and border. Simply then anchor the textures to the right side of the fontstring and hey presto. The frame then appears to change size in response to the width of the string ( the targets name in this case ) The only caveat is that the only part of the frame that is clickable is the portrait itself, which in and of itself is desirable is this case... less chance of a random, mid-battle misclick.

There we go, if you can't to do it properly... hack!

V
  Reply With Quote
12-06-17, 03:05 PM   #14
aallkkaa
A Warpwood Thunder Caller
 
aallkkaa's Avatar
AddOn Author - Click to view addons
Join Date: Jun 2017
Posts: 98
Originally Posted by vis781 View Post
Oh, so you're saying it's possible to change the frame just fine, but there would be no way for me to get the with of the string in to the secure snippet?
Erm, no, that's not what I was saying. This is what I was saying:
Code:
local width, height = frame:GetSize()
is exactly the same as:
Code:
local width, height = frame:GetWidth(), frame:GetHeight()
BUT only the later works in a restricted environment (i.e. for a frame that inherits from a secure template).
  Reply With Quote
12-06-17, 03:09 PM   #15
aallkkaa
A Warpwood Thunder Caller
 
aallkkaa's Avatar
AddOn Author - Click to view addons
Join Date: Jun 2017
Posts: 98
Originally Posted by vis781 View Post
Wait a sec... you're saying that the Blizzard function UnitName is not callable from a secure snippet? But why not, that actually doesn't make sense at all.
If you're saying that because said function isn't on the list provided in Wowpedia, well... that's a user-maintained wiki, it's NOT official. It may, and often will, be incomplete or out of date.
The FrameXML source is The Book for that. Only, it can be a pain to get...
  Reply With Quote
12-06-17, 03:11 PM   #16
aallkkaa
A Warpwood Thunder Caller
 
aallkkaa's Avatar
AddOn Author - Click to view addons
Join Date: Jun 2017
Posts: 98
Originally Posted by vis781 View Post
Rightio, for anyone that might be interested in how to accomplish this, here is the quicker and much dirtier answer.....

No need to worry about changing the size of the frame itself. Since texture are not clipped to the frame and they can "live" outside of it, one solution is to have the frame the size of your portrait and then set textures for the fill and border. Simply then anchor the textures to the right side of the fontstring and hey presto. The frame then appears to change size in response to the width of the string ( the targets name in this case ) The only caveat is that the only part of the frame that is clickable is the portrait itself, which in and of itself is desirable is this case... less chance of a random, mid-battle misclick.

There we go, if you can't to do it properly... hack!

V
LOL. That's the spirit!
Or rather, KISS.
  Reply With Quote
12-06-17, 04:07 PM   #17
Ammako
A Frostmaul Preserver
AddOn Author - Click to view addons
Join Date: Jun 2016
Posts: 256
Originally Posted by aallkkaa View Post
If you're saying that because said function isn't on the list provided in Wowpedia, well... that's a user-maintained wiki, it's NOT official. It may, and often will, be incomplete or out of date.
The FrameXML source is The Book for that. Only, it can be a pain to get...
Not really, you just add -console argument to your game settings on battle.net app and "exportInterfaceFiles code" on character select screen. Takes the better part of 30 seconds.

Townlong-Yak is useful though for the diffs, and you can probably just work straight off of it without dumping the files yourself. But dumping it yourself you get more than just the FrameXML too, so there's that.

Last edited by Ammako : 12-06-17 at 04:09 PM.
  Reply With Quote
12-06-17, 04:22 PM   #18
Kanegasi
A Molten Giant
 
Kanegasi's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2007
Posts: 666
Originally Posted by Ammako View Post
Townlong-Yak is useful though for the diffs, and you can probably just work straight off of it without dumping the files yourself. But dumping it yourself you get more than just the FrameXML too, so there's that.
Another very useful part of townlong-yak is the "Helix" folder, included alongside all the other FrameXML folders. It's where the maintainer of t-y keeps special extracts, such as a full list of every event, every function, all "constants" (ALL_CAPS variables containing only numbers and IDs), widgets and their functions (like FontString, buttons, etc), "atlas" info (basically a bunch of tiny icons within larger images, like how Minecraft stores their icons), and a list of texture paths matched with their new file IDs. Unfortunately, they only have the texture IDs, atlasinfo, and event list available. They haven't extracted the others in a few months.
  Reply With Quote
12-06-17, 06:41 PM   #19
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by vis781 View Post
Wait a sec... you're saying that the Blizzard function UnitName is not callable from a secure snippet? But why not, that actually doesn't make sense at all.
It makes sense since somebody could come up with an secure automation based on the unit's name. CC unit X, nuke unit Y, heal unit Z with a single button. This was entirely possible (and even a lot nastier things too) up to WotLK.

Last edited by Resike : 12-06-17 at 06:44 PM.
  Reply With Quote
12-06-17, 06:51 PM   #20
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 431
Originally Posted by vis781 View Post
Wait a sec... you're saying that the Blizzard function UnitName is not callable from a secure snippet? But why not, that actually doesn't make sense at all.
This actually makes perfect sense. This is the type of data that can be used to extend the functionality of the environment, which is why it's intentionally left out. For example, you could map buttons to do specific things when targeting specific mobs, instead of having to make the decision of what to cast yourself.

Here's a list of what's available:
https://www.townlong-yak.com/framexm...ronment.lua#74
__________________
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Dynamic frame resize, whilst in combat?

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off