Thread Tools Display Modes
07/23/14, 03:59 AM   #1
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
Creating a whole bunch of Elements dynamic from code

I have been thinking for a while now about making something I call the "Event Explorer". A single window that allows you to register every event in the game for simple debugging/testing purposes.
LibConstantMapper provides me the ability to get all the Event ID and thier names in a fully automatic fashion. And later even get me subgroups. My current count for 1.2.6 is 469 Event ID's

The only piece still missing is the GUI side of the equation.
At a simple level the window will look like this:
Window
->Row1
-->Label with event ID
-->Label with event Name
-->Checkbox to enabeled/disable listening to the event
-->maybe extra checkboxes for the way the data is output (into chat, onscreen notification, how detailed the output should be (all parameters or only that the event was fired?))
->Row2
-->Label with event ID
->Row3

I propably have to add some paging/register cards for efficiency.
A later version will likely have some categories/filters/grouping for specific event groups (like all COMBAT Events).

But for now the big issues are the handlers on the first checkbox.
Basically I need one handler that can automagically identify to wich Row (and thus event ID) it belongs too. One handler to regsiter it 469 times at 469 UI Elements.
I wil propably need a big code behind table anyway to hold all the data (wich setting is enabeled/disabeled). So if I need to store something like the UI Element reference after creating it would not be an issue.
  Reply With Quote
07/23/14, 05:04 AM   #2
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
I think paging will be the way to go. That way you create say 50 rows from a template, which you can write in xml with checkbox and labels already in it. You can put any data you want in the row control, similar to how inventory rows have control.data={bagId=1, slotIndex=2, etc}. There were ingame scripts from Aug 2013 on XeNTaX forum, where loot window was paged, and it did pretty much exactly what I described - OnInitialize created a fixed number of rows from a template, and on EVENT_LOOT_UPDATED and when switching pages, updated data in those rows.

Later you can even make a search filter, e.g. events containing "TRADE" in their name

edit: can we even publish snippets from ingame scripts? It's so awkward to always tell people "there is something somewhere ..."

Last edited by merlight : 07/23/14 at 05:07 AM.
  Reply With Quote
07/23/14, 06:07 AM   #3
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
Originally Posted by merlight View Post
I think paging will be the way to go. That way you create say 50 rows from a template, which you can write in xml with checkbox and labels already in it. You can put any data you want in the row control, similar to how inventory rows have control.data={bagId=1, slotIndex=2, etc}. There were ingame scripts from Aug 2013 on XeNTaX forum, where loot window was paged, and it did pretty much exactly what I described - OnInitialize created a fixed number of rows from a template, and on EVENT_LOOT_UPDATED and when switching pages, updated data in those rows.

Later you can even make a search filter, e.g. events containing "TRADE" in their name

edit: can we even publish snippets from ingame scripts? It's so awkward to always tell people "there is something somewhere ..."
Controls have a data property? That makes this a whole lot easier.
I know that as "Tag" property from WinForms and WPF. It is the second best solution for such a problem.

What is the way to get the "parent" XML Element of a control?
I would perfer to just drop the Event's ID as data in the Row. The event handler would get the Checkboxes Reference. Then I would go up on step to get the Row it is contained in and use the ID from that.

Edit:
I think I found it. Something liek thsi event handler code?
Lua Code:
  1. local function eventHandler(sender)
  2.     local senderParent = sender.GetParent()
  3.     local EventID = senderParent.data
  4.  
  5.     --Appropirate code that can now work with the EventID of the dynamicalyl created control
  6. end

Last edited by zgrssd : 07/23/14 at 06:10 AM.
  Reply With Quote
07/23/14, 06:21 AM   #4
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
I tried to write some untested code for illustration. Careful with dot where colon should be -- control:GetParent()

edit: or look at LAM controls, they too have custom data:
control.panel is the panel it's contained in
control.data is the optionData it was created from

