Can someone explain UIDropDownMenuTemplate and patch 11.0.0

I have been working on an addon and it has few dropdown frames that use UIDropDownMenuTemplate reading the townlong-yak.(com)/framexml/latest/Blizzard_Menu/11_0_0_MenuImplementationGuide.lua Am I to understand its going to be changed maybe someone who can make this simple to understand ( im a self taught addon maker ) can explain if the frame and menus will still function using UIDropDownMenuTemplate or do i need to read the guide and adjust so my those parts of my addon function properly into ver 11.0.0 thanks!

You would be far better off using the new dropdown as the original was/is a taint fest.

https://warcraft.wiki.gg/wiki/Patch_11.0.0/API_changes#New_menu_system

A quick example of the new dropdown:

-- list with "My xxx"
local function GeneratorFunction(owner, rootDescription)
	rootDescription:CreateTitle("My Title")
	rootDescription:CreateButton("|TInterface\\ICONS\\ClassIcon_Evoker:16:16|t My Button", function(data)
    		-- Button handling here.
    		print("My Button Clicked!")
	end)
end

-- list with "Next xxx"
local function GeneratorFunction2(owner, rootDescription)
	rootDescription:CreateTitle("Next Title")
	rootDescription:CreateButton("Next Button", function(data)
    		-- Button handling here.
    		print("NEXT!!!")
	end)
end

local dropdown = CreateFrame("DropdownButton", nil, UIParent, "WowStyle1DropdownTemplate")
dropdown:SetDefaultText("My Dropdown")
dropdown:SetPoint("TOP", 0, -20)
dropdown:SetupMenu(GeneratorFunction)

-- button to close the drop list if open
local f = CreateFrame("Button", nil, dropdown, "UIPanelButtonTemplate")
f:SetSize(20, 20)
f:SetText("C")
f:SetPoint("LEFT", dropdown, "RIGHT")
f:SetScript("OnClick", function(self)
	dropdown:CloseMenu()
end)

-- button to switch drop list options between "My xxx" and "Next xxx"
local toggle 
local f2 = CreateFrame("Button", nil, dropdown, "UIPanelButtonTemplate")
f2:SetSize(20, 20)
f2:SetText("O")
f2:SetPoint("LEFT", f, "RIGHT")
f2:SetScript("OnClick", function(self)
	toggle = not toggle
	dropdown:SetupMenu(toggle and GeneratorFunction2 or GeneratorFunction)
end)

I believe the old UIDropDown wil still be around for a while as it hasn’t “moved” to deprecated yet (set for removal in the next xpac version) as far as I can tell but should be considered as such.

3 Likes

Nice, I Like the texture part its neat, I was able to clean up my function its very clean now, I instead of making more functions and bloating my .lua I just put the function in with the frame details, I think its more clear at least to myself this way

local function PopulateContentFrame_GeneralSettings(optionsFrame)
local contentFrame = optionsFrame.contentFrame

-- Create a label for the Font Dropdown
local fontLabel = contentFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
fontLabel:SetPoint("TOPLEFT", contentFrame, "TOPLEFT", 20, -20)
fontLabel:SetText("Guild Chat Fonts")
fontLabel:SetTextColor(1, 1, 1, 1) 

-- Create the Font Dropdown
local fontDropdown = CreateFrame("DropdownButton", "FontDropdown", contentFrame, "WowStyle1DropdownTemplate")
fontDropdown:SetPoint("TOPLEFT", fontLabel, "BOTTOMLEFT", -5, -5)
fontDropdown:SetWidth(200)
fontDropdown:SetHeight(30)
fontDropdown:SetDefaultText("Select Font")
fontDropdown:SetupMenu(function(self, rootDescription)
    for fontName, fontData in pairs(Fonts) do
        rootDescription:CreateButton("|TInterface\\Icons\\INV_Letter_01:16:16|t " .. fontName, function(data)
            ApplyFont(GuildChatWindow.editBox, fontData)
            print("Selected Font:", fontName)
        end)
    end
end)

-- Create a label for the Theme Dropdown
local themeLabel = contentFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
themeLabel:SetPoint("TOPLEFT", fontDropdown, "BOTTOMLEFT", 5, -20)
themeLabel:SetText("Guild Chat Themes")
themeLabel:SetTextColor(1, 1, 1, 1)

-- Create the Theme Dropdown
local themeDropdown = CreateFrame("DropdownButton", "ThemeDropdown", contentFrame, "WowStyle1DropdownTemplate")
themeDropdown:SetPoint("TOPLEFT", themeLabel, "BOTTOMLEFT", -5, -5)
themeDropdown:SetWidth(200)
themeDropdown:SetHeight(30)
themeDropdown:SetDefaultText("Select Theme")
themeDropdown:SetupMenu(function(self, rootDescription)
    for themeName, themeData in pairs(Themes) do
        rootDescription:CreateButton("|TInterface\\Store\\category-icon-placeholder:16:16|t" .. themeName, function(data)
            ApplyTheme(GuildChatWindow, themeData)
            print("Selected Theme:", themeName)
        end)
    end
end)
end

This is how Ive done it, thanks for your reply, I gota give chatGPT a stern talking to hes suggesting depreciated sh*t to me left and right lol. Im stealing your |T|t too, just need the logic somehow while looping the tables to make the icon = Name… if you can cook that up Id kiss you :stuck_out_tongue:

ChatGPT has a problem of outdated training sets, so there’s a chance that if you ask about anything that’s changed in the last couple of years, you’ll get an incorrect old answer.

1 Like

I’m not sure what table(s) you are looping?

their named in the pairs for each loop, you don’t need the details, the for loop pulls all that, ill have to do some extra thinking, right now the for loop looks at the tables in named in pairs the key is the name the value is data. The ‘do’ is creating the buttons for each of name as it iterates over the table and passing the data for each name with it and its working flawlessly. The snag is if I wanted custom textures for each button name, I would either have to make the table keys wild names like [“"|Tpath\to\custom\textur:16:16|t” … “Keyname”"] or have a really good looking dev teach me some better Lua then chatGPT can :smiley: cause key names like that wouldnt work… or would they?

I’m not if this is the sort of thing you are looking for and if the path to the textures is consistant (or icon width/height) you could reduce this but maybe something like:

local MenuTable = {
	{
		text = "Item 1",
		icon = "Interface\\Icons\\INV_Letter_01",
		iwidth = 16,
		iheight = 16,
	},
	{
		text = "Item 2",
		icon = "Interface\\Icons\\INV_Letter_02",
		iwidth = 16,
		iheight = 16,
	},
}

local itemString = "|T%s:%s:%s|t%s"
-- list with "My xxx"
local function GeneratorFunction(owner, rootDescription)
	rootDescription:CreateTitle("My Title")
	for i, v in ipairs(MenuTable) do
		rootDescription:CreateButton(format(itemString, v.icon, v.iwidth, v.iheight, v.text), function(data)
    		-- Button handling here.
    			print(v.text, "Button Clicked!")
		end)
	end
end

not really, I just might drop the idea of putting textures with it the button names, it looks classy but the issue is with your example is the texture will reside in the value, and the key is the button name, your first example is a string that concats with the … to the string of the key aka fontName or themeName so the icon texture has to be either set in the key with some clever way like I was mentioning or theres a solution I dont have the coding knowledge to grasp yet

It sound like it would work with maybe a change to the table structure but I have no idea what you are using.

if your table is something like.

{
    "Item 1",
    "Item 2",
}

The change to making each key value a sub-table with the added information is pretty straight forward (as above). It’s part of the power of lua tables.

TABLE = {
[“KEY”] = {
DATA = print(“rootDescription:CreateButton(”|TInterface\Icons\INV_Letter_01:16:16|t " … KEY YOU UNDERSTAND?“),
DATA2 = print(“or ITEM2 OR WHATEVER - ITS THE KEY THAT IS THE STRING - THE TEXTURE IS A STRING COMBINED using the ‘…’ TO THE KEY IN 'CreateButton(”|TInterface\Icons\INV_Letter_01:16:16|t " … KEY’ — CLEARER?”) },
},
}

I’m guessing the table example is pcode and the print statements aren’t part of it (and most likely the rootDescription:CreateButton( bits either).

Maybe it’s more like:

local MenuTable = {
	["KEY"] = {
		DATA = "|TInterface\\Icons\\INV_Letter_01:16:16|t",
		DATA2 = "|TInterface\\Icons\\INV_Letter_02:16:16|t",
	},
}

local function GeneratorFunction(owner, rootDescription)
	rootDescription:CreateTitle("My Title")
	for k, v in pairs(MenuTable.KEY) do
		rootDescription:CreateButton(v..k, function(data)
    		-- Button handling here.
    			print(k, "Button Clicked!")
		end)
	end
end

local dropdown = CreateFrame("DropdownButton", nil, UIParent, "WowStyle1DropdownTemplate")
dropdown:SetDefaultText("My Dropdown")
dropdown:SetPoint("TOP", 0, -20)
dropdown:SetupMenu(GeneratorFunction)

If more detail is required, the table could be changed eg.

local MenuTable = {
	["KEY"] = {
		DATA = {
			icon = "|TInterface\\Icons\\INV_Letter_01:16:16}|t",
			text = "Some Text for data",
		},
		DATA2 = {
			icon = "|TInterface\\Icons\\INV_Letter_02:16:16|t",
			text = "Some Text for data2",
		},
	},
}
for k, v in pairs(MenuTable.KEY) do
    rootDescription:CreateButton(v.icon .. k, function(data)
        print(v.text, "Clicked!")
    end)
end

As an aside, the order of keys returned in a table using string keys pairs is not guaranteed to be the order of the table in code. If you want to gurarantee the order, you should use numbered keys and ipairs or a for loop

for i=1, #MenuTable.KEY do -- 1 to highest consecutive numbered key
   local val = MenuTable.KEY[i]
    ...
end

sorry im being a jerk, thank you for your help… the solution was to make an entry in the key - so now i have dropDownIcon = “|TInterface\\AddOns\\AddonName\\Themes\custom_icon:16:16|t” and its called like this:

themeDropdown:SetupMenu(function(self, rootDescription)
for themeName, themeData in pairs(Themes) do
rootDescription:CreateButton(themeData.dropDownIcon .. themeName, function(data)
ApplyTheme(GuildChatWindow, themeData)
print(“Selected Theme:”, themeName)
end)
end
end)
sorry for being a jerk =D It works wonderfully <3

for themeName, themeData in pairs(Themes) do is lopping through the Themes table. Each iteration returns two values:
themeName – the name of the key
themeData – the value assigned to the key

rootDescription:CreateButton( – creates a menu item button in the dropdown list

|TInterface\Store\category-icon-placeholder:16:16|t adds an icon texture at the begining of the button text (16x16 pixels in size)

.. themeName contatinates the value returned as themeName (the key)

function(data)
	ApplyTheme(GuildChatWindow, themeData)
	print(“Selected Theme:”, themeName)
end

The click function associated with the menu item, prints Selected Theme: followed by themeName (the key again)

In my pairs code I used
for k, v in pairs(MenuTable.KEY) do
k and v are replacements for themeName and themeData (short for key, value)

In the first iteration v would be the MenuTable[“KEY”][“DATA”] table
v.icon would end up being the value from
MenuTable["KEY"]["DATA"]["icon"]
which can also be written as
MenuTable.KEY.DATA.icon

again, using pairs() does not guarantee the returns will be in any specific order.

1 Like

Excellent, with that level of understanding you know why I dont use ipairs clearly not how the table was structured, Now, for bonus points is it possible to use the fileID # instead of |T or does |T have a way of using the fileID# and not require a path, like it is used with SetTexture(1336637) --“Interface/Challenges/ChallengeMode” ?

"|T1336637:16:16|t"

1 Like

well done ;>

Except 1336637 appears to be the base texture for some atlases or a texture requiring TexCoords (which can be done with "T see the Textures section at https://warcraft.wiki.gg/wiki/UI_escape_sequences)

i just used that as an example my good man, as its the challenge mode texture and has a cool id# :wink: