Ok so I feel like I’m close on this but I’m obviously doing something wrong. As an example if you wanted to create say a control for every member in a raid it makes more sense to do that dynamically so if there are only ten people in raid you create 10 controls not 40. So is there a way to create controls using variables? I currently have this;
local MyAddonTexs = {};
local MyAddonFS = {};
for i = 1,8,1
do
-- Create eight groups
for j = 1,5,1
do
-- Create five players per line
-- Create the textures for each player
MyAddon.texture = MyAddonTexs["MyAddonTexsG"..i.."P"..j];
MyAddonTexs["MyAddonTexsG"..i.."P"..j]:SetAllPoints();
MyAddonTexs["MyAddonTexsG"..i.."P"..j]:SetColorTexture(1,1,0.5);
MyAddonTexs["MyAddonTexsG"..i.."P"..j]:SetAlpha(1.0);
-- Create each player in the group
MyAddon.font = MyAddonFS["MyAddonFSG"..i.."P"..j];
MyAddonFS["MyAddonFSG"..i.."P"..j] = MyAddon:CreateFontString();
MyAddonFS["MyAddonFSG"..i.."P"..j]:SetFont("Fonts\\FRIZQT__.TTF", 24);
MyAddonFS["MyAddonFSG"..i.."P"..j]:SetPoint("TOP", 60*j , -100*i);
MyAddonFS["MyAddonFSG"..i.."P"..j]:SetTextColor(0,0,0);
MyAddonFS["MyAddonFSG"..i.."P"..j]:SetText("Name"..i..j);
MyAddonTexs["MyAddonTexsG"..i.."P"..j]:SetAllPoints(MyAddonFS["MyAddonFSG"..i.."P"..j]);
print("Group "..i.." Player "..j);
end
end
The logic was that I’d create two control arrays, one for the fontstrings and one for the textures. Then each FS and tex would be dynamically created in the loops. I know I can tidy this up more by creating a template and inheriting but I’m just trying to get the basics working first.
Any ideas what I’m doing wrong?
edit: As far as I can tell they’re being created fine. But it’s falling over on the line where I try to bind each texture to a FontString.
In this instance, it would probably be easier to create a frame for each “unit” and then add the texture/fontstring to that. This would allow you set a fixed size for the unit frames to make alignment easier while the text and it’s backgound can remain evenly spaced (quick and dirty example)
local Units = {}
local topOnLine
local function CreateUnit(parent, id)
local f = CreateFrame("Frame", "CanackiRaidUnit"..id, parent)
Units[id] = f
f:SetSize(80, 20)
f.Texture = f:CreateTexture()
f.Texture:SetTexture("Interface/BUTTONS/WHITE8X8")
f.Texture:SetVertexColor(1,1,0.5)
f.Text = f:CreateFontString()
f.Text:SetFont("Fonts\\FRIZQT__.TTF", 12)
f.Text:SetTextColor(0, 0, 0)
f.Texture:SetAllPoints(f.Text)
f.Text:SetPoint("CENTER")
if id == 1 then
f:SetPoint("TOPLEFT", 5, -5)
topOnLine = f
elseif mod(id-1, 5) == 0 then
f:SetPoint("LEFT", topOnLine, "RIGHT")
topOnLine = f
else
f:SetPoint("TOP", Units[id-1], "BOTTOM")
end
f.Text:SetText("Raid"..id)
end
local f = CreateFrame("Frame", "CanackiAddonFrame", UIParent)
f:SetSize(500, 120)
f:SetPoint("TOPLEFT", 20, -20)
f.Texture = f:CreateTexture()
f.Texture:SetAllPoints()
f.Texture:SetTexture("Interface/BUTTONS/WHITE8X8")
f.Texture:SetVertexColor(0, 0, 0)
for i=1, 25 do -- add 25 "units"
CreateUnit(CanackiAddonFrame, i)
end
Units[25].Text:SetText("Last Unit") -- change the name of the last unit
CreateUnit(CanackiAddonFrame, #Units + 1)
Units[#Units].Text:SetText("No I am") -- change the name of the last unit
You could make the fontstrings a fixed size without the frames but this approach would probably be easier for starting off.
Thanks again for your help. Splitting out the code into it’s own function is a good idea that was on my list of things to do - once I got the initial design working.
Can you tell me whether there’s much (if any) benefit trying to do it the way I was with just textures and fontstrings? I assumed not creating the extra frames would reduce overhead, but I guess if it’s minimal then maybe it’s not worth the effort.
It was mainly to do with spacing. If you are creating background texture the same size as the fontstring then they will be different sizes unless the text is always the “length” so you have to juggle alignment unless, you make something a fixed size (the texture or fontstrings or in the above case the frame).
You can do it any way that works for you like changing the function to just use textures/fontstrings and say make the texture a fixed size.
local function CreateUnit(parent, id)
local f = parent:CreateTexture()
Units[id] = f
f:SetSize(75, 18)
f:SetTexture("Interface/BUTTONS/WHITE8X8")
f:SetVertexColor(1,1,0.5)
f.Text = parent:CreateFontString()
f.Text:SetFont("Fonts\\FRIZQT__.TTF", 12)
f.Text:SetTextColor(0, 0, 0)
f.Text:SetPoint("CENTER", f)
if id == 1 then
f:SetPoint("TOPLEFT", 5, -5)
topOnLine = f
elseif mod(id-1, 5) == 0 then
f:SetPoint("LEFT", topOnLine, "RIGHT", 5, 0)
topOnLine = f
else
f:SetPoint("TOP", Units[id-1], "BOTTOM", 0, -5)
end
f.Text:SetText("Raid"..id)
end
You could make the fontstring a fixed size or jump through whatever hoops to get everything to align (or not), it’s up to you.
Good point about the spacing. Thanks for the clarification. I’m just trying to learn a bit about good practice with Lua in WoW as well.
My initial test design was using XML and Lua and it seems like the current practice is to not use an XML file for the layout anymore. So I was trying to learn “the right way” to do it in Lua (if there is one).
XML or all lua or a bit of both, WoW doesn’t care and at the end of the day, you will have to read it to maintain it.
About the only things you NEED XML for is inheriting secure temeplates (or any other XML templates) or creating intrinsics, neither of which you seem to be doing atm.
I want to retouch on this because I’ve been silly in my naming conventions. And before I ask, yes I should turn the saved values into a table. But the issue bugs me so I’d like an answer…
Assuming I have saved variables along these lines;
ValueOneText = "my name"
ValueTwoText = "another name"
ValueThreeText = "yet another name"
So if I want to display them in fontstrings on in a grid I would try to loop through the values and create matching fontstrings. I’d like to name my Fontstrings based on the variables so I can find them again later if I need to change or reference them (like for positioning). So what I want to be able to do is refer to;
I know the code from earlier in this thread deals perfectly with sequential items, but it references them as item[1] and I was wondering if it’s possible to create variable and object names from dynamic strings.
Ultimately I will change the way I store my code to something more like;
When creating widgets you can use $parent in the widgets name to prepend the name of the parent frame(s). Because the name is added to the global table as a reference you can then use that to “find” the widget ie.
local f = CreateFrame("Frame", "CarnFrame", UIParent)
f.Fontrstring1 = f:CreateFontString("$parentText", "OVERLAY", "GameTooltipText")
The “$parentText” being a string can be created from your variables list/table.
You can now use the following for getting/setting the text of f.Fontrstring1
f.Fontrstring1:SetText("Blah") -- use the local reference
CarnFrame.Fontrstring1:SetText("Blah") -- Global frame reference + widget key
CarnFrameText:SetText("Blah") -- global reference to the fontstring
_G["CarnFrameText"]:SetText("Blah") -- As above but useful "building" widget names from string values (like in Saved Variables etc. eg. _G["CarnFrame"..SomeVariableWithTheRestOfTheName])
The $parent will subsitute ALL parent names of ALL parent frames which is why some names in /fstack can get pretty long and convoluted.
Hmm ok. I think I follow that. If I understand correctly then every object you name that way winds up being “ParentName”…something. So you literally can’t create a fontstring called “ThisName” if the main frame is “SomethingElse”. The closest you’d get is “SomethingElseThisName”.
I think that’s only going to confuse me more. I’ll just stick with saving the values in tables and dealing with them (and widgets) in tables.
local T = xxx:CreateFontString("ThisName")
ThisName:SetText("Blah")
But because the name “ThisName” is added to the global table along with the names of all the other widgets from all the other addons including the entire Blizzard UI plus their global variables, global functions etc. etc., your names need to be competely unique. Using $parent just makes that easier by say using the addon name as the base frame name and not having to re-type it for every child frame/widget.
It’s also why storing children as keys of the parent instead of long names becomes convenient.
The second parameter in SetPoint is a reference to the widget you are anchoring to (all widgets are tables). Using _G[…] allows you to get that reference using the frame name just like getting any string key from a table
NS.SomeFrame = CreateFrame("Frame")
is the same as
NS["SomeFrame"] = CreateFrame("Frame")
so
local x = NS.SomeFrame
is the same as
local x = NS["SomeFrame"]
The dot notation is an easier form when accessing known string key values. The [] is more flexable and also used for numeric key values.
But if you add a name to a widget, it will be placed in the global table as a reference regardless of any other place you store that referece (the addon private table (NS in this case) or some local variable or table or as a key on some other widget etc.)
The reference is essentially pointing to the widget (table) in memory and all the references will point to the same place (there it is, go get it!)
Ahh sorry I was confusing setpoint and createframe (it’s late and I’m getting tired).
On a closer inspection I see it’s SetPoint(“LEFT”, MainFrame) compared to CreateFrame(“Frame”, “MainFrame”). Sorry about that.
I guess with the naming I’m trying to understand what will and won’t work. So if you use the dot notation trying to build an object name dynamically from strings isn’t going to work. But if you use [] it should be possible.
As for the idea about using NS, I was thinking that would be less likely to encounter name collisions than using _G. So if instead of using “MyCrazyHopefullyUniqueComboOfWords3EditBox” I used “MainEditBox1” I should get my widget not one from another addon that happens to be named the same. Or am I understanding that completely wrong.
Using “MainEditBox1” as the name in Createxxx() will put MainEditBox1 in the global table regarless of where you store other references. NS.MainEditBox is certainly easier to type than MyCrazyHopefullyUniqueComboOfWords3EditBox or _G["MyCrazyHopefullyUniqueComboOfWords3EditBox"]
You can use either (NS.MainEditBox and MyCrazyHopefullyUniqueComboOfWords3EditBox both point to the same EditBox).
If you used say
local x = CreateFrame("Frame", nil, UIParent)
with no name then x is your only reference to the frame other than going through the list of UIParents child frames (GetChildren) and somehow trying to figure out which one it is.
The ones with no names that show up un /fstack as as just random looking numbers and letter.s
So maybe I’m not understanding the creation of an addon namespace properly. I’d assume if I use NS.MyName then sure MyName will be in both NS and _G, but if have another addon installed that used MyName it’d be in their namespace and _G, but not mine.
So me using NS.MyName will get “Carn’s” MyName not “OtherAddon” MyName. Or does the fact they’re all ultimately in _G mean that I can make NS.MyName but someone elses MyName will literally overwrite it anyway?
The “NameSpace” table is private and exclusive to each addon. Each addon gets it’s own private table passed to its .lua files via the local AddonsName, NS = ....
Think of the lua file itself as a function and the … are the parameters passed to that function (first parameter is a string with the addon, second parameter is the table that’s exclusive to the addon and others may be added in future)
In your case, NS and _G are two completely different tables _G is common to every addon, NS is private to your addon.
CreateFrame adds the refernce to _G ujsing the name but you can store a copy of that reference in NS as anything you like.
Something I did when I was working on an ugly (and ultimately abandoned) button bar replacement was like this:
local frameList = {}
function f.MakeSpecialFrame(frameInternalName, frameParent)
local x = CreateFrame("Frame", nil, frameParent)
frameList[frameInternalName] = x
end
That’s an oversimplification and the scope of frameList was not really local to the module (it was local to the addon).
But tracking frame relationships in a table for that purpose was simpler for me than dealing with _G space or using the anonymous frame names that you get if you don’t name them there.
This is where I’m stumbling though. So I’ve created a Frame and it’s in NS and _G so I can refer to it either way. But any addon on my machine can access _G right? So if I’ve used a super common name then another addon can say change the Frame colour if they reference it using _G?