Thread Tools Display Modes
07/11/16, 11:38 AM   #1
tgolsson
Join Date: Jul 2016
Posts: 5
Question Resolve name for descendant of instantiated virtual control?

Hello,

I am developing a unit frame addon, and am having some struggles with lacking documentation. I have a UnitFrame template which I want to dynamically populate with data, and I can spawn these using CreateControl, as in my example.

Code:
<GuiXml> 
    <TopLevelControl name="UnitFrame" hidden="false" virtual="true">
    <Controls>
        <Label name="$(parent)Name" text="Hello!" />
    </Controls>
</GuiXml>

Lua Code:
  1. Controls[0] = CreateControlFromVirtual("Target", GuiRoot, "UnitFrame")  
  2. TargetName:SetText("Bob")

Now, for the party and raid frames I need to do this for group1...group24, and at that point it becomes quite awkward. What I'd like to do is something like
Lua Code:
  1. Controls[unitTag].Name:SetText("Bob")
, but I can't find any way to do this. Surely this must be doable without using massive if-statements?

I have considered creating one list for each element I may need to access, so I could have
Lua Code:
  1. self.ControlsName = {
  2.     [group1] = Group1Name,
  3.     [group2] = Group2Name,
  4.     -- ...
  5. }
  6.  
  7. self.ControlsHealthBar = {
  8.     [group1] = Group1HealthBar,
  9.     [group2] = Group2HealthBar,
  10.     -- ...
  11. }

But this becomes quite verbose as well. Are there any options I am missing? I know about string evaluation/introspection, but I fear it might hurt performance a lot.
  Reply With Quote
07/11/16, 11:52 AM   #2
Haho
Join Date: Jul 2016
Posts: 15
I'm not gonna answer your question, but if i understand you'll have as many top level controls as group members with this.

You want to have only one toplevelcontrol to control the visibility of the whole group, then simple controls for groups as children of this one, and others simple controls (or labels directly) for members as great-children, so you can control the visibility of each level.

But don't multiply the toplevel controls or you'll have a hell making options later.
  Reply With Quote
07/11/16, 12:04 PM   #3
sirinsidiator
 
sirinsidiator's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 1,567
Welcome to ESOUI and addon development!

If you haven't already read the Getting Started guide, I suggest you take a look to find out where you can find "documentation" and useful info about the API.

For something like group unit frames you should create the controls once when you need them and keep a table where you associate a unitTag to the frame control.

Lua Code:
  1. local unitFrames = {}
  2. local function GetUnitFrame(unitTag)
  3.   if(not unitFrames[unitTag]) then
  4.     unitFrames[unitTag] = CreateControlFromVirtual("Target", GuiRoot, "UnitFrame")
  5.   end
  6.   return unitFrames[unitTag]
  7. end

Whenever you react to some change to a group member you would then just call GetUnitFrame and pass the unitTag of the affected player.

One thing you should keep in mind when creating controls is that for every control you create, a global variable is generated implicitly. Meaning you should not call a control "Target" or "UnitFrame", but instead "MyUnitFrameAddonTarget" and "MyUnitFrameAddonUnitFrameTemplate" to avoid name collisions.
  Reply With Quote
07/11/16, 12:23 PM   #4
tgolsson
Join Date: Jul 2016
Posts: 5
Originally Posted by Haho View Post
I'm not gonna answer your question, but if i understand you'll have as many top level controls as group members with this.

You want to have only one toplevelcontrol to control the visibility of the whole group, then simple controls for groups as children of this one, and others simple controls (or labels directly) for members as great-children, so you can control the visibility of each level.

But don't multiply the toplevel controls or you'll have a hell making options later.
Well, my intended idea is sort of like this:

Code:
Addon,
PlayerFrame,
TargetFrame,
PartyFrame = [ UnitFrame, UnitFrame, UnitFrame, UnitFrame ]
RaidFrame = [ UnitFrame, ... ]
So I will indeed have many toplevel controls as I use the virtual dynamic creation. But I will have one manager for all of them that controls positioning, updating, etc. Perhaps there is a better way of doing this, but the functionality is horribly undocumented.

I develop a lot in Java, and to give an analogy (if it makes any sense to you) what I am trying to do is create View for each group member, and then create a Controller for managing all these views. It's called the "DRY" principle: "Don't repeat yourself". It's the same thing for each group member, so I should have only one piece of logic and markup for it.
  Reply With Quote
07/11/16, 12:25 PM   #5
tgolsson
Join Date: Jul 2016
Posts: 5
Originally Posted by sirinsidiator View Post
Welcome to ESOUI and addon development!

If you haven't already read the Getting Started guide, I suggest you take a look to find out where you can find "documentation" and useful info about the API.

For something like group unit frames you should create the controls once when you need them and keep a table where you associate a unitTag to the frame control.