Code:
<Control name="EventExplorerRow" virtual="true">
    <Dimensions y="45"/>
    <Controls>
        <Label name="$(parent)Id" font="ZoFontGame" horizontalAlignment="RIGHT">
            <Anchor point="RIGHT" relativePoint="LEFT" offsetX="50"/>
        </Label>
        <Label name="$(parent)Name" font="ZoFontGame">
            <!-- I don't know how, but it's definitely possible to make this clickable,
                 so that you can enable/disable events by cliking on the name (see "ZO_CheckButtonLabel") -->
            <Anchor point="LEFT" relativeTo="$(parent)Id" relativePoint="RIGHT" offsetX="20"/>
        </Label>
    </Controls>
</Control>
Lua Code:
  1. function EventExplorer:createRows()
  2.     local function onRowClicked(...)
  3.         self:onRowClicked(...)
  4.     end
  5.     self.rows = {}
  6.     for i = 1, NUM_PAGE_ROWS do
  7.         local row = CreateControlFromVirtual("$(parent)Row", self.pageScrollWindow, "EventExplorerRow", i)
  8.         row.data = {}
  9.         row:SetHandler("OnClicked", onRowClicked)
  10.         table.insert(self.rows, row)
  11.     end
  12. end
  13.  
  14. function EventExplorer:onRowClicked(control, button)
  15.     -- this handler should be usable for both labels and even the parent row control
  16.     -- (which I think will be useful so that cliking in the empty space between labels works)
  17.     local row
  18.     if control.data then
  19.         row = control
  20.     else
  21.         row = control:GetParent()
  22.     end
  23.     local status = self:toggleEventEnabled(row.data.eventId)
  24.     row:SetEnabled(status)
  25. end
Lua Code:
  1. -- this method will be used to fill the page with event ids and labels;
  2. -- you'd store all event ids returned from a filter in self.selectedEventIds;
  3. -- after the search you'd fill the 1st page with self:setPage(1);
  4. -- if there are more events than NUM_PAGE_ROWS, and you provide
  5. -- a control for switching to the next page, it can call self:setPage(self.currentPage);
  6. function EventExplorer:setPage(pageNumber)
  7.     local offset = math.min(0, pageNumber - 1) * NUM_PAGE_ROWS
  8.     for i, row in ipairs(self.rows) do
  9.         local eventId = self.selectedEventIds[i + offset]
  10.         local idLabel = row:GetNamedChild("Id")
  11.         local nameLabel = row:GetNamedChild("Name")
  12.         row.data.eventId = eventId
  13.         if eventId then
  14.             idLabel:SetText(tostring(eventId))
  15.             nameLabel:SetText(self:getEventName(eventId))
  16.             nameLabel:SetEnabled(self:isEventEnabled(eventId))
  17.         else
  18.             idLabel:SetText("")
  19.             nameLabel:SetText("")
  20.             nameLabel:SetEnabled(false)
  21.         end
  22.     end
  23. end
  24.  
  25. -- toggleEventEnabled, isEventEnabled will work with an internal table
  26. -- that will keep track of what events you have registered

Last edited by merlight : 07/23/14 at 06:30 AM.
  Reply With Quote
07/23/14, 06:28 AM   #5
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
Originally Posted by zgrssd View Post
Controls have a data property?
I'm spamming a bit, but this deserves a post separate from the garbage I posted above
Controls are userdata with metatables, and their __index and __newindex are plain tables, so you can put anything you want in them.
  Reply With Quote
07/23/14, 02:00 PM   #6
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
I took the basic window from AIResearch Grid:
xml Code:
  1. <GuiXml>
  2.     <Controls>
  3.         <TopLevelControl name="EventExplorerWindow" mouseEnabled="true" movable="true" clampedToScreen="true" hidden="true">
  4.             <Dimensions x="760" y="650" />
  5.             <Anchor point="CENTER" />
  6.             <Controls>
  7.  
  8.                 <Backdrop name="$(parent)BG" inherits="ZO_DefaultBackdrop" />
  9.  
  10.             </Controls>
  11.         </TopLevelControl>
  12.     </Controls>
  13. </GuiXml>

