Topic: UI AddOns 101 (Tutorials/explanations)

Well for all of you adventurous folks, heres a tutorial to get you going with AddOns.  I will explain the basic purpose of each of the files, and later explain a simple clock AddOn.

In your World of Warcraft directory, there might be a folder called "Interface" (without the quotes), depending on how you installed it and whether or not you have AddOns installed currently.  If this folder does not exist, you will need to create one.  Inside this folder needs to be another folder called "AddOns", again, if it does not exist, create one.  The AddOns folder holds all of the individual AddOn folders.
The individual AddOn folder contains 3 different files.  The first is the .toc (Table of Contents) file.  This file contains all the information necessary for the game to display the AddOn in the AddOns menu and load the AddOn into the game.  There are 7 components to this file:

## Interface:
## Title:
## Notes:
## SavedVariables:
## Dependencies:
## OptionalDeps:
.xml


Interface specificies the interface version number that WoW is running at.  This number is 4 digits long, currently being 10900.
Title has no effect on how the AddOn will run, it simply gives WoW a name to call it when necessary.
Notes is the description of the AddOn.  Again, it does not effect how it runs.
SavedVariables is the variable names that will hold information between WoW sessions.  These variables are stored in the savedvariables.lua file.
Dependencies specify what other AddOns need to be enabled for this AddOn to load.
OptionalDeps is optional dependencies, some AddOns have certain parts that will communicate with other AddOns or have special features if this AddOn is loaded.  Don't worry about this line right now.
The last line (or lines) is the .xml file that the AddOn loads.  If you want it to load more than one .xml file, have each on its own line.

The second file is the .xml file.  This file contains the information for how the AddOn will appear.  This contains which graphics to load, the size, position, etc.  It also specifies the .lua script file to load and when to call the certain functions.  This file will always be structured:

<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/">
(The layout stuff)
</Ui>


(Normally the whole <Ui xmlns...> line would go on one line, but I split it into 2 for viewing purposes.)
Dont worry about what each part of that tag means, its just information WoW uses.
As for the basic XML syntax relating to the WoW AddOns, each tag has a pair, <opening tag> and </closing tag>.  Inbetween these two tags, there might be more tags which would be linked to the outer tags.  For example:

<Frame name="george">
<Size>
<AbsDimension x="2" y="3">
</AbsDimension>
</Size>
</Frame>


This will create a frame named george with a size of 2x3.  Each of the tags has its pair, but this code could also be written as:

<Frame name="george">
<Size>
<AbsDimension x="2" y="3"/>
</Size>
</Frame>


Notice that the AbsDimension tag no longer has its own pair shown, but has '/>' instead of only '>'.  This combines the opening and closing tags together.  Note: This will only work if you do not want any other tages to be inside it as it is closed before anything can be inside.
In order for WoW to know what script file to load to make the AddOn do something, you have to add the script tag.

<Script file="filename.lua"/>


This will tell it what script file to use, but not what functions to run and when.  In order to do this, you need to add scripts tags like the following:

<Scripts>
<OnLoad>
OnLoad_Function();
</OnLoad>
<OnUpdate>
OnUpdate_Function(arg1);
</OnUpdate>
<OnEvent>
OnEvent_Function();
</OnEvent>
<OnDragStart>
OnDragStart_Function();
</OnDragStart>
<OnDragStop>
OnDragStop_Function();
</OnDragStop>
<OnMouseUp>
OnMouseUp_Function();
</OnMouseUp>
</Scripts>


These are pretty self-explanitory.  The functions that it calls are located inside the .lua file, and the scripts that are run use .lua syntax.

The third file is the .lua file.  This file contains all the scripts and functions that the AddOn uses to make it function.  LUA is a very simple language and should not be hard to learn what you need.

--This is a comment, it starts with '--'

--A variable, it is set outside of a function, so it is global:
GLOBAL_VARIABLE = "hi";

--A function, starts with "function [function_name]()" and ends with "end":
function OnLoad_Function()
    --Stuff to occur when function is ran goes in here of course, this one is called by the XML file when the addon loads

    --This variable is called variable and its value is the string Bobby
    variable = "Bobby";