Lua Code:
  1. local unitFrames = {}
  2. local function GetUnitFrame(unitTag)
  3.   if(not unitFrames[unitTag]) then
  4.     unitFrames[unitTag] = CreateControlFromVirtual("Target", GuiRoot, "UnitFrame")
  5.   end
  6.   return unitFrames[unitTag]
  7. end

Whenever you react to some change to a group member you would then just call GetUnitFrame and pass the unitTag of the affected player.

One thing you should keep in mind when creating controls is that for every control you create, a global variable is generated implicitly. Meaning you should not call a control "Target" or "UnitFrame", but instead "MyUnitFrameAddonTarget" and "MyUnitFrameAddonUnitFrameTemplate" to avoid name collisions.
How would I change the label inside the unit frame, in this case? Because that is my original problem.
  Reply With Quote
07/11/16, 12:42 PM   #6
Haho
Join Date: Jul 2016
Posts: 15
Originally Posted by tgolsson View Post
Well, my intended idea is sort of like this:

Code:
Addon,
PlayerFrame,
TargetFrame,
PartyFrame = [ UnitFrame, UnitFrame, UnitFrame, UnitFrame ]
RaidFrame = [ UnitFrame, ... ]
So I will indeed have many toplevel controls as I use the virtual dynamic creation. But I will have one manager for all of them that controls positioning, updating, etc. Perhaps there is a better way of doing this, but the functionality is horribly undocumented.

I develop a lot in Java, and to give an analogy (if it makes any sense to you) what I am trying to do is create View for each group member, and then create a Controller for managing all these views. It's called the "DRY" principle: "Don't repeat yourself". It's the same thing for each group member, so I should have only one piece of logic and markup for it.
your "Addon" level is your TopLevelControl then

then make your virtual be only "Control" and set your toplevelcontrol as parent when your generate them.
later work on your controls as you see fit. But TopLevelControls have specific functions and rules attached to them, and you don't want them on all of your controls.


I usually create everything in lua, but there are many examples of xml in other addons to understand how names are created.


The name you determine in lua is a variable you can check in your code, but for the UI what matter is the named control. You can get it back with a
local mycontrolvariable = GetControl("TopLevelNameChildNameLabelNAme") for example.

in your example :
local mylabel = GetControl("UnitFrameName")
mylabel:SetText("Bob")

Edit : sorry, i didn't re-read your first post before writing, it would be instead local mylabel = GetControl("TargetName") since UnitFrame is the name of the Template. sry again.
and you can use a suffix to the name when generating your controls in a loop :
CreateControlFromVirtual(name, parent, templateName, optionalNameSuffix)
that can be helpful.


edit: Controls dont need to all have a size and place etc, they can be virtual containers for the sake of having properties inherited by a group of children. I mean CT_CONTROL controls...

Last edited by Haho : 07/11/16 at 02:00 PM.
  Reply With Quote
07/11/16, 12:50 PM   #7
tgolsson
Join Date: Jul 2016
Posts: 5
Originally Posted by Haho View Post
your "Addon" level is your TopLevelControl then

then make your virtual be only "Control" and set your toplevelcontrol as parent when your generate them.
later work on your controls as you see fit. But TopLevelControls have specific functions and rules attached to them, and you don't want them on all of your controls.


I usually create everything in lua, but there are many examples of xml in other addons to understand how names are created.


The name you determine in lua is a variable you can check in your code, but for the UI what matter is the named control. You can get it back with a
local mycontrolvariable = GetControl("TopLevelNameChildNameLabelNAme") for example.

in your example :
local mylabel = GetControl("UnitFrameName")
mylabel:SetText("Bob")

edit: Controls dont need to all have a size and place etc, they can be virtual containers for the sake of having properties inherited by a group of children. I mean CT_CONTROL controls...
ooh, that's helpful. I thought I HAD to have a TopLevelControl to contain the controls. This removes a few levels of nesting at least. Can I also then include them in other XML files as long as I load the files in the correct order? So I could make my raidframe with 24 unit frames and two backdrops?
  Reply With Quote
07/11/16, 12:56 PM   #8
Haho
Join Date: Jul 2016
Posts: 15
lol no, toplevelcontrol is the one attached to the Guiroot directly. Think of it like your own paper sheet to decorate. Then inside, make your controls groups like you intended to at first.