Added merlights template:
xml Code:
  1. <Control name="EventExplorerRow" virtual="true">
  2.     <Dimensions y="45"/>
  3.     <Controls>
  4.         <Label name="$(parent)Id" font="ZoFontGame" horizontalAlignment="RIGHT">
  5.             <Anchor point="RIGHT" relativePoint="LEFT" offsetX="50"/>
  6.         </Label>
  7.         <Label name="$(parent)Name" font="ZoFontGame">
  8.             <Anchor point="LEFT" relativeTo="$(parent)Id" relativePoint="RIGHT" offsetX="20"/>
  9.         </Label>
  10.     </Controls>
  11. </Control>

And made up some basic code to get the table and fill the window with entries:
Lua Code:
  1. local uniqueID = "d893fa70102add4c118054adcc1a1f82"
  2. local LCM = LibStub:GetLibrary("LibConstantMapper")
  3.  
  4. local dataList = {}
  5.  
  6. --get the list of Events
  7. local Events = LCM:getMappedData("Events")
  8.  
  9. local function fillWindow()
  10.     for key, value in ipairs(Events) do
  11.         local row = CreateControlFromVirtual("$(parent)Row", EventExplorerWindow, "EventExplorerRow", key)
  12.     end
  13. end
  14.  
  15. local function windowToggle()
  16.     EventExplorerWindow:SetHidden(not EventExplorerWindow:IsHidden())
  17. end
  18.  
  19. local function OnAddOnLoaded(eventID, AddonName)
  20.     if (AddonName~= "EventExplorer") then return end
  21.    
  22.     fillWindow()
  23.    
  24.     SLASH_COMMANDS["/eventexplo"] = windowToggle
  25. end
  26.  
  27. EVENT_MANAGER:RegisterForEvent("MyAddOn", EVENT_ADD_ON_LOADED, OnAddOnLoaded)
I only added the OnLoadedEvent because I got the errors from below and asumed the code was a bit to "early". But that was not it.


And all I get are those error messages and an empty window:
Code:
CreateControlFromVirtual failed.  ControlName[EventExplorerDynamicRow1], ParentName[EventExplorerWindow], VirtualName[EventExplorerRow].
CreateControlFromVirtual failed.  ControlName[EventExplorerDynamicRow2], ParentName[EventExplorerWindow], VirtualName[EventExplorerRow].
CreateControlFromVirtual failed.  ControlName[EventExplorerDynamicRow3], ParentName[EventExplorerWindow], VirtualName[EventExplorerRow].
And there is no explanation what exactly went wrong. Or even what remotely went wrong.
  Reply With Quote
07/23/14, 02:19 PM   #7
Garkin
 
Garkin's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 832
How your xml looks like? It should be something like this:

xml Code:
  1. <GuiXml>
  2.     <Controls>
  3.         <Control name="EventExplorerRow" virtual="true">
  4.             <Dimensions y="45"/>
  5.             <Controls>
  6.                 <Label name="$(parent)Id" font="ZoFontGame" horizontalAlignment="RIGHT">
  7.                     <Anchor point="RIGHT" relativePoint="LEFT" offsetX="50"/>
  8.                 </Label>
  9.                 <Label name="$(parent)Name" font="ZoFontGame">
  10.                     <Anchor point="LEFT" relativeTo="$(parent)Id" relativePoint="RIGHT" offsetX="20"/>
  11.                 </Label>
  12.             </Controls>
  13.         </Control>
  14.         <TopLevelControl name="EventExplorerWindow" mouseEnabled="true" movable="true" clampedToScreen="true" hidden="true">
  15.             <Dimensions x="760" y="650" />
  16.             <Anchor point="CENTER" />
  17.             <Controls>
  18.                 <Backdrop name="$(parent)BG" inherits="ZO_DefaultBackdrop" />
  19.             </Controls>
  20.         </TopLevelControl>
  21.     </Controls>
  22. </GuiXml>

There is no UI error with this .xml file.
  Reply With Quote
07/23/14, 02:57 PM   #8
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
Originally Posted by Garkin View Post
How your xml looks like? It should be something like this:

