---@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 sub, format, lower, upper, gsub = string.sub, string.format, string.lower, string.upper, string.gsub local tsort = table.sort -- ~~| WoW Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- ~~| ComboBox |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ local Type = "DiesalComboBox" local Version = 1 -- ~~| ComboBox Stylesheets |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ local Stylesheet = { ["frame-background"] = { type = "texture", layer = "BACKGROUND", color = "000000", alpha = 0.7, }, ["frame-inline"] = { type = "outline", layer = "BORDER", color = "000000", alpha = 0.7, }, ["frame-outline"] = { type = "outline", layer = "BORDER", color = "FFFFFF", alpha = 0.02, position = 1, }, ["button-background"] = { type = "texture", layer = "BACKGROUND", gradient = { "VERTICAL", Colors.UI_500_GR[1], Colors.UI_500_GR[2] }, }, ["button-outline"] = { type = "outline", layer = "ARTWORK", color = "000000", alpha = 0.9, }, ["button-inline"] = { type = "outline", layer = "BORDER", gradient = { "VERTICAL", "FFFFFF", "FFFFFF" }, alpha = { 0.07, 0.02 }, position = -1, }, ["button-hover"] = { type = "texture", layer = "HIGHLIGHT", color = "ffffff", alpha = 0.05, }, ["button-arrow"] = { type = "texture", layer = "BORDER", image = { "DiesalGUIcons", { 2, 1, 16, 256, 128 } }, alpha = 0.5, position = { nil, -4, -5, nil }, height = 4, width = 5, }, ["editBox-hover"] = { type = "texture", layer = "HIGHLIGHT", color = "ffffff", alpha = 0.1, position = { -1, 0, -1, -1 }, }, ["editBox-font"] = { 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", }, } -- ~~| ComboBox 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 -- ~~| ComboBox Methods |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ---@class Diesal.GUI.ComboBox.Methods ---@field OnAcquire fun(self: Diesal.GUI.Object.ComboBox) ---@field OnRelease fun(self: Diesal.GUI.Object.ComboBox) ---@field ApplySettings fun(self: Diesal.GUI.Object.ComboBox): boolean | nil ---@field SetList fun(self: Diesal.GUI.Object.ComboBox, list: table, orderedKeys: table) ---@field SetValue fun(self: Diesal.GUI.Object.ComboBox, key: string) ---@field SetText fun(self: Diesal.GUI.Object.ComboBox, text: string) ---@field SetJustify fun(self: Diesal.GUI.Object.ComboBox, j: string) ---@field SetFocus fun(self: Diesal.GUI.Object.ComboBox) ---@field ClearFocus fun(self: Diesal.GUI.Object.ComboBox) ---@field ClearSelection fun(self: Diesal.GUI.Object.ComboBox) local methods = { ["OnAcquire"] = function(self) self:ApplySettings() self:SetStylesheet(Stylesheet) -- self:SetStylesheet(wireFrameSheet) self:Show() end, ["OnRelease"] = function(self) end, ["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) self.editBox:SetPoint("RIGHT", -settings.buttonWidth, 0) self.button:SetWidth(settings.buttonWidth) -- dropdown content:SetPoint("TOPLEFT", settings.dropdownPadding[1], -settings.dropdownPadding[3]) content:SetPoint("BOTTOMRIGHT", -settings.dropdownPadding[2], settings.dropdownPadding[4]) local menuHeight = 0 for i = 1, #children do menuHeight = menuHeight + children[i].frame:GetHeight() end dropdown:SetHeight(settings.dropdownPadding[3] + menuHeight + settings.dropdownPadding[4]) end, ["SetList"] = function(self, list, orderedKeys) self:ReleaseChildren() self:SetText("") local settings = self.settings local orderedKeys = sortList(list, orderedKeys) settings.list = list for position, key in ipairs(orderedKeys) do local comboBoxItem = DiesalGUI:Create("DiesalComboBoxItem") --[[ @asDiesal.GUI.Object.ComboBox.Itemm ]] self:AddChild(comboBoxItem) comboBoxItem:SetParentObject(self) comboBoxItem:SetSettings({ key = key, value = list[key], position = position, }, true) end self:ApplySettings() end, ["SetValue"] = function(self, key) for i = 1, #self.children do self.children[i]:SetSelected(false) end for i = 1, #self.children do if self.children[i].settings.key == key then self.children[i]:SetSelected(true) self:SetText(self.children[i].settings.value) self.editBox:SetCursorPosition(0) break end end end, ["SetText"] = function(self, text) self.editBox:SetText(text) end, ---@param j "LEFT"|"CENTER"|"RIGHT" ["SetJustify"] = function(self, j) self.editBox:SetJustifyH(j) end, ["SetFocus"] = function(self) DiesalGUI:SetFocus(self) end, ["ClearFocus"] = function(self) self.dropdown:Hide() end, ["ClearSelection"] = function(self) for i = 1, #self.children do self.children[i]:SetSelected(false) end self:SetText("") end, } ---@class DiesalComboBox : Diesal.GUI.Object.ComboBox -- ~~| ComboBox Constructor |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ local function Constructor() ---@class Diesal.GUI.Object.ComboBox : Diesal.GUI.ObjectBase, Diesal.GUI.ComboBox.Methods ---@field editBox Diesal.GUI.Region.EditBox ---@field button Button ---@field dropdown Frame ---@field content Frame ---@field children Diesal.GUI.Object.ComboBox.Item[] ---@field settings { width: number, height: number, buttonWidth: number, dropdownPadding: table, dropdownButtonWidth: number, list: table, selectedKey: string, selectedValue: string, oldValue: string} local self = DiesalGUI:Create(Type, true) self.isContainer = true local frame = CreateFrame("Frame", nil, DiesalGUI.UIParent) self.frame = frame -- ~~ Default Settings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ self.defaults = { width = 100, height = 16, buttonWidth = 16, dropdownPadding = { 4, 4, 4, 4 }, dropdownButtonWidth = 16, } -- ~~ Registered Events ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- OnValueSelected, OnRenameValue -- OnEnter, OnLeave -- OnButtonClick, OnButtonEnter, OnButtonLeave -- ~~ Construct ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ local editBox = self:CreateRegion("EditBox", "editBox", frame) editBox:SetPoint("TOPLEFT") editBox:SetPoint("BOTTOMLEFT") editBox:SetAutoFocus(false) editBox:SetJustifyH("RIGHT") editBox:SetJustifyV("MIDDLE") editBox:SetTextInsets(1, 2, 2, 0) editBox:SetScript("OnEnterPressed", function(this) local text = this:GetText() DiesalGUI:ClearFocus() if text ~= self.settings.oldValue then self:FireEvent("OnRenameValue", self.settings.selectedKey, text) end end) editBox:HookScript("OnEscapePressed", function(this, ...) this:SetText(self.settings.oldValue) end) editBox:HookScript("OnEditFocusGained", function(this) self.settings.oldValue = this:GetText() end) editBox:HookScript("OnEditFocusLost", function(this, ...) self:SetText(self.settings.oldValue) end) editBox:SetScript("OnEnter", function(this) self:FireEvent("OnEnter") end) editBox:SetScript("OnLeave", function(this) self:FireEvent("OnLeave") end) local button = self:CreateRegion("Button", "button", frame) button:SetPoint("TOPRIGHT") button:SetPoint("BOTTOMRIGHT") button:SetScript("OnEnter", function(this) self:FireEvent("OnButtonEnter") end) button:SetScript("OnLeave", function(this) self:FireEvent("OnButtonLeave") end) ---@param this Button ---@param b mouseButton button:SetScript("OnClick", function(this, b) self:FireEvent("OnButtonClick") local dropdown = self.dropdown local visible = dropdown:IsVisible() DiesalGUI:OnMouse(this, b) dropdown[visible and "Hide" or "Show"](dropdown) end) local dropdown = self:CreateRegion("Frame", "dropdown", frame) dropdown:SetFrameStrata("FULLSCREEN_DIALOG") dropdown:SetPoint("TOPRIGHT", frame, "BOTTOMRIGHT", 0, -2) dropdown:SetPoint("TOPLEFT", frame, "BOTTOMLEFT", 0, -2) dropdown:SetScript("OnShow", function(this) this:SetFocus() end) dropdown:Hide() self:CreateRegion("Frame", "content", dropdown) -- ~~ Methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ self:SetMethods(methods) self:SetObj(self.frame) --[[ for method, func in pairs(methods) do self[method] = func end ]] -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ return self end DiesalGUI:RegisterObjectConstructor(Type, Constructor, Version)