WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Question about hooks (https://www.wowinterface.com/forums/showthread.php?t=52631)

evilbib 08-19-15 11:32 AM

Question about hooks
 
Hi,

lets assume I have this setup:
AddOn1\file1.lua
Lua Code:
  1. local addon, ns = ...
  2. local function DoSomething()
  3.     local frame = CreateFrame("Frame")
  4. end

AddOn2\file2.lua
Lua Code:
  1. --ready to hook the function DoSomething() from file1.lua

So is it possible to access the created "frame" in file2.lua?

Phanx 08-19-15 11:48 AM

Well, I'm not sure "hooks" are actually what you're asking about, and you certainly shouldn't create a function in one file in your addon and hook it in another. Hooks are for when you want to modify something in Blizzard code or another addon. If you're writing your own code, just write it the way you want it in the first place.

That said, to share something between files in your addon, just add it to your addon's private table; you've named it "ns" in your code:

AddOn1\file1.lua
Lua Code:
  1. local addon, ns = ...
  2. local frame = CreateFrame("Frame")
  3. ns.frame = frame

AddOn2\file2.lua
Lua Code:
  1. local addon, ns = ...
  2. local frame = ns.frame

evilbib 08-19-15 12:36 PM

Quote:

Originally Posted by Phanx (Post 310446)
Hooks are for when you want to modify something in Blizzard code or another addon.

Thats exactly what I want to do, modify something from another addon (not mine).
AddOn1/file1.lua is all what this addon provides.

Phanx 08-19-15 12:39 PM

Well, then this is where posting fake code examples gets you in trouble... if the actual code is set up like your example (local "frame" with no name, parent, or distinguishing features created inside a local function) then no, there's no way to access it from another file in another addon. However, it seems unlikely that a real addon would actually do that, so there's probably a way... but without seeing the actual code, there's no way to tell.

evilbib 08-19-15 02:17 PM

Quote:

Originally Posted by Phanx (Post 310453)
Well, then this is where posting fake code examples gets you in trouble... if the actual code is set up like your example (local "frame" with no name, parent, or distinguishing features created inside a local function) then no, there's no way to access it from another file in another addon. However, it seems unlikely that a real addon would actually do that, so there's probably a way... but without seeing the actual code, there's no way to tell.

Actually the addon (teksLoot) returns this frame, this is the whole function:
Lua Code:
  1. local function CreateRollFrame()
  2.     local frame = CreateFrame("Frame", nil, UIParent)
  3.     frame:SetWidth(328)
  4.     frame:SetHeight(26)
  5.     frame:SetBackdrop(backdrop)
  6.     frame:SetBackdropColor(0, 0, 0, .9)
  7.     frame:SetScript("OnEvent", OnEvent)
  8.     frame:RegisterEvent("CANCEL_LOOT_ROLL")
  9.     frame:CreateBeautyBorder(11)
  10.     frame:SetBeautyBorderPadding(-1)
  11.     frame:Hide()
  12.  
  13.     local button = CreateFrame("Button", nil, frame)
  14.     button:SetPoint("LEFT", 0, 0)
  15.     button:SetWidth(28)
  16.     button:SetHeight(28)
  17.     --button:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
  18.     button:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square")
  19.     button:GetHighlightTexture():SetBlendMode("ADD")
  20.     button:SetScript("OnEnter", SetItemTip)
  21.     button:SetScript("OnLeave", HideTip2)
  22.     button:SetScript("OnUpdate", ItemOnUpdate)
  23.     button:SetScript("OnClick", LootClick)
  24.     frame.button = button
  25.  
  26.     local buttonborder = CreateFrame("Frame", nil, button)
  27.     buttonborder:SetWidth(32)
  28.     buttonborder:SetHeight(32)
  29.     buttonborder:SetPoint("CENTER", button, "CENTER")
  30.     buttonborder:SetBackdrop(backdrop)
  31.     buttonborder:SetBackdropColor(1, 1, 1, 0)
  32.     buttonborder:CreateBeautyBorder(11)
  33.     buttonborder:SetBeautyBorderPadding(-1)
  34.     frame.buttonborder = buttonborder
  35.  
  36.     local tfade = frame:CreateTexture(nil, "BORDER")
  37.     tfade:SetPoint("TOPLEFT", frame, "TOPLEFT", 4, -4)
  38.     tfade:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -4, 4)
  39.     tfade:SetTexture("Interface\\ChatFrame\\ChatFrameBackground")
  40.     tfade:SetBlendMode("ADD")
  41.     tfade:SetGradientAlpha("VERTICAL", .1, .1, .1, 0, .25, .25, .25, 1)
  42.  
  43.     local status = CreateFrame("StatusBar", nil, frame)
  44.     status:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -4, -4)
  45.     status:SetPoint("BOTTOM", frame, "BOTTOM", 0, 4)
  46.     status:SetPoint("LEFT", frame.button, "RIGHT", -1, 0)
  47.     status:SetScript("OnUpdate", StatusUpdate)
  48.     status:SetFrameLevel(status:GetFrameLevel()-1)
  49.     status:SetStatusBarTexture("Interface\\AddOns\\teksLoot\\media\\statusbar.tga")
  50.     status:SetStatusBarColor(.8, .8, .8, .9)
  51.     status.parent = frame
  52.     frame.status = status
  53.  
  54.     local spark = frame:CreateTexture(nil, "OVERLAY")
  55.     spark:SetWidth(14)
  56.     spark:SetHeight(35)
  57.     spark:SetTexture("Interface\\CastingBar\\UI-CastingBar-Spark")
  58.     spark:SetBlendMode("ADD")
  59.     status.spark = spark
  60.  
  61.     local need, needtext = CreateRollButton(frame, "Interface\\Buttons\\UI-GroupLoot-Dice-Up", "Interface\\Buttons\\UI-GroupLoot-Dice-Highlight", "Interface\\Buttons\\UI-GroupLoot-Dice-Down", 1, NEED, "LEFT", frame.button, "RIGHT", 5, -1)
  62.     local greed, greedtext = CreateRollButton(frame, "Interface\\Buttons\\UI-GroupLoot-Coin-Up", "Interface\\Buttons\\UI-GroupLoot-Coin-Highlight", "Interface\\Buttons\\UI-GroupLoot-Coin-Down", 2, GREED, "LEFT", need, "RIGHT", 0, -1)
  63.     local de, detext
  64.     de, detext = CreateRollButton(frame, "Interface\\Buttons\\UI-GroupLoot-DE-Up", "Interface\\Buttons\\UI-GroupLoot-DE-Highlight", "Interface\\Buttons\\UI-GroupLoot-DE-Down", 3, ROLL_DISENCHANT, "LEFT", greed, "RIGHT", 0, -1)
  65.     local pass, passtext = CreateRollButton(frame, "Interface\\Buttons\\UI-GroupLoot-Pass-Up", nil, "Interface\\Buttons\\UI-GroupLoot-Pass-Down", 0, PASS, "LEFT", de or greed, "RIGHT", 0, 2.2)
  66.     frame.needbutt, frame.greedbutt, frame.disenchantbutt = need, greed, de
  67.     frame.need, frame.greed, frame.pass, frame.disenchant = needtext, greedtext, passtext, detext
  68.  
  69.     local bind = frame:CreateFontString()
  70.     bind:SetPoint("LEFT", pass, "RIGHT", 3, 1)
  71.     bind:SetFont("Fonts\\FRIZQT__.TTF", 13, "OUTLINE")
  72.     frame.fsbind = bind
  73.  
  74.     local loot = frame:CreateFontString(nil, "ARTWORK", "SystemFont_Outline")
  75.     loot:SetPoint("LEFT", bind, "RIGHT", 0, .12)
  76.     loot:SetPoint("RIGHT", frame, "RIGHT", -5, 0)
  77.     loot:SetHeight(16)
  78.     loot:SetJustifyH("LEFT")
  79.     frame.fsloot = loot
  80.  
  81.     frame.rolls = {}
  82.  
  83.     return frame
  84. end

