Files
coa-bartender/libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua
T
florian.berthold 57a5cdabdf ascension: 4.4.2 → vendored 4.4.2-2-g3b02ee4 (in-game AddOns dir)
Imported from /srv/add01/wow-ascension/Interface/AddOns/Bartender4 — the
build Ascension's WotLK 3.3.5 client ships.

Single vendored drop: Ascension's build process bundles their custom
patches with the standard CurseForge packager output (embedded libs),
and the individual patches aren't published separately.

Net delta vs Nevcairiel 4.4.2, excluding bundled libs and CRLF
normalization: 21 files, 2213+/52- — the Ascension-specific
adaptations for WotLK 3.3.5 hero classes / custom action systems.

License: All rights reserved (per .toc).
2026-05-08 03:45:58 +02:00

708 lines
18 KiB
Lua

--[[ $Id: AceGUIWidget-DropDown.lua 916 2010-03-15 12:24:36Z nevcairiel $ ]]--
local AceGUI = LibStub("AceGUI-3.0")
-- Lua APIs
local min, max, floor = math.min, math.max, math.floor
local select, pairs, ipairs = select, pairs, ipairs
local tsort = table.sort
-- WoW APIs
local PlaySound = PlaySound
local UIParent, CreateFrame = UIParent, CreateFrame
local _G = _G
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script
-- GLOBALS: CLOSE
local function fixlevels(parent,...)
local i = 1
local child = select(i, ...)
while child do
child:SetFrameLevel(parent:GetFrameLevel()+1)
fixlevels(child, child:GetChildren())
i = i + 1
child = select(i, ...)
end
end
local function fixstrata(strata, parent, ...)
local i = 1
local child = select(i, ...)
parent:SetFrameStrata(strata)
while child do
fixstrata(strata, child, child:GetChildren())
i = i + 1
child = select(i, ...)
end
end
do
local widgetType = "Dropdown-Pullout"
local widgetVersion = 3
--[[ Static data ]]--
local backdrop = {
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
edgeSize = 32,
tileSize = 32,
tile = true,
insets = { left = 11, right = 12, top = 12, bottom = 11 },
}
local sliderBackdrop = {
bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
tile = true, tileSize = 8, edgeSize = 8,
insets = { left = 3, right = 3, top = 3, bottom = 3 }
}
local defaultWidth = 200
local defaultMaxHeight = 600
--[[ UI Event Handlers ]]--
-- HACK: This should be no part of the pullout, but there
-- is no other 'clean' way to response to any item-OnEnter
-- Used to close Submenus when an other item is entered
local function OnEnter(item)
local self = item.pullout
for k, v in ipairs(self.items) do
if v.CloseMenu and v ~= item then
v:CloseMenu()
end
end
end
-- See the note in Constructor() for each scroll related function
local function OnMouseWheel(this, value)
this.obj:MoveScroll(value)
end
local function OnScrollValueChanged(this, value)
this.obj:SetScroll(value)
end
local function OnSizeChanged(this)
this.obj:FixScroll()
end
--[[ Exported methods ]]--
-- exported
local function SetScroll(self, value)
local status = self.scrollStatus
local frame, child = self.scrollFrame, self.itemFrame
local height, viewheight = frame:GetHeight(), child:GetHeight()
local offset
if height > viewheight then
offset = 0
else
offset = floor((viewheight - height) / 1000 * value)
end
child:ClearAllPoints()
child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset)
child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", self.slider:IsShown() and -12 or 0, offset)
status.offset = offset
status.scrollvalue = value
end
-- exported
local function MoveScroll(self, value)
local status = self.scrollStatus
local frame, child = self.scrollFrame, self.itemFrame
local height, viewheight = frame:GetHeight(), child:GetHeight()
if height > viewheight then
self.slider:Hide()
else
self.slider:Show()
local diff = height - viewheight
local delta = 1
if value < 0 then
delta = -1
end
self.slider:SetValue(min(max(status.scrollvalue + delta*(1000/(diff/45)),0), 1000))
end
end
-- exported
local function FixScroll(self)
local status = self.scrollStatus
local frame, child = self.scrollFrame, self.itemFrame
local height, viewheight = frame:GetHeight(), child:GetHeight()
local offset = status.offset or 0
if viewheight < height then
self.slider:Hide()
child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, offset)
self.slider:SetValue(0)
else
self.slider:Show()
local value = (offset / (viewheight - height) * 1000)
if value > 1000 then value = 1000 end
self.slider:SetValue(value)
self:SetScroll(value)
if value < 1000 then
child:ClearAllPoints()
child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset)
child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -12, offset)
status.offset = offset
end
end
end
-- exported, AceGUI callback
local function OnAcquire(self)
self.frame:SetParent(UIParent)
--self.itemFrame:SetToplevel(true)
end
-- exported, AceGUI callback
local function OnRelease(self)
self:Clear()
self.frame:ClearAllPoints()
self.frame:Hide()
end
-- exported
local function AddItem(self, item)
self.items[#self.items + 1] = item
local h = #self.items * 16
self.itemFrame:SetHeight(h)
self.frame:SetHeight(min(h + 34, self.maxHeight)) -- +34: 20 for scrollFrame placement (10 offset) and +14 for item placement
item.frame:SetPoint("LEFT", self.itemFrame, "LEFT")
item.frame:SetPoint("RIGHT", self.itemFrame, "RIGHT")
item:SetPullout(self)
item:SetOnEnter(OnEnter)
end
-- exported
local function Open(self, point, relFrame, relPoint, x, y)
local items = self.items
local frame = self.frame
local itemFrame = self.itemFrame
frame:SetPoint(point, relFrame, relPoint, x, y)
local height = 8
for i, item in pairs(items) do
if i == 1 then
item:SetPoint("TOP", itemFrame, "TOP", 0, -2)
else
item:SetPoint("TOP", items[i-1].frame, "BOTTOM", 0, 1)
end
item:Show()
height = height + 16
end
itemFrame:SetHeight(height)
fixstrata("TOOLTIP", frame, frame:GetChildren())
frame:Show()
self:Fire("OnOpen")
end
-- exported
local function Close(self)
self.frame:Hide()
self:Fire("OnClose")
end
-- exported
local function Clear(self)
local items = self.items
for i, item in pairs(items) do
AceGUI:Release(item)
items[i] = nil
end
end
-- exported
local function IterateItems(self)
return ipairs(self.items)
end
-- exported
local function SetHideOnLeave(self, val)
self.hideOnLeave = val
end
-- exported
local function SetMaxHeight(self, height)
self.maxHeight = height or defaultMaxHeight
if self.frame:GetHeight() > height then
self.frame:SetHeight(height)
elseif (self.itemFrame:GetHeight() + 34) < height then
self.frame:SetHeight(self.itemFrame:GetHeight() + 34) -- see :AddItem
end
end
-- exported
local function GetRightBorderWidth(self)
return 6 + (self.slider:IsShown() and 12 or 0)
end
-- exported
local function GetLeftBorderWidth(self)
return 6
end
--[[ Constructor ]]--
local function Constructor()
local count = AceGUI:GetNextWidgetNum(widgetType)
local frame = CreateFrame("Frame", "AceGUI30Pullout"..count, UIParent)
local self = {}
self.count = count
self.type = widgetType
self.frame = frame
frame.obj = self
self.OnAcquire = OnAcquire
self.OnRelease = OnRelease
self.AddItem = AddItem
self.Open = Open
self.Close = Close
self.Clear = Clear
self.IterateItems = IterateItems
self.SetHideOnLeave = SetHideOnLeave
self.SetScroll = SetScroll
self.MoveScroll = MoveScroll
self.FixScroll = FixScroll
self.SetMaxHeight = SetMaxHeight
self.GetRightBorderWidth = GetRightBorderWidth
self.GetLeftBorderWidth = GetLeftBorderWidth
self.items = {}
self.scrollStatus = {
scrollvalue = 0,
}
self.maxHeight = defaultMaxHeight
frame:SetBackdrop(backdrop)
frame:SetBackdropColor(0, 0, 0)
frame:SetFrameStrata("FULLSCREEN_DIALOG")
frame:SetClampedToScreen(true)
frame:SetWidth(defaultWidth)
frame:SetHeight(self.maxHeight)
--frame:SetToplevel(true)
-- NOTE: The whole scroll frame code is copied from the AceGUI-3.0 widget ScrollFrame
local scrollFrame = CreateFrame("ScrollFrame", nil, frame)
local itemFrame = CreateFrame("Frame", nil, scrollFrame)
self.scrollFrame = scrollFrame
self.itemFrame = itemFrame
scrollFrame.obj = self
itemFrame.obj = self
local slider = CreateFrame("Slider", "AceGUI30PulloutScrollbar"..count, scrollFrame)
slider:SetOrientation("VERTICAL")
slider:SetHitRectInsets(0, 0, -10, 0)
slider:SetBackdrop(sliderBackdrop)
slider:SetWidth(8)
slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical")
slider:SetFrameStrata("FULLSCREEN_DIALOG")
self.slider = slider
slider.obj = self
scrollFrame:SetScrollChild(itemFrame)
scrollFrame:SetPoint("TOPLEFT", frame, "TOPLEFT", 6, -12)
scrollFrame:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -6, 12)
scrollFrame:EnableMouseWheel(true)
scrollFrame:SetScript("OnMouseWheel", OnMouseWheel)
scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
scrollFrame:SetToplevel(true)
scrollFrame:SetFrameStrata("FULLSCREEN_DIALOG")
itemFrame:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, 0)
itemFrame:SetPoint("TOPRIGHT", scrollFrame, "TOPRIGHT", -12, 0)
itemFrame:SetHeight(400)
itemFrame:SetToplevel(true)
itemFrame:SetFrameStrata("FULLSCREEN_DIALOG")
slider:SetPoint("TOPLEFT", scrollFrame, "TOPRIGHT", -16, 0)
slider:SetPoint("BOTTOMLEFT", scrollFrame, "BOTTOMRIGHT", -16, 0)
slider:SetScript("OnValueChanged", OnScrollValueChanged)
slider:SetMinMaxValues(0, 1000)
slider:SetValueStep(1)
slider:SetValue(0)
scrollFrame:Show()
itemFrame:Show()
slider:Hide()
self:FixScroll()
AceGUI:RegisterAsWidget(self)
return self
end
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
end
do
local widgetType = "Dropdown"
local widgetVersion = 22
--[[ Static data ]]--
--[[ UI event handler ]]--
local function Control_OnEnter(this)
this.obj:Fire("OnEnter")
end
local function Control_OnLeave(this)
this.obj:Fire("OnLeave")
end
local function Dropdown_OnHide(this)
local self = this.obj
if self.open then
self.pullout:Close()
end
end
local function Dropdown_TogglePullout(this)
local self = this.obj
PlaySound("igMainMenuOptionCheckBoxOn") -- missleading name, but the Blizzard code uses this sound
if self.open then
self.open = nil
self.pullout:Close()
AceGUI:ClearFocus()
else
self.open = true
self.pullout:SetWidth(self.frame:GetWidth())
self.pullout:Open("TOPLEFT", self.frame, "BOTTOMLEFT", 0, self.label:IsShown() and -2 or 0)
AceGUI:SetFocus(self)
end
end
local function OnPulloutOpen(this)
local self = this.userdata.obj
local value = self.value
if not self.multiselect then
for i, item in this:IterateItems() do
item:SetValue(item.userdata.value == value)
end
end
self.open = true
end
local function OnPulloutClose(this)
local self = this.userdata.obj
self.open = nil
self:Fire("OnClosed")
end
local function ShowMultiText(self)
local text
for i, widget in self.pullout:IterateItems() do
if widget.type == "Dropdown-Item-Toggle" then
if widget:GetValue() then
if text then
text = text..", "..widget:GetText()
else
text = widget:GetText()
end
end
end
end
self:SetText(text)
end
local function OnItemValueChanged(this, event, checked)
local self = this.userdata.obj
if self.multiselect then
self:Fire("OnValueChanged", this.userdata.value, checked)
ShowMultiText(self)
else
if checked then
self:SetValue(this.userdata.value)
self:Fire("OnValueChanged", this.userdata.value)
else
this:SetValue(true)
end
if self.open then
self.pullout:Close()
end
end
end
--[[ Exported methods ]]--
-- exported, AceGUI callback
local function OnAcquire(self)
local pullout = AceGUI:Create("Dropdown-Pullout")
self.pullout = pullout
pullout.userdata.obj = self
pullout:SetCallback("OnClose", OnPulloutClose)
pullout:SetCallback("OnOpen", OnPulloutOpen)
self.pullout.frame:SetFrameLevel(self.frame:GetFrameLevel() + 1)
fixlevels(self.pullout.frame, self.pullout.frame:GetChildren())
self:SetHeight(44)
self:SetWidth(200)
end
-- exported, AceGUI callback
local function OnRelease(self)
if self.open then
self.pullout:Close()
end
AceGUI:Release(self.pullout)
self.pullout = nil
self:SetText("")
self:SetLabel("")
self:SetDisabled(false)
self:SetMultiselect(false)
self.value = nil
self.list = nil
self.open = nil
self.hasClose = nil
self.frame:ClearAllPoints()
self.frame:Hide()
end
-- exported
local function SetDisabled(self, disabled)
self.disabled = disabled
if disabled then
self.text:SetTextColor(0.5,0.5,0.5)
self.button:Disable()
self.label:SetTextColor(0.5,0.5,0.5)
else
self.button:Enable()
self.label:SetTextColor(1,.82,0)
self.text:SetTextColor(1,1,1)
end
end
-- exported
local function ClearFocus(self)
if self.open then
self.pullout:Close()
end
end
-- exported
local function SetText(self, text)
self.text:SetText(text or "")
end
-- exported
local function SetLabel(self, text)
if text and text ~= "" then
self.label:SetText(text)
self.label:Show()
self.dropdown:SetPoint("TOPLEFT",self.frame,"TOPLEFT",-15,-18)
self.frame:SetHeight(44)
else
self.label:SetText("")
self.label:Hide()
self.dropdown:SetPoint("TOPLEFT",self.frame,"TOPLEFT",-15,0)
self.frame:SetHeight(26)
end
end
-- exported
local function SetValue(self, value)
if self.list then
self:SetText(self.list[value] or "")
end
self.value = value
end
-- exported
local function GetValue(self)
return self.value
end
-- exported
local function SetItemValue(self, item, value)
if not self.multiselect then return end
for i, widget in self.pullout:IterateItems() do
if widget.userdata.value == item then
if widget.SetValue then
widget:SetValue(value)
end
end
end
ShowMultiText(self)
end
-- exported
local function SetItemDisabled(self, item, disabled)
for i, widget in self.pullout:IterateItems() do
if widget.userdata.value == item then
widget:SetDisabled(disabled)
end
end
end
local function AddListItem(self, value, text)
local item = AceGUI:Create("Dropdown-Item-Toggle")
item:SetText(text)
item.userdata.obj = self
item.userdata.value = value
item:SetCallback("OnValueChanged", OnItemValueChanged)
self.pullout:AddItem(item)
end
local function AddCloseButton(self)
if not self.hasClose then
local close = AceGUI:Create("Dropdown-Item-Execute")
close:SetText(CLOSE)
self.pullout:AddItem(close)
self.hasClose = true
end
end
-- exported
local sortlist = {}
local function SetList(self, list)
self.list = list
self.pullout:Clear()
self.hasClose = nil
if not list then return end
for v in pairs(list) do
sortlist[#sortlist + 1] = v
end
tsort(sortlist)
for i, value in pairs(sortlist) do
AddListItem(self, value, list[value])
sortlist[i] = nil
end
if self.multiselect then
ShowMultiText(self)
AddCloseButton(self)
end
end
-- exported
local function AddItem(self, value, text)
if self.list then
self.list[value] = text
AddListItem(self, value, text)
end
end
-- exported
local function SetMultiselect(self, multi)
self.multiselect = multi
if multi then
ShowMultiText(self)
AddCloseButton(self)
end
end
-- exported
local function GetMultiselect(self)
return self.multiselect
end
--[[ Constructor ]]--
local function Constructor()
local count = AceGUI:GetNextWidgetNum(widgetType)
local frame = CreateFrame("Frame", nil, UIParent)
local dropdown = CreateFrame("Frame", "AceGUI30DropDown"..count, frame, "UIDropDownMenuTemplate")
local self = {}
self.type = widgetType
self.frame = frame
self.dropdown = dropdown
self.count = count
frame.obj = self
dropdown.obj = self
self.OnRelease = OnRelease
self.OnAcquire = OnAcquire
self.ClearFocus = ClearFocus
self.SetText = SetText
self.SetValue = SetValue
self.GetValue = GetValue
self.SetList = SetList
self.SetLabel = SetLabel
self.SetDisabled = SetDisabled
self.AddItem = AddItem
self.SetMultiselect = SetMultiselect
self.GetMultiselect = GetMultiselect
self.SetItemValue = SetItemValue
self.SetItemDisabled = SetItemDisabled
self.alignoffset = 31
frame:SetHeight(44)
frame:SetWidth(200)
frame:SetScript("OnHide",Dropdown_OnHide)
dropdown:ClearAllPoints()
dropdown:SetPoint("TOPLEFT",frame,"TOPLEFT",-15,0)
dropdown:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",17,0)
dropdown:SetScript("OnHide", nil)
local left = _G[dropdown:GetName() .. "Left"]
local middle = _G[dropdown:GetName() .. "Middle"]
local right = _G[dropdown:GetName() .. "Right"]
middle:ClearAllPoints()
right:ClearAllPoints()
middle:SetPoint("LEFT", left, "RIGHT", 0, 0)
middle:SetPoint("RIGHT", right, "LEFT", 0, 0)
right:SetPoint("TOPRIGHT", dropdown, "TOPRIGHT", 0, 17)
local button = _G[dropdown:GetName() .. "Button"]
self.button = button
button.obj = self
button:SetScript("OnEnter",Control_OnEnter)
button:SetScript("OnLeave",Control_OnLeave)
button:SetScript("OnClick",Dropdown_TogglePullout)
local text = _G[dropdown:GetName() .. "Text"]
self.text = text
text.obj = self
text:ClearAllPoints()
text:SetPoint("RIGHT", right, "RIGHT" ,-43, 2)
text:SetPoint("LEFT", left, "LEFT", 25, 2)
local label = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
label:SetPoint("TOPLEFT",frame,"TOPLEFT",0,0)
label:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,0)
label:SetJustifyH("LEFT")
label:SetHeight(18)
label:Hide()
self.label = label
AceGUI:RegisterAsWidget(self)
return self
end
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
end