Thread Tools Display Modes
08-21-14, 08:55 PM   #1
RyinntheDK
A Murloc Raider
 
RyinntheDK's Avatar
Join Date: Aug 2014
Posts: 6
LUA CreateFrame, then RemoveFrame??

Hello all!

I'm about 3 hours in to my first attempt at creating (err, finding one and building on to it) an addon. I found an addon that I thought was a good start, but lacked a lot of what I desired, so why not learn LUA and write my own eh?

What I've had a tough time doing is creating a toggle effect when using slash commands + Msg.

As you can see in the code, if Msg == "on" then I CreateFrame. If Msg == "off", essentially I would like to just undo the CreateFrame that I just created. I can't figure out how to do this without just applying a ReloadUI (as you see commented out), which, while effective, rather annoying.

Any help would be much appreciated!

Lua Code:
  1. --Tribute to Kip who's code I copied and altered... Consider this Kudos for your 'Bootstrap'
  2.  
  3. --define global vars (saved between sessions)
  4. Enabled = true
  5.  
  6. --define local module vars and defaults
  7. local AddonVersion = GetAddOnMetadata("RyinnsCursorFinder", "Version")
  8.  
  9. local function print(msg)
  10.     DEFAULT_CHAT_FRAME:AddMessage("RyinnsCursorFinder: " .. tostring(msg))
  11. end
  12.  
  13. function Ryinn_Command(Msg,Editbox)
  14.     if Msg then Msg=strlower(Msg); end
  15.     if Msg == "help" then
  16.         print("v"..AddonVersion)
  17.         print("Use /rcf + on/off to Enable/Disable")
  18.         print("Example: /rcf on")
  19.     elseif Msg == "on" then
  20.                 local frame = CreateFrame("Frame", nil, UIParent);
  21.                 frame:SetFrameStrata("TOOLTIP");
  22.  
  23.                 local texture = frame:CreateTexture();
  24.                 texture:SetTexture([[Interface\Cooldown\ping4]]);
  25.                 texture:SetBlendMode("ADD");
  26.                 texture:SetAlpha(0.5);
  27.  
  28.                 local x = 0;
  29.                 local y = 0;
  30.                 local speed = 0;
  31.                 local function OnUpdate(_, elapsed)
  32.                   local dX = x;
  33.                   local dY = y;
  34.                   x, y = GetCursorPosition();
  35.                   dX = x - dX;
  36.                   dY = y - dY;
  37.                   local weight = 2048 ^ -elapsed;
  38.                   speed = math.min(weight * speed + (1 - weight) * math.sqrt(dX * dX + dY * dY) / elapsed, 768);
  39.                   local size = speed / 6 - 16;
  40.                   if (size > 0) then
  41.                     local scale = UIParent:GetEffectiveScale();
  42.                     texture:SetHeight(size);
  43.                     texture:SetWidth(size);
  44.                     texture:SetPoint("CENTER", UIParent, "BOTTOMLEFT", (x + 0.5 * dX) / scale, (y + 0.5 * dY) / scale);
  45.                     texture:Show();
  46.                   else
  47.                     texture:Hide();
  48.                   end
  49.                 end
  50.                 frame:SetScript("OnUpdate", OnUpdate);
  51.                 print("Ryinn's Flash Cursor is Now Enabled. Use /ryn off to disable")
  52.     elseif Msg == "off" then
  53.     Frame1:SetScript("OnShow",nil);
  54.     --StaticPopup_Show("ReloadPop")
  55.     print("test")
  56.     else
  57.         Ryinn_Command("help")
  58.     end
  59. end
  60.  
  61. --Create an anonymous blank frame
  62. local Ryinn = CreateFrame("Frame")
  63. Ryinn:RegisterEvent("PLAYER_REGEN_ENABLED")
  64. Ryinn:RegisterEvent("PLAYER_REGEN_DISABLED")
  65. Ryinn:SetScript("OnEvent", Ryinn_OnEvent)
  66.  
  67. --setup slash command feature
  68. SlashCmdList["Ryinn"]=Ryinn_Command
  69. SLASH_Ryinn1="/rcf",
  70. Ryinn_Command("help")
  71.  
  72. --Setup our Pop Up  Warning for Reload UI
  73. --StaticPopupDialogs["ReloadPop"] = {
  74. --text = "In order to remove the cursor texture, you need to reload your UI.  Is that okay?",
  75. --button1 = "Yes",
  76. --button2 = "No",
  77. --OnAccept = function() ReloadUI() end,
  78. --timeout = 0,
  79. --sound = "RaidWarning",
  80. --whileDead = true,
  81. --hideOnEscape = true,
  82. --preferredIndex = 3,  -- avoid some UI taint, see [url]http://www.wowace.com/announcements/how-to-avoid-some-ui-taint/[/url]
  83. --}
  Reply With Quote
