Thread Tools Display Modes
05-09-23, 06:54 AM   #1
Benalish
A Flamescale Wyrmkin
 
Benalish's Avatar
Join Date: Dec 2012
Posts: 122
Appending function properly

First I defined the `AppendScript` function

Lua Code:
  1. local mt = {
  2.             AppendScript = function(self, handler, method)
  3.                 local func = self:GetScript(handler)
  4.                 self:SetScript(handler, function(...)
  5.                     func(...)
  6.                     method()
  7.                 end)
  8.             end,
  9.         }
  10.        
  11.     setmetatable(object, { __index = setmetatable(mt, getmetatable(object)) })
This way I can write

Lua Code:
  1. local method = function()
  2.                        --do stuffs
  3.                    end
  4.     object:AppendScript(handler, method)

for append method to the handler script that, for example, I defined previously.

I would like to make sure that the function is not appended indefinitely: in a nutshell that the function is not appended every time the event fires.

it was recommended to make the Function Constructor in Metamethod __newindex and decide in AppendScript if it has to be recreated/destroyed, but I'm still a bit inexperienced with metatables.

Can you help me?
  Reply With Quote
05-09-23, 09:49 AM   #2
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,834
It seems a little over complicated. A version of a Mixin for scripts might be easier to get along with for using on a variety of the same widget type.

Lua Code:
  1. -- Generic script application function
  2. local function AddScripts(frame, scripts)
  3.     for k, v in pairs(scripts) do
  4.         frame:SetScript(k, v)
  5.     end
  6. end
  7.  
  8. -- Scripts for Buttons
  9. local ButtonScripts = {}
  10. function ButtonScripts.OnClick(self, button, down)
  11.     -- ...
  12. end
  13. function ButtonScripts.OnEnter(self)
  14.     -- ...
  15. end
  16. function ButtonScripts.OnLeave(self)
  17.     -- ...
  18. end
  19.  
  20. -- Create Button, Apply Scripts
  21. local f = CreateFrame("Button", "xxx", UIParent)
  22. AddScripts(f, ButtonScripts)
  23.  
  24. -- Scripts for sliders
  25. local SliderScripts = {}
  26. function SliderScripts.OnValueChanged(self, value)
  27.     -- ...
  28. end
  29.  
  30. -- Create Slider, Apply Scripts
  31. local s = CreateFrame("Slider", "zzz", UIParent)
  32. AddScripts(s, SliderScripts)

Just a thought
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.

Last edited by Fizzlemizz : 05-09-23 at 09:52 AM.
  Reply With Quote
05-09-23, 10:23 AM   #3
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,834
If you wanted to do it like that (needed to append multiple scripts and not use HookScript) an example would look something like:

Lua Code:
  1. local mt = {
  2.     AppendScript = function(self, handler, method)
  3.         local func = self:GetScript(handler)
  4.         self:SetScript(handler, function(...)
  5.             func(...)
  6.             method()
  7.         end)
  8.     end,
  9. }
  10.  
  11. local frame = CreateFrame("BUTTON", "MyParty1", UIParent, "BackdropTemplate")
  12.  
  13. setmetatable(frame, { __index = setmetatable(mt, getmetatable(frame)) })
  14.  
  15. frame:SetSize(200, 40)
  16. frame:SetBackdrop({ bgFile = "Interface\\BUTTONS\\WHITE8X8", tile = true, tileSize = 8 })
  17. frame:SetBackdropColor(0, 0, 0)
  18. frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
  19.  
  20. local count = 0
  21. frame:SetScript("OnEnter", function(self) -- Initial SetScript is required so others can be added.
  22.     count = count + 1
  23.     print(count, "First Enter")
  24. end)
  25.  
  26. local function FirstAdded(self)
  27.     print(count, "First Added On Enter!!!")
  28. end
  29. frame:AppendScript("OnEnter", FirstAdded)
  30.  
  31. local function SecondAdded(self)
  32.     print(count, "Second Added On Enter!!!")
  33. end
  34. frame:AppendScript("OnEnter", SecondAdded)
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.

Last edited by Fizzlemizz : 05-09-23 at 10:27 AM.
  Reply With Quote
05-09-23, 12:14 PM   #4
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,834
I kept getting the feeling I was misunderstanding what you are trying to do. Maybe you're looking for a way to run something only the first time a script is used hence the Constructor analogy