xml Code:
  1. <GuiXml>
  2.     <Controls>
  3.         <Control name="EventExplorerRow" virtual="true">
  4.             <Dimensions y="45"/>
  5.             <Controls>
  6.                 <Label name="$(parent)Id" font="ZoFontGame" horizontalAlignment="RIGHT">
  7.                     <Anchor point="RIGHT" relativePoint="LEFT" offsetX="50"/>
  8.                 </Label>
  9.                 <Label name="$(parent)Name" font="ZoFontGame">
  10.                     <Anchor point="LEFT" relativeTo="$(parent)Id" relativePoint="RIGHT" offsetX="20"/>
  11.                 </Label>
  12.             </Controls>
  13.         </Control>
  14.         <TopLevelControl name="EventExplorerWindow" mouseEnabled="true" movable="true" clampedToScreen="true" hidden="true">
  15.             <Dimensions x="760" y="650" />
  16.             <Anchor point="CENTER" />
  17.             <Controls>
  18.                 <Backdrop name="$(parent)BG" inherits="ZO_DefaultBackdrop" />
  19.             </Controls>
  20.         </TopLevelControl>
  21.     </Controls>
  22. </GuiXml>

There is no UI error with this .xml file.
I think I get it. The template was not properly put into <GuiXml> and <Controls> Tags. Hence the template was never properly read and could not be found

After solving this issues and some minor issue with the retreival of data I have anotehr issue:
Nothing is shown in the window. I double checked by giving the lables text and putting d(row) into the code - it is executed and the items are created. They are just not shown.

I asume that I am adding them on a level too high or that something in my window is wrong.
  Reply With Quote
07/23/14, 03:08 PM   #9
Garkin
 
Garkin's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 832
Originally Posted by zgrssd View Post
I think I get it. The template was not properly put into <GuiXml> and <Controls> Tags. Hence the template was never properly read and could not be found

After solving this issues and some minor issue with the retreival of data I have anotehr issue:
Nothing is shown in the window. I double checked by giving the lables text and putting d(row) into the code - it is executed and the items are created. They are just not shown.

I asume that I am adding them on a level too high or that something in my window is wrong.
Its because rows are not properly anchored to the window.

Try this code:
xml Code:
  1. <GuiXml>
  2.     <Controls>
  3.         <Control name="EventExplorerRow" virtual="true">
  4.             <Dimensions y="25"/>
  5.             <Controls>
  6.                 <Label name="$(parent)Id" font="ZoFontGame" horizontalAlignment="RIGHT">
  7.                     <Dimensions x="60"/>
  8.                     <Anchor point="LEFT" />
  9.                 </Label>
  10.                 <Label name="$(parent)Name" font="ZoFontGame">
  11.                     <Anchor point="LEFT" relativeTo="$(parent)Id" relativePoint="RIGHT" offsetX="20"/>
  12.                 </Label>
  13.             </Controls>
  14.         </Control>
  15.         <TopLevelControl name="EventExplorerWindow" mouseEnabled="true" movable="true" clampedToScreen="true" hidden="true">
  16.             <Dimensions x="760" y="650" />
  17.             <Anchor point="CENTER" />
  18.             <Controls>
  19.                 <Label name="$(parent)Title" inherits="ZO_WindowTitle" text="Event Explorer" />
  20.                 <Button name="$(parent)Close" inherits="ZO_CloseButton">
  21.                     <Anchor point="TOPRIGHT" offsetY="3" />
  22.                     <OnClicked>
  23.                         EventExplorerWindow:SetHidden(true)
  24.                     </OnClicked>
  25.                 </Button>
  26.                 <Control name="$(parent)Container" inherits="ZO_ScrollContainer">
  27.                     <Anchor point="TOPLEFT" offsetY="30" />
  28.                     <Anchor point="BOTTOMRIGHT" />
  29.                 </Control>
  30.                 <Backdrop name="$(parent)BG" inherits="ZO_DefaultBackdrop" />
  31.             </Controls>
  32.         </TopLevelControl>
  33.     </Controls>
  34. </GuiXml>

Lua Code:
  1. local LCM = LibStub("LibConstantMapper")
  2.  
  3. local dataList = {}
  4. local lastRow
  5.  
  6. --get the list of Events
  7. local Events = LCM:getDataByMapping("Events")
  8.  
  9. local function fillWindow()
  10.     for key, value in ipairs(Events) do
  11.         local row = CreateControlFromVirtual("$(parent)Row", EventExplorerWindowContainerScrollChild, "EventExplorerRow", key)
  12.         if key == 1 then
  13.             row:SetAnchor(TOPLEFT, EventExplorerWindowContainerScrollChild, TOPLEFT, 0, 0)
  14.         else
  15.             row:SetAnchor(TOP, lastRow, BOTTOM, 0, 0)
  16.         end
  17.         row:GetNamedChild("Id"):SetText(tostring(value.value))        
  18.         row:GetNamedChild("Name"):SetText(value.key)
  19.         lastRow = row        
  20.     end
  21. end
  22.  
  23. local function windowToggle()
  24.     EventExplorerWindow:SetHidden(not EventExplorerWindow:IsHidden())
  25. end
  26.  
  27. local function OnAddOnLoaded(eventID, AddonName)
  28.     if (AddonName~= "EventExplorer") then return end
  29.    
  30.     fillWindow()
  31.    
  32.     SLASH_COMMANDS["/eventexplo"] = windowToggle
  33. end
  34.  
  35. EVENT_MANAGER:RegisterForEvent("MyAddOn", EVENT_ADD_ON_LOADED, OnAddOnLoaded)

EDIT:
By the way list of events in your library contains global reference to EVENT_MANAGER.
Updated mapping:
lua Code:
  1. { mapping = "Events", pattern = "^EVENT_", exclude = "^EVENT_MANAGER"},

Last edited by Garkin : 07/23/14 at 03:11 PM. Reason: added LibConstantMapper note
  Reply With Quote
07/23/14, 03:30 PM   #10
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
Originally Posted by Garkin View Post
EDIT:
By the way list of events in your library contains global reference to EVENT_MANAGER.
Updated mapping:
lua Code:
  1. { mapping = "Events", pattern = "^EVENT_", exclude = "^EVENT_MANAGER"},
Fixed that.
Then I noticed the list also includes "EVENT_REASON_HARDWARE" & SOFTWARE.
And I cannot fix that until I get multiple-exclusions patterns running.

I think I understand it now a bit better, but have to let it go through my head a bit more.

By the way, are there any Container controlls? Stack Pannels, Scroll Pannels, Grids, that kind of thing?
Right now I am just dropping the labels as children of the same level onto the Window. I prefer to have a proper visual tree.
  Reply With Quote
07/23/14, 04:36 PM   #11
Sephiroth018
 
Sephiroth018's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 20
Originally Posted by zgrssd View Post
By the way, are there any Container controlls? Stack Pannels, Scroll Pannels, Grids, that kind of thing?
Right now I am just dropping the labels as children of the same level onto the Window. I prefer to have a proper visual tree.
Not really, there is just ZO_ScrollContainer, which provides vertical scrolling over all controls it contains. That requires you to have all controls created in it, one for every line you want to display (and, of course, properly positioned), which can easily lead to the damned "Too many anchors processed" error when creating many controls at once.

But before implementing such functionalities yourself, you could use the code I have written for my addon ItemSetGuide. I have made an helper that creates as much rows as are possible in it's parent and adds and handles a vertical scrollbar all by itself:
Lua Code:
  1. function libDwemerAssistants.CreateScrollControl(container, headerRow, createRowFunction, rowDataUpdateFunction, initialData)
  • container: is the parent container where the controls should be created and displayed
  • headerRow: is optional and just places the given control in the container, using it as header
  • createRowFunction: provides a function to create an empty row control for initialization and must return the empty row control and take the following arguments:
    • container: the parent container again
    • index: The number of the created control, starting with 1
  • rowDataUpdateFunction: A function that is called when another element has to be displayed in a row, requires the following arguments:
    • row: the row control that needs to be updated
  • initialData: optional, the data that should be set after creation

The container gets the following fields:
  • rows: A table containing all displayed rows
  • numberOfRows: The number of rows displayed at once, just to help me so I don't have to always count the elements in "rows" when needing that value.
  • setNewDataFunction: A function for replacing the current data table with a new one, including setting the scrollbar back to the top and displaying the first x elements of the new data table. Takes the following arguments:
    • control: The container itself
    • data: The data table containing the new data
  • currentData: The table containing all data that should be displayed
  • currentDataRow: The index of the element that is currently the first one

