Thread Tools Display Modes
07-16-13, 02:50 PM   #1
Yup
A Murloc Raider
 
Yup's Avatar
Join Date: Jul 2013
Posts: 8
Removing an item from a UIDropDownMenu

[This is a cross-post from the wowace forum.]

I've just recently got into WoW AddOn programming and am designing my first interface and have came across what seems like a rather simple problem. I'm trying to make an options dialog (not in the the options menu, mostly because I wanted to test how to create frames by themselves) with a profiles drop-down menu that updates dynamically as the user creates and deletes profiles. There's no problem with creating profiles. As soon as the user enters a name it will show up in the drop-down menu the next time it's dropped. The problem comes when a user wishes to delete a profile. I've set it up so it will successfully delete the profile from the SavedVariables table, and delete it from the menu's tables, but the button's still in the drop-down until I /reload the interface. It seems to me that the problem is that once an item is added to them menu with UIDropDownMenu_AddButton() it's there permanently. I've done some digging and it looks like the AddButton function creates a button frame. Is there some way to retrieve the name of the button and hide it? Or is it something more complicated than that?

CA_UserProfile is a SavedVariablesPerCharacter variable that holds the profile to default to when a character loads into the game. (Set to "Default" by default.) CA_ChatAnnouncements is the SavedVariables variable that contains the table with the various setups. mainFrame is the parent frame for the whole dialog. The ADDON_LOADED event script runs InitializeDropDown() to make sure the SavedVariables are all loaded with the profiles before trying to create the menu.

Frame creation and initialization function:
Lua Code:
  1. local dropDownProfiles = CreateFrame("Button", "DropDownProfiles", mainFrame, "UIDropDownMenuTemplate")
  2. dropDownProfiles:SetPoint("TOPLEFT", -15, -21)
  3. dropDownProfiles:Show()
  4. dropDownProfiles:RegisterEvent("ADDON_LOADED")
  5.  
  6. local info = {}
  7. local dropDownItems = {}
  8.  
  9. local function initialize(self, level)
  10.     for _,item in pairs(dropDownItems) do
  11.         info = UIDropDownMenu_CreateInfo()
  12.         info.text = item
  13.         info.value = item
  14.         info.func = OnClick
  15.         UIDropDownMenu_AddButton(info, level)
  16.     end
  17. end

Initialization function wrapper:
Lua Code:
  1. local function InitiateDropDownMenu()
  2.     tinsert(dropDownItems, "Default")
  3.            
  4.     for item,_ in pairs(CA_ChatAnnouncements) do
  5.         if item ~= "Default" then
  6.             tinsert(dropDownItems, item)
  7.         end
  8.     end
  9.        
  10.     UIDropDownMenu_Initialize(dropDownProfiles, initialize)
  11.     UIDropDownMenu_SetWidth(dropDownProfiles, 100)
  12.     UIDropDownMenu_SetButtonWidth(dropDownProfiles, 124)
  13.     UIDropDownMenu_SetSelectedValue(dropDownProfiles, CA_UserProfile)
  14.     UIDropDownMenu_JustifyText(dropDownProfiles, "LEFT")
  15.    
  16.     if CA_UserProfile == "Default" then
  17.         deleteButton:Disable()
  18.     end
  19. end

What I was trying to do with deleteButton:
Lua Code:
  1. deleteButton:SetScript("PostClick",
  2.     function()
  3.         CA_ChatAnnouncements[value] = nil
  4.         dropDownItems[value] = nil
  5.        
  6.         InitiateDropDownMenu()
  7.        
  8.         OnClick(nil, "Default")
  9.     end)

The OnClick function for reference. I added the virtual variable so I can change button states without needing user input. The variable value is there so I can check the state of the drop-down menu across the AddOn:
Lua Code:
  1. local value
  2.  
  3. local function OnClick(self, virtual)
  4.     if type(virtual) == "string" then
  5.         value = virtual
  6.     else
  7.         value = self.value
  8.     end
  9.    
  10.     UIDropDownMenu_SetSelectedValue(dropDownProfiles, value)
  11.    
  12.     if value == "Default" then
  13.         deleteButton:Disable()
  14.     elseif deleteButton:GetButtonState() == "DISABLED" then
  15.         deleteButton:Enable()
  16.     end
  17.    
  18.     local announcementGroup = CA_ChatAnnouncements[value]
  19.    
  20.     announcementOneBox:SetText(announcementGroup["Announcement1"])
  21.     announcementTwoBox:SetText(announcementGroup["Announcement2"])
  22.     announcementThreeBox:SetText(announcementGroup["Announcement3"])
  23.     announcementFourBox:SetText(announcementGroup["Announcement4"])
  24.     announcementFiveBox:SetText(announcementGroup["Announcement5"])
  25. end

