Thread Tools Display Modes
04/08/14, 09:45 AM   #21
thelegendaryof
 
thelegendaryof's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 161
I have to say mixing code with layout-structure always reminds me about using inline JS and inline CSS in HTML:

Bad practice

There is a reason you have both.

1. XML is for structure (as in describing your layout)
2. LUA is for functionality that uses that structure (as in bringing that layout to life)

While some coders do prefer doing everything with only code due to performance reasons (which might be valid and better if there isn't much going on) the usability and maintenance of it is significantly harder especially if things get more complex.

For example when they introduce bigger API changes the XML-Definition is high likely to stay the same -
while the API-Functions itself are most likely to change. Resulting in a broken layout that needs to get adjusted.

That taken aside when you have multiple people working on a project (speaking from a professional side) it 's way easier for the Designers to just jump in and make their adjustments in a simple XML-File then by digging in your Code (and breaking the functionality instead of changing the Layout).

At least that is how one should tell it to a beginner in terms of optimal viewpoints overall for both the Designer as well as the Developers.

Pawkette's Projects are an good example at how you could / should mix them properly (in my opinion)

Last edited by thelegendaryof : 04/08/14 at 10:04 AM.
  Reply With Quote
04/08/14, 10:35 AM   #22
Xrystal
caritas omnia vincit
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 369
I can see where you are coming from and I don't negate anything you said. However.

My main reasons for doing everything in Lua is as follows:

1. Ability to create un-named frames to keep them out of the global namespace and local to the file itself.
2. Ability to at a later date allow access outside of the addon to one or more frames/tables at will with a simple function.
3. Error track ability. Lua related errors will show file name and line that the last error was noticed. XML related errors will not even mention what file let alone which element within the file is triggering the problem.

So here goes my view on Pros and Cons.

Both XML and Lua
Pros
-- Separates layout and functionality
-- Allows easier relocation of individual frames without the need to change functionality
Cons
-- Forces global naming and public access to every frame regardless to whether you wanted to or not
-- Forces unique and normally longwinded naming due to the global nature of XML structure
-- Errors are harder to identify if they are triggered in the XML and not the Lua file first.

Just Lua
Pros
-- Full control over process order
-- The ability to keep all data out of the global namespace and private to the addon
-- Allows realistic naming of variables as they are only used in your addon.
-- Errors are easier to identify as file name and line number are reported when errors occur
Cons
-- Some functionality, so far, seems to only be available inside of XML files meaning a Lua only project may not be possible.
-- Changing of layout may be somewhat more work, depending on how it was coded in the first place.

I have never said or felt that XML users were doing anything wrong, just that I felt more comfortable to use just Lua. I have no real problem using XML and Lua in my projects but I don't like the idea of having frames unnecessarily in the global table. Which at present all my frames are, and my addon still hasn't reached it's peak yet so I won't be surprised to find myself adding more frames later on for one functionality or another which will mean I will have even more frames flooding the global table needlessly. Unless of course there is a way to make un named frames with XML ? I doubt that the name field is optional if you need to access it in your lua file.

Last edited by Xrystal : 04/08/14 at 10:43 AM.
  Reply With Quote
04/08/14, 12:32 PM   #23
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 648
Sorry, Xrystal, guess I was too tired and missed a couple of things. >< I'll look at it again tonight.
  Reply With Quote
04/08/14, 01:01 PM   #24
thelegendaryof
 
thelegendaryof's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 161
Originally Posted by Xrystal View Post
I can see where you are coming from and I don't negate anything you said. However.

My main reasons for doing everything in Lua is as follows:

1. Ability to create un-named frames to keep them out of the global namespace and local to the file itself.
2. Ability to at a later date allow access outside of the addon to one or more frames/tables at will with a simple function.
3. Error track ability. Lua related errors will show file name and line that the last error was noticed. XML related errors will not even mention what file let alone which element within the file is triggering the problem.

So here goes my view on Pros and Cons.

Both XML and Lua
Pros
-- Separates layout and functionality
-- Allows easier relocation of individual frames without the need to change functionality
Cons
-- Forces global naming and public access to every frame regardless to whether you wanted to or not
-- Forces unique and normally longwinded naming due to the global nature of XML structure
-- Errors are harder to identify if they are triggered in the XML and not the Lua file first.

Just Lua
Pros
-- Full control over process order
-- The ability to keep all data out of the global namespace and private to the addon
-- Allows realistic naming of variables as they are only used in your addon.
-- Errors are easier to identify as file name and line number are reported when errors occur
Cons
-- Some functionality, so far, seems to only be available inside of XML files meaning a Lua only project may not be possible.
-- Changing of layout may be somewhat more work, depending on how it was coded in the first place.

I have never said or felt that XML users were doing anything wrong, just that I felt more comfortable to use just Lua. I have no real problem using XML and Lua in my projects but I don't like the idea of having frames unnecessarily in the global table. Which at present all my frames are, and my addon still hasn't reached it's peak yet so I won't be surprised to find myself adding more frames later on for one functionality or another which will mean I will have even more frames flooding the global table needlessly. Unless of course there is a way to make un named frames with XML ? I doubt that the name field is optional if you need to access it in your lua file.
Yip absolutely valid as well. Wasn't basically directed towards you or any other advanced developer more like a general rule for the thread opener and alike. As always if you're experienced - break the rule when you feel like it 's right to do so (there 's always pros and cons).