end


This is just the basic LUA setup, I'll get into the specific code stuff in the clock tutorial which will come later.

"The first duty in life is to assume a pose. What the second duty is, no one has yet found out."
-Oscar Wilde

Re: UI AddOns 101 (Tutorials/explanations)

Well here it is, the Clock tutorial

Clock.toc

## Interface: 10900
## Title: Clock
## Notes: Basic Clock
## SavedVariables: Clock_Save
Clock.xml


Interface version is 10900
Addon is called Clock
Description is Basic Clock
It keeps a saved variable of Clock_Save
The xml file is called Clock.xml

Clock.xml

<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/">
    <Script file="Clock.lua"/>

</UI>


Your script file is called Clock.lua

You have your addon, which would load if you ran it like this, but nothing would be present, you need a Frame containing a backdrop

<Frame name="Clock" frameStrata="HIGH" toplevel="true" enableMouse="true" movable="true" parent="UIParent">
        <Size>
            <AbsDimension x="128" y="32"/>
        </Size>
        <Anchors>
            <Anchor point="TOP"/>
        </Anchors>
        <Backdrop name="$parentBackdrop" bgFile="Interface\DialogFrame\UI-DialogBox-Background" 
edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
            <EdgeSize>
                <AbsValue val="16"/>
            </EdgeSize>
            <TileSize>
                <AbsValue val="32"/>
            </TileSize>
            <BackgroundInsets>
                <AbsInset left="5" right="5" top="5" bottom="5"/>
            </BackgroundInsets>
        </Backdrop>
</Frame>


This creates a frame named Clock that is visible, movable, able to be clicked, etc.  Its size is 128x32 anchored to the top of the screen.  It has a backdrop named ClockBackdrop ('$parent' calls the name of the frame/layer/button that its in, in this case a frame named Clock) Don't worry about EdgeSize and TileSize, just put it in, it makes it work.  BackgroundInsets just sets it inside the frame a bit.

We have a visible object, but no text to display the time on, so lets add some!  Inbetween the closing Backdrop tag and the closing Frame tag (so that it is a part of the frame) add:

<Layers>
    <Layer level="BACKGROUND">
        <FontString name="ClockText" inherits="GameFontNormal">
            <Size>
                <AbsDimension x="128" y="12"/>
            </Size>
            <Anchors>
                <Anchor point="TOP">
                    <Offset>
                        <AbsDimension x="0" y="-10"/>
                    </Offset>
                </Anchor>
            </Anchors>
        </FontString>
    </Layer>
</Layers>


This will create a Text object using the game's font, size 128,12, anchored to the top of frame its in (Clock) with an offset of 10 down.  This basically centers it in the Clock frame.

We have our frame, our backdrop, our text, so now we need to tell it what to do when, so after the closing Frame tag, we need to add some Scripts

<Scripts>
    <OnLoad>
        Clock_OnLoad();
    </OnLoad>
    <OnUpdate>
        Clock_OnUpdate(arg1);
    </OnUpdate>
    <OnDragStart>
        Clock_DragStart();
    </OnDragStart>
    <OnDragStop>
        Clock_DragStop();
    </OnDragStop>
    <OnMouseUp>
        Clock_DragStop();
    </OnMouseUp>
</Scripts>


Self explanitory, it runs certain functions at certain times.
Thats it for the .xml file.

Clock.lua

CLOCK_UPDATE_RATE = 0.1;


This will be used later on to determine whether its time for the clock to be updated or not, it can also be adjusted if you are really trying to conserve memory

Clock_Save = {};
Clock_Save["HourOff"] = 0;
Clock_Save["MinuteOff"] = 0;
Clock_Save['Visible'] = true;


These are the saved variable, although they are set in the .lua file, after it is loaded, they are reset to the state they were in when saved in the SavedVariables.lua file.

