---@type Diesal.GUI local DiesalGUI = LibStub("DiesalGUI-2.0") ---@type Diesal.Tools local DiesalTools = LibStub("DiesalTools-2.0") ---@type Diesal.Style local DiesalStyle = LibStub("DiesalStyle-2.0") -- ~~| Diesal Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ local Colors = DiesalStyle.Colors local HSL, ShadeColor, TintColor = DiesalTools.HSL, DiesalTools.ShadeColor, DiesalTools.TintColor -- ~~| Lua Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ local tsort = table.sort local sub, format, lower, upper, gsub = string.sub, string.format, string.lower, string.upper, string.gsub -- ~~| WoW Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- ~~| Dropdown |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ local Type = "DiesalDropDown" local Version = 2 -- ~~| Dropdown Stylesheets |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ local Stylesheet = { ["frame-background"] = { type = "texture", layer = "BACKGROUND", gradient = { "VERTICAL", Colors.UI_400_GR[1], Colors.UI_400_GR[2] }, }, ["frame-outline"] = { type = "outline", layer = "BORDER", color = "000000", }, ["frame-inline"] = { type = "outline", layer = "BORDER", gradient = { "VERTICAL", "FFFFFF", "FFFFFF" }, alpha = { 0.07, 0.02 }, position = -1, }, ["frame-hover"] = { type = "texture", layer = "HIGHLIGHT", color = "ffffff", alpha = 0.05, }, ["frame-arrow"] = { type = "texture", layer = "BORDER", image = { "DiesalGUIcons", { 2, 1, 16, 256, 128 } }, alpha = 0.5, position = { nil, -5, -7, nil }, height = 3, width = 5, }, ["text-color"] = { type = "Font", color = Colors.UI_TEXT, }, ["dropdown-background"] = { type = "texture", layer = "BACKGROUND", color = Colors.UI_100, alpha = 0.95, }, ["dropdown-inline"] = { type = "outline", layer = "BORDER", color = "ffffff", alpha = 0.02, position = -1, }, ["dropdown-shadow"] = { type = "shadow", }, } -- ~~| Dropdown Locals |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ local function compare(a, b) return a.value < b.value end local function sortList(list, orderedKeys) if orderedKeys then return orderedKeys end local sortedList = {} local orderedKeys = {} for key, value in pairs(list) do sortedList[#sortedList + 1] = { key = key, value = value } end tsort(sortedList, compare) for i, value in ipairs(sortedList) do orderedKeys[#orderedKeys + 1] = value.key end return orderedKeys end -- ~~| Dropdown Methods |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ---@class Diesal.GUI.DropDown.Methods local methods = { ---@param self Diesal.GUI.Object.DropDown OnAcquire = function(self) self:ApplySettings() self:SetStylesheet(Stylesheet) -- self:SetStylesheet(wireFrameSheet) self:Show() self:SetFrameStrata("TOOLTIP") end, ---@param self Diesal.GUI.Object.DropDown OnRelease = function(self) end, ---@param self Diesal.GUI.Object.DropDown ApplySettings = function(self) local settings = self.settings local content = self.content local frame = self.frame local children = self.children local dropdown = self.dropdown frame:SetWidth(settings.width) frame:SetHeight(settings.height) content:SetPoint("TOPLEFT", dropdown, settings.dropdownPadLeft, -settings.dropdownPadTop) content:SetPoint("BOTTOMRIGHT", dropdown, -settings.dropdownPadRight, settings.dropdownPadBottom) local menuHeight = 0 for i = 1, #children do menuHeight = menuHeight + children[i].frame:GetHeight() end dropdown:SetHeight(settings.dropdownPadTop + menuHeight + settings.dropdownPadBottom) end, ---@param self Diesal.GUI.Object.DropDown ---@param list table SetList = function(self, list) self:ReleaseChildren() self:SetText("") local settings = self.settings settings.list = list local foldColor = "353535" local expandColor = "5a5a5a" self.dropdown:SetFrameStrata("TOOLTIP") for position, item in ipairs(list) do local dropdownItem = DiesalGUI:Create("DiesalDropDownItem") DiesalGUI:OnMouse(dropdownItem.frame, "LeftButton") self:AddChild(dropdownItem) dropdownItem:SetParentObject(self) dropdownItem:SetSettings({ key = item.key, value = item.value, position = position, clickable = item.clickable, indent = item.indent or 0, icon2 = item.icon2, }, true) dropdownItem.text:SetPoint("TOPLEFT", 12 + (item.indent * 6), -2) if item.indent and item.indent > 0 then local leftOffset = -6 + (-6 * item.indent) dropdownItem:UpdateStyle("frame-lineV", { type = "texture", layer = "BORDER", color = foldColor, position = { leftOffset, nil, -8, nil }, height = 1, width = 6, }) dropdownItem:UpdateStyle("frame-lineH", { type = "texture", layer = "BORDER", color = foldColor, position = { leftOffset, nil, 0, 0 }, width = 1, }) if item.last then dropdownItem:UpdateStyle("frame-lineH", { type = "texture", position = { leftOffset, nil, 0, -7 }, }) end end end self:ApplySettings() end, ---@param self Diesal.GUI.Object.DropDown SetValue = function(self, key) local selectionTable = {} local selectedKey, dropdownText, selectedValue local selectedCount = 0 if key ~= "CLEAR" then if self.settings.multiSelect then for i = 1, #self.children do if self.children[i].settings.key == key then selectedKey = key self.children[i]:SetSelected(true) end if self.children[i].settings.selected then selectedCount = selectedCount + 1 if dropdownText then dropdownText = format("%s, %s", dropdownText, self.children[i].settings.value) else dropdownText = self.children[i].settings.value end selectionTable[#selectionTable + 1] = self.children[i].settings.key end end else for i = 1, #self.children do local child = self.children[i] child:SetSelected(false) if child.settings.icon2 then child.icon2:Show() else child.icon2:Hide() end if child.settings.key == key then child:SetSelected(true) dropdownText = child.settings.value selectionTable = { key } selectedKey = key selectedValue = self.value end end end else self:ClearSelection() end if self.settings.multiSelect then dropdownText = string.format("+%d", selectedCount) end if selectedKey then self:SetText(dropdownText) self:FireEvent("OnValueChanged", selectedKey, selectedValue, selectionTable) else self:SetText("") self:FireEvent("OnValueChanged", selectedKey, selectedValue, selectionTable) end end, ---@param self Diesal.GUI.Object.DropDown ClearSelection = function(self) for i = 1, #self.children do self.children[i]:SetSelected(false) end self:SetText("") end, ---@param self Diesal.GUI.Object.DropDown SetValueTable = function(self, keyTable) if not self.settings.multiSelect or type(keyTable) ~= "table" then return end local dropdownItems = self.children local selectionTable = {} local selectedKey local dropdownText local selectedCount = 0 for i = 1, #dropdownItems do local dropdownItem = dropdownItems[i] dropdownItem:SetSelected(false) for _, key in ipairs(keyTable) do if dropdownItem.settings.key == key then dropdownItem:SetSelected(true) selectedCount = selectedCount + 1 if not self.settings.multiSelect then dropdownText = dropdownText and format("%s, %s", dropdownText, dropdownItem.settings.value) or dropdownItem.settings.value end selectionTable[#selectionTable + 1] = dropdownItem.settings.key end end end self:FireEvent("OnValueChanged", nil, nil, selectionTable) if self.settings.multiSelect then dropdownText = string.format("+%d", selectedCount) end self:SetText(dropdownText) end, ---@param self Diesal.GUI.Object.DropDown SetMultiSelect = function(self, state) self.settings.multiSelect = state end, ---@param self Diesal.GUI.Object.DropDown SetText = function(self, text) self.text:SetText(text) for i = 1, #self.children do local child = self.children[i] if child.settings.value == text then self.value = child.settings.key end end end, ---@param self Diesal.GUI.Object.DropDown SetFocus = function(self) DiesalGUI:SetFocus(self) end, ---@param self Diesal.GUI.Object.DropDown ClearFocus = function(self) self.dropdownShown = false self.dropdown:Hide() end, ---@param self Diesal.GUI.Object.DropDown EnableMouse = function(self, state) self.frame:EnableMouse(state) end, ---@param self Diesal.GUI.Object.DropDown RegisterForClicks = function(self, ...) self.frame:RegisterForClicks(...) end, ---@param self Diesal.GUI.Object.DropDown SetJustifyV = function(self, justify) self.text:SetJustifyV(justify) end, ---@param self Diesal.GUI.Object.DropDown SetJustifyH = function(self, justify) self.text:SetJustifyH(justify) end, ---@param self Diesal.GUI.Object.DropDown ShowDropDown = function(self) self.dropdown:SetFrameStrata("TOOLTIP") self.dropdown:SetParent(self.frame) self.dropdown:Show() self.dropdownShown = true end, ---@param self Diesal.GUI.Object.DropDown HideDropDown = function(self) self.dropdown:Hide() self.dropdownShown = false end, ---@param self Diesal.GUI.Object.DropDown ToggleDropDown = function(self) if self.dropdownShown then self:HideDropDown() else self:ShowDropDown() end end, ---@param self Diesal.GUI.Object.DropDown ---@param strata FrameStrata ---@param parent Frame ---@param children Frame[] FixStrata = function(self, strata, parent, children) parent:SetFrameStrata(strata) for i, child in ipairs(children) do self:FixStrata(strata, child, { child:GetChildren() --[[@as Frame]], }) end end, } ---@class Diesal.GUI.Object.DropDown.Settings : Diesal.GUI.ObjectBase.Settings ---@field dropdownPadLeft number ---@field dropdownPadRight number ---@field dropdownPadTop number ---@field dropdownPadBottom number ---@field itemHeight number ---@field width number ---@field height number ---@field list table ---@field multiSelect boolean ---@class DiesalDropDown : Diesal.GUI.Object.DropDown local f = CreateFrame("Button", nil, UIParent) -- ~~| Dropdown Constructor |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ local function Constructor() ---@class Diesal.GUI.Object.DropDown : Diesal.GUI.ObjectBase, Diesal.GUI.DropDown.Methods ---@field settings Diesal.GUI.Object.DropDown.Settings ---@field children Diesal.GUI.Object.DropDown.Item[] ---@field text FontString ---@field dropdown Frame ---@field content Frame ---@field value string local self = DiesalGUI:Create(Type, true) self:SetMethods(methods) self.dropdownShown = true local frame = CreateFrame("Button", nil, UIParent) frame:SetFrameStrata("TOOLTIP") frame:SetClampedToScreen(true) self.frame = frame self.isContainer = true self.defaults = { dropdownPadLeft = 4, dropdownPadRight = 4, dropdownPadTop = 4, dropdownPadBottom = 4, itemHeight = 16, width = 100, height = 16, } -- ~~ Registered Events ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- OnValueChanged(event,selectedKey,selectedValue,selectionTable) -- OnValueSelected(event,selectedKey,selectedValue,selectionTable) -- OnEnter, OnLeave -- ~~ Construct ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ frame:SetScript("OnClick", function(this, button, down) if button == "LeftButton" then if self.dropdown:IsVisible() then self.dropdown:Hide() else DiesalGUI:OnMouse(self.dropdown, button) self:FixStrata("TOOLTIP", self.dropdown, { self.dropdown:GetChildren() --[[@as Frame]], }) self.dropdown:Show() end end self:FireEvent("OnClick", button, down) end) frame:SetScript("OnEnter", function(this, ...) self:FireEvent("OnEnter", ...) end) frame:SetScript("OnLeave", function(this, ...) self:FireEvent("OnLeave", ...) end) local text = self:CreateRegion("FontString", "text", frame) text:ClearAllPoints() text:SetPoint("TOPLEFT", 4, -1) text:SetPoint("BOTTOMRIGHT", -14, 1) text:SetJustifyV("MIDDLE") text:SetJustifyH("LEFT") local dropdown = self:CreateRegion("Frame", "dropdown", frame) dropdown:SetFrameStrata("TOOLTIP") dropdown:SetFrameLevel(dropdown:GetFrameLevel() + 2) dropdown:SetPoint("TOPRIGHT", frame, "BOTTOMRIGHT", 0, -2) dropdown:SetPoint("TOPLEFT", frame, "BOTTOMLEFT", 0, -2) dropdown:SetScript("OnShow", function(this) self:SetFocus() end) dropdown:SetScript("OnHide", function(this) self.dropdownShown = false end) dropdown:Hide() self.dropdown = dropdown self:CreateRegion("Frame", "content", dropdown) -- ~~ Methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --self:SetMethods(methods) --[[ for method, func in pairs(methods) do self[method] = func end ]] -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ return self end DiesalGUI:RegisterObjectConstructor(Type, Constructor, Version)