Last edited by thelegendaryof : 04/08/14 at 01:06 PM.
  Reply With Quote
04/08/14, 01:28 PM   #25
Brainling
Join Date: Apr 2014
Posts: 18
In the professional world, mixing your code and layout are absolute no-no's. UI programming 101 stuff.

That said, this isn't a professional environment. If people are more comfortable in pure code, let them use pure code. Bugs and maintenance headaches caused by this aren't likely to lose anyone money or cause direct harm to a 'business'. People are writing these add-ons for fun, and in many cases aren't professional software engineers. Provided their style of coding isn't directly causing client issues (high memory and/or CPU usage), I'm all for letting people do things the way they are comfortable and find fun.

Personally I'll be going the route of using XML and virtual XML templates for my UI, as that's the environment I feel comfortable in coming from a professional web and WPF background. The idea of layout markup being fundamentally separated from the code is like a warm blanket for me.
  Reply With Quote
04/08/14, 01:57 PM   #26
Xrystal
caritas omnia vincit
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 369
Originally Posted by Seerah View Post
Sorry, Xrystal, guess I was too tired and missed a couple of things. >< I'll look at it again tonight.
It's cool. It gave me a chance to try and figure it out myself but none of my thoughts and ideas panned out rofl. But it also showed me how close I was to converting it correctly, it almost looked like my code rofl.
  Reply With Quote
04/08/14, 04:47 PM   #27
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 648
Tada!!! Didn't have to make one from scratch, I found a nice and easy template in the UI files. (Sorry guys, we still don't have permission to upload them. )

From the character sheet, the dropdown that you can select a title in uses this template...
Code:
        <Control name="ZO_StatsDropdownRow" virtual="true">
            <Dimensions x="607" y="30" />
            <OnInitialized>
                self.name = self:GetNamedChild("Name")
                self.dropdown = ZO_ComboBox_ObjectFromContainer(self:GetNamedChild("Dropdown"))
            </OnInitialized>
            <Controls>
                <Label name="$(parent)Name" inherits="ZO_StatsRowName"/>
                <Control name="$(parent)Dropdown" inherits="ZO_ComboBox">
                    <Dimensions x="300"/>
                    <Anchor point="RIGHT"/>
                </Control>
            </Controls>
        </Control>
To just Lua, using the pre-existing template shown above:
Lua Code:
  1. local wm = WINDOW_MANAGER  --just an upvalue
  2. local choices = {"apple", "banana", "cherry"}  --this is the table of choices to go in the dropdown
  3.  
  4. local myFrame = wm:CreateTopLevelWindow("myFrameForXrystal")  --this can be whatever toplevel frame you need it to be to anchor the dropdown stuff to
  5.     myFrame:SetAnchor(CENTER)
  6.     myFrame:SetDimensions(200, 50)
  7. local dropdownContainer = wm:CreateControlFromVirtual("myFrameForXrystalDropdown", myFrame, "ZO_StatsDropdownRow")  --create your dropdown container using the template above
  8.     dropdownContainer:SetAnchor(TOPLEFT)  --anchor this container however you need to
  9.     dropdownContainer:GetNamedChild("Dropdown"):SetWidth(200)  --change your dimensions if different from the template's (607, 30)
  10. local selected = dropdownContainer.name  --the template put the label in our container's table, you don't need this line unless you want it
  11. local dropdown = dropdownContainer.dropdown  --the template put our actual dropdown object into our container's table. Here's a local reference so we don't have to keep doing a table look-up
  12.     dropdown:SetSelectedItem("cherry")  --set your initial dropdown selection - usually taken from the saved variables
  13.  
  14. local function OnItemSelect(_, choiceText, choice)  --this is the callback function for when an item gets selected in the dropdown
  15.     d(choiceText, choice)
  16. end
  17.  
  18. for i=1,#choices do  --loop through your table to add the selections to the dropdown
  19.     local entry = dropdown:CreateItemEntry(choices[i], OnItemSelect)  --this really just creates a table with {name = choices[i], callback = OnItemSelect} - you may be able to skip this step and just pass the correctly formatted table into the below function...
  20.     dropdown:AddItem(entry)  --again, entry is just a table with the above args stored in it
  21. end