The row control gets the following fields:
  • rowData: The element displayed in that row
  • rowDataUpdateFunction: The function passed to libDwemerAssistants.CreateScrollControl to update the row

I know it could be better, but it's a start
I plan to make this available as a library here on esoui as soon as I am happy with the implementation.
  Reply With Quote
07/23/14, 04:40 PM   #12
Garkin
 
Garkin's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 832
Originally Posted by zgrssd View Post
Fixed that.
Then I noticed the list also includes "EVENT_REASON_HARDWARE" & SOFTWARE.
And I cannot fix that until I get multiple-exclusions patterns running.

I think I understand it now a bit better, but have to let it go through my head a bit more.

By the way, are there any Container controlls? Stack Pannels, Scroll Pannels, Grids, that kind of thing?
Right now I am just dropping the labels as children of the same level onto the Window. I prefer to have a proper visual tree.
I know just about two scroll templates - simple ZO_ScrollContainer used in my code above and ZO_ScrollList.
Example of ZO_ScrollList:
http://www.esoui.com/downloads/info5...stExample.html
  Reply With Quote
07/24/14, 05:28 AM   #13
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
Originally Posted by Garkin View Post
I know just about two scroll templates - simple ZO_ScrollContainer used in my code above and ZO_ScrollList.
Example of ZO_ScrollList:
http://www.esoui.com/downloads/info5...stExample.html
I don't understand your example. Mainly because you do at least 5 other things beside making a scroll list and I have no idea where wich part ends.

Please give me an example for this simple case:
I have a Window of Size 400x400
I have three labels 400x200 to put into that window. Since the labels together are higher then the window, I need to put a scrollist in the window and the labels in the scrollist.
How do I use ZoScrollList to do that?
If possible, make a pure XML example (I am not sure you can even use ZoScrollList in XML as it seems not valid as control type when I tried).

My expierence would say the XML tree would look roughly like this:
Window
->ZoScrollList
-->Label1
-->Label2
-->Label2
->Maybe other controls contained in the Window like menu strip, satus bar, etc.
  Reply With Quote
07/24/14, 06:42 AM   #14
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
Originally Posted by zgrssd View Post
If possible, make a pure XML example (I am not sure you can even use ZoScrollList in XML as it seems not valid as control type when I tried).
You create a <Control> with attribute inherits="ZO_ScrollList". ZO_ScrollList is itself a <Control> with attribute virtual="true".
In Garkin's XML above, it's this part (with ZO_ScrollContainer instead):

Originally Posted by Garkin View Post
xml Code:
  1. <GuiXml>
  2.     <Controls>
  3.         ...
  4.         <TopLevelControl name="EventExplorerWindow" mouseEnabled="true" movable="true" clampedToScreen="true" hidden="true">
  5.             <Dimensions x="760" y="650" />
  6.             <Anchor point="CENTER" />
  7.             <Controls>
  8.                 ...
  9.                 <Control name="$(parent)Container" inherits="ZO_ScrollContainer">
  10.                     <Anchor point="TOPLEFT" offsetY="30" />
  11.                     <Anchor point="BOTTOMRIGHT" />
  12.                 </Control>
  13.                 ...
  14.             </Controls>
  15.         </TopLevelControl>
  16. </GuiXml>
ZO_ScrollContainer is a control that contains the slider bar, buttons and the scrolled area, which is named "$(parent)ScrollChild".

"EventExplorerWindow" -> "Container" -> "ScrollChild" is then named EventExplorerWindowContainerScrollChild in _G, look that up in Garkins code, this control is used as the parent of created rows.
  Reply With Quote
07/24/14, 07:11 AM   #15
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
Originally Posted by merlight View Post
You create a <Control> with attribute inherits="ZO_ScrollList". ZO_ScrollList is itself a <Control> with attribute virtual="true".
In Garkin's XML above, it's this part (with ZO_ScrollContainer instead):



ZO_ScrollContainer is a control that contains the slider bar, buttons and the scrolled area, which is named "$(parent)ScrollChild".

