Of Slash Commands and Drop-down Menus

This last week I was able to make some good headway (for the noob I am) on WoWPUGBuilder. I created my first two slash commands and a drop down menu. Creating the slash command was an easy task. I did, however, have some initial difficulites with creating the drop down menu. It ended up not wanting to play nicely with the UI I had designed so far. To fix the problem, I went back to the drawing board and simplified the graphics for the UI quite a bit. I conceded to using the same background and border that I had used with WoWPedometer.
Slash Commands
I realized I needed a slash command to at the bare minimum, show and hide the AddOn UI. I used this article over at WoW Wiki to learn how to create slash commands.
Here is the code in a nutshell..
SLASH_WOWPUGBUILDER1 = '/wpb';
function SlashCmdList.WOWPUGBUILDER(msg, editbox)
if msg == 'show' then
print('your command was show');
WoWPUGBuilderFrame:Show();
elseif msg == 'hide' then
print('your command was hide');
WoWPUGBuilderFrame:Hide();
else
print('You did not type a command. Use "show" to show the window or "hide" to hide it.');
end
end
... the first statement SLAH_WOWPUGBUILDER1 = '/wpb'; defines the slash command that will used for the AddOn. AddOns can have multiple slash commands, which I'm not going to get into at the moment (see the WoWWiki article for now). After this statement is the function which will handle the arguments provided after the slash command. In this case, I used a simple if/then statement to determine which argument was used and called the appropriate function.
For WoWPUGBuilder, I chose to use "/wpg" because it's easy to type. The slash command takes one argument in the form of either the word "show" or "hide". "/wpb show" will show the AddOn interface (if it is currently hidden) and "/wpb hide" will hide the AddOn interface (if it is currently showing). Both commands arguments will display a feedback message in the chat window indicating which argument they passed to the AddOn. If the user does not include an argument in the slash command, a message will be displayed in the chat windows to indicate that they did not enter an argument and also provide what the available arguments are and their function.
Drop-down Menus
Now on to the more challenging issue I was having. I wanted to create a drop down menu to provide the user with a method by which they they can choose which instances they would like to have displayed in their auto generated LFM advertisement. Following the steps outlined at this WoWWiki article, I was able to create the code for a drop down menu, but for some reason it was not showing up on the AddOn when I logged into the game. Nothing in the FrameXML.log indicated that there was an error nor did a validation run through XMLNanny spot anything fishy. I was able to elicit some help from the WoW Programming forums with this posting. Eventually, running out of culprits, I decided that there must be something funky going on with the UI elements I swiped from Blizzard_TimeManager. I decided that I should try creating the drop down menu example given in the WoW Programming text (chapter 23). Strangely enough, it worked just as it should. I then scrapped my existing UI and instead use the more simplistic UI background and boarder that was used in the text books examples and my previous AddOn exercise, WoWPedometer. Wa-La! Drop-down menu!
So, on to the details. The XML code consists of a <Button> and a <Frame> element.
Button name="Advertise_Button" inherits="GameMenuButtonTemplate" text="Advertise Now">
<Anchors>
<Anchor point="CENTER">
<Offset x="0" y="0"/>
</Anchor>
</Anchors>
<Scripts>
<OnClick>
Advertise_ButtonOnClick(self, button, down)
</OnClick>
</Scripts>
</Button>
This code basically builds the button, which when pressed, will display the drop down menu. The function Advertise_ButtonOnClick(self, button, down), is called during OnClick.
<Frame name="ChooseInstance_DropDown" inherits="UIDropDownMenuTemplate" frameStrata="DIALOG_FULLSCREEN">
<Scripts>
<OnLoad>
ChooseInstance_DropDownOnLoad(self)
</OnLoad>
</Scripts>
</Frame>
This <Frame> tag creates the frame that is generated when the users clicks on the drop down menu button. ChooseInstance_DropDownOnLoad(self) is called OnLoad in order to populate the menu with the available choices.
On to the Lua functions...
There were two major components to creating the drop down menu, generating the menu list itself and providing the functionality of those choices. This first function initializes and populates the drop down menu itself...
function ChooseInstance_InitializeDropDown(level)
print('ChooseInstance_InitializeDropDown')
-- Create a table to use for button information
local info = {}
-- Create a title button
info.text = "Instances"
info.isTitle = 1
UIDropDownMenu_AddButton(info)
-- Create a normal button
info = {}
info.text = "Ahn'kahet: The Old Kingdom"
info.checked = OldKingdom
function info.func(arg1, arg2)
OldKingdom = not OldKingdom
end
UIDropDownMenu_AddButton(info)
-- Create another normal button
info = {}
info.text = "Azjol-Nerub"
info.checked = AzjolNerub
function info.func(arg1, arg2)
AzjolNerub = not AzjolNerub
end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "Caverns of Time: The Culling of Stratholme"
info.checked = CullingofStratholme
function info.func(arg1, arg2)
CullingofStratholme = not CullingofStratholme
end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "Drak'Tharon Keep"
info.checked = DrakTharonKeep
function info.func(arg1, arg2)
DrakTharonKeep = not DrakTharonKeep
end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "Gundrak"
info.checked = Gundrak
function info.func(arg1, arg2)
Gundrak = not Gundrak
end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "The Nexus"
info.checked = TheNexus
function info.func(arg1, arg2)
TheNexus = not TheNexus
end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "The Oculus"
info.checked = TheOculus
function info.func(arg1, arg2)
TheOculus = not TheOculus
end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "Trial of the Champion"
info.checked = TrialoftheChampion
function info.func(arg1, arg2)
TrialoftheChampion = not TrialoftheChampion
end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "Ulduar: Halls of Lightning"
info.checked = HallsofLightning
function info.func(arg1, arg2)
HallsofLightning = not HallsofLightning
end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "Ulduar: Halls of Stone"
info.checked = HallsofStone
function info.func(arg1, arg2)
HallsofStone = not HallsofStone
end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "Utgarde Keep"
info.checked = UtgardeKeep
function info.func(arg1, arg2)
UtgardeKeep = not UtgardeKeep
end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "Utgarde Pinnacle"
info.checked = UtgardePinnacle
function info.func(arg1, arg2)
UtgardePinnacle = not UtgardePinnacle
end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "Violet Hold"
info.checked = VioletHold
function info.func(arg1, arg2)
VioletHold = not VioletHold
end
UIDropDownMenu_AddButton(info)
end
... the next function initializes the the menu during OnLoad...
function ChooseInstance_DropDownOnLoad(self)
UIDropDownMenu_Initialize(self, ChooseInstance_InitializeDropDown)
print('ChooseInstance_DropDownOnLoad')
end
... and finally this function handles the toggling of the menu frame during an OnClick...
function ChooseInstance_ButtonOnClick(self, button, down)
ToggleDropDownMenu(1, nil, ChooseInstance_DropDown, self:GetName(), 10, 0)
end
The next two functions handle the functionality of the items which are selected in the menu itself...
function AdvertiseMessageConstruction()
local instances = {}
if OldKingdom then
table.insert(instances, "Old Kingdom")
end
if AzjolNerub then
table.insert(instances, "Azjol-Nerub")
end
if CullingofStratholme then
table.insert(instances, "Culling of Stratholme")
end
if DrakTharonKeep then
table.insert(instances, "Drak'Tharon Keep")
end
if Gundrak then
table.insert(instances, "Gundrak")
end
if TheNexus then
table.insert(instances, "Nexus")
end
if TheOculus then
table.insert(instances, "Oculus")
end
if TrialoftheChampion then
table.insert(instances, "Trial of the Champion")
end
if HallsofLightning then
table.insert(instances, "Halls of Lightning")
end
if HallsofStone then
table.insert(instances, "Halls of Stone")
end
if UtgardKeep then
table.insert(instances, "Utgarde Keep")
end
if UtgardePinnacle then
table.insert(instances, "Utgarde Pinnacle")
end
if VioletHold then
table.insert(instances, "Violet Hold")
end
instancelist = table.tostring(instances)
local msg = string.format("Lookin for group for %s", instancelist)
return msg
end
... this function determines what items are checked and then concatenates the corresponding instance name to the string instances.
Next, the function...
function Advertise_ButtonOnClick(self, button, down)
print('ADVERTISE BUTTON TEST')
local instancemessage = AdvertiseMessageConstruction()
local msg = string.format("%s", instancemessage)
SendChatMessage(msg, "GUILD")
end
... provides for the functionality of the advertise button.
In order to get the instance names to concatenate a table's contents to the end of a string, I needed to use the following code to provide the function table.tostring
function table.val_to_str ( v )
if "string" == type( v ) then
v = string.gsub( v, "\n", "\\n" )
if string.match( string.gsub(v,"[^'\"]",""), '^"+$' ) then
return "'" .. v .. "'"
end
return string.gsub(v,'"', '\\"' ) .. ','
else
return "table" == type( v ) and table.tostring( v ) or
tostring( v )
end
end
function table.key_to_str ( k )
if "string" == type( k ) and string.match( k, "^[_%a][_%a%d]*$" ) then
return k
else
return "[" .. table.val_to_str( k ) .. "]"
end
end
function table.tostring( tbl )
local result, done = {}, {}
for k, v in ipairs( tbl ) do
table.insert( result, table.val_to_str( v ) )
done[ k ] = true
end
for k, v in pairs( tbl ) do
if not done[ k ] then
table.insert( result,
table.key_to_str( k ) .. "=" .. table.val_to_str( v ) )
end
end
return table.concat( result, "," )
end
I snagged this code from the Lua website, which I would have normally have provided a link to but I've lost the link and will have to re-search for it. Until then... ;)
There's still a lot of work to be done to get this where I want it. jnwhiteh recommended some code in the post I linked to up top that would generate a button more befitting of a drop down menu so I'm going to be looking into that this week. I would also like to get together the automated advertisement functionality as well as include the "Looking For" options (ie tank, heals, or DPS). Now that I seem to be making some serious headway, perhaps things will progress a bit faster. ;)
Comments