Also, the code ran for when the "Create" button is hit:
Lua Code:
  1. StaticPopupDialogs["CA_CREATEDIALOG"] = {
  2.     text = "Enter the name of your new profile:",
  3.     hasEditBox = true,
  4.     button1 = "Accept",
  5.     button2 = "Cancel",
  6.     timeout = 0,
  7.     whileDead = true,
  8.     hideOnEscape = true,
  9.     preferredIndex = 3,
  10.     EditBoxOnTextChanged = function(self)
  11.         if tContains(dropDownItems, self:GetText()) then
  12.             self:GetParent().button1:Disable()
  13.         elseif self:GetParent().button1:GetButtonState() == "DISABLED" then
  14.             self:GetParent().button1:Enable()
  15.         end
  16.     end,
  17.     EditBoxOnEnterPressed = function(self)
  18.         self:GetParent().button1:Click()
  19.     end,
  20.     OnAccept = function(self)
  21.         tinsert(dropDownItems, self.editBox:GetText())
  22.         CA_ChatAnnouncements[self.editBox:GetText()] = CA_ChatAnnouncements["Default"]
  23.     end,
  24. }
  25.  
  26. createButton:SetScript("PostClick",
  27.     function()
  28.         StaticPopup_Show("CA_CREATEDIALOG")
  29.     end)

Sorry if this is a bit too much code in one post, but I feel it's all relevant.
  Reply With Quote
07-16-13, 04:36 PM   #2
Vrul
A Scalebane Royal Guard
 
Vrul's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2007
Posts: 404
In InitiateDropDownMenu you are constantly adding to dropDownItems but never removing anything. I know you have "dropDownItems[value] = nil" in your OnClick function but value is a string and dropDownItems is an array so that line doesn't do anything. Here are the changes (untested) that I would make to remove some unneeded function calls, redundant variable assignments, and fix your issue:
Code:
local dropDownProfiles = CreateFrame("Button", "DropDownProfiles", mainFrame, "UIDropDownMenuTemplate")
dropDownProfiles:SetPoint("TOPLEFT", -15, -21)
dropDownProfiles:Show()
dropDownProfiles:RegisterEvent("ADDON_LOADED")
 
local dropDownItems = {}
 
local function initialize(self, level)
    local info = UIDropDownMenu_CreateInfo()
    info.func = OnClick
    for index = 1, #dropDownItems do
        info.text = dropDownItems[index]
        info.value = dropDownItems[index]
        UIDropDownMenu_AddButton(info, level)
    end
end
Code:
local function InitiateDropDownMenu()
    wipe(dropDownItems)
    dropDownItems[1] = "Default"
            
    for item in pairs(CA_ChatAnnouncements) do
        if item ~= "Default" then
            dropDownItems[#dropDownItems + 1] = item
        end
    end
        
    UIDropDownMenu_Initialize(dropDownProfiles, initialize)
    UIDropDownMenu_SetWidth(dropDownProfiles, 100)
    UIDropDownMenu_SetButtonWidth(dropDownProfiles, 124)
    UIDropDownMenu_SetSelectedValue(dropDownProfiles, CA_UserProfile)
    UIDropDownMenu_JustifyText(dropDownProfiles, "LEFT")
    
    if CA_UserProfile == "Default" then
        deleteButton:Disable()
    end
end
Code:
deleteButton:SetScript("PostClick", function()
    CA_ChatAnnouncements[value] = nil
    InitiateDropDownMenu()
    OnClick(nil, "Default")
end)
I would also change "DropDownProfiles" to something less generic such as yourAddonName .. "DropDownProfiles"
  Reply With Quote
07-16-13, 06:44 PM   #3
Yup
A Murloc Raider
 
Yup's Avatar
Join Date: Jul 2013
Posts: 8
It's working good now, thanks! Except, there is one thing. When clicking on an item in the menu now, it also "selects" (Although it doesn't change value, so the rest of the program works fine) all the items under it. It's just a visual thing, but still a bit annoying.