08-21-14, 09:07 PM   #2
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,313
There is no way to remove a frame from memory once created. What you can do is create the frame when you load the addon and hide it immediately. When you use the slash command, you can toggle the visibility of the frame in order to obtain the effect you want.



Globals are also not saved between sessions. You can however register a specific global to be saved for your addon if defined in its TOC file. For example, the following tag defines RYINNCURSOR_Enabled to be saved between sessions. You can retrieve the data in these variables after ADDON_LOADED fires for your addon.
Code:
## SavedVariables: RYINNCURSOR_Enabled
__________________
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 : 08-21-14 at 09:49 PM.
  Reply With Quote
08-21-14, 09:08 PM   #3
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
There is no RemoveFrame function, nor any other way to destroy a frame once it's been created. Instead, you should create the frame(s) only once, and then just :Hide() them when not in use. You can :Show() them again later. If you need to change what's displayed on the frame, just change things as necessary, using methods like :SetText() on font strings, :SetTexture() and :SetVertexColor() on textures, :SetSize() on frames, etc.

Also, "Enabled" is an absolutely unacceptable name for a global variable. There is an extremely high chance of some other addon (or even the default UI) leaking a variable with that name into the global namespace, overwriting your variable or vice versa. Global variables and object names should always follow two guidelines:

1. The name is unique, and unlikely to collide with the name used by any other addon or the default UI. A simple way to ensure uniqueness is to use your addon name as a prefix, eg. "MyAddon_Enabled".

2. The name clearly identifies the addon that owns it. This way, if it shows up in an error message, the user knows who to tell about it. Using your addon name as a prefix also solves this problem.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
08-22-14, 04:23 AM   #4
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
An easy way to do what they sayed would be to add a name to you frame and to reference it later on. Like
Lua Code:
  1. local frame = _G["RyinnMainFrame"] or CreateFrame("Frame", "RyinnMainFrame", UIParent);
  Reply With Quote
08-22-14, 07:57 AM   #5
RyinntheDK
A Murloc Raider
 
RyinntheDK's Avatar
Join Date: Aug 2014
Posts: 6
I mentioned that I'm a complete beginner here - and was wondering if someone can help me with the code, perhaps help me re-write it properly for what I'm trying to achieve. Would someone be willing to help me with that?

While I completely understand what you're saying about first Creating the frame, and hiding it immediately, then show or hide works as the toggle, I'm having a difficulty putting it all together.

I really appreciate any help!
  Reply With Quote
08-22-14, 09:10 AM   #6
Choonstertwo
A Chromatic Dragonspawn
 
Choonstertwo's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2011
Posts: 194
I've cleaned up the code a little and added a few comments (all prefixed with my name) explaining the changes and questioning why certain things are the way they are.

