View Single Post
03-26-14, 08:39 PM   #1
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
Spellflyout, SpellFlyout_Toggle, and taint

Hello all

I'm stuck with a bad problem again.


My intention is to use Blizzards spellflyout feature, and to modify the layout of the flyout itself if the flyout buttons are shown (means: the expanding list of spells).

My first approach was this:

Lua Code:
  1. SecureHandler_OnLoad(_G["SpellFlyoutButton1"])
  2. _G["SpellFlyoutButton1"]:WrapScript(_G["SpellFlyoutButton1"], "OnShow", [[
  3.     local flyoutButtonSize = 29
  4.     local rangeFromAButton = 5
  5.     local t = string.sub(self:GetName(), 18)
  6.     local degrees = self:GetParent():GetParent():GetAttribute("degree") * 3.14159265 / 180
  7.     local nx = math.cos(degrees) - (((flyoutButtonSize * t) + rangeFromAButton) * math.sin(degrees))
  8.     local ny = math.sin(degrees) + (((flyoutButtonSize * t) + rangeFromAButton) * math.cos(degrees))
  9.     if self then
  10.         self:ClearAllPoints()
  11.         self:SetPoint("CENTER", self:GetParent():GetParent(), "CENTER", nx, ny)
  12.     end
  13. ]])

SpellFlyoutButton1 is the first of the expanding flyout buttons, and the solution works very well for the first button. The buttons new position is exactly as expected.

But ... there's a problem with the next buttons (a flyout can have a lot of buttons as you know). If the UI loads then only the first of the buttons (SpellFlyoutButton1) is created. All other buttons are created 'on the fly' if they are really needed.

Here's a part of the code for this from the Blizz interface file SpellFlyout.lua ("Createframe" at the bottom):

Lua Code:
  1. function SpellFlyout_Toggle(self, flyoutID, parent, direction, distance, isActionBar, specID, showFullTooltip)
  2.     if (self:IsShown() and self:GetParent() == parent) then
  3.         self:Hide();
  4.         return;
  5.     end
  6.  
  7.     local offSpec = specID and (specID ~= 0);
  8.    
  9.     -- Save previous parent to update at the end
  10.     local oldParent = self:GetParent();
  11.     local oldIsActionBar = self.isActionBar;
  12.  
  13.     local _, _, numSlots, isKnown = GetFlyoutInfo(flyoutID);
  14.     local actionBar = parent:GetParent();
  15.     self:SetParent(parent);
  16.     self.isActionBar = isActionBar;
  17.  
  18.     -- Make sure this flyout is known or we are showing an offSpec flyout
  19.     if ((not isKnown and not offSpec) or numSlots == 0) then
  20.         self:Hide();
  21.         return;
  22.     end
  23.    
  24.     if (not direction) then
  25.         direction = "UP";
  26.     end
  27.    
  28.     -- Update all spell buttons for this flyout
  29.     local prevButton = nil;
  30.     local numButtons = 0;
  31.     for i=1, numSlots do
  32.         local spellID, overrideSpellID, isKnown, spellName, slotSpecID = GetFlyoutSlotInfo(flyoutID, i);
  33.         local visible = true;
  34.        
  35.         -- Ignore Call Pet spells if there isn't a pet in that slot
  36.         local petIndex, petName = GetCallPetSpellInfo(spellID);
  37.         if (isActionBar and petIndex and (not petName or petName == "")) then
  38.             visible = false;
  39.         end
  40.        
  41.         if ( ((not offSpec or slotSpecID == 0) and visible and isKnown) or (offSpec and slotSpecID == specID) ) then
  42.             local button = _G["SpellFlyoutButton"..numButtons+1];
  43.             if (not button) then
  44.                 button = CreateFrame("CHECKBUTTON", "SpellFlyoutButton"..numButtons+1, SpellFlyout, "SpellFlyoutButtonTemplate");
  45.             end

Now the problem: Obviously I can't set up my WrapScript before the button exists. So I have to listen if the player clicks on a flyout button for the first time (for example via hooking "SpellFlyout_Toggle" - see above) and to apply my script then. Unfortunately this could happen if the player is in combat. And if I then set the WrapScript everything is tainted. :/

The only possible way to work around this I can think of is to force the creation of all flyout buttons before the player enters combat.
My first approach to do this was calling SpellFlyout_Toggle() with a set of suitable arguments to initiate the frame creation. Which worked fine. I've managed it to call the function, the flyout was visible, I've wrapped my script to all of the flyout buttons and everything was great.
Until I entered combat and tried to open the flyout button ... then the interface stated my code was tainted (when executing the wrapped script). :/

That means, if I call SpellFlyout_Toggle() manually from unsecure code, and if the flyout frames are created by SpellFlyout_Toggle() then they are unsecure!? I'm not sure if I do understand why.

The second point is: how do I force the flyout button frames to get build from secure code (like inside a secure snippet) if I can't use SpellFlyout_Toggle() or reference the "Spellflyout" frame there?

I'm a bit lost to be honest. Any thoughts or words that could help to enlighten me are greatly appreciated. Thank you.
  Reply With Quote