Fizzlemizz 08-19-15 02:41 PM

Because the function that creates the frame is local, only code within that .lua file can call CreateRollFrame().

Becasue the frame is not given a name, there is no way for code outside that .lua file to access the frame once it has been created unless the fames is parented to another frame that at some stage has been given a name.

Banknorris 08-19-15 04:20 PM

If that frame has some distinctive features you might be able to use EnumerateFrames() to get a pointer to it. For example this code catches all existent action buttons (from standard UI, Bartender4, ButtonForge, Dominos etc) and new ones will be added as well. Doesn't matter if they have a name or parent. (code extracted and adapted from SetMacroIcon lib)

Lua Code:
  1. local action_buttons = {} --this table will contain all action buttons (present and future)
  2.  
  3. local hook_all_actionbuttons
  4. local CreateFrame_hook
  5.  
  6. local hook_new_buttons_frame = CreateFrame("Frame")
  7. hook_new_buttons_frame:Hide()
  8.  
  9. local f = CreateFrame("Frame")
  10. f:SetScript("OnEvent",function(self,event,...)
  11.     if event=="PLAYER_LOGIN" then
  12.         hook_all_actionbuttons()
  13.         hooksecurefunc("CreateFrame",CreateFrame_hook)
  14.     end
  15. end)
  16. f:RegisterEvent("PLAYER_LOGIN")
  17.            
  18. function CreateFrame_hook(frame_type,frame_name,frame_parent,frame_template)
  19.     --put code to identify viable candidates for the desired frame here (like bellow)
  20.     if string_upper(frame_type)=="CHECKBUTTON" and frame_template and string_upper(frame_template):match("ACTIONBUTTONTEMPLATE") then
  21.         hook_new_buttons_frame:Show()
  22.     end
  23. end
  24.  
  25. do
  26. local last_frame
  27. function hook_all_actionbuttons()
  28.     local frame = EnumerateFrames(last_frame)
  29.     while frame do
  30.         --put code to identify the desired frame here (like bellow)
  31.         local frame_type = frame:GetObjectType()
  32.         if frame_type=="CheckButton" and frame.GetAttribute and frame.icon and frame.Border and frame.Count then
  33.             action_buttons[frame] = true
  34.         end
  35.         last_frame = frame
  36.         frame = EnumerateFrames(frame)
  37.     end
  38. end
  39. end
  40.  
  41. hook_new_buttons_frame:SetScript("OnUpdate",function(self,elapsed)
  42.     self:Hide()
  43.     hook_all_actionbuttons()
  44. end)

