WoWInterface SVN PhanxConfigWidgets

[/] [trunk/] [PhanxConfig-Dropdown/] [PhanxConfig-Dropdown.lua] - Rev 191

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

Compare with Previous | Blame