local p=LibStub("\065\099\101\071\085\073-\051\046\048")local K,a,w=math.min,math.max,math.floor local R,H,C,c,f=select,pairs,ipairs,type,tostring local U=table.sort local W=PlaySound local G,M=UIParent,CreateFrame local b=_G local function k(p,...)local K=1 local a=R(K,...)while a do a:SetFrameLevel(p:GetFrameLevel()+1)k(a,a:GetChildren())K=K+1 a=R(K,...)end end local function e(p,K,...)local a=1 local w=R(a,...)K:SetFrameStrata(p)while w do e(p,w,w:GetChildren())a=a+1 w=R(a,...)end end do local R="\068\114\111\112\100\111\119\110-\080\117\108\108\111\117\116"local c=5 local f={bgFile="\073\110\116\101\114\102\097\099\101\092\067\104\097\116\070\114\097\109\101\092\067\104\097\116\070\114\097\109\101\066\097\099\107\103\114\111\117\110\100",edgeFile="\073\110\116\101\114\102\097\099\101\092\068\105\097\108\111\103\070\114\097\109\101\092\085\073-\068\105\097\108\111\103\066\111\120-\066\111\114\100\101\114",edgeSize=32,tileSize=32,tile=true;insets={left=11;right=12;top=12,bottom=11}}local U={bgFile="\073\110\116\101\114\102\097\099\101\092\066\117\116\116\111\110\115\092\085\073-\083\108\105\100\101\114\066\097\114-\066\097\099\107\103\114\111\117\110\100";edgeFile="\073\110\116\101\114\102\097\099\101\092\066\117\116\116\111\110\115\092\085\073-\083\108\105\100\101\114\066\097\114-\066\111\114\100\101\114";tile=true,tileSize=8,edgeSize=8,insets={left=3;right=3,top=3,bottom=3}}local W=200 local b=600 local function k(p)local K=p.pullout for K,a in C(K.items)do if a.CloseMenu and a~=p then a:CloseMenu()end end end local function D(p,K)p.obj:MoveScroll(K)end local function h(p,K)p.obj:SetScroll(K)end local function F(p)p.obj:FixScroll()end local function I(p,K)local a=p.scrollStatus local R,H=p.scrollFrame,p.itemFrame local C,c=R:GetHeight(),H:GetHeight()local f if C>c then f=0 else f=w(((c-C)/1000)*K)end H:ClearAllPoints()H:SetPoint("\084\079\080\076\069\070\084",R,"\084\079\080\076\069\070\084",0,f)H:SetPoint("\084\079\080\082\073\071\072\084",R,"\084\079\080\082\073\071\072\084",p.slider:IsShown()and-12 or 0,f)a.offset=f a.scrollvalue=K end local function u(p,w)local R=p.scrollStatus local H,C=p.scrollFrame,p.itemFrame local c,f=H:GetHeight(),C:GetHeight()if c>f then p.slider:Hide()else p.slider:Show()local H=c-f local C=1 if w<0 then C=-1 end p.slider:SetValue(K(a(R.scrollvalue+C*(1000/(H/45)),0),1000))end end local function z(p)local K=p.scrollStatus local a,w=p.scrollFrame,p.itemFrame local R,H=a:GetHeight(),w:GetHeight()local C=K.offset or 0 if H<R then p.slider:Hide()w:SetPoint("\084\079\080\082\073\071\072\084",a,"\084\079\080\082\073\071\072\084",0,C)p.slider:SetValue(0)else p.slider:Show()local c=(C/(H-R))*1000 if c>1000 then c=1000 end p.slider:SetValue(c)p:SetScroll(c)if c<1000 then w:ClearAllPoints()w:SetPoint("\084\079\080\076\069\070\084",a,"\084\079\080\076\069\070\084",0,C)w:SetPoint("\084\079\080\082\073\071\072\084",a,"\084\079\080\082\073\071\072\084",-12,C)K.offset=C end end end local function N(p)p.frame:SetParent(G)end local function d(p)p:Clear()p.frame:ClearAllPoints()p.frame:Hide()end local function s(p,a)p.items[#p.items+1]=a local w=#p.items*16 p.itemFrame:SetHeight(w)p.frame:SetHeight(K(w+34,p.maxHeight))a.frame:SetPoint("\076\069\070\084",p.itemFrame,"\076\069\070\084")a.frame:SetPoint("\082\073\071\072\084",p.itemFrame,"\082\073\071\072\084")a:SetPullout(p)a:SetOnEnter(k)end local function J(p,K,a,w,R,C)local c=p.items local f=p.frame local U=p.itemFrame f:SetPoint(K,a,w,R,C)local W=8 for p,K in H(c)do K:SetPoint("\084\079\080",U,"\084\079\080",0,-2+(p-1)*-16)K:Show()W=W+16 end U:SetHeight(W)e("\084\079\079\076\084\073\080",f,f:GetChildren())f:Show()p:Fire("\079\110\079\112\101\110")end local function Z(p)p.frame:Hide()p:Fire("\079\110\067\108\111\115\101")end local function t(K)local a=K.items for K,w in H(a)do p:Release(w)a[K]=nil end end local function T(p)return C(p.items)end local function i(p,K)p.hideOnLeave=K end local function m(p,K)p.maxHeight=K or b if p.frame:GetHeight()>K then p.frame:SetHeight(K)elseif p.itemFrame:GetHeight()+34<K then p.frame:SetHeight(p.itemFrame:GetHeight()+34)end end local function o(p)return 6+(p.slider:IsShown()and 12 or 0)end local function L(p)return 6 end local function B()local K=p:GetNextWidgetNum(R)local a=M("\070\114\097\109\101","\065\099\101\071\085\073\051\048\080\117\108\108\111\117\116"..K,G,"\066\097\099\107\100\114\111\112\084\101\109\112\108\097\116\101")local w={}w.count=K w.type=R w.frame=a a.obj=w w.OnAcquire=N w.OnRelease=d w.AddItem=s w.Open=J w.Close=Z w.Clear=t w.IterateItems=T w.SetHideOnLeave=i w.SetScroll=I w.MoveScroll=u w.FixScroll=z w.SetMaxHeight=m w.GetRightBorderWidth=o w.GetLeftBorderWidth=L w.items={}w.scrollStatus={scrollvalue=0}w.maxHeight=b a:SetBackdrop(f)a:SetBackdropColor(0,0,0)a:SetFrameStrata("\070\085\076\076\083\067\082\069\069\078\095\068\073\065\076\079\071")a:SetClampedToScreen(true)a:SetWidth(W)a:SetHeight(w.maxHeight)local H=M("\083\099\114\111\108\108\070\114\097\109\101",nil,a)local C=M("\070\114\097\109\101",nil,H)w.scrollFrame=H w.itemFrame=C H.obj=w C.obj=w local c=M("\083\108\105\100\101\114","\065\099\101\071\085\073\051\048\080\117\108\108\111\117\116\083\099\114\111\108\108\098\097\114"..K,H,"\066\097\099\107\100\114\111\112\084\101\109\112\108\097\116\101")c:SetOrientation("\086\069\082\084\073\067\065\076")c:SetHitRectInsets(0,0,-10,0)c:SetBackdrop(U)c:SetWidth(8)c:SetThumbTexture("\073\110\116\101\114\102\097\099\101\092\066\117\116\116\111\110\115\092\085\073-\083\108\105\100\101\114\066\097\114-\066\117\116\116\111\110-\086\101\114\116\105\099\097\108")c:SetFrameStrata("\070\085\076\076\083\067\082\069\069\078\095\068\073\065\076\079\071")w.slider=c c.obj=w H:SetScrollChild(C)H:SetPoint("\084\079\080\076\069\070\084",a,"\084\079\080\076\069\070\084",6,-12)H:SetPoint("\066\079\084\084\079\077\082\073\071\072\084",a,"\066\079\084\084\079\077\082\073\071\072\084",-6,12)H:EnableMouseWheel(true)H:SetScript("\079\110\077\111\117\115\101\087\104\101\101\108",D)H:SetScript("\079\110\083\105\122\101\067\104\097\110\103\101\100",F)H:SetToplevel(true)H:SetFrameStrata("\070\085\076\076\083\067\082\069\069\078\095\068\073\065\076\079\071")C:SetPoint("\084\079\080\076\069\070\084",H,"\084\079\080\076\069\070\084",0,0)C:SetPoint("\084\079\080\082\073\071\072\084",H,"\084\079\080\082\073\071\072\084",-12,0)C:SetHeight(400)C:SetToplevel(true)C:SetFrameStrata("\070\085\076\076\083\067\082\069\069\078\095\068\073\065\076\079\071")c:SetPoint("\084\079\080\076\069\070\084",H,"\084\079\080\082\073\071\072\084",-16,0)c:SetPoint("\066\079\084\084\079\077\076\069\070\084",H,"\066\079\084\084\079\077\082\073\071\072\084",-16,0)c:SetScript("\079\110\086\097\108\117\101\067\104\097\110\103\101\100",h)c:SetMinMaxValues(0,1000)c:SetValueStep(1)c:SetValue(0)H:Show()C:Show()c:Hide()w:FixScroll()p:RegisterAsWidget(w)return w end p:RegisterWidgetType(R,B,c)end do local K="\068\114\111\112\100\111\119\110"local a=36 local function w(p)p.obj.button:LockHighlight()p.obj:Fire("\079\110\069\110\116\101\114")end local function R(p)p.obj.button:UnlockHighlight()p.obj:Fire("\079\110\076\101\097\118\101")end local function W(p)local K=p.obj if K.open then K.pullout:Close()end end local function e(K)local a=K.obj if a.open then a.open=nil a.pullout:Close()p:ClearFocus()else a.open=true a.pullout:SetWidth(a.pulloutWidth or a.frame:GetWidth())a.pullout:Open("\084\079\080\076\069\070\084",a.frame,"\066\079\084\084\079\077\076\069\070\084",0,a.label:IsShown()and-2 or 0)p:SetFocus(a)end end local function D(p)local K=p.userdata.obj local a=K.value if not K.multiselect then for p,K in p:IterateItems()do K:SetValue(K.userdata.value==a)end end K.open=true K:Fire("\079\110\079\112\101\110\101\100")end local function h(p)local K=p.userdata.obj K.open=nil K:Fire("\079\110\067\108\111\115\101\100")end local function F(p)local K for p,a in p.pullout:IterateItems()do if a.type=="\068\114\111\112\100\111\119\110-\073\116\101\109-\084\111\103\103\108\101"then if a:GetValue()then if K then K=K..("\044 "..a:GetText())else K=a:GetText()end end end end p:SetText(K)end local function I(p,K,a)local w=p.userdata.obj if w.multiselect then w:Fire("\079\110\086\097\108\117\101\067\104\097\110\103\101\100",p.userdata.value,a)F(w)else if a then w:SetValue(p.userdata.value)w:Fire("\079\110\086\097\108\117\101\067\104\097\110\103\101\100",p.userdata.value)else p:SetValue(true)end if w.open then w.pullout:Close()end end end local function u(K)local a=p:Create("\068\114\111\112\100\111\119\110-\080\117\108\108\111\117\116")K.pullout=a a.userdata.obj=K a:SetCallback("\079\110\067\108\111\115\101",h)a:SetCallback("\079\110\079\112\101\110",D)K.pullout.frame:SetFrameLevel(K.frame:GetFrameLevel()+1)k(K.pullout.frame,K.pullout.frame:GetChildren())K:SetHeight(44)K:SetWidth(200)K:SetLabel()K:SetPulloutWidth(nil)K.list={}end local function z(K)if K.open then K.pullout:Close()end p:Release(K.pullout)K.pullout=nil K:SetText("")K:SetDisabled(false)K:SetMultiselect(false)K.value=nil K.list=nil K.open=nil K.hasClose=nil K.frame:ClearAllPoints()K.frame:Hide()end local function N(p,K)p.disabled=K if K then p.text:SetTextColor(.5,.5,.5)p.button:Disable()p.button_cover:Disable()p.label:SetTextColor(.5,.5,.5)else p.button:Enable()p.button_cover:Enable()p.label:SetTextColor(1,.82,0)p.text:SetTextColor(1,1,1)end end local function d(p)if p.open then p.pullout:Close()end end local function s(p,K)p.text:SetText(K or"")end local function J(p,K)if K and K~=""then p.label:SetText(K)p.label:Show()p.dropdown:SetPoint("\084\079\080\076\069\070\084",p.frame,"\084\079\080\076\069\070\084",-15,-14)p:SetHeight(40)p.alignoffset=26 else p.label:SetText("")p.label:Hide()p.dropdown:SetPoint("\084\079\080\076\069\070\084",p.frame,"\084\079\080\076\069\070\084",-15,0)p:SetHeight(26)p.alignoffset=12 end end local function Z(p,K)p:SetText(p.list[K]or"")p.value=K end local function t(p)return p.value end local function T(p,K,a)if not p.multiselect then return end for p,w in p.pullout:IterateItems()do if w.userdata.value==K then if w.SetValue then w:SetValue(a)end end end F(p)end local function i(p,K,a)for p,w in p.pullout:IterateItems()do if w.userdata.value==K then w:SetDisabled(a)end end end local function m(K,a,w,R)if not R then R="\068\114\111\112\100\111\119\110-\073\116\101\109-\084\111\103\103\108\101"end local H=p:GetWidgetVersion(R)if not H then error(("\084\104\101 \103\105\118\101\110 \105\116\101\109 \116\121\112\101\044 \037\113\044 \100\111\101\115 \110\111\116 \101\120\105\115\116 \119\105\116\104\105\110 \065\099\101\071\085\073-\051\046\048"):format(f(R)),2)end local C=p:Create(R)C:SetText(w)C.userdata.obj=K C.userdata.value=a C:SetCallback("\079\110\086\097\108\117\101\067\104\097\110\103\101\100",I)K.pullout:AddItem(C)end local function o(K)if not K.hasClose then local a=p:Create("\068\114\111\112\100\111\119\110-\073\116\101\109-\069\120\101\099\117\116\101")a:SetText(CLOSE)K.pullout:AddItem(a)K.hasClose=true end end local L={}local function B(p,K)local a,w=tonumber(p),tonumber(K)if a and w then return a<w else return f(p)<f(K)end end local function V(p,K,a,w)p.list=K or{}p.pullout:Clear()p.hasClose=nil if not K then return end if c(a)~="\116\097\098\108\101"then for p in H(K)do L[#L+1]=p end U(L,B)for a,R in C(L)do m(p,R,K[R],w)L[a]=nil end else for a,R in C(a)do m(p,R,K[R],w)end end if p.multiselect then F(p)o(p)end end local function j(p,K,a,w)p.list[K]=a m(p,K,a,w)end local function x(p,K)p.multiselect=K if K then F(p)o(p)end end local function Y(p)return p.multiselect end local function X(p,K)p.pulloutWidth=K end local function A()local a=p:GetNextWidgetNum(K)local H=M("\070\114\097\109\101",nil,G)local C=M("\070\114\097\109\101","\065\099\101\071\085\073\051\048\068\114\111\112\068\111\119\110"..a,H,"\085\073\068\114\111\112\068\111\119\110\077\101\110\117\084\101\109\112\108\097\116\101")local c={}c.type=K c.frame=H c.dropdown=C c.count=a H.obj=c C.obj=c c.OnRelease=z c.OnAcquire=u c.ClearFocus=d c.SetText=s c.SetValue=Z c.GetValue=t c.SetList=V c.SetLabel=J c.SetDisabled=N c.AddItem=j c.SetMultiselect=x c.GetMultiselect=Y c.SetItemValue=T c.SetItemDisabled=i c.SetPulloutWidth=X c.alignoffset=26 H:SetScript("\079\110\072\105\100\101",W)C:ClearAllPoints()C:SetPoint("\084\079\080\076\069\070\084",H,"\084\079\080\076\069\070\084",-15,0)C:SetPoint("\066\079\084\084\079\077\082\073\071\072\084",H,"\066\079\084\084\079\077\082\073\071\072\084",17,0)C:SetScript("\079\110\072\105\100\101",nil)local f=b[C:GetName().."\076\101\102\116"]local U=b[C:GetName().."\077\105\100\100\108\101"]local k=b[C:GetName().."\082\105\103\104\116"]U:ClearAllPoints()k:ClearAllPoints()U:SetPoint("\076\069\070\084",f,"\082\073\071\072\084",0,0)U:SetPoint("\082\073\071\072\084",k,"\076\069\070\084",0,0)k:SetPoint("\084\079\080\082\073\071\072\084",C,"\084\079\080\082\073\071\072\084",0,17)local D=b[C:GetName().."\066\117\116\116\111\110"]c.button=D D.obj=c D:SetScript("\079\110\069\110\116\101\114",w)D:SetScript("\079\110\076\101\097\118\101",R)D:SetScript("\079\110\067\108\105\099\107",e)local h=M("\066\085\084\084\079\078",nil,c.frame)c.button_cover=h h.obj=c h:SetPoint("\084\079\080\076\069\070\084",c.frame,"\066\079\084\084\079\077\076\069\070\084",0,25)h:SetPoint("\066\079\084\084\079\077\082\073\071\072\084",c.frame,"\066\079\084\084\079\077\082\073\071\072\084")h:SetScript("\079\110\069\110\116\101\114",w)h:SetScript("\079\110\076\101\097\118\101",R)h:SetScript("\079\110\067\108\105\099\107",e)local F=b[C:GetName().."\084\101\120\116"]c.text=F F.obj=c F:ClearAllPoints()F:SetPoint("\082\073\071\072\084",k,"\082\073\071\072\084",-43,2)F:SetPoint("\076\069\070\084",f,"\076\069\070\084",25,2)local I=H:CreateFontString(nil,"\079\086\069\082\076\065\089","\071\097\109\101\070\111\110\116\078\111\114\109\097\108\083\109\097\108\108")I:SetPoint("\084\079\080\076\069\070\084",H,"\084\079\080\076\069\070\084",0,0)I:SetPoint("\084\079\080\082\073\071\072\084",H,"\084\079\080\082\073\071\072\084",0,0)I:SetJustifyH("\076\069\070\084")I:SetHeight(18)I:Hide()c.label=I p:RegisterAsWidget(c)return c end p:RegisterWidgetType(K,A,a)end
--[[ $Id: AceGUIWidget-DropDown.lua 1284 2022-09-25 09:15:30Z nevcairiel $ ]]--
local AceGUI = LibStub("AceGUI-3.0")

-- Lua APIs
local min, max, floor = math.min, math.max, math.floor
local select, pairs, ipairs, type, tostring = select, pairs, ipairs, type, tostring
local tsort = table.sort

-- WoW APIs
local PlaySound = PlaySound
local UIParent, CreateFrame = UIParent, CreateFrame
local _G = _G

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 = 5

	--[[ 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
			item:SetPoint("TOP", itemFrame, "TOP", 0, -2 + (i - 1) * -16)
			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, "BackdropTemplate")
		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, "BackdropTemplate")
		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 = 36

	--[[ Static data ]]--

	--[[ UI event handler ]]--

	local function Control_OnEnter(this)
		this.obj.button:LockHighlight()
		this.obj:Fire("OnEnter")
	end

	local function Control_OnLeave(this)
		this.obj.button:UnlockHighlight()
		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
		if self.open then
			self.open = nil
			self.pullout:Close()
			AceGUI:ClearFocus()
		else
			self.open = true
			self.pullout:SetWidth(self.pulloutWidth or 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
		self:Fire("OnOpened")
	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)
		self:SetLabel()
		self:SetPulloutWidth(nil)
		self.list = {}
	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: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.button_cover:Disable()
			self.label:SetTextColor(0.5,0.5,0.5)
		else
			self.button:Enable()
			self.button_cover: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,-14)
			self:SetHeight(40)
			self.alignoffset = 26
		else
			self.label:SetText("")
			self.label:Hide()
			self.dropdown:SetPoint("TOPLEFT",self.frame,"TOPLEFT",-15,0)
			self:SetHeight(26)
			self.alignoffset = 12
		end
	end

	-- exported
	local function SetValue(self, value)
		self:SetText(self.list[value] or "")
		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, itemType)
		if not itemType then itemType = "Dropdown-Item-Toggle" end
		local exists = AceGUI:GetWidgetVersion(itemType)
		if not exists then error(("The given item type, %q, does not exist within AceGUI-3.0"):format(tostring(itemType)), 2) end

		local item = AceGUI:Create(itemType)
		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 sortTbl(x,y)
		local num1, num2 = tonumber(x), tonumber(y)
		if num1 and num2 then -- numeric comparison, either two numbers or numeric strings
			return num1 < num2
		else -- compare everything else tostring'ed
			return tostring(x) < tostring(y)
		end
	end
	local function SetList(self, list, order, itemType)
		self.list = list or {}
		self.pullout:Clear()
		self.hasClose = nil
		if not list then return end

		if type(order) ~= "table" then
			for v in pairs(list) do
				sortlist[#sortlist + 1] = v
			end
			tsort(sortlist, sortTbl)

			for i, key in ipairs(sortlist) do
				AddListItem(self, key, list[key], itemType)
				sortlist[i] = nil
			end
		else
			for i, key in ipairs(order) do
				AddListItem(self, key, list[key], itemType)
			end
		end
		if self.multiselect then
			ShowMultiText(self)
			AddCloseButton(self)
		end
	end

	-- exported
	local function AddItem(self, value, text, itemType)
		self.list[value] = text
		AddListItem(self, value, text, itemType)
	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

	local function SetPulloutWidth(self, width)
		self.pulloutWidth = width
	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.SetPulloutWidth = SetPulloutWidth

		self.alignoffset = 26

		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 button_cover = CreateFrame("BUTTON",nil,self.frame)
		self.button_cover = button_cover
		button_cover.obj = self
		button_cover:SetPoint("TOPLEFT",self.frame,"BOTTOMLEFT",0,25)
		button_cover:SetPoint("BOTTOMRIGHT",self.frame,"BOTTOMRIGHT")
		button_cover:SetScript("OnEnter",Control_OnEnter)
		button_cover:SetScript("OnLeave",Control_OnLeave)
		button_cover: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