Lua Code:
  1. --Tribute to Kip who's code I copied and altered... Consider this Kudos for your 'Bootstrap'
  2.  
  3. --define global vars (saved between sessions)
  4. RyinnsCursorFinder_Enabled = true -- Choonster: I gave this global variable your Addon's name as a prefix so it's unique
  5.  
  6. --define local module vars and defaults
  7. local AddonVersion = GetAddOnMetadata("RyinnsCursorFinder", "Version")
  8.  
  9. local function print(msg)
  10.     DEFAULT_CHAT_FRAME:AddMessage("RyinnsCursorFinder: " .. tostring(msg))
  11. end
  12.  
  13. -- Choonster: I've moved the frame creation into the main body of the script. This is only executed once.
  14. -- I've also given it a name. I'd recommend giving any visible frame a name with your AddOn's name in it so the user knows which AddOn adds it.
  15. local frame = CreateFrame("Frame", "RyinnsCursorFinder_MainFrame", UIParent);
  16. frame:SetFrameStrata("TOOLTIP");
  17. frame:Hide() -- Choonster: Hide the frame initially
  18.  
  19. local texture = frame:CreateTexture();
  20. texture:SetTexture([[Interface\Cooldown\ping4]]);
  21. texture:SetBlendMode("ADD");
  22. texture:SetAlpha(0.5);
  23.  
  24. -- Choonster: Do these variables need to be declared outside of the OnUpdate function? Are they ever used by another function? Do they need to be saved between each call of the function?
  25. local x = 0;
  26. local y = 0;
  27. local speed = 0;
  28.  
  29. -- Choonster: I've passed the function directly to :SetScript here instead of declaring it first and then passing it in.
  30. -- If you're never going to call a function yourself (like most script handler functions), you don't have to give it a name.
  31. frame:SetScript("OnUpdate", function(_, elapsed)
  32.   local dX = x;
  33.   local dY = y;
  34.   x, y = GetCursorPosition();
  35.   dX = x - dX;
  36.   dY = y - dY;
  37.   local weight = 2048 ^ -elapsed;
  38.   speed = math.min(weight * speed + (1 - weight) * math.sqrt(dX * dX + dY * dY) / elapsed, 768);
  39.   local size = speed / 6 - 16;
  40.   if (size > 0) then
  41.     local scale = UIParent:GetEffectiveScale();
  42.     texture:SetHeight(size);
  43.     texture:SetWidth(size);
  44.     texture:SetPoint("CENTER", UIParent, "BOTTOMLEFT", (x + 0.5 * dX) / scale, (y + 0.5 * dY) / scale);
  45.     texture:Show();
  46.   else
  47.     texture:Hide();
  48.   end
  49. end);
  50.  
  51. -- Choonster: I've made this function local, it doesn't need to be global.
  52. local function Ryinn_Command(Msg,Editbox)
  53.     if Msg then Msg=strlower(Msg); end
  54.     if Msg == "help" then
  55.         print("v"..AddonVersion)
  56.         print("Use /rcf + on/off to Enable/Disable")
  57.         print("Example: /rcf on")
  58.     elseif Msg == "on" then
  59.         frame:Show() -- Choonster: Showing the frame makes it visible and allows its OnUpdate handler to fire.
  60.         print("Ryinn's Flash Cursor is Now Enabled. Use /ryn off to disable")
  61.     elseif Msg == "off" then
  62.         frame:Hide() -- Choonster: Hiding the frame makes it invisible and stops its OnUpdate handler from firing.
  63.         --StaticPopup_Show("ReloadPop")
  64.         print("test")
  65.     else
  66.         Ryinn_Command("help")
  67.     end
  68. end
  69.  
  70. --Create an anonymous blank frame
  71. local Ryinn = CreateFrame("Frame")
  72. Ryinn:RegisterEvent("PLAYER_REGEN_ENABLED")
  73. Ryinn:RegisterEvent("PLAYER_REGEN_DISABLED")
  74. Ryinn:SetScript("OnEvent", Ryinn_OnEvent)
  75.  
  76. --setup slash command feature
  77. SlashCmdList["Ryinn"]=Ryinn_Command
  78. SLASH_Ryinn1="/rcf",
  79. Ryinn_Command("help")
  80.  
  81. --Setup our Pop Up  Warning for Reload UI
  82. --StaticPopupDialogs["ReloadPop"] = {
  83. --text = "In order to remove the cursor texture, you need to reload your UI.  Is that okay?",
  84. --button1 = "Yes",
  85. --button2 = "No",
  86. --OnAccept = function() ReloadUI() end,
  87. --timeout = 0,
  88. --sound = "RaidWarning",
  89. --whileDead = true,
  90. --hideOnEscape = true,
  91. --preferredIndex = 3,  -- avoid some UI taint, see [url]http://www.wowace.com/announcements/how-to-avoid-some-ui-taint/[/url]
  92. --}

It's not perfect and I can't guarantee it will work, but it probably will.

If you're going to be saving whether or not the AddOn is enabled, you should use the ADDON_LOADED event to set the default enabled state and then show/hide your frame based on the enabled state.

Last edited by Choonstertwo : 08-22-14 at 09:28 AM.
  Reply With Quote
08-22-14, 09:32 AM   #7
RyinntheDK
A Murloc Raider
 
RyinntheDK's Avatar
Join Date: Aug 2014
Posts: 6
Choonster, thank you! This is great!

And I also very much appreciate the comments, which help me learn.

These aren't going to be used elsewhere so how you have it is fine!

local x = 0;
local y = 0;
local speed = 0;
Now to enhance the experience of the user, how would i pass show/hide on just /rcf, like a toggle?
__________________
There is no try. Only do or don't do. - Yoda
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » LUA CreateFrame, then RemoveFrame??

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