elcius 08-19-15 04:48 PM

there is no clean way to access a local anonymous frame.
Code:

local hooked = {};

-- run on START_LOOT_ROLL
local frames = {GetFramesRegisteredForEvent('CANCEL_LOOT_ROLL')};
for i,frame in pairs(frames) do
        if (not hooked[frame]) and frame.status and frame.status:GetStatusBarTexture():match('teksLoot') then
                -- hook frame, or just apply changes here once.
                hooked[frame] = true;
        end
end


SDPhantom 08-19-15 04:54 PM

Scanning EnumerateFrames() can be very taxing on the system considering the default UI alone creates hundreds of frames. Trying to "hack" your way to get access to a local frame is customized to that specific frame. One way I can think of that would be much easier on the system is to use GetFramesRegisteredForEvent("CANCEL_LOOT_ROLL") and cross-check the taint record of any existing index.

Lua Code:
  1. local function GetTeksRollFrame()
  2.     local list={GetFramesRegisteredForEvent("CANCEL_LOOT_ROLL")};
  3.     for i,j in ipairs(list) do
  4.         if j.button and select(2,issecurevariable(j,"button"))=="teksLoot" then
  5.             return j;
  6.         end
  7.     end
  8. end

Hacking these frames isn't always going to be easy and it takes a lot of understanding with the environment they exist in. Not only the function creating a frame, but every function that takes the frame in as an argument is a possible point of entry to capture it. Scanning methods like the ones posted here are a last resort if you can't find a viable point of entry to get direct access.

Phanx 08-20-15 05:39 PM

Quote:

Originally Posted by pingumania (Post 310455)
Actually the addon (teksLoot) ...

In that specific case you're probably better off just modifying the addon directly. It's so small and infrequently updated -- in fact, the last change was made in 2012 -- that porting your changes between versions is trivial. I actually maintain a script that applies small patches to a number of addons after updating, so I don't have to do it by hand.

evilbib 08-21-15 02:44 AM

Quote:

Originally Posted by Phanx (Post 310476)
In that specific case you're probably better off just modifying the addon directly. It's so small and infrequently updated -- in fact, the last change was made in 2012 -- that porting your changes between versions is trivial. I actually maintain a script that applies small patches to a number of addons after updating, so I don't have to do it by hand.

Thats what I did in the end :)


All times are GMT -6. The time now is 11:25 AM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI