if not WeakAuras.IsLibsOK() then return end local Type, Version = "WeakAurasTwoColumnDropdown", 6 local AceGUI = LibStub and LibStub("AceGUI-3.0", true) if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end local secondLevelMt = {} -- Tag for our tables local function CreateSecondLevelTable() local t = {} setmetatable(t, secondLevelMt) return t end local function IsSecondLevelTable(t) return getmetatable(t) == secondLevelMt end local function CompareValues(a, b) if type(a) == "table" and type(b) == "table" then for ak, av in pairs(a) do if b[ak] ~= av then return false end end for bk, bv in pairs(b) do if a[bk] ~= bv then return false end end return true else return a == b end end local methods = { ["DoLayout"] = function(self, mode) self.mode = mode if mode == "one" then self.firstDropdown.frame:Show() self.secondDropDown.frame:Hide() self.firstDropdown.frame:SetAllPoints(self.frame) else local halfWidth = self.frame:GetWidth() / 2 self.firstDropdown.frame:Show() self.secondDropDown.frame:Show() self.firstDropdown.frame:ClearAllPoints() self.firstDropdown.frame:SetPoint("TOPLEFT", self.frame) self.firstDropdown.frame:SetPoint("BOTTOMRIGHT", self.frame, "BOTTOMLEFT", halfWidth, 0) self.secondDropDown.frame:SetPoint("TOPLEFT", self.frame, halfWidth, 0) self.secondDropDown.frame:SetPoint("BOTTOMRIGHT", self.frame, "BOTTOMRIGHT") end end, ["OnAcquire"] = function(widget) local firstDropdown = AceGUI:Create("Dropdown") local secondDropDown = AceGUI:Create("Dropdown") firstDropdown:SetParent(widget) secondDropDown:SetParent(widget) firstDropdown:SetPulloutWidth(200) secondDropDown:SetLabel(" ") secondDropDown:SetPulloutWidth(200) secondDropDown.userdata.defaultSelection = {} widget.firstDropdown = firstDropdown widget.secondDropDown = secondDropDown local OnFirstDropdownValueChanged = function(self, event, value) local displayName = widget.userdata.firstList[value] local treeValue = widget.userdata.tree[displayName] if IsSecondLevelTable(treeValue) then local oldValue if widget.userdata.secondList then local v = widget.secondDropDown:GetValue() if v then oldValue = widget.userdata.secondList[v] end end local secondList = {} for displayName, _ in pairs(treeValue) do tinsert(secondList, displayName) end table.sort(secondList) local oldValueIndex = tIndexOf(secondList, oldValue) widget.userdata.secondList = secondList widget.secondDropDown:SetList(secondList) widget:DoLayout("two") if (oldValueIndex) then widget.secondDropDown:SetValue(oldValueIndex) local v = widget:GetValue() if (v) then widget:Fire("OnValueChanged", v) end else local default = widget.secondDropDown.userdata.defaultSelection[displayName] if default then local index = tIndexOf(secondList, default) widget.secondDropDown:SetValue(index) local v = widget:GetValue() if (v) then widget:Fire("OnValueChanged", v) end else widget.secondDropDown:SetValue() end end else widget.userdata.secondList = nil widget:DoLayout("one") widget:Fire("OnValueChanged", treeValue) end end firstDropdown.OnFirstDropdownValueChanged = OnFirstDropdownValueChanged local OnSecondDropdownValueChanged = function(self, event, value) widget:Fire("OnValueChanged", widget:GetValue()) end firstDropdown:SetCallback("OnValueChanged", OnFirstDropdownValueChanged) secondDropDown:SetCallback("OnValueChanged", OnSecondDropdownValueChanged) local function FireOnEnter(self, event) widget:Fire("OnEnter") end local function FireOnLeave(self, event) widget:Fire("OnLeave") end firstDropdown:SetCallback("OnEnter", FireOnEnter) firstDropdown:SetCallback("OnLeave", FireOnLeave) secondDropDown:SetCallback("OnEnter", FireOnEnter) secondDropDown:SetCallback("OnLeave", FireOnLeave) widget:DoLayout("two") end, ["OnRelease"] = function(self) self.firstDropdown:SetCallback("OnValueChanged", nil) self.secondDropDown:SetCallback("OnValueChanged", nil) self.firstDropdown:SetCallback("OnEnter", nil) self.firstDropdown:SetCallback("OnLeave", nil) self.secondDropDown:SetCallback("OnEnter", nil) self.secondDropDown:SetCallback("OnLeave", nil) AceGUI:Release(self.firstDropdown) AceGUI:Release(self.secondDropDown) self.firstDropdown = nil self.secondDropDown = nil end, ["SetLabel"] = function(self, ...) self.firstDropdown:SetLabel(...) end, ["SetValue"] = function(self, value) for displayName, treeValue in pairs(self.userdata.tree) do if CompareValues(treeValue, value) then self:DoLayout("one") self.firstDropdown:SetValue(tIndexOf(self.userdata.firstList, displayName)) return elseif IsSecondLevelTable(treeValue) then for displayName2, key in pairs(treeValue) do if CompareValues(key, value) then self:DoLayout("two") local index = tIndexOf(self.userdata.firstList, displayName); self.firstDropdown:SetValue(index) self.firstDropdown:OnFirstDropdownValueChanged("", index) self.secondDropDown:SetValue(tIndexOf(self.userdata.secondList, displayName2)) return end end end end self:DoLayout("one") self.firstDropdown:SetValue(nil) end, ["GetValue"] = function(self) local displayName1 = self.userdata.firstList[self.firstDropdown:GetValue()] local treeValue = self.userdata.tree[displayName1] if not treeValue then return nil end if not IsSecondLevelTable(treeValue) then return treeValue end local displayName2 = self.userdata.secondList[self.secondDropDown:GetValue()] treeValue = treeValue[displayName2] if not treeValue then return nil end return treeValue end, ["SetList"] = function(self, list, order, itemType) local tree = {} for key, displayName in pairs(list) do if type(displayName) == "table" then local base = displayName[1] local suffix = displayName[2] tree[base] = tree[base] or CreateSecondLevelTable() tree[base][suffix] = key if displayName[3] == true then self.secondDropDown.userdata.defaultSelection[base] = suffix end else tree[displayName] = key end end self.userdata.tree = tree local firstList = {} for displayName, _ in pairs(tree) do tinsert(firstList, displayName) end table.sort(firstList) self.userdata.firstList = firstList self.firstDropdown:SetList(firstList, order, itemType) end, ["OnWidthSet"] = function(self) self:DoLayout(self.mode) end } local function Constructor() local frame = CreateFrame("Frame", nil, UIParent) frame:SetHeight(50) frame:SetWidth(50) local content = CreateFrame("Frame", nil, frame) content:SetPoint("TOPLEFT", 0, 0) content:SetPoint("BOTTOMRIGHT", 0, 0) local widget = { frame = frame, content = content, type = Type } for method, func in pairs(methods) do widget[method] = func end return AceGUI:RegisterAsWidget(widget) end AceGUI:RegisterWidgetType(Type, Constructor, Version)