I’m late to this thread, and I admittedly didn’t read it all, so apologies if this derails the discussion. (Anything Fizzlemizz says I’d consider 100% correct so anything I suggest that disagrees with her is just a different approach and one method isn’t better than another)
That said, one advice I have in structuring your controls is to use the unordered table-ness of frames and regions. Tables are the heart and soul of Lua and the hierarchical parent-child relationship of frames and regions is the heart of soul of XML. Embrace it.
Here is a little dialog that creates one global, MyMainFrame, with two panels that alternate with an Ok button. Everything built off it has a relationship to the main parent:
local f = CreateFrame("Frame","MyMainFrame",UIParent,"BasicFrameTemplate")
f:SetSize(300,300)
f:SetPoint("CENTER",-200,0)
f.TitleText:SetText("Test Dialog")
f.Panel1 = CreateFrame("Frame",nil,f,"InsetFrameTemplate")
f.Panel1:SetPoint("TOPLEFT",4,-24)
f.Panel1:SetPoint("BOTTOMRIGHT",-7,6)
f.Panel1.Bg:SetDrawLayer("BACKGROUND",1)
f.Panel1.Instructions = f.Panel1:CreateFontString(nil,"ARTWORK","GameFontNormal")
f.Panel1.Instructions:SetPoint("TOP",0,-32)
f.Panel1.Instructions:SetText("Enter your name and click Ok")
f.Panel1.EditBox = CreateFrame("EditBox",nil,f.Panel1,"InputBoxTemplate")
f.Panel1.EditBox:SetSize(200,24)
f.Panel1.EditBox:SetPoint("TOP",f.Panel1.Instructions,"BOTTOM",0,-16)
f.Panel1.EditBox:SetAutoFocus(false)
f.Panel1.Button = CreateFrame("Button",nil,f.Panel1,"UIPanelButtonTemplate")
f.Panel1.Button:SetSize(120,22)
f.Panel1.Button:SetText("Ok")
f.Panel1.Button:SetPoint("TOP",f.Panel1.EditBox,"BOTTOM",0,-16)
-- when Ok button clicked in Panel1, hide Panel1, show Panel2, and say Hello <name>
f.Panel1.Button:SetScript("OnClick",function(self)
f.Panel1:Hide()
f.Panel2:Show()
f.Panel2.Results:SetText("Hello "..f.Panel1.EditBox:GetText())
end)
-- if [enter] key hit in editbox, click the Ok button
f.Panel1.EditBox:SetScript("OnEnterPressed",function(self)
f.Panel1.Button:Click()
end)
f.Panel2 = CreateFrame("Frame",nil,f,"InsetFrameTemplate")
f.Panel2:SetPoint("TOPLEFT",4,-24)
f.Panel2:SetPoint("BOTTOMRIGHT",-7,6)
f.Panel2.Bg:SetDrawLayer("BACKGROUND",1)
f.Panel2:Hide()
f.Panel2.Results = f.Panel2:CreateFontString(nil,"ARTWORK","GameFontNormal")
f.Panel2.Results:SetPoint("TOP",0,-48)
f.Panel2.Button = CreateFrame("Button",nil,f.Panel2,"UIPanelButtonTemplate")
f.Panel2.Button:SetSize(120,22)
f.Panel2.Button:SetText("Ok")
f.Panel2.Button:SetPoint("TOP",f.Panel2.Results,"BOTTOM",0,-16)
-- when Ok button clicked in Panel2, hide Panel2, show Panel1, and reset editbox
f.Panel2.Button:SetScript("OnClick",function(self)
f.Panel2:Hide()
f.Panel1:Show()
f.Panel1.EditBox:SetText("")
f.Panel1.EditBox:SetFocus(true)
end)
I use f as a local reference as reflexive habit (less typing!), but f is also equal to MyMainFrame, so if you can use MyMainFrame also. If you want to update the panel 1 instructions, you can do
MyMainFrame.Panel1.Instructions:SetText("Not that name!")
Everything is reference-able in the heiarchy:
And because everything has a relationship this way, you can go up and down the tree too. The OnClick for Panel1’s button could be:
f.Panel1.Button:SetScript("OnClick",function(self)
self:GetParent():Hide()
self:GetParent():GetParent().Panel2:Show()
self:GetParent():GetParent().Panel2.Results:SetText("Hello "..self:GetParent().EditBox:GetText())
end)
If you wan to dynamically create a list/grid of frames, create a table and put your frames in it:
f.Panel3.GridButtons = {}
for i=1,20 do
local button = CreateFrame("Button",nil,f.Panel3,"UIPanelButtonTemplate")
tinsert(f.Panel3.GridButtons,button)
end
And also remember that once instantiated, these are references to the objects. For your themes, if you want to store buttons in an easy-to-iterate list:
MyMainFrame.Themes = {
Buttons = {},
FontStrings = {},
EditBoxes = {}
}
Then somewhere you can just insert them:
tinsert(MyMainFrame.Themes.Buttons,MyMainFrame.Panel1.Button)
tinsert(MyMainFrame.Themes.Buttons,MyMainFrame.Panel2.Button)
tinsert(MyMainFrame.Themes.FontStrings,MyMainFrame.Panel1.Instructions)
tinsert(MyMainFrame.Themes.FontStrings,MyMainFrame.Panel2.Results)
tinsert(MyMainFrame.Themes.EditBoxes,MyMainFrame.Panel1.EditBox)
This is not saying to avoid names. It’s very courteous to name stuff, especially anything that will be on screen that you or a user may want to /fstack.
But I think trying to give everything a global name so you can reference by that name will give you a one-dimensional abstract of your UI and make it difficult to maintain, especially as you start getting elements name like MyMainFramePanel1EditBoxSearchIconOverlay.