"EventExplorerWindow" -> "Container" -> "ScrollChild" is then named EventExplorerWindowContainerScrollChild in _G, look that up in Garkins code, this control is used as the parent of created rows.
So instead of being a seperate type of control (like <Label/>, <EditBox/> and the like) that has other elements as childs, the scroll container is a "Control" whose inherits atribute was set? The same way you set a <Backdrop/> inherits atrbute, to tell it wich Backdrop it has to look like?


I try to get some understanding of what happens via the rules that apply to WPF. There writing code like this:
xml Code:
  1. <Label>
  2.     <Content>
  3.         "Test"
  4.     <Content/>
  5. </Label>

would just be different syntax for this:
xml Code:
  1. <Label Content="Test"/>
With the first syntax having the potentioal for a lot more complex content then a mere string (A label could contain a image. Or a container that in turn has dozens of sub elments).


Going from there:
xml Code:
  1. <GuiXml>
  2.     <Controls>
  3.         </Controls>
  4. </GuiXML>
I just the way to set the "Controls" Field/Property of the GuiXML element.


Wich elements all have a "Controls" property and are thus containers?
Is it only "GuiXML", "Control" and "TopLevelControl"? All of them? All of them but a few?
  Reply With Quote
07/24/14, 09:01 AM   #16
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
Originally Posted by zgrssd View Post
So instead of being a seperate type of control (like <Label/>, <EditBox/> and the like) that has other elements as childs, the scroll container is a "Control" whose inherits atribute was set? The same way you set a <Backdrop/> inherits atrbute, to tell it wich Backdrop it has to look like?
Not exactly "instead of being a separate type of control", it's just a generic type of control which doesn't have an appearance of its own, a container for other controls. Any control may inherit attributes & contents from a template. But I guess you can only sensibly inherit from the same type of control, i.e. Backdrop inherits from another Backdrop, Label from another Label, etc.

Originally Posted by zgrssd View Post
I try to get some understanding of what happens via the rules that apply to WPF.
I would refrain from drawing similarities. Although I don't know WPF, there will certainly be differences, and concepts from one system might not apply to another. If we're talking strictly XML DOM, then your two examples are completely different things:

This is element node <Label> with no attributes and 1 child element node <Content>, which in turn has 1 child text node with value "Test":
Originally Posted by zgrssd View Post
xml Code:
  1. <Label>
  2.     <Content>
  3.         "Test"
  4.     <Content/>
  5. </Label>
Whereas this is element node <Label> with 1 attribute Content="Test":
Originally Posted by zgrssd View Post
xml Code:
  1. <Label Content="Test"/>
I don't know how ESO parses XML, but I tell you if I were to do that, I'd take a ready-made library that would parse the file and give me DOM tree, and then just walk the tree. That attribute<=>text equality (or ambiquity) you decribed is a hack invented by people who thought XML should be written by humans, and they complicate their parsers to make that torture less painful.


Now back to ESO. They made their UI elements reusable through inheritance, so that any control can be used as a template. For example:
xml Code:
  1. <!-- these are templates -->
  2. <Label name="LeftBoldText" font="ZoFontGameBold" horizontalAlignment="LEFT" virtual="true" />
  3. <Label name="RightBoldText" font="ZoFontGameBold" horizontalAlignment="RIGHT" virtual="true" />
  4.  
  5. <!-- these are actual controls; you can have 50 of them,
  6.        and if you decide to change the font, you change it in the template -->
  7. <Label name="Label1" inherits="LeftBoldText"> ... </Label>
  8. <Label name="Label2" inherits="RightBoldText"> ... </Label>


Originally Posted by zgrssd View Post
Wich elements all have a "Controls" property and are thus containers?
Is it only "GuiXML", "Control" and "TopLevelControl"? All of them? All of them but a few?
In addition to those I found <Slider>, <EditBox>, <Tooltip>, <Label>, <Cooldown> with inner <Controls>. Perhaps all controls can have children, to me it'd seem logical, since <Control> can have them and I think that's the base for other controls, but who knows.

Last edited by merlight : 07/24/14 at 09:08 AM.
  Reply With Quote
07/24/14, 12:56 PM   #17
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
Virtuals sole purpose seem to be to be inherited. Template might not be the right word after all.
It's a bit like comparing a virtual control to a abstract class - it is only there to be inhereted, not be shown itself directly. And CreateFromVirtual does little more then create a element that does inherit it.