This example is a combination of the previous one with the concept of a "constructor" (run once). If you tried to use __newindex you would only get errors trying to do anything with the frame. (I hope this covers it because I'm out of ideas as to what you're looking for )

Lua Code:
  1. local mt = {
  2.     AppendScript = function(self, handler, method)
  3.         local func = self:GetScript(handler)
  4.         self:SetScript(handler, function(self, ...)
  5.             if func then -- SetScript() if used
  6.                 func(self, ...)
  7.             end
  8.             method(self, ...) -- then appended script
  9.         end)
  10.     end,
  11.  
  12.     ConstructScript = function(self, handler, method)
  13.         local func = self:GetScript(handler)
  14.         self:SetScript(handler, function(self, ...)
  15.             if method then -- Constuctor method runs first
  16.                 method(self, ...)
  17.                 method = nil
  18.             end
  19.             if func then -- then SetScript() if used.
  20.                 func(self, ...)
  21.             end
  22.         end)
  23.     end,
  24. }
  25.  
  26. local frame = CreateFrame("BUTTON", "MyHookedFrame", UIParent, "BackdropTemplate")
  27.  
  28. setmetatable(frame, { __index = setmetatable(mt, getmetatable(frame)) })
  29.  
  30. frame:SetSize(200, 40)
  31. frame:SetBackdrop({ bgFile = "Interface\\BUTTONS\\WHITE8X8", tile = true, tileSize = 8 })
  32. frame:SetBackdropColor(0, 0, 0)
  33. frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
  34.  
  35. local count = 0
  36. frame:SetScript("OnEnter", function(self) -- Set/HookScript required to allow other scripts to be appended
  37.     count = count + 1
  38.     print(count, "|cff00ff00First Frame OnEnter Script|r")
  39. end)
  40.  
  41. local function Construct(self, ...)
  42.     print(count, self:GetName(), "|cffff0000Only going to show you this once!!!|r", ...)
  43. end
  44. frame:ConstructScript("OnEnter", Construct)
  45.  
  46. local function AppendScriptOne(self, ...)
  47.     print(count, self:GetName(), "|cff0000ffFirst Appended On Enter!!!|r", ...)
  48. end
  49. frame:AppendScript("OnEnter", AppendScriptOne)
  50.  
  51. local function AppendScriptTwo(self, ...)
  52.     print(count, self:GetName(), "|Cffffff00Second Appended On Enter!!!|r", ...)
  53. end
  54. frame:AppendScript("OnEnter", AppendScriptTwo)
  55.  
  56. local frame2 = CreateFrame("BUTTON", "MyHookedFrame2", UIParent, "BackdropTemplate")
  57.  
  58. setmetatable(frame2, { __index = setmetatable(mt, getmetatable(frame2)) })
  59.  
  60. frame2:SetSize(200, 40)
  61. frame2:SetBackdrop({ bgFile = "Interface\\BUTTONS\\WHITE8X8", tile = true, tileSize = 8 })
  62. frame2:SetBackdropColor(0, 0, 0)
  63. frame2:SetPoint("TOP", frame, "BOTTOM", 0, -10)
  64.  
  65. -- Optional SetScript not used here (unless you want to uncomment it.)
  66. --frame2:SetScript("OnEnter", function(self) -- Set/HookScript required to allow other scripts to be appended
  67. --  count = count + 10
  68. --  print(count, "|cff00ff00Second Frame OnEnter Script|r")
  69. --end)
  70.  
  71. frame2:ConstructScript("OnEnter", Construct)
  72. frame2:AppendScript("OnEnter", AppendScriptOne)
  73. frame2:AppendScript("OnEnter", AppendScriptTwo)

Overly complicated!
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.

Last edited by Fizzlemizz : 05-09-23 at 02:44 PM.
  Reply With Quote
05-09-23, 09:34 PM   #5
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,304
In general, I have a variable keep track if I have hooked the script and only do so if I haven't.

For example:
Lua Code:
  1. local function OnScript(self)
  2. --  Do Stuff
  3. end
  4.  
  5. local Hooked={};
  6. hooksecurefunc(SomeFrameMixin,"SomeMethod",function(self)
  7.     if not Hooked[self] then
  8.         self:HookScript("ScriptType",OnScript);
  9.         Hooked[self]=true;
  10.     end
  11. end);

PS: I don't see a reason to not use :HookScript() when you're essentially reinventing it anyway.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)

Last edited by SDPhantom : 05-09-23 at 09:37 PM.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Appending function properly

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