So yes you have to have one (or you don't if your controls are children of an existing control, but i doubt it in your case) But one is enough

for the xml question, i dont get it... are you making one xml file/control?
you can write everything in the same xml file.

the virtual one will be separated from the "nesting"... i'm not a fan of xml anyway, as i said look into any addon with a UI and a xml and you should see how it works. Or someone else would be more precise on this.

so basically : toplevel will be defined, and you'll have after that your virtual definition for the controls you'll be creating dynamically. And they'll have toplevel as parent instead of Guiroot.

Last edited by Haho : 07/11/16 at 01:03 PM.
  Reply With Quote
07/11/16, 01:14 PM   #9
tgolsson
Join Date: Jul 2016
Posts: 5
Originally Posted by Haho View Post
lol no, toplevelcontrol is the one attached to the Guiroot directly. Think of it like your own paper sheet to decorate. Then inside, make your controls groups like you intended to at first.

So yes you have to have one (or you don't if your controls are children of an existing control, but i doubt it in your case) But one is enough

for the xml question, i dont get it... are you making one xml file/control?
you can write everything in the same xml file.

the virtual one will be separated from the "nesting"... i'm not a fan of xml anyway, as i said look into any addon with a UI and a xml and you should see how it works. Or someone else would be more precise on this.

so basically : toplevel will be defined, and you'll have after that your virtual definition for the controls you'll be creating dynamically. And they'll have toplevel as parent instead of Guiroot.
Sorry, I was perhaps a bit too brief.

I was wondering whether I could do
Code:
<GuiXml>
    <Controls>
        <Control name="MyAddonUnitFrame" virtual="true">
             <Controls>
                 <Label name="$(parent)Name" text="bob" />
             </Controls>
        </Control>
    </Controls>
</GuiXml>
<!-- another file -->
<GuiXml>
    <Controls>
        <TopLevelControl>
            <Controls>
                <MyAddonUnitFrame name="AddonGroup1" />
                <MyAddonUnitFrame name="AddonGroup2" />
                <MyAddonUnitFrame name="AddonGroup3" />
            </Controls>
        </TopLevelControl>
    </Controls>
</GuiXml>
Or something similar to this.

Last edited by tgolsson : 07/11/16 at 01:17 PM.
  Reply With Quote
07/11/16, 01:19 PM   #10
Haho
Join Date: Jul 2016
Posts: 15
Originally Posted by tgolsson View Post
Sorry, I was perhaps a bit too brief.

I was wondering whether I could do
Code:
<GuiXml>
    <Controls>
        <Control name="MyAddonUnitFrame" virtual="true">
             <Controls>
                 <Label name="$(parent)Name" text="bob" />
             </Controls>
        </Control>
    </Controls>
</GuiXml>
<!-- another file -->
<GuiXml>
    <Controls>
        <TopLevelControl>
            <Controls>
                <MyAddonUnitFrame name="AddonGroup1" />
            </Controls>
        </TopLevelControl>
    </Controls>
</GuiXml>
Or something similar to this.

i'd say more like :
Code:
<GuiXml>
    <Controls>
        <TopLevelControl name="MyAddon"> 
        </TopLevelControl>
   

<!-- same file -->

        <Control name="MyAddonUnitFrame" virtual="true">
             <Controls>
                 <Label name="$(parent)Name" text="bob" />
             </Controls>
        </Control>
   </Controls>
</GuiXml>

Last edited by Haho : 07/11/16 at 01:22 PM.
  Reply With Quote
07/11/16, 02:08 PM   #11
Sasky
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 231
Originally Posted by tgolsson View Post
I develop a lot in Java, and to give an analogy (if it makes any sense to you) what I am trying to do is create View for each group member, and then create a Controller for managing all these views. It's called the "DRY" principle: "Don't repeat yourself". It's the same thing for each group member, so I should have only one piece of logic and markup for it.
It might be worth taking a look at CyrHUD, where I do a similar approach. There instead of unit frames, it's showing information about ongoing battles in PvP. I have a view object for each displayed row (classes/Label.lua) as well as model objects for each battle (classes/Battle.lua). It's not a pure MVC model, as some of the controller logic is mixed in with the model class, with the rest in an update loop (not an object).

Also, it has a fair amount of OOP, which might be a more comfortable style if you're coming from Java.

http://git.esoui.com/?a=tree&p=CyrHUD
  Reply With Quote
07/11/16, 02:21 PM   #12
Haho
Join Date: Jul 2016
Posts: 15
for the part where you edited to have more groups in your example : no, not in the xml

once your template is done as a virtual in your xml, you have to use lua to generate your different group controls as you did in your first post :

Code:
for i = 1, numberOfGroups do    -- avoid 0 index in lua btw

   Controls[i] = CreateControlFromVirtual("Target", TopLevelName, TemplateName, "Suffix".. i )  
   GetControl("TargetSuffix".. i .. "Name"):SetText(Bob[i])

end
or to change the label more easily : Control[i]:GetNamedChild("Name"):SetText("Bobi")

Last edited by Haho : 07/11/16 at 03:48 PM.
  Reply With Quote

ESOUI » Developer Discussions » Lua/XML Help » Resolve name for descendant of instantiated virtual control?

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