ESOUI

ESOUI (https://www.esoui.com/forums/index.php)
-   Lua/XML Help (https://www.esoui.com/forums/forumdisplay.php?f=175)
-   -   Resolve name for descendant of instantiated virtual control? (https://www.esoui.com/forums/showthread.php?t=6417)

tgolsson 07/11/16 11:38 AM

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.

Haho 07/11/16 11:52 AM

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.

sirinsidiator 07/11/16 12:04 PM

Welcome to ESOUI and addon development! :D

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.

tgolsson 07/11/16 12:23 PM

Quote:

Originally Posted by Haho (Post 27743)
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.

tgolsson 07/11/16 12:25 PM

Quote:

Originally Posted by sirinsidiator (Post 27744)
Welcome to ESOUI and addon development! :D

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.

Haho 07/11/16 12:42 PM

Quote:

Originally Posted by tgolsson (Post 27746)
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...

tgolsson 07/11/16 12:50 PM

Quote:

Originally Posted by Haho (Post 27748)
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?

Haho 07/11/16 12:56 PM

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.

tgolsson 07/11/16 01:14 PM

Quote:

Originally Posted by Haho (Post 27750)
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.

Haho 07/11/16 01:19 PM

Quote:

Originally Posted by tgolsson (Post 27751)
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>


Sasky 07/11/16 02:08 PM

Quote:

Originally Posted by tgolsson (Post 27746)
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

Haho 07/11/16 02:21 PM

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")


All times are GMT -6. The time now is 08:49 PM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2014 - 2022 MMOUI