Already figured out that Property Element Syntax of WPF does not work here.
Instead they seem to have a special "kind" of Cildren. "Atribute Children" or "Property Children" might be a propper name. They are children with the sole purpose to define stuff about thier parent. They have no meaning of thier own.
Property Children do not inherit from Control and seem mostly structures. But they may also have inherentianc chains and functions (like AnimationBase and it's Inheritors).

'Controls' is just one of the "Property Children" of Control and it's job is to contain a list of other controls. Every control itself seems to be derived from control, hence every control is also a container itself.

Now stuff makes a lot more sense then it did before.
  Reply With Quote
07/24/14, 01:11 PM   #18
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
Originally Posted by zgrssd View Post
Virtuals sole purpose seem to be to be inherited. Template might not be the right word after all.
Well it's the word ZOS uses, so we went with it
Lua Code:
  1. function CreateControlFromVirtual(name, parent, templateName, optionalNameSuffix)
xml Code:
  1. <Control name="ZO_RadialMenuTemplate" hidden="true" virtual="true">
  Reply With Quote
07/24/14, 01:39 PM   #19
zgrssd
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 280
Currently my XML looks like this:
xml Code:
  1. <GuiXml>
  2.     <Controls>
  3.         <TopLevelControl name="EventExplorerWindow" mouseEnabled="true" movable="true" clampedToScreen="true" hidden="true" >
  4.             <Dimensions x="760" y="650" />
  5.             <Anchor point="CENTER" />
  6.             <Controls>
  7.                 <Backdrop name="$(parent)BG" inherits="ZO_DefaultBackdrop" />
  8.                 <Control name="$(parent)Scroll" inherits="ZO_ScrollList">
  9.                     <Anchor point="TOPLEFT" offsetY="30" />
  10.                     <Anchor point="BOTTOMRIGHT" />
  11.                 </Control>
  12.             </Controls>
  13.         </TopLevelControl>
  14.        
  15.         <Control name="EventExplorerRow" virtual="true">
  16.             <Dimensions y="25"/>
  17.             <Controls>
  18.                 <Label name="$(parent)Id" font="ZoFontGame" horizontalAlignment="RIGHT" >
  19.                     <Dimensions x="60"/>
  20.                     <Anchor point="LEFT" />
  21.                 </Label>
  22.                 <Label name="$(parent)Name" font="ZoFontGame" >
  23.                     <Anchor point="LEFT" relativeTo="$(parent)Id" relativePoint="RIGHT" offsetX="20"/>
  24.                 </Label>
  25.             </Controls>
  26.         </Control>
  27.     </Controls>
  28. </GuiXml>

with fill Window looking like:
Lua Code:
  1. local function fillWindow()
  2.     for key, value in ipairs(Events) do
  3.         local row = CreateControlFromVirtual("$(parent)Row", EventExplorerWindowScroll, "EventExplorerRow", key)
  4.         if key == 1 then
  5.             row:SetAnchor(TOPLEFT, EventExplorerWindowScroll, TOPLEFT, 0, 0)
  6.         else
  7.             row:SetAnchor(TOP, lastRow, BOTTOM, 0, 0)
  8.         end
  9.         row:GetNamedChild("Id"):SetText(tostring(value.value))        
  10.         row:GetNamedChild("Name"):SetText(value.key)
  11.         lastRow = row  
  12.     end
  13. end

Still not getting quite the results I expected, but at least I am hitting the right container element:


I would guess the Scroll Window is not properly aware that it's own Dimensions should bve confined to the Windows Dimensions. So it will automatically stretch to it's contents size instead of doing scroll panel stuff.
Attached Thumbnails
Click image for larger version

Name:	post.PNG
Views:	1646
Size:	659.4 KB
ID:	360  
  Reply With Quote
07/24/14, 01:43 PM   #20
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
ZO_ScrollList has a child <Scroll name="$(parent)Contents" mouseEnabled="true">, use that as row parent, i.e. EventExplorerWindowScrollContents.
  Reply With Quote

ESOUI » Developer Discussions » Lua/XML Help » Creating a whole bunch of Elements dynamic from code


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