← XML UI
This article is a guide to XML basics] as an introduction to XML, and is intended as a sort of prerequisite for the more in depth WoW specific UI XML tutorial. For more background see XML Introduction at xmlfiles.com.
XML (.xml) files can be used to define any part of an AddOn that draws to the screen, by creating frames with buttons and so on. If you're going to be creating addons, you'll want to learn this sooner rather than later. As with .lua, you can use any text editor to write and modify XML files. Notepad on Windows or TextEdit on OS X should do the trick. There are many better editors available, such as E for Windows and TextMate for the Mac, should you choose to upgrade.
XML files are structured as a bunch of nested tags, each with content and attributes. A tag is used to provide information about something. Say we wanted to use XML to describe the contents of our fridge. We would start by creating an empty "fridge" tag.
Now that we have a fridge, we can start adding things to it. Let's put a couple pizzas in our fridge, by adding them as content to the "<fridge>" tag.
<fridge> <pizza></pizza> <pizza></pizza> </fridge>
But wait — those pizzas aren't the same kind. One of them is pepperoni, and one is vegetarian. Since this is an extremely important distinction, let's add it as an attribute to the "<pizza>" tag.
<fridge> <pizza toppings="pepperoni"></pizza> <pizza toppings="peppers onions mushrooms"></pizza> </fridge>
That's essentially how XML works. You need a root node that contains all the other data in the XML document (In this case, <fridge>). More data can be added by creating content and attributes in any existing element.
In World of Warcraft AddOn development, any XML file used for the interface needs a root element "<Ui>". You'll need to define three attributes in this tag. Don't feel compelled to memorize them; copy/pasting is fine. They just tell the program parsing the XML document about the format you're using to structure the data.
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\FrameXML\UI.xsd"> </Ui>
These are the building blocks of each scheme. You can think about them as virtual objects with their own properties and events. Those that are visible on screen are called widgets (buttons, textboxes, etc.), but some of them are always invisible (fonts).
Each element is represented by a tag. Its name defines the type of tag. For the button we use
<Button> ... </Button>
There are numerous properties of each element — they can be defined in two ways: by attribute
<Button name="Attribute"> ... </Button>
or by tag
<FontString> <Color r="1.0" g="1.0" b="0.0"> ... </FontString>
The choice will depend mostly on readability. For example it's much easier to put all scripts inside <scripts> than filling up the element tag with attributies
<Button onclick="dosomething();" onmove="dosomethingelse();">
For backward compatibility some of them can be defined both ways:
<Offset x="15" y="10"/> or <Offset> <AbsDimension x="15" y="10"/> </Offset>
For script interaction you need to give a name for element. This name must be unique - not just for your addon, but also for any loaded addon, so if some of them have the same names, they will conflict.
Names are case sensitive - "myTemplate" does not equal "mytemplate". However, for readability's sake, it might be better to further differentiate variable names beyond mere character case differences. It is not necessary to name each element, but you cannot access unnamed elements in scripts.
For repetitive elements (e.g., bag slots) you can use an identification number to distinguish them, but they still need to have a unique name:
<Button name="MyButton" id="3"> ...</Button>
Widgets require specification of size and position on the monitor. Both of them can be specified in absolute values (pixels) or relative values (some percent of parent size). Relative values are rarely used, and will not be discussed in this article.
Now from easy to hard.
1) You can specify exact size with the size tag:
<Button> <Size> <AbsDimension x="100" y="40"/> </Size> </Button>
Now the only thing left is to specify position. For this reason you use anchors. Imagine your element fixed to some other element with a hook. You need:
- position of hook on your element (point)
- position of hook on element it is fixed to (relativepoint)
- name of relative element (relativeto)
- offset if hooks separated on some distance (offset tag).
- If point attribute skipped it's set to center (needs testing)
- If relativepoint attribute skipped it is set to the same of point attribute
- If relativeto attribute skipped it's set to parent (element that's contain inside this one)
- If offset tag is skipped it's taked as zero
<Button> <Size> <Absdimension x="100" y="40"/> </Size> <Anchors> <Anchor point="TOPLEFT"/> </Anchors> </Button>
This one puts element to topleft corner of its container (another element)
<Button> <Size> <Absdimension x="100" y="40"/> </Size> <Anchors> <Anchor point="TOPLEFT" RelativePoint="BOTTOMRIGHT"/> </Anchors> </Button>
This one puts the element outside of parent one, so that upper-left corner will be in same place where lower-right corner of container is. (This way you can easily put elements one after another, similar to a standard action bar, or bank slots)
<Button> <Size> <Absdimension x="100" y="40"/> </Size> <Anchors> <Anchor point="TOPLEFT" relativePoint="BOTTOMRIGHT"> <Offset x="5" y="-5"/> </Anchor> </Anchors> </Button>
This gives 5 pixels distance between corners for a slightly separated effect
<Button> <Size> <AbsDimension x="100" y="40"/> </Size> <Anchors> <Anchor point="TOPLEFT" relativePoint="BOTTOMRIGHT" relativeTo="Minimap"> <Offset x="5" y="-5"/> </Anchor> </Anchors> </Button>
This will put the element not inside its container, but fix it to minimap.
There is a more complex way to define element position. You can define two or more anchors. In this case your element size will be overridden by anchors:
<Button> <Size> <Absdimension x="100" y="40"/> </Size> <Anchors> <Anchor point="TOPLEFT"/> <Anchor point="TOPRIGHT"/> </Anchors> </Button>
This will put your element to the top of parent element; its width will be same as its parent, but height will still be 40 pixels.
Or without size at all
<Button> <Anchors> <Anchor point="TOPLEFT"> <Offset x="5" y="-5"/> </Anchor> <Anchor point="BOTTOMRIGHT"> <Offset x="-5" y="5"/> </Anchor> </Anchors> </Button>
Here, your element will be 5 pixels smaller from each border of parent element.
Last two examples needed when your element size can change depends on its contents, so you don't need to change size of all child elements, just top one.
It's wrong to think when you define a button size and position it's all you need for it to be drawn on screen. Actually nothing will shown (Or standard textures will be used - to be tested). To specify what textures and message you'll see on it you need to use <Layers> tag.
You can put elements inside another ones (children into parent). To do so put them to <Frames> tag. Some widgets can have another elements defined outside of <Frames> tag, this is exception depends on type of element. For example you need to specify normal, disabled and highlight fonts for a button, you do this putting them inside <NormalFont>, <DisabledFont>, and <HighlightFont> tags respectively instead of inside <Frames>. This options is stricted, so normalfont inside a frame will be ignored (to be tested).
Sometimes you need to put same looking and acting elements (like bag or bank slots), so to avoid typing same code 40 times you can define a template — element that's not actually exist, but all it's properies are copied to whatever elements created from it (inherited). Template is marked with attribute "virtual=true" and any inherited element use attribute "inherits" with name of template.
<Button name="MyTemplate" virtual="true"> ...some data here... </Button> <Button name="MyButton1" inherits="MyTemplate"> ... </Button> <Button name="MyButton2" inherits="MyTemplate"> ... </Button> <Button name="MyButton3" inherits="MyTemplate"> ... </Button>
All properties from template are copied to three buttons so they will look same as long, as any of those properties replaced inside it(Any property defined inside element will override same property from template). You need specify exact name of template as it's case sensitive. If you use for example "Mytemplate" it couldn't be found since it's not exist and your element won't get properties of "MyTemplate", keep eye for that.
Templates needs to be placed inside <Ui> tag only. Other ones ignored (This also needs testing, but i never saw addon ignoring that rule)
Note yourself that for some reason you don't need to specify template with exact type as element. It's common in default interface when fontstring inherits font template. This can be done probably because template attributies and tags are just being copied, no any kind of check performed.
Interfaces build up from elements - their type is defined by their name, their properties are defined with all attributies and tags inside the element tag, except some special tags:
- Frames - keeps all elements placed inside this one
Therefore this element becomes a parent for other elements — they become childs.
- Layers - appearance on display is defined here
- Some extra tags depending on type of element
Properties of each element depends of its type. Those not supported are ignored. Each element can be named, widgets need to have position and size defined.
On to the WoW UI XML tutorial... :)