--[[-------------------------------------------------------------------- |
PhanxConfig-Dropdown |
Simple scrolling dropdown widget generator. |
Based on tekKonfig-Dropdown by Tekkub and OmniCC_Options by Tuller. |
Requires LibStub. |
https://github.com/phanx/PhanxConfigWidgets |
Copyright (c) 2009-2014 Phanx. All rights reserved. |
See the accompanying README and LICENSE files for more information. |
----------------------------------------------------------------------]] |
|
local MINOR_VERSION = tonumber(strmatch("$Revision$", "%d+")) |
|
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.dropdown.list then |
self.dropdown.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 or dropdown.Callback |
if callback then |
callback(dropdown, self.value) |
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() |
local items = dropdown.items |
|
if dropdown.PreUpdate then |
dropdown:PreUpdate(items) |
end |
|
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 or dropdown.ListButtonCallback |
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(parent) -- local |
local dropdown = parent |
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 |
|
-- backwards compat? |
dropdown.dropdown = dropdown |
|
return dropdown |
end |
|
function lib.CreateDropdown(...) return lib:New(...) end |