function Clock_OnLoad()
    if( Clock_Save['Visible'] == false ) then
        Clock:Hide();
    end
    Clock:RegisterForDrag("LeftButton");
    Clock.TimeSinceLastUpdate = 0;

    SlashCmdList["ClockCMD"] = Clock_Command;
    SLASH_ClockCMD1 = "/Clock";
end


Here is the OnLoad function, it checks to see if it should hide the Clock frame, or leave it visible, allows it to be drug, and sets the slash commands.
Slash command setup is simple

SlashCmdList[name] = command_function;
SLASH_name# = (slash command);


You can have more than one slash command, all that would have to be done is add SLASH_ClockCMD2 = (other slash command);

In order for your slash commands to work, you need the function

function Clock_Command(msg)
    local setting = strsub(string.lower(msg), 1, 4);
    if( setting == "hour" ) then
        Clock_Save["HourOff"] = strsub(msg, 6, strlen(msg));
        DEFAULT_CHAT_FRAME:AddMessage("Hour offset set to "..Clock_Save["HourOff"]);
    elseif( setting == "mnut" ) then
        Clock_Save["MinuteOff"] = strsub(msg, 6, strlen(msg));
        DEFAULT_CHAT_FRAME:AddMessage("Minute offset set to "..Clock_Save["MinuteOff"]);
    elseif( setting == "show" ) then
        Clock:Show();
        Clock_Save['Visible'] = true;
    elseif( setting == "hide" ) then
        Clock:Hide();
        Clock_Save['Visible'] = false;
    else
        DEFAULT_CHAT_FRAME:AddMessage("Commands are:"); 
        DEFAULT_CHAT_FRAME:AddMessage("'/Clock hour (time)' Changes the hour offset");
        DEFAULT_CHAT_FRAME:AddMessage("'/Clock mnut (time)' Changes the minute offset");
        DEFAULT_CHAT_FRAME:AddMessage("'/Clock show' Show the clock");
        DEFAULT_CHAT_FRAME:AddMessage("'/Clock hide' Hide the clock");
    end
end


This takes the message that comes after your slash command, and takes characters 1-4 from it.  It then checks to see if it is the same as one of the phrases that you have attached to settings (hour, mnut, show, or hide).  If it is one of those, it does something depending on which it is.  "hour" changes the hour offset of the clock, "mnut" changes the minute offset of the clock, "show" shows the clock, and "hide" hides the clock.  If it is not any of those strings, then it adds messages to your default chat frame listing the commands.

We still need the clock to update and change times, so:

function Clock_OnUpdate(arg1)
    Clock.TimeSinceLastUpdate = Clock.TimeSinceLastUpdate + arg1;
    local Hour_Offset = Clock_Save["HourOff"];
    local Minute_Offset = Clock_Save["MinuteOff"];
    if( Clock.TimeSinceLastUpdate > CLOCK_UPDATE_RATE ) then
        local hour, minute = GetGameTime();
        hour = hour + Hour_Offset;
        minute = minute + Minute_Offset;
        local TimeString = format(TEXT(TIME_TWENTYFOURHOURS), hour, minute);
        ClockText:SetText(TimeString);
        Clock.TimeSinceLastUpdate = 0;
    end
end


This function's argument of arg1 is the time since the OnUpdate tag was last run.
It then takes the global hour and minute offset times and gives local variables their values.
The function will then check to see if the time since it last updated is greater than the update rate which was set earlier, if it is, it will update, if not, it wont.
During updating, it gets the game time, hours and minutes, and then adds (or subtracts if the offset if negative) the offset that you had specified.  It then takes the hour and minute and formats it into a text string in 24hr format, and sets your ClockText to that string.  After that it sets the time since the last update to 0 again.

For convenience, it should be movable, but functions are required to do this, they aren't complicated, and shouldnt need to be explained

function Clock_DragStart()
    Clock:StartMoving();
end

function Clock_DragStop()
    Clock:StopMovingOrSizing();
end

If you want to be sure you got all of the order and coding correct, heres a .zip file with all of the files in it

"The first duty in life is to assume a pose. What the second duty is, no one has yet found out."
-Oscar Wilde