Compare with Previous | Blame | View Log
--[[-------------------------------------------------------------------- PhanxConfig-Dropdown Simple scrolling dropdown widget generator. Requires LibStub. Based on tekKonfig-Dropdown by Tekkub and OmniCC_Options by Tuller. https://github.com/Phanx/PhanxConfig-Dropdown Copyright (c) 2009-2014 Phanx <addons@phanx.net>. All rights reserved. Permission is granted for anyone to use, read, or otherwise interpret this software for any purpose, without any restrictions. Permission is granted for anyone to embed or include this software in another work not derived from this software that makes use of the interface provided by this software for the purpose of creating a package of the work and its required libraries, and to distribute such packages as long as the software is not modified in any way, including by modifying or removing any files. Permission is granted for anyone to modify this software or sample from it, and to distribute such modified versions or derivative works as long as neither the names of this software nor its authors are used in the name or title of the work or in any other way that may cause it to be confused with or interfere with the simultaneous use of this software. This software may not be distributed standalone or in any other way, in whole or in part, modified or unmodified, without specific prior written permission from the authors of this software. The names of this software and/or its authors may not be used to promote or endorse works derived from this software without specific prior written permission from the authors of this software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------]] local MINOR_VERSION = 20141201 local lib, oldminor = LibStub:NewLibrary("PhanxConfig-Dropdown", MINOR_VERSION) if not lib then return end lib.listFrames = lib.listFrames or {} local MAX_LIST_SIZE = 15 ------------------------------------------------------------------------ local CreateList local function OpenDropdown(dropdown) local list = dropdown.list if not list then list = CreateList(dropdown) dropdown.list = list end local show = not list:IsShown() CloseDropDownMenus() if show then list:Show() list:Raise() local selectedIndex local items, selected = dropdown.items, dropdown.selected for i = 1, #items do if items[i] == selected then selectedIndex = i break end end if selectedIndex then local _, maxScroll = list.scrollFrame.ScrollBar:GetMinMaxValues() list.scrollFrame.ScrollBar:SetValue((maxScroll / (#items - 15)) * (selectedIndex - 5)) -- #TODO: where does this 15 come from in BlizzBugsSuck ??? end end end local function CloseDropdowns(_, _, dropDownFrame, _, _, _, _, clickedButton) for i = 1, #lib.listFrames do lib.listFrames[i]:Hide() end end hooksecurefunc("CloseDropDownMenus", CloseDropdowns) hooksecurefunc("ToggleDropDownMenu", CloseDropdowns) ------------------------------------------------------------------------ local function Frame_OnEnter(self) if self.OnEnter then self:OnEnter() elseif self.tooltipText then GameTooltip:SetOwner(self, "ANCHOR_RIGHT") GameTooltip:SetText(self.tooltipText, nil, nil, nil, nil, true) GameTooltip:Show() end end local function Frame_OnLeave(self) if self.OnLeave then self:OnLeave() else GameTooltip:Hide() end end local function Frame_OnHide(self) if self.list then self.list:Hide() end end ------------------------------------------------------------------------ local function ListButton_OnClick(self) local dropdown = self:GetParent():GetParent() dropdown.selected = self.value dropdown.list:Hide() dropdown.valueText:SetText(self:GetText() or self.value) local callback = dropdown.OnValueChanged if callback then callback(dropdown, self.value, self:GetText()) end PlaySound("UChatScrollButton") if dropdown.keepShownOnClick then OpenDropdown(dropdown) end end local function CreateListButton(parent) local button = CreateFrame("Button", nil, parent) button:SetHeight(UIDROPDOWNMENU_BUTTON_HEIGHT) --[[ local bg = button:CreateTexture(nil, "BACKGROUND") bg:SetPoint("BOTTOMLEFT", 1, 1) bg:SetPoint("TOPRIGHT", -1, -1) bg:SetTexture(0, 128, 255, 0.25) ]] local label = button:CreateFontString(nil, "OVERLAY") label:SetPoint("LEFT", 27, 0) label:SetFont((GameFontHighlightSmallLeft:GetFont()), UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT) label:SetJustifyH("LEFT") button:SetFontString(label) button.label = label -- DEPRECATED local check = button:CreateTexture(nil, "ARTWORK") check:SetPoint("LEFT") check:SetSize(24, 24) check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") button.check = check local highlight = button:CreateTexture(nil, "BACKGROUND") highlight:SetAllPoints(button) highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") highlight:SetAlpha(0.4) highlight:SetBlendMode("ADD") highlight:Hide() button:SetHighlightTexture(highlight) button:SetScript("OnClick", ListButton_OnClick) return button end local emptyList = { { text = GRAY_FONT_COLOR_CODE .. EMPTY, value = EMPTY, disabled = true, empty = true, } } local function UpdateList(self) local buttons = self.buttons local dropdown = self:GetParent() if dropdown.PreUpdate then dropdown:PreUpdate() end local items = dropdown.items if #items == 0 then --print("List is empty!") items = emptyList end local listSize = min(#items, MAX_LIST_SIZE) local scrollFrame = self.scrollFrame local offset = scrollFrame.offset FauxScrollFrame_Update(scrollFrame, #items, listSize, UIDROPDOWNMENU_BUTTON_HEIGHT) local selected = dropdown.selected local width = 0 for i = 1, #items do local item = items[i] if type(item) == "table" then --print(i, "table", item.text or item.value) self.text:SetText(item.text or item.value) else --print(i, "string", item) self.text:SetText(item) end width = max(width, self.text:GetStringWidth()) end local EXTRA_WIDTH = scrollFrame:IsShown() and 50 or 30 width = max(width + 27 + EXTRA_WIDTH, dropdown:GetWidth() + 10) self:SetWidth(width) width = width - EXTRA_WIDTH self:SetHeight((listSize * UIDROPDOWNMENU_BUTTON_HEIGHT) + (UIDROPDOWNMENU_BORDER_HEIGHT * 2)) for i = 1, listSize do local index = i + offset local button = buttons[i] local item = items[index] if item then if type(item) == "table" then --print(i, "table", item.value, "|", item.text or item.value, "|", item.selected or item.value == selected) button.value = item.value button:SetText(item.text or item.value) button.check:SetShown(item.selected or item.value == selected) if item.disabled then button.label:SetTextColor(GameFontDisable:GetTextColor()) else button.label:SetTextColor(GameFontHighlight:GetTextColor()) end --button:SetEnabled(not item.disabled) else --print(i, "string", item, "|", item == selected) button.value = item button:SetText(item) button.check:SetShown(item == selected) button.label:SetTextColor(GameFontHighlight:GetTextColor()) --button:SetEnabled(true) end button:SetWidth(width) button:Show() else button.value = nil button:SetText() button.check:Hide() button:Hide() end local callback = dropdown.OnListButtonChanged if callback then callback(dropdown, button, item, selected) end end for i = listSize + 1, #buttons do --print(i, "Hide") buttons[i]:Hide() end end local id = 0 function CreateList(dropdown) -- local if dropdown.list then return dropdown.list end id = id + 1 local list = CreateFrame("Button", "PhanxConfigDropdown" .. id, dropdown) list:SetToplevel(true) list:Hide() list:SetPoint("TOPLEFT", dropdown, "BOTTOMLEFT", -4, 3) list:SetScript("OnShow", UpdateList) list.text = list:CreateFontString() list.text:SetFont((GameFontNormal:GetFont()), UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT + 2) list.buttons = setmetatable({}, { __index = function(t, i) local button = CreateListButton(list) if i > 1 then button:SetPoint("TOPLEFT", t[i-1], "BOTTOMLEFT") else button:SetPoint("TOPLEFT", 15, -15) end t[i] = button return button end }) list.scrollFrame = CreateFrame("ScrollFrame", list:GetName() .. "ScrollFrame", list, "FauxScrollFrameTemplate") list.scrollFrame:SetPoint("TOPLEFT", 12, -14) list.scrollFrame:SetPoint("BOTTOMRIGHT", -36, 13) list.scrollFrame:SetScript("OnVerticalScroll", function(self, delta) FauxScrollFrame_OnVerticalScroll(self, delta, UIDROPDOWNMENU_BUTTON_HEIGHT, function() UpdateList(list) end) end) list:SetBackdrop({ bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background", edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border", insets = { left = 11, right = 12, top = 12, bottom = 11 }, tile = true, tileSize = 32, edgeSize = 32, }) --list:SetScript("OnHide", list.Hide) -- wat --list:SetScript("OnClick", list.Hide) -- wat tinsert(lib.listFrames, list) dropdown.list = list return list end ------------------------------------------------------------------------ local function Button_OnClick(self) PlaySound("igMainMenuOptionCheckBoxOn") local dropdown = self:GetParent() OpenDropdown(dropdown) end local function Button_OnEnter(self) return Frame_OnEnter(self:GetParent()) end local function Button_OnLeave(self) return Frame_OnLeave(self:GetParent()) end ------------------------------------------------------------------------ local methods = {} function methods:GetValue() return self.selected or self.valueText:GetText() end function methods:SetValue(value, text) self.selected = value self.valueText:SetText(text or value) end function methods:GetLabel() return self.labelText:GetText() end function methods:SetLabel(text) if type(text) ~= "string" then text = nil end self.labelText:SetText(text) end function methods:GetTooltip() return self.tooltipText end function methods:SetTooltip(text) if type(text) ~= "string" then text = nil end self.tooltipText = text end function methods:GetList() return self.items end function methods:SetList(list) if type(list) ~= "table" then list = nil end self.items = list end function methods:SetKeepShownOnClick(value) self.keepShownOnClick = value end function methods:Enable() self.labelText:SetFontObject(GameFontNormal) self.valueText:SetFontObject(GameFontHighlightSmall) self.button:Enable() end function methods:Disable() self.labelText:SetFontObject(GameFontDisable) self.valueText:SetFontObject(GameFontDisableSmall) self.button:Disable() end ------------------------------------------------------------------------ function lib:New(parent, name, tooltipText, items, keepShownOnClick) assert(type(parent) == "table" and type(rawget(parent, 0)) == "userdata", "PhanxConfig-Dropdown: parent must be a frame") local dropdown = CreateFrame("Frame", nil, parent) dropdown:SetSize(186, 42) dropdown:EnableMouse(true) dropdown:SetScript("OnEnter", Frame_OnEnter) dropdown:SetScript("OnLeave", Frame_OnLeave) dropdown:SetScript("OnHide", Frame_OnHide) --[[ dropdown.bg = dropdown:CreateTexture(nil, "BACKGROUND") dropdown.bg:SetAllPoints(true) dropdown.bg:SetTexture(0, 128, 0, 0.5) ]] local left = dropdown:CreateTexture(nil, "BORDER") left:SetPoint("TOPLEFT", dropdown, "BOTTOMLEFT", -16, 45) left:SetSize(25, 64) left:SetTexture("Interface\\Glues\\CharacterCreate\\CharacterCreate-LabelFrame") left:SetTexCoord(0, 0.1953125, 0, 1) dropdown.bgLeft = left local right = dropdown:CreateTexture(nil, "BORDER") right:SetPoint("TOPRIGHT", dropdown, "BOTTOMRIGHT", 15, 45) right:SetSize(25, 64) right:SetTexture("Interface\\Glues\\CharacterCreate\\CharacterCreate-LabelFrame") right:SetTexCoord(0.8046875, 1, 0, 1) dropdown.bgRight = right local middle = dropdown:CreateTexture(nil, "BORDER") middle:SetPoint("BOTTOMLEFT", left, "BOTTOMRIGHT") middle:SetPoint("TOPRIGHT", right, "TOPLEFT") middle:SetTexture("Interface\\Glues\\CharacterCreate\\CharacterCreate-LabelFrame") middle:SetTexCoord(0.1953125, 0.8046875, 0, 1) dropdown.bgMiddle = middle local label = dropdown:CreateFontString(nil, "OVERLAY", "GameFontNormal") label:SetPoint("TOPLEFT", 5, 0) label:SetPoint("TOPRIGHT", -5, 0) label:SetJustifyH("LEFT") dropdown.labelText = label local value = dropdown:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall") value:SetPoint("LEFT", left, 26, 0) value:SetPoint("RIGHT", right, -43, 0) value:SetJustifyH("LEFT") value:SetHeight(10) dropdown.valueText = value local button = CreateFrame("Button", nil, dropdown) button:SetSize(24, 24) button:SetPoint("TOPRIGHT", right, -16, -18) button:SetPoint("TOPLEFT", left, 16, -18) local normal = button:CreateTexture(nil, "ARTWORK") normal:SetPoint("RIGHT") normal:SetSize(24, 24) normal:SetTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Up") button:SetNormalTexture(normal) local pushed = button:CreateTexture(nil, "ARTWORK") pushed:SetPoint("RIGHT") pushed:SetSize(24, 24) pushed:SetTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Down") button:SetPushedTexture(pushed) local disabled = button:CreateTexture(nil, "ARTWORK") disabled:SetPoint("RIGHT") disabled:SetSize(24, 24) disabled:SetTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Disabled") button:SetDisabledTexture(disabled) local highlight = button:CreateTexture(nil, "HIGHLIGHT") highlight:SetPoint("RIGHT") highlight:SetSize(24, 24) highlight:SetTexture("Interface\\Buttons\\UI-Common-MouseHilight") highlight:SetBlendMode("ADD") button:SetHighlightTexture(highlight) button:SetScript("OnEnter", Button_OnEnter) button:SetScript("OnLeave", Button_OnLeave) button:SetScript("OnClick", Button_OnClick) dropdown.button = button for name, func in pairs(methods) do dropdown[name] = func end dropdown:SetLabel(name) dropdown:SetTooltip(tooltipText) dropdown:SetList(items) dropdown.keepShownOnClick = keepShownOnClick return dropdown end function lib.CreateDropdown(...) return lib:New(...) end