Example:

[ ] Default
[ ] ToT
[x] Battlegrounds
[x] Trade
[x] Guild


Before it would just select one at a time, so I'm unsure what could be causing it now.
  Reply With Quote
07-16-13, 09:20 PM   #4
Vrul
A Scalebane Royal Guard
 
Vrul's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2007
Posts: 404
Here's a cleaned up (and hopefully fixed) version:
Code:
local dropDownItems = { "Default" }

local dropDownProfiles = CreateFrame("Button", "CA_DropDownProfiles", mainFrame, "UIDropDownMenuTemplate")
dropDownProfiles:SetPoint("TOPLEFT", -15, -21)
dropDownProfiles:Show()

UIDropDownMenu_SetWidth(dropDownProfiles, 100)
UIDropDownMenu_SetButtonWidth(dropDownProfiles, 124)
UIDropDownMenu_JustifyText(dropDownProfiles, "LEFT")

local function SetUserProfile(_, profile)
    CA_UserProfile = profile
    UIDropDownMenu_SetSelectedName(dropDownProfiles, profile)

    local announcementGroup = CA_ChatAnnouncements[profile]
    announcementOneBox:SetText(announcementGroup["Announcement1"])
    announcementTwoBox:SetText(announcementGroup["Announcement2"])
    announcementThreeBox:SetText(announcementGroup["Announcement3"])
    announcementFourBox:SetText(announcementGroup["Announcement4"])
    announcementFiveBox:SetText(announcementGroup["Announcement5"])

    if profile ~= "Default" then
        deleteButton:Enable()
    else
        deleteButton:Disable()
    end
end

dropDownProfiles:SetScript("OnEvent", function(self, event, name)
    if event == "ADDON_LOADED" then
        if name ~= "ThisAddonName" then return end
        if type(CA_ChatAnnouncements) ~= "table" then
            CA_ChatAnnouncements = { }
        end
        if type(CA_UserProfile) ~= "string" or type(CA_ChatAnnouncements[CA_UserProfile]) ~= "table" then
            CA_UserProfile = "Default"
	end
        for profile in pairs(CA_ChatAnnouncements) do
            if profile ~= "Default" then
                dropDownItems[#dropDownItems + 1] = profile
            end
        end
	SetUserProfile(nil, CA_UserProfile)
    end
end)
dropDownProfiles:RegisterEvent("ADDON_LOADED")

dropDownProfiles.initialize = function(self, level)
    local info = UIDropDownMenu_CreateInfo()
    info.func = SetUserProfile
    for index = 1, #dropDownItems do
        info.text = dropDownItems[index]
        info.arg1 = dropDownItems[index]
        UIDropDownMenu_AddButton(info, level)
    end
end
Code:
deleteButton:SetScript("PostClick", function()
    CA_ChatAnnouncements[CA_UserProfile] = nil
    for index = 2, #dropDownItems do
        if dropDownItems[index] == CA_UserProfile then
            tremove(dropDownItems, index)
            break
        end
    end
    SetUserProfile(nil, "Default")
end)
And your "Create" button's OnAccept script only points the new profile to the default so if either are edited then both are changed. Here's a version that copies the current profile to the new profile and then sets it as the active profile when creating a new one:
Code:
OnAccept = function(self)
    local profile, data = self.editBox:GetText(), { }
    for key, value in pairs(CA_ChatAnnouncements[CA_UserProfile]) do
        data[key] = value
    end
    dropDownItems[#dropDownItems + 1] = profile
    CA_ChatAnnouncements[profile] = data
    SetUserProfile(nil, profile)
end
  Reply With Quote
07-17-13, 02:28 AM   #5
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
For future reference, when you cross-post the same thing on two closely related forums, please state that prominently at the top of your post in both places, and provide a link from each to the other. It's beyond frustrating to spend 30 minutes typing up a lengthy reply with explanations and examples, only to find your cross-post on the other site afterwards where someone had already answered the question.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
07-17-13, 06:27 PM   #6
Yup
A Murloc Raider
 
Yup's Avatar
Join Date: Jul 2013
Posts: 8
I'm sorry about the cross-post thing. I wasn't entirely sure on Forum etiquette and did what I thought was right, but as it turns out is wrong. I haven't gotten the opportunity to try out any of the suggestions, but when I do I will be posting to this forum.
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » Removing an item from a UIDropDownMenu


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