If everything works right, we can put it on the wiki.

Last edited by Seerah : 04/08/14 at 07:54 PM.
  Reply With Quote
04/08/14, 05:43 PM   #28
thelegendaryof
 
thelegendaryof's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 161
Originally Posted by Seerah View Post
I found a nice and easy template in the UI files. (Sorry guys, we still don't have permission to upload them.
That 's nice and sad as well .

At least you have them - did you get them officially or did you RE it?
  Reply With Quote
04/08/14, 05:44 PM   #29
Xrystal
caritas omnia vincit
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 369
It worked great with that little extra change.

The downside is that it must overwrite the font sizes so gonna try and get it run after the addon is loaded and see how different it works. But first screen shot shows it working as follows:

edit:

Well combined your two posts into the following piece of code so that you could create multiple combo boxes ( dropdowns ) in the same Top Level Window.

Lua Code:
  1. local wm = WINDOW_MANAGER
  2. local choices1 = {"alpha","beta","gamma","delta","epsilon","zita","ita","theta","iota","kappa","lambda","mu","nu","omicron","pi","rho","sigma","tau","ipsilon","omega"}
  3. local choices2 = {"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"}
  4.  
  5. local function CreateTopLevelWindow(name)
  6.     local tlw = wm:CreateTopLevelWindow(name)
  7.     tlw:SetAnchor(CENTER)
  8.     tlw:SetDimensions(200, 50)
  9.     return tlw
  10. end
  11.  
  12. local function CreateDropDown(name,parent,data,selected)
  13.     local combo = wm:CreateControlFromVirtual(parent:GetName()..name,parent,"ZO_StatsDropdownRow")
  14.     combo:SetAnchor(CENTER)
  15.     combo:GetNamedChild("Dropdown"):SetWidth(200)
  16.  
  17.     combo.selected = combo.name
  18.     combo.selected:SetFont("ZoFontGameLarge")
  19.  
  20.     combo.dropdown = combo.dropdown
  21.     combo.dropdown:SetFont("ZoFontGameLarge")
  22.     if selected then combo.dropdown:SetSelectedItem(selected) end
  23.  
  24.     combo.dropdown.OnSelect = function(self,value)
  25.         self:SetSelectedItem(value)
  26.     end
  27.  
  28.     for i = 1,#data do
  29.         local entry = combo.dropdown:CreateItemEntry(data[i],combo.dropdown.OnSelect)
  30.         combo.dropdown:AddItem(entry)
  31.     end
  32.     return combo
  33. end
  34.  
  35. local function AddOnLoaded(eventID,addon)
  36.     if addon ~= "ZO_ComboBoxTest" then return end
  37.     EVENT_MANAGER:UnregisterForEvent(addon,eventID)
  38.     local testTLW = CreateTopLevelWindow("ZO_ComboBoxTest_TLW")
  39.     testTLW:SetDimensions(200,120) 
  40.     local GreekAlphabet = CreateDropDown("GreekAlphabet",testTLW,choices1,"omega")
  41.     GreekAlphabet:SetAnchor(TOP)
  42.     local Weekdays = CreateDropDown("Weekdays",testTLW,choices2,"Sunday")
  43.     Weekdays:SetAnchor(BOTTOM)
  44. end
  45.  
  46. EVENT_MANAGER:RegisterForEvent( "ZO_ComboBoxTest" ,EVENT_ADD_ON_LOADED , AddOnLoaded )

2nd picture shows the 2 together on the screen.

edit 3:
But as you can see, the font still isn't letting you change it for some reason. Maybe you would have to make a template of the template and change the fonts at that point. But no biggie.
Attached Thumbnails
Click image for larger version

Name:	Screenshot_20140409_004156.jpg
Views:	625
Size:	364.0 KB
ID:	108  Click image for larger version

Name:	Screenshot_20140409_011016.jpg
Views:	659
Size:	426.1 KB
ID:	109  

Last edited by Xrystal : 04/08/14 at 06:14 PM.
  Reply With Quote
04/08/14, 07:53 PM   #30
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 648
Hmm... I am able to get the font to change with only
Lua Code:
  1. dropdown:SetFont("ZoFontBookPaper")
Attached Thumbnails
Click image for larger version

Name:	Capture.PNG
Views:	631
Size:	378.4 KB
ID:	112  
  Reply With Quote
04/08/14, 08:40 PM   #31
Xrystal
caritas omnia vincit
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 369
Hmm, guess ZoFontGameLarge isn't that much larger than ZoFontGame rofl. I probably didn't notice the difference.

I added another combo box with a selection of built in fonts listed in Zgoo, not figured out whether there is a way to set the font per option but probably not a good idea seeing as it seems to be using the same font for the whole control.

I adjusted my combo box function to add an option callback function and in the OnSelect function I return the font selected to the callback function so that it can use it and I told it to change the font for the dropdowns of the combo boxes. It changes the selected font to the same font as well.

Some don't look much different but some of them you can definitely see the change.

SetResizeToFitDescendents don't seem to work unless I am expecting it to do something different at the wrong time.

Anyway,

Function header line was changed to
Lua Code:
  1. local function CreateDropDown(name,parent,data,selected,callback)
And the OnSelect function was changed to
Lua Code:
  1. combo.dropdown.OnSelect = function(self,value)
  2.     self:SetSelectedItem(value)
  3.     if callback then callback(value) end
  4. end
The call to this function changed to ..
Lua Code:
  1. Fonts = CreateDropDown("Fonts",testTLW,choices3,"ZoFontGame",function(value) UseFont(value) end)
And that callback function
Lua Code:
  1. local function UseFont(fontName)
  2.     Fonts.dropdown:SetFont(fontName)
  3.     GreekAlphabet.dropdown:SetFont(fontName)
  4.     Weekdays.dropdown:SetFont(fontName)
  5. end

Picture showing what it looks like now. Just did a quick test to see if you can turn off the names but nada .. so even though the variables are local the frames/windows still have global names .. which is a pity.
Attached Thumbnails
Click image for larger version

Name:	Screenshot_20140409_033706.jpg
Views:	649
Size:	406.5 KB
ID:	113  
  Reply With Quote
04/09/14, 03:07 AM   #32
Shinni
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 167
I tried using lua instead of xml but i must have done something wrong:

Lua Code:
  1. local control = WINDOW_MANAGER:CreateTopLevelWindow("TestTopLevel")
  2. control:SetHandler("OnUpdate", function() d(123) end )

the OnUpdate function doesn't seem to be called...

edit:
function(self, time)
doesnt work as well

edit2:
Lua Code:
  1. local b = WINDOW_MANAGER:CreateControlFromVirtual("asd", GuiRoot, "ZO_StatsDropdownRow")
  2. local a = WINDOW_MANAGER:CreateControl("asd2", GuiRoot, CT_CONTROL )
  3. b:SetHandler("OnUpdate", function(...) d(123) end )
  4. a:SetHandler("OnUpdate", function(...) d(456) end )
hmm the control from CreateControlFromVirtual works, but the other one doesn't...

Last edited by Shinni : 04/09/14 at 04:11 AM.
  Reply With Quote
04/09/14, 05:06 AM   #33
Xrystal
caritas omnia vincit
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 369
Ah, so that's why sometimes OnUpdate has been working for some people from Lua and other times not. Good find Shinni.
  Reply With Quote
04/09/14, 12:40 PM   #34
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 648
I think I (or someone else?) have mentioned this "bug" before - it was noticed during Beta. When creating a control from scratch, the OnUpdate handler is missing. You need to set it in XML or use a template that already has it set.
  Reply With Quote
04/09/14, 12:42 PM   #35
Xrystal
caritas omnia vincit
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 369
Originally Posted by Seerah View Post
I think I (or someone else?) have mentioned this "bug" before - it was noticed during Beta. When creating a control from scratch, the OnUpdate handler is missing. You need to set it in XML or use a template that already has it set.
Ah, I know it was suggested to use the XML to get the OnUpdate routine working but I never knew the reason for it not working.

Thanks Seerah.
  Reply With Quote
04/10/14, 09:51 AM   #36
Stormknight
 
Stormknight's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 128
Posting this here as it may help someone else.

I was getting odd "attempt to index a nil value" message on loading from my add-on, from a line in the OnUpdate() function.

The reason it was happening is because I have the <OnUpdate> declared within the XML and it was firing before my add-on had completed it's initialisation, which included loading saved variables.

So, the OnUpdate() function was trying to access a saved variable that hadn't been loaded yet.

I resolved this by simply creating an initialised variable in my add-on.

Code:
MyAddon = ()
MyAddon.initialised = false
MyAddon.name = "MyAddon"

function MyAddon.OnUpdate()
    -- Bail if we haven't completed the initialisation routine yet.
    if (not MyAddon.initialised) then return end
    -- code I wanted to execute here
end

function MyAddon.Initialise(eventCode, addOnName)
    -- Only initialize our own addon
    if (MyAddon.name ~= addOnName) then return end
    -- Do my initialisation tasks here, including loading saved variables etc
    MyAddon.initialised = true
end

EVENT_MANAGER:RegisterForEvent("MyAddon", EVENT_ADD_ON_LOADED, MyAddon.Initialise)
with the XML being something like
Code:
<GuiXml>
    <Controls>
        <TopLevelControl name="MyAddon" mouseEnabled="true" movable="true" clampedToScreen="true">
            <Dimensions x="200" y="200" />
            <OnUpdate>
                MyAddon.OnUpdate()
            </OnUpdate>
        </TopLevelControl>
    </Controls>
</GuiXml>
  Reply With Quote
04/10/14, 10:13 AM   #37
Brainling
Join Date: Apr 2014
Posts: 18
Great stuff Stormknight. Thanks for the tip. Since I am using XML for my UI's as well, I'm going to find that handy I'm sure.
  Reply With Quote
04/10/14, 08:38 PM   #38
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 648
Upon creation of your frame in the XML, you can hide it. This will stop it from running the OnUpdate script. When you are ready to, you can show the frame again.
  Reply With Quote
04/10/14, 09:30 PM   #39
Stormknight
 
Stormknight's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2014
Posts: 128
Originally Posted by Seerah View Post
Upon creation of your frame in the XML, you can hide it. This will stop it from running the OnUpdate script. When you are ready to, you can show the frame again.
Ah, nice, it hadn't occured to me that a hidden frame wouldn't receive update events, but it makes sense.
  Reply With Quote
05/11/14, 01:02 AM   #40
CatoTheElder
Join Date: May 2014
Posts: 44
Angry

Originally Posted by Brainling View Post
In the professional world, mixing your code and layout are absolute no-no's. UI programming 101 stuff.

That said, this isn't a professional environment. If people are more comfortable in pure code, let them use pure code. Bugs and maintenance headaches caused by this aren't likely to lose anyone money or cause direct harm to a 'business'. People are writing these add-ons for fun, and in many cases aren't professional software engineers. Provided their style of coding isn't directly causing client issues (high memory and/or CPU usage), I'm all for letting people do things the way they are comfortable and find fun.

Personally I'll be going the route of using XML and virtual XML templates for my UI, as that's the environment I feel comfortable in coming from a professional web and WPF background. The idea of layout markup being fundamentally separated from the code is like a warm blanket for me.
This has been a huge argument, for a long time. I am a professional software developer (linux kernel and drivers), so I can do API scripting, but it is far more difficult, especially without documentation. That said, in a professional environment you need to maximize your efficiency. This means clear memory when you're done with it (especially arrays/tables), dispose of objects when they're no longer required, minimize indexing/searching arrays etc. This is the reason XML should not be used at all. It is insecure, inefficient, and as a result requires more system resources than necessary.

ESPECIALLY IF YOU HOOK OnUpdate() - OnUpdate() gets called every frame re-draw (ie 60 FPS = 60 calls to OnUpdate(). This creates a huge drain on system resources, even from minimal code.

XML:
Parses file, creates templates (or objects) on addon load, loads them into memory in the global name space, and leaves them there forever, allowing another to modify/overwrite your controls, accidentally or otherwise. So, bad security, bad memory management. Don't use XML.

Professional LUA Script:
Controls are dynamically loaded in to memory when needed.
Controls are protected from tampering by being in a private memory space
Controls are dynamically unloaded, freeing memory as soon as the control is no longer required.
Multiple controls can easily be created by using a function.

I've seen addons that require higher memory usage, and CPU utilization than entire operating systems. This is why it shouldn't be "okay" for people to "do things the way they are comfortable."

I spend a lot of time and effort keeping my system optimized, and poor code is extremely frustrating, especially from so-called professional web developers. Gee, I wonder what GUI is used to make your operating sytem's GUI? ... Oh, right, that's an infinite loop. At the bottom, the GUI is written in code. Absolute no-nos? Please, stop talking.

Last edited by CatoTheElder : 05/11/14 at 01:04 AM. Reason: ignorant people piss me off
  Reply With Quote

ESOUI » Developer Discussions » General Authoring Discussion » XML vs Lua for GUI Best Practices

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