PageRenderTime 216ms CodeModel.GetById 120ms app.highlight 60ms RepoModel.GetById 21ms app.codeStats 0ms

/Tukui/modules/bags/bags.lua

http://github.com/Asphyxia/Tukui
Lua | 1492 lines | 1167 code | 269 blank | 56 comment | 223 complexity | 2bda14fc143267015c5b465bed2fe999 MD5 | raw file
   1local T, C, L = unpack(select(2, ...)) -- Import: T - functions, constants, variables; C - config; L - locales
   2
   3--[[
   4	A featureless, 'pure' version of Stuffing. 
   5	This version should work on absolutely everything, 
   6	but I've removed pretty much all of the options.
   7	
   8	All credits of this bags script is by Stuffing and his author Hungtar.
   9	Special Thank's to Hungtar to allow me to use his bag mod for T.
  10--]]
  11
  12if not C["bags"].enable == true then return end
  13
  14local bags_BACKPACK = {0, 1, 2, 3, 4}
  15local bags_BANK = {-1, 5, 6, 7, 8, 9, 10, 11}
  16local ST_NORMAL = 1
  17local ST_FISHBAG = 2
  18local ST_SPECIAL = 3
  19local bag_bars = 0
  20
  21-- hide bags options in default interface
  22InterfaceOptionsDisplayPanelShowFreeBagSpace:Hide()
  23
  24Stuffing = CreateFrame ("Frame", nil, UIParent)
  25Stuffing:RegisterEvent("ADDON_LOADED")
  26Stuffing:RegisterEvent("PLAYER_ENTERING_WORLD")
  27Stuffing:SetScript("OnEvent", function(this, event, ...)
  28	Stuffing[event](this, ...)
  29end)
  30
  31-- stub for localization.
  32local Loc = setmetatable({}, {
  33	__index = function (t, v)
  34		t[v] = v
  35		return v
  36	end
  37})
  38
  39
  40local function Print (x)
  41	DEFAULT_CHAT_FRAME:AddMessage("|cffC495DDTukui:|r " .. x)
  42end
  43
  44local function Stuffing_Sort(args)
  45	if not args then
  46		args = ""
  47	end
  48
  49	Stuffing.itmax = 0
  50	Stuffing:SetBagsForSorting(args)
  51	Stuffing:SortBags()
  52end
  53
  54
  55local function Stuffing_OnShow()
  56	Stuffing:PLAYERBANKSLOTS_CHANGED(29)	-- XXX: hack to force bag frame update
  57
  58	Stuffing:Layout()
  59	Stuffing:SearchReset()
  60end
  61
  62
  63local function StuffingBank_OnHide()
  64	CloseBankFrame()
  65	if Stuffing.frame:IsShown() then
  66		Stuffing.frame:Hide()
  67	end
  68end
  69
  70
  71local function Stuffing_OnHide()
  72	if Stuffing.bankFrame and Stuffing.bankFrame:IsShown() then
  73		Stuffing.bankFrame:Hide()
  74	end
  75end
  76
  77
  78local function Stuffing_Open()
  79	Stuffing.frame:Show()
  80end
  81
  82
  83local function Stuffing_Close()
  84	Stuffing.frame:Hide()
  85end
  86
  87
  88local function Stuffing_Toggle()
  89	if Stuffing.frame:IsShown() then
  90		Stuffing.frame:Hide()
  91		if ContainerFrame1:IsShown() then
  92			ToggleKeyRing() -- we want keyring to close when we close bags :)
  93		end
  94	else
  95		Stuffing.frame:Show()
  96	end
  97end
  98
  99
 100local function Stuffing_ToggleBag(id)
 101	if id == -2 then
 102		ToggleKeyRing()
 103		return
 104	end
 105	Stuffing_Toggle()
 106end
 107
 108
 109--
 110-- bag slot stuff
 111--
 112local trashParent = CreateFrame("Frame", nil, UIParent)
 113local trashButton = {}
 114local trashBag = {}
 115
 116-- for the tooltip frame used to scan item tooltips
 117local StuffingTT = nil
 118
 119-- mostly from carg.bags_Aurora
 120local QUEST_ITEM_STRING = nil
 121
 122function Stuffing:SlotUpdate(b)
 123	if not TukuiBags:IsShown() then return end -- don't do any slot update if bags are not show
 124	local texture, count, locked = GetContainerItemInfo (b.bag, b.slot)
 125	local clink = GetContainerItemLink(b.bag, b.slot)
 126	
 127	-- set all slot color to default tukui on update
 128	if not b.frame.lock then
 129		b.frame:SetBackdropBorderColor(unpack(C.media.bordercolor))
 130	end
 131	
 132	if b.Cooldown then
 133		local cd_start, cd_finish, cd_enable = GetContainerItemCooldown(b.bag, b.slot)
 134		CooldownFrame_SetTimer(b.Cooldown, cd_start, cd_finish, cd_enable)
 135	end
 136
 137	if(clink) then
 138		local iType
 139		b.name, _, b.rarity, _, _, iType = GetItemInfo(clink)
 140		
 141		-- color slot according to item quality
 142		if not b.frame.lock and b.rarity and b.rarity > 1 then
 143			b.frame:SetBackdropBorderColor(GetItemQualityColor(b.rarity))
 144		end
 145
 146			if not StuffingTT then
 147				StuffingTT = CreateFrame("GameTooltip", "StuffingTT", nil, "GameTooltipTemplate")
 148				StuffingTT:Hide()
 149			end
 150
 151			if QUEST_ITEM_STRING == nil then
 152				-- GetItemInfo returns a localized item type.
 153				-- this is to figure out what that string is.
 154				local t = {GetAuctionItemClasses()}
 155				QUEST_ITEM_STRING = t[#t]	-- #t == 12
 156			end
 157
 158			-- load tooltip, check if ITEM_BIND_QUEST ("Quest Item") is in it.
 159			-- If the tooltip says its a quest item, we assume it is a quest item
 160			-- and ignore the item type from GetItemInfo.
 161			StuffingTT:SetOwner(WorldFrame, "ANCHOR_NONE")
 162			StuffingTT:ClearLines()
 163			StuffingTT:SetBagItem(b.bag, b.slot)
 164			for i = 1, StuffingTT:NumLines() do
 165				local txt = getglobal("StuffingTTTextLeft" .. i)
 166				if txt then
 167					local text = txt:GetText()
 168					if string.find (txt:GetText(), ITEM_BIND_QUEST) then
 169						iType = QUEST_ITEM_STRING
 170					end
 171				end
 172			end
 173
 174			if iType and iType == QUEST_ITEM_STRING then
 175				b.qitem = true
 176				-- color quest item red
 177				if not b.frame.lock then b.frame:SetBackdropBorderColor(1.0, 0.3, 0.3) end
 178			else
 179				b.qitem = nil
 180			end
 181	else
 182		b.name, b.rarity, b.qitem = nil, nil, nil
 183	end
 184	
 185	SetItemButtonTexture(b.frame, texture)
 186	SetItemButtonCount(b.frame, count)
 187	SetItemButtonDesaturated(b.frame, locked, 0.5, 0.5, 0.5)
 188	
 189	local scount = _G[b.frame:GetName() .. "Count"]
 190	scount:SetFont(C.media.pixelfont, C["datatext"].fontsize, "MONOCHROMEOUTLINE")
 191	scount:Point("BOTTOMRIGHT", 0, 2)
 192	b.scount = scount
 193
 194	b.frame:Show()
 195end
 196
 197
 198function Stuffing:BagSlotUpdate(bag)
 199	if not self.buttons then
 200		return
 201	end
 202
 203	for _, v in ipairs (self.buttons) do
 204		if v.bag == bag then
 205			self:SlotUpdate(v)
 206		end
 207	end
 208end
 209
 210
 211function Stuffing:BagFrameSlotNew (slot, p)
 212	for _, v in ipairs(self.bagframe_buttons) do
 213		if v.slot == slot then
 214			--print ("found " .. slot)
 215			return v, false
 216		end
 217	end
 218
 219	--print ("new " .. slot)
 220	local ret = {}
 221	local tpl
 222
 223	if slot > 3 then
 224		ret.slot = slot
 225		slot = slot - 4
 226		tpl = "BankItemButtonBagTemplate"
 227		ret.frame = CreateFrame("CheckButton", "StuffingBBag" .. slot, p, tpl)
 228		ret.frame:SetID(slot + 4)
 229		ret.frame:SetNormalTexture("")
 230		ret.frame:SetPushedTexture("")
 231		ret.frame:SetHeight(30)
 232		ret.frame:SetWidth(30)
 233
 234		table.insert(self.bagframe_buttons, ret)
 235
 236		BankFrameItemButton_Update(ret.frame)
 237		BankFrameItemButton_UpdateLocked(ret.frame)
 238
 239		if not ret.frame.tooltipText then
 240			ret.frame.tooltipText = ""
 241		end
 242	else
 243		tpl = "BagSlotButtonTemplate"
 244		ret.frame = CreateFrame("CheckButton", "StuffingFBag" .. slot .. "Slot", p, tpl)
 245		ret.frame:SetNormalTexture("")
 246		ret.frame:SetPushedTexture("")
 247		ret.frame:SetHeight(30)
 248		ret.frame:SetWidth(30)
 249
 250		ret.slot = slot
 251		table.insert(self.bagframe_buttons, ret)
 252	end
 253
 254	return ret
 255end
 256
 257
 258function Stuffing:SlotNew (bag, slot)
 259	for _, v in ipairs(self.buttons) do
 260		if v.bag == bag and v.slot == slot then
 261			return v, false
 262		end
 263	end
 264
 265	local tpl = "ContainerFrameItemButtonTemplate"
 266
 267	if bag == -1 then
 268		tpl = "BankItemButtonGenericTemplate"
 269	end
 270
 271	local ret = {}
 272
 273	if #trashButton > 0 then
 274		local f = -1
 275		for i, v in ipairs(trashButton) do
 276			local b, s = v:GetName():match("(%d+)_(%d+)")
 277
 278			b = tonumber(b)
 279			s = tonumber(s)
 280
 281			--print (b .. " " .. s)
 282			if b == bag and s == slot then
 283				f = i
 284				break
 285			end
 286		end
 287
 288		if f ~= -1 then
 289			--print("found it")
 290			ret.frame = trashButton[f]
 291			table.remove(trashButton, f)
 292		end
 293	end
 294
 295	if not ret.frame then
 296		ret.frame = CreateFrame("Button", "StuffingBag" .. bag .. "_" .. slot, self.bags[bag], tpl)
 297	end
 298
 299	ret.bag = bag
 300	ret.slot = slot
 301	ret.frame:SetID(slot)
 302
 303	ret.Cooldown = _G[ret.frame:GetName() .. "Cooldown"]
 304	ret.Cooldown:Show()
 305
 306	self:SlotUpdate (ret)
 307
 308	return ret, true
 309end
 310
 311
 312-- from OneBag
 313 
 314local BAGTYPE_PROFESSION = 0x0008 + 0x0010 + 0x0020 + 0x0040 + 0x0080 + 0x0200 + 0x0400
 315local BAGTYPE_FISHING = 32768
 316
 317function Stuffing:BagType(bag)
 318	local bagType = select(2, GetContainerNumFreeSlots(bag))
 319	
 320	if bit.band(bagType, BAGTYPE_FISHING) > 0 then
 321		return ST_FISHBAG
 322	elseif bit.band(bagType, BAGTYPE_PROFESSION) > 0 then		
 323		return ST_SPECIAL
 324	end
 325
 326	return ST_NORMAL
 327end
 328
 329
 330function Stuffing:BagNew (bag, f)
 331	for i, v in pairs(self.bags) do
 332		if v:GetID() == bag then
 333			v.bagType = self:BagType(bag)
 334			return v
 335		end
 336	end
 337
 338	local ret
 339
 340	if #trashBag > 0 then
 341		local f = -1
 342		for i, v in pairs(trashBag) do
 343			if v:GetID() == bag then
 344				f = i
 345				break
 346			end
 347		end
 348
 349		if f ~= -1 then
 350			--print("found bag " .. bag)
 351			ret = trashBag[f]
 352			table.remove(trashBag, f)
 353			ret:Show()
 354			ret.bagType = self:BagType(bag)
 355			return ret
 356		end
 357	end
 358
 359	--print("new bag " .. bag)
 360	ret = CreateFrame("Frame", "StuffingBag" .. bag, f)
 361	ret.bagType = self:BagType(bag)
 362
 363	ret:SetID(bag)
 364	return ret
 365end
 366
 367
 368function Stuffing:SearchUpdate(str)
 369	str = string.lower(str)
 370
 371	for _, b in ipairs(self.buttons) do
 372		if b.frame and not b.name then
 373			b.frame:SetAlpha(.2)
 374		end
 375		if b.name then
 376			if not string.find (string.lower(b.name), str, 1, true) then
 377				SetItemButtonDesaturated(b.frame, 1, 1, 1, 1)
 378				b.frame:SetAlpha(.2)
 379			else
 380				SetItemButtonDesaturated(b.frame, 0, 1, 1, 1)
 381				b.frame:SetAlpha(1)
 382			end
 383		end
 384	end
 385end
 386
 387
 388function Stuffing:SearchReset()
 389	for _, b in ipairs(self.buttons) do
 390		b.frame:SetAlpha(1)
 391		SetItemButtonDesaturated(b.frame, 0, 1, 1, 1)
 392	end
 393end
 394
 395-- drop down menu stuff from Postal
 396local Stuffing_DDMenu = CreateFrame("Frame", "Stuffing_DropDownMenu")
 397Stuffing_DDMenu.displayMode = "MENU"
 398Stuffing_DDMenu.info = {}
 399Stuffing_DDMenu.HideMenu = function()
 400	if UIDROPDOWNMENU_OPEN_MENU == Stuffing_DDMenu then
 401		CloseDropDownMenus()
 402	end
 403end
 404
 405function Stuffing:CreateBagFrame(w)
 406	local n = "Tukui"  .. w
 407	local f = CreateFrame ("Frame", n, UIParent)
 408	f:SetTemplate("Transparent")
 409	f:CreateShadow("Default")
 410	f:CreateBorder(true, true)
 411	f:EnableMouse(1)
 412	f:SetMovable(1)
 413	f:SetToplevel(1)
 414	f:SetFrameStrata("HIGH")
 415	f:SetFrameLevel(20)
 416
 417	local function bagUpdate(f, ...)
 418		if w == "Bank" then
 419			if not C["chat"].background then
 420				f:SetPoint("BOTTOMLEFT", TukuiInfoLeft, "TOPLEFT", 0, 3)
 421			else
 422				f:SetPoint("BOTTOMLEFT", TukuiChatBackgroundLeft, "TOPLEFT", 0, 3)
 423			end
 424		else
 425			if not C["actionbar"].enable then
 426				if not C["chat"].background then
 427					f:SetPoint("BOTTOMLEFT", TukuiInfoRight, "TOPLEFT", 0, 3)
 428				else
 429					f:SetPoint("BOTTOMRIGHT", TukuiChatBackgroundRight, "TOPRIGHT", 0, 3)
 430				end
 431			else
 432				if not C["chat"].background then
 433					f:SetPoint("BOTTOMLEFT", TukuiInfoRight, "TOPLEFT", 0, 3)
 434				elseif HasPetUI() then
 435					if C["actionbar"].vertical_rightbars then
 436						f:SetPoint("BOTTOMRIGHT", TukuiChatBackgroundRight, "TOPRIGHT", 0, 3)
 437					else
 438						f:SetPoint("BOTTOM", TukuiPetBar, "TOP", 0, 3)
 439					end
 440				elseif UnitHasVehicleUI("player") then
 441					f:SetPoint("BOTTOMRIGHT", TukuiChatBackgroundRight, "TOPRIGHT", 0, 3)
 442				else
 443					if C["actionbar"].vertical_rightbars then
 444						f:SetPoint("BOTTOMRIGHT", TukuiChatBackgroundRight, "TOPRIGHT", 0, 3)
 445					else
 446						if TukuiSaved.rightbars >= 1 then
 447							f:SetPoint("BOTTOMRIGHT", TukuiRightBar, "TOPRIGHT", 0, 3)
 448						else
 449							f:SetPoint("BOTTOMRIGHT", TukuiChatBackgroundRight, "TOPRIGHT", 0, 3)
 450						end
 451					end
 452				end
 453			end
 454		end
 455	end
 456	f:HookScript("OnUpdate", bagUpdate)
 457	
 458		-- CLOSE BUTTON	
 459local function ModifiedBackdrop(self)
 460	local color = RAID_CLASS_COLORS[T.myclass]
 461	self:SetBackdropColor(unpack(C["media"].backdropcolor))
 462	self:SetBackdropBorderColor(color.r, color.g, color.b)
 463end
 464
 465local function OriginalBackdrop(self)
 466	self:SetBackdropColor(unpack(C["media"].backdropcolor))
 467	self:SetBackdropBorderColor(unpack(C["media"].bordercolor))
 468end
 469	
 470	f.b_close = CreateFrame("Button", "Stuffing_CloseButton" .. w, f)
 471	f.b_close:Width(50)
 472	f.b_close:Height(20)
 473	f.b_close:Point("TOPRIGHT", -3, -3)
 474	f.b_close:SetScript("OnClick", function(self, btn)
 475		if self:GetParent():GetName() == "TukuiBags" and btn == "RightButton" then
 476			if Stuffing_DDMenu.initialize ~= Stuffing.Menu then
 477				CloseDropDownMenus()
 478				Stuffing_DDMenu.initialize = Stuffing.Menu
 479			end
 480			ToggleDropDownMenu(1, nil, Stuffing_DDMenu, self:GetName(), 0, 0)
 481			return
 482		end
 483		self:GetParent():Hide()
 484	end)
 485	f.b_close:RegisterForClicks("AnyUp")
 486	f.b_close:SetTemplate("Default")
 487	f.b_close:SetFrameStrata("HIGH")
 488	f.b_text = f.b_close:CreateFontString(nil, "OVERLAY")
 489	f.b_text:SetFont(C.media.pixelfont, C["datatext"].fontsize, "MONOCHROMEOUTLINE")
 490	f.b_text:SetPoint("CENTER", 0, 0)
 491	f.b_text:SetText(T.datacolor.."Close")
 492	f.b_close:CreateOverlay(f.b_close)
 493	f.b_close:SetWidth(f.b_text:GetWidth() + 20)
 494	
 495	f.b_close:HookScript("OnEnter", ModifiedBackdrop)
 496	f.b_close:HookScript("OnLeave", OriginalBackdrop)
 497
 498	-- create the bags frame
 499	local fb = CreateFrame ("Frame", n .. "BagsFrame", f)
 500	fb:Point("BOTTOMLEFT", f, "TOPLEFT", 0, 3)
 501	fb:SetFrameStrata("HIGH")
 502	fb:SetTemplate("Transparent")
 503	fb:CreateShadow("Default")
 504	fb:CreateBorder(true, true)
 505	f.bags_frame = fb
 506
 507	return f
 508end
 509
 510
 511function Stuffing:InitBank()
 512	if self.bankFrame then
 513		return
 514	end
 515
 516	local f = self:CreateBagFrame("Bank")
 517	f:SetScript("OnHide", StuffingBank_OnHide)
 518	self.bankFrame = f
 519end
 520
 521
 522local parent_startmoving = function(self)
 523	StartMoving(self:GetParent())
 524end
 525
 526
 527local parent_stopmovingorsizing = function (self)
 528	StopMoving(self:GetParent())
 529end
 530
 531
 532function Stuffing:InitBags()
 533	if self.frame then
 534		return
 535	end
 536
 537	self.buttons = {}
 538	self.bags = {}
 539	self.bagframe_buttons = {}
 540
 541	local f = self:CreateBagFrame("Bags")
 542	f:SetScript("OnShow", Stuffing_OnShow)
 543	f:SetScript("OnHide", Stuffing_OnHide)
 544
 545	-- search editbox (tekKonfigAboutPanel.lua)
 546	local editbox = CreateFrame("EditBox", nil, f)
 547	editbox:Hide()
 548	editbox:SetAutoFocus(true)
 549	editbox:Height(32)
 550	editbox:SetTemplate("Default")
 551
 552	local resetAndClear = function (self)
 553		self:GetParent().detail:Show()
 554		self:GetParent().gold:Show()
 555		self:ClearFocus()
 556		Stuffing:SearchReset()
 557	end
 558
 559	local updateSearch = function(self, t)
 560		if t == true then
 561			Stuffing:SearchUpdate(self:GetText())
 562		end
 563	end
 564
 565	editbox:SetScript("OnEscapePressed", resetAndClear)
 566	editbox:SetScript("OnEnterPressed", resetAndClear)
 567	editbox:SetScript("OnEditFocusLost", editbox.Hide)
 568	editbox:SetScript("OnEditFocusGained", editbox.HighlightText)
 569	editbox:SetScript("OnTextChanged", updateSearch)
 570	editbox:SetText(L.bags_search)
 571
 572
 573	local detail = f:CreateFontString(nil, "ARTWORK", "GameFontHighlightLarge")
 574	detail:Point("TOPLEFT", f, 12, -10)
 575	detail:Point("RIGHT",-(16 + 24), 0)
 576	detail:SetJustifyH("LEFT")
 577	detail:SetText("|cff9999ff" .. "Search")
 578	editbox:SetAllPoints(detail)
 579
 580	local gold = f:CreateFontString(nil, "ARTWORK", "GameFontHighlightLarge")
 581	gold:SetJustifyH("RIGHT")
 582	gold:Point("RIGHT", f.b_close, "LEFT", -20, 0)
 583
 584	f:SetScript("OnEvent", function (self, e)
 585		self.gold:SetText(GetMoneyString(GetMoney(), 12))
 586	end)
 587
 588	f:RegisterEvent("PLAYER_MONEY")
 589	f:RegisterEvent("PLAYER_LOGIN")
 590	f:RegisterEvent("PLAYER_TRADE_MONEY")
 591	f:RegisterEvent("TRADE_MONEY_CHANGED")
 592
 593	local OpenEditbox = function(self)
 594		self:GetParent().detail:Hide()
 595		self:GetParent().gold:Hide()
 596		self:GetParent().editbox:Show()
 597		self:GetParent().editbox:HighlightText()
 598	end
 599
 600	local button = CreateFrame("Button", nil, f)
 601	button:EnableMouse(1)
 602	button:RegisterForClicks("LeftButtonUp", "RightButtonUp")
 603	button:SetAllPoints(detail)
 604	button:SetScript("OnClick", function(self, btn)
 605		if btn == "RightButton" then
 606			OpenEditbox(self)
 607		else
 608			if self:GetParent().editbox:IsShown() then
 609				self:GetParent().editbox:Hide()
 610				self:GetParent().editbox:ClearFocus()
 611				self:GetParent().detail:Show()
 612				self:GetParent().gold:Show()
 613				Stuffing:SearchReset()
 614			end
 615		end
 616	end)
 617
 618	local tooltip_hide = function()
 619		GameTooltip:Hide()
 620	end
 621
 622	local tooltip_show = function (self)
 623		GameTooltip:SetOwner(self, "ANCHOR_CURSOR")
 624		GameTooltip:ClearLines()
 625		GameTooltip:SetText(L.bags_rightclick_search)
 626	end
 627
 628	button:SetScript("OnEnter", tooltip_show)
 629	button:SetScript("OnLeave", tooltip_hide)
 630
 631	f.editbox = editbox
 632	f.detail = detail
 633	f.button = button
 634	f.gold = gold
 635	self.frame = f
 636	f:Hide()
 637end
 638
 639
 640function Stuffing:Layout(lb)
 641	local slots = 0
 642	local rows = 0
 643	local off = 26
 644	local cols
 645	local f
 646	local bs
 647	
 648	local bgvalue = 0
 649	if not C["chat"].background then
 650		bgvalue = 10
 651	end
 652	
 653	if lb then
 654		bs = bags_BANK
 655		cols = (floor((T.InfoLeftRightWidth - bgvalue)/370 * 10) + 1)
 656		f = self.bankFrame
 657	else
 658		bs = bags_BACKPACK
 659		cols = (floor((T.InfoLeftRightWidth - bgvalue)/370 * 10) + 1)
 660		f = self.frame
 661
 662		f.gold:SetText(GetMoneyString(GetMoney(), 12))
 663		f.editbox:SetFont(C.media.pixelfont, C["datatext"].fontsize, "MONOCHROMEOUTLINE")
 664		f.detail:SetFont(C.media.pixelfont, C["datatext"].fontsize, "MONOCHROMEOUTLINE")
 665		f.gold:SetFont(C.media.pixelfont, C["datatext"].fontsize, "MONOCHROMEOUTLINE")
 666
 667		f.detail:ClearAllPoints()
 668		f.detail:Point("TOPLEFT", f, 12, -10)
 669		f.detail:Point("RIGHT", -(16 + 24), 0)
 670	end
 671
 672	f:SetClampedToScreen(1)
 673
 674	-- bag frame stuff
 675	local fb = f.bags_frame
 676	if bag_bars == 1 then
 677		fb:SetClampedToScreen(1)
 678
 679		local bsize = 24
 680		if lb then bsize = 23.3 end
 681
 682		local w = 2 * 12
 683		w = w + ((#bs - 1) * bsize)
 684		w = w + (12 * (#bs - 2))
 685
 686		fb:Height(2 * 12 + bsize)
 687		fb:Width(w)
 688		fb:Show()
 689	else
 690		fb:Hide()
 691	end
 692
 693
 694
 695	local idx = 0
 696	for _, v in ipairs(bs) do
 697		if (not lb and v <= 3 ) or (lb and v ~= -1) then
 698			local bsize = 30
 699			if lb then bsize = 30 end
 700
 701			local b = self:BagFrameSlotNew(v, fb)
 702
 703			local xoff = 12
 704
 705			xoff = xoff + (idx * bsize) -- 31)
 706			xoff = xoff + (idx * 4)
 707
 708			b.frame:ClearAllPoints()
 709			b.frame:Point("LEFT", fb, "LEFT", xoff, 0)
 710			b.frame:Show()
 711
 712			-- this is for the bagbar icons
 713			local iconTex = _G[b.frame:GetName() .. "IconTexture"]
 714			iconTex:SetTexCoord(.09, .91, .09, .91)
 715			iconTex:Point("TOPLEFT", b.frame, 2, -2)
 716			iconTex:Point("BOTTOMRIGHT", b.frame, -2, 2)
 717
 718			iconTex:Show()
 719			b.iconTex = iconTex
 720
 721			b.frame:SetTemplate("Default")
 722			b.frame:SetBackdropColor(0,0,0)
 723			b.frame:StyleButton()
 724
 725			idx = idx + 1
 726		end
 727	end
 728
 729
 730	for _, i in ipairs(bs) do
 731		local x = GetContainerNumSlots(i)
 732		if x > 0 then
 733			if not self.bags[i] then
 734				self.bags[i] = self:BagNew(i, f)
 735			end
 736
 737			slots = slots + GetContainerNumSlots(i)
 738		end
 739	end
 740
 741
 742	rows = floor (slots / cols)
 743	if (slots % cols) ~= 0 then
 744		rows = rows + 1
 745	end
 746	
 747	--f:Width(T.InfoLeftRightWidth + 8 - bgvalue)
 748	f:Width(C["chat"].width - bgvalue)
 749	f:Height(rows * 30 + (rows - 1) * 2 + off + 12 * 2)
 750
 751	local sf = CreateFrame("Frame", "SlotFrame", f)
 752	sf:Width((31 + 1) * cols)
 753	sf:Height(f:GetHeight() - (6))
 754	sf:Point("BOTTOM", f, "BOTTOM")
 755	
 756	local idx = 0
 757	for _, i in ipairs(bs) do
 758		local bag_cnt = GetContainerNumSlots(i)
 759
 760		if bag_cnt > 0 then
 761			self.bags[i] = self:BagNew(i, f)
 762			local bagType = self.bags[i].bagType
 763
 764			self.bags[i]:Show()
 765			for j = 1, bag_cnt do
 766				local b, isnew = self:SlotNew (i, j)
 767				local xoff
 768				local yoff
 769				local x = (idx % cols)
 770				local y = floor(idx / cols)
 771
 772				if isnew then
 773					table.insert(self.buttons, idx + 1, b)
 774				end
 775
 776				xoff = (x * 31) + (x * 1)
 777
 778				yoff = off + 12 + (y * 30) + ((y - 1) * 2)
 779
 780				yoff = yoff * -1
 781
 782				b.frame:ClearAllPoints()
 783				b.frame:Point("TOPLEFT", sf, "TOPLEFT", xoff, yoff)
 784				b.frame:Height(29)
 785				b.frame:Width(29)
 786				b.frame:SetPushedTexture("")
 787				b.frame:SetNormalTexture("")
 788				b.frame:Show()
 789				b.frame:SetTemplate("Default")
 790				b.frame:SetBackdropColor(0,0,0)
 791				b.frame:StyleButton()
 792				
 793				-- color fish bag border slot to red
 794				if bagType == ST_FISHBAG then b.frame:SetBackdropBorderColor(1, 0, 0) b.frame.lock = true end
 795				-- color profession bag slot border ~yellow
 796				if bagType == ST_SPECIAL then b.frame:SetBackdropBorderColor(255/255, 243/255,  82/255) b.frame.lock = true end
 797				
 798				self:SlotUpdate(b)
 799				
 800				local iconTex = _G[b.frame:GetName() .. "IconTexture"]
 801				iconTex:SetTexCoord(.09, .91, .09, .91)
 802				iconTex:Point("TOPLEFT", b.frame, 2, -2)
 803				iconTex:Point("BOTTOMRIGHT", b.frame, -2, 2)
 804
 805				iconTex:Show()
 806				b.iconTex = iconTex
 807				
 808				idx = idx + 1
 809			end
 810		end
 811	end
 812end
 813
 814
 815function Stuffing:SetBagsForSorting(c)
 816	Stuffing_Open()
 817
 818	self.sortBags = {}
 819
 820	local cmd = ((c == nil or c == "") and {"d"} or {strsplit("/", c)})
 821
 822	for _, s in ipairs(cmd) do
 823		if s == "c" then
 824			self.sortBags = {}
 825		elseif s == "d" then
 826			if not self.bankFrame or not self.bankFrame:IsShown() then
 827				for _, i in ipairs(bags_BACKPACK) do
 828					if self.bags[i] and self.bags[i].bagType == ST_NORMAL then
 829						table.insert(self.sortBags, i)
 830					end
 831				end
 832			else
 833				for _, i in ipairs(bags_BANK) do
 834					if self.bags[i] and self.bags[i].bagType == ST_NORMAL then
 835						table.insert(self.sortBags, i)
 836					end
 837				end
 838			end
 839		elseif s == "p" then
 840			if not self.bankFrame or not self.bankFrame:IsShown() then
 841				for _, i in ipairs(bags_BACKPACK) do
 842					if self.bags[i] and self.bags[i].bagType == ST_SPECIAL then
 843						table.insert(self.sortBags, i)
 844					end
 845				end
 846			else
 847				for _, i in ipairs(bags_BANK) do
 848					if self.bags[i] and self.bags[i].bagType == ST_SPECIAL then
 849						table.insert(self.sortBags, i)
 850					end
 851				end
 852			end
 853		else
 854			if tonumber(s) == nil then
 855				Print(string.format(Loc["Error: don't know what \"%s\" means."], s))
 856			end
 857
 858			table.insert(self.sortBags, tonumber(s))
 859		end
 860	end
 861
 862	local bids = L.bags_bids
 863	for _, i in ipairs(self.sortBags) do
 864		bids = bids .. i .. " "
 865	end
 866
 867	Print(bids)
 868end
 869
 870
 871-- slash command handler
 872local function StuffingSlashCmd(Cmd)
 873	local cmd, args = strsplit(" ", Cmd:lower(), 2)
 874
 875	if cmd == "config" then
 876		Stuffing_OpenConfig()
 877	elseif cmd == "sort" then
 878		Stuffing_Sort(args)
 879	elseif cmd == "psort" then
 880		Stuffing_Sort("c/p")
 881	elseif cmd == "stack" then
 882		Stuffing:SetBagsForSorting(args)
 883		Stuffing:Restack()
 884	elseif cmd == "test" then
 885		Stuffing:SetBagsForSorting(args)
 886	elseif cmd == "purchase" then
 887		-- XXX
 888		if Stuffing.bankFrame and Stuffing.bankFrame:IsShown() then
 889			local cnt, full = GetNumBankSlots()
 890			if full then
 891				Print(L.bags_noslots)
 892				return
 893			end
 894
 895			if args == "yes" then
 896				PurchaseSlot()
 897				return
 898			end
 899
 900			Print(string.format(L.bags_costs, GetBankSlotCost() / 10000))
 901			Print(L.bags_buyslots)
 902		else
 903			Print(L.bags_openbank)
 904		end
 905	else
 906		Print("sort - " .. L.bags_sort)
 907		Print("stack - " .. L.bags_stack)
 908		Print("purchase - " .. L.bags_buybankslot)
 909	end
 910end
 911
 912
 913function Stuffing:ADDON_LOADED(addon)
 914	if addon ~= "Tukui" then
 915		return nil
 916	end
 917
 918	self:RegisterEvent("BAG_UPDATE")
 919	self:RegisterEvent("ITEM_LOCK_CHANGED")
 920
 921	self:RegisterEvent("BANKFRAME_OPENED")
 922	self:RegisterEvent("BANKFRAME_CLOSED")
 923	self:RegisterEvent("PLAYERBANKSLOTS_CHANGED")
 924
 925	self:RegisterEvent("BAG_CLOSED")
 926
 927	SlashCmdList["STUFFING"] = StuffingSlashCmd
 928	SLASH_STUFFING1 = "/bags"
 929
 930	self:InitBags()
 931	
 932	tinsert(UISpecialFrames,"TukuiBags")
 933
 934	ToggleBackpack = Stuffing_Toggle
 935	ToggleBag = Stuffing_ToggleBag
 936	ToggleAllBags = Stuffing_Toggle
 937	OpenAllBags = Stuffing_Open
 938	OpenBackpack = Stuffing_Open
 939	CloseAllBags = Stuffing_Close
 940	CloseBackpack = Stuffing_Close
 941
 942	BankFrame:UnregisterAllEvents()
 943end
 944
 945function Stuffing:PLAYER_ENTERING_WORLD()
 946	-- please don't do anything after 1 player_entering_world event.
 947	Stuffing:UnregisterEvent("PLAYER_ENTERING_WORLD")
 948	
 949	if T.toc >= 40200 then return end
 950
 951	-- hooking and setting key ring bag
 952	-- this is just a reskin of Blizzard key bag to fit Tukui
 953	-- hooking OnShow because sometime key max slot changes.
 954	ContainerFrame1:HookScript("OnShow", function(self)
 955		local keybackdrop = CreateFrame("Frame", nil, self)
 956		keybackdrop:Point("TOPLEFT", 9, -40)
 957		keybackdrop:Point("BOTTOMLEFT", 0, 0)
 958		keybackdrop:Size(179,215)
 959		keybackdrop:SetTemplate("Default")
 960		ContainerFrame1CloseButton:Hide()
 961		ContainerFrame1Portrait:Hide()
 962		ContainerFrame1Name:Hide()
 963		ContainerFrame1BackgroundTop:SetAlpha(0)
 964		ContainerFrame1BackgroundMiddle1:SetAlpha(0)
 965		ContainerFrame1BackgroundMiddle2:SetAlpha(0)
 966		ContainerFrame1BackgroundBottom:SetAlpha(0)
 967		for i=1, GetKeyRingSize() do
 968			local slot = _G["ContainerFrame1Item"..i]
 969			local t = _G["ContainerFrame1Item"..i.."IconTexture"]
 970			slot:SetPushedTexture("")
 971			slot:SetNormalTexture("")
 972			t:SetTexCoord(.08, .92, .08, .92)
 973			t:Point("TOPLEFT", slot, 2, -2)
 974			t:Point("BOTTOMRIGHT", slot, -2, 2)
 975			slot:SetTemplate("Default")
 976			--slot.overlay:Kill()
 977			slot:SetBackdropColor(0,0,0)
 978			slot:StyleButton()
 979		end		
 980	end)
 981	
 982	ContainerFrame1:ClearAllPoints()
 983	ContainerFrame1:Point("BOTTOMRIGHT", TukuiInfoRight, "TOPRIGHT", 4, 3)
 984	ContainerFrame1.ClearAllPoints = T.dummy
 985	ContainerFrame1.SetPoint = T.dummy
 986end
 987
 988function Stuffing:PLAYERBANKSLOTS_CHANGED(id)
 989	if id > 28 then
 990		for _, v in ipairs(self.bagframe_buttons) do
 991			if v.frame and v.frame.GetInventorySlot then
 992
 993				BankFrameItemButton_Update(v.frame)
 994				BankFrameItemButton_UpdateLocked(v.frame)
 995
 996				if not v.frame.tooltipText then
 997					v.frame.tooltipText = ""
 998				end
 999			end
1000		end
1001	end
1002
1003	if self.bankFrame and self.bankFrame:IsShown() then
1004		self:BagSlotUpdate(-1)
1005	end
1006end
1007
1008
1009function Stuffing:BAG_UPDATE(id)
1010	self:BagSlotUpdate(id)
1011end
1012
1013
1014function Stuffing:ITEM_LOCK_CHANGED(bag, slot)
1015	if slot == nil then
1016		return
1017	end
1018
1019	for _, v in ipairs(self.buttons) do
1020		if v.bag == bag and v.slot == slot then
1021			self:SlotUpdate(v)
1022			break
1023		end
1024	end
1025end
1026
1027
1028function Stuffing:BANKFRAME_OPENED()
1029	Stuffing_Open()
1030	
1031	if not self.bankFrame then
1032		self:InitBank()
1033	end
1034
1035	self:Layout(true)
1036	for _, x in ipairs(bags_BANK) do
1037		self:BagSlotUpdate(x)
1038	end
1039	self.bankFrame:Show()
1040end
1041
1042
1043function Stuffing:BANKFRAME_CLOSED()
1044	if not self.bankFrame then
1045		return
1046	end
1047
1048	self.bankFrame:Hide()
1049end
1050
1051
1052function Stuffing:BAG_CLOSED(id)
1053	local b = self.bags[id]
1054	if b then
1055		table.remove(self.bags, id)
1056		b:Hide()
1057		table.insert (trashBag, #trashBag + 1, b)
1058	end
1059
1060	while true do
1061		local changed = false
1062
1063		for i, v in ipairs(self.buttons) do
1064			if v.bag == id then
1065				v.frame:Hide()
1066				v.iconTex:Hide()
1067
1068				table.insert (trashButton, #trashButton + 1, v.frame)
1069				table.remove(self.buttons, i)
1070
1071				v = nil
1072				changed = true
1073			end
1074		end
1075
1076		if not changed then
1077			break
1078		end
1079	end
1080end
1081
1082
1083function Stuffing:SortOnUpdate(e)
1084	if not self.elapsed then
1085		self.elapsed = 0
1086	end
1087
1088	if not self.itmax then
1089		self.itmax = 0
1090	end
1091
1092	self.elapsed = self.elapsed + e
1093
1094	if self.elapsed < 0.1 then
1095		return
1096	end
1097
1098	self.elapsed = 0
1099	self.itmax = self.itmax + 1
1100
1101	local changed, blocked  = false, false
1102
1103	if self.sortList == nil or next(self.sortList, nil) == nil then
1104		-- wait for all item locks to be released.
1105		local locks = false
1106
1107		for i, v in pairs(self.buttons) do
1108			local _, _, l = GetContainerItemInfo(v.bag, v.slot)
1109			if l then
1110				locks = true
1111			else
1112				v.block = false
1113			end
1114		end
1115
1116		if locks then
1117			-- something still locked. wait some more.
1118			return
1119		else
1120			-- all unlocked. get a new table.
1121			self:SetScript("OnUpdate", nil)
1122			self:SortBags()
1123
1124			if self.sortList == nil then
1125				return
1126			end
1127		end
1128	end
1129
1130	-- go through the list and move stuff if we can.
1131	for i, v in ipairs (self.sortList) do
1132		repeat
1133			if v.ignore then
1134				blocked = true
1135				break
1136			end
1137
1138			if v.srcSlot.block then
1139				changed = true
1140				break
1141			end
1142
1143			if v.dstSlot.block then
1144				changed = true
1145				break
1146			end
1147
1148			local _, _, l1 = GetContainerItemInfo(v.dstSlot.bag, v.dstSlot.slot)
1149			local _, _, l2 = GetContainerItemInfo(v.srcSlot.bag, v.srcSlot.slot)
1150
1151			if l1 then
1152				v.dstSlot.block = true
1153			end
1154
1155			if l2 then
1156				v.srcSlot.block = true
1157			end
1158
1159			if l1 or l2 then
1160				break
1161			end
1162
1163			if v.sbag ~= v.dbag or v.sslot ~= v.dslot then
1164				if v.srcSlot.name ~= v.dstSlot.name then
1165					v.srcSlot.block = true
1166					v.dstSlot.block = true
1167					PickupContainerItem (v.sbag, v.sslot)
1168					PickupContainerItem (v.dbag, v.dslot)
1169					changed = true
1170					break
1171				end
1172			end
1173		until true
1174	end
1175
1176	self.sortList = nil
1177
1178	if (not changed and not blocked) or self.itmax > 250 then
1179		self:SetScript("OnUpdate", nil)
1180		self.sortList = nil
1181		Print (L.bags_sortingbags)
1182	end
1183end
1184
1185
1186local function InBags(x)
1187	if not Stuffing.bags[x] then
1188		return false
1189	end
1190
1191	for _, v in ipairs(Stuffing.sortBags) do
1192		if x == v then
1193			return true
1194		end
1195	end
1196	return false
1197end
1198
1199
1200function Stuffing:SortBags()
1201	if (UnitAffectingCombat("player")) then return end
1202	
1203	local free
1204	local total = 0
1205	local bagtypeforfree
1206	
1207	if StuffingFrameBank and StuffingFrameBank:IsShown() then
1208		for i = 5, 11 do
1209			free, bagtypeforfree = GetContainerNumFreeSlots(i)
1210			if bagtypeforfree == 0 then			
1211				total = free + total
1212			end
1213		end
1214		
1215		total = select(1, GetContainerNumFreeSlots(-1)) + total
1216	else
1217		for i = 0, 4 do
1218			free, bagtypeforfree = GetContainerNumFreeSlots(i)
1219			if bagtypeforfree == 0 then			
1220				total = free + total
1221			end
1222		end
1223	end
1224
1225	if total == 0 then
1226		print("|cffff0000"..ERROR_CAPS.." - "..ERR_INV_FULL.."|r")
1227		return	
1228	end
1229	
1230	local bs = self.sortBags
1231	if #bs < 1 then
1232		Print (L.bags_nothingsort)
1233		return
1234	end
1235
1236	local st = {}
1237	local bank = false
1238
1239	Stuffing_Open()
1240
1241	for i, v in pairs(self.buttons) do
1242		if InBags(v.bag) then
1243			self:SlotUpdate(v)
1244
1245			if v.name then
1246				local tex, cnt, _, _, _, _, clink = GetContainerItemInfo(v.bag, v.slot)
1247				local n, _, q, iL, rL, c1, c2, _, Sl = GetItemInfo(clink)
1248				table.insert(st, {
1249					srcSlot = v,
1250					sslot = v.slot,
1251					sbag = v.bag,
1252					--sort = q .. iL .. c1 .. c2 .. rL .. Sl .. n .. i,
1253					--sort = q .. iL .. c1 .. c2 .. rL .. Sl .. n .. (#self.buttons - i),
1254					sort = q .. c1 .. c2 .. rL .. n .. iL .. Sl .. (#self.buttons - i),
1255					--sort = q .. (#self.buttons - i) .. n,
1256				})
1257			end
1258		end
1259	end
1260
1261	-- sort them
1262	table.sort (st, function(a, b)
1263		return a.sort > b.sort
1264	end)
1265
1266	-- for each button we want to sort, get a destination button
1267	local st_idx = #bs
1268	local dbag = bs[st_idx]
1269	local dslot = GetContainerNumSlots(dbag)
1270 
1271	for i, v in ipairs (st) do
1272		v.dbag = dbag
1273		v.dslot = dslot
1274		v.dstSlot = self:SlotNew(dbag, dslot)
1275 
1276		dslot = dslot - 1
1277 
1278		if dslot == 0 then
1279			while true do
1280				st_idx = st_idx - 1
1281 
1282				if st_idx < 0 then
1283					break
1284				end
1285 
1286				dbag = bs[st_idx]
1287 
1288				if Stuffing:BagType(dbag) == ST_NORMAL or Stuffing:BagType(dbag) == ST_SPECIAL or dbag < 1 then
1289					break
1290				end
1291			end
1292 
1293			dslot = GetContainerNumSlots(dbag)
1294		end
1295	end
1296
1297	-- throw various stuff out of the search list
1298	local changed = true
1299	while changed do
1300		changed = false
1301		-- XXX why doesn't this remove all x->x moves in one pass?
1302
1303		for i, v in ipairs (st) do
1304
1305			-- source is same as destination
1306			if (v.sslot == v.dslot) and (v.sbag == v.dbag) then
1307				table.remove (st, i)
1308				changed = true
1309			end
1310		end
1311	end
1312
1313	-- kick off moving of stuff, if needed.
1314	if st == nil or next(st, nil) == nil then
1315		Print(L.bags_sortingbags)
1316		self:SetScript("OnUpdate", nil)
1317	else
1318		self.sortList = st
1319		self:SetScript("OnUpdate", Stuffing.SortOnUpdate)
1320	end
1321end
1322
1323
1324function Stuffing:RestackOnUpdate(e)
1325	if not self.elapsed then
1326		self.elapsed = 0
1327	end
1328
1329	self.elapsed = self.elapsed + e
1330
1331	if self.elapsed < 0.1 then
1332		return
1333	end
1334
1335	self.elapsed = 0
1336	self:Restack()
1337end
1338
1339
1340function Stuffing:Restack()
1341	local st = {}
1342
1343	Stuffing_Open()
1344
1345	for i, v in pairs(self.buttons) do
1346		if InBags(v.bag) then
1347			local tex, cnt, _, _, _, _, clink = GetContainerItemInfo(v.bag, v.slot)
1348			if clink then
1349				local n, _, _, _, _, _, _, s = GetItemInfo(clink)
1350
1351				if cnt ~= s then
1352					if not st[n] then
1353						st[n] = {{
1354							item = v,
1355							size = cnt,
1356							max = s
1357						}}
1358					else
1359						table.insert(st[n], {
1360							item = v,
1361							size = cnt,
1362							max = s
1363						})
1364					end
1365				end
1366			end
1367		end
1368	end
1369
1370	local did_restack = false
1371
1372	for i, v in pairs(st) do
1373		if #v > 1 then
1374			for j = 2, #v, 2 do
1375				local a, b = v[j - 1], v[j]
1376				local _, _, l1 = GetContainerItemInfo(a.item.bag, a.item.slot)
1377				local _, _, l2 = GetContainerItemInfo(b.item.bag, b.item.slot)
1378
1379				if l1 or l2 then
1380					did_restack = true
1381				else
1382					PickupContainerItem (a.item.bag, a.item.slot)
1383					PickupContainerItem (b.item.bag, b.item.slot)
1384					did_restack = true
1385				end
1386			end
1387		end
1388	end
1389
1390	if did_restack then
1391		self:SetScript("OnUpdate", Stuffing.RestackOnUpdate)
1392	else
1393		self:SetScript("OnUpdate", nil)
1394		Print (L.bags_stackend)
1395	end
1396end
1397
1398function Stuffing.Menu(self, level)
1399	if not level then
1400		return
1401	end
1402
1403	local info = self.info
1404
1405	wipe(info)
1406
1407	if level ~= 1 then
1408		return
1409	end
1410
1411	wipe(info)
1412	info.text = L.bags_sortmenu
1413	info.notCheckable = 1
1414	info.func = function()
1415		Stuffing_Sort("d")
1416	end
1417	UIDropDownMenu_AddButton(info, level)
1418	
1419	wipe(info)
1420	info.text = L.bags_sortspecial
1421	info.notCheckable = 1
1422	info.func = function()
1423		Stuffing_Sort("c/p")
1424	end
1425	UIDropDownMenu_AddButton(info, level)
1426
1427	wipe(info)
1428	info.text = L.bags_stackmenu
1429	info.notCheckable = 1
1430	info.func = function()
1431		Stuffing:SetBagsForSorting("d")
1432		Stuffing:Restack()
1433	end
1434	UIDropDownMenu_AddButton(info, level)
1435	
1436	wipe(info)
1437	info.text = L.bags_stackspecial
1438	info.notCheckable = 1
1439	info.func = function()
1440		Stuffing:SetBagsForSorting("c/p")
1441		Stuffing:Restack()
1442	end
1443	UIDropDownMenu_AddButton(info, level)
1444
1445	wipe(info)
1446	info.text = L.bags_showbags
1447	info.checked = function()
1448		return bag_bars == 1
1449	end
1450
1451	info.func = function()
1452		if bag_bars == 1 then
1453			bag_bars = 0
1454		else
1455			bag_bars = 1
1456		end
1457		Stuffing:Layout()
1458		if Stuffing.bankFrame and Stuffing.bankFrame:IsShown() then
1459			Stuffing:Layout(true)
1460		end
1461
1462	end
1463	UIDropDownMenu_AddButton(info, level)
1464
1465	if T.toc < 40200 then
1466		wipe(info)
1467		info.text = KEYRING
1468		info.checked = function()
1469			return key_ring == 1
1470		end
1471
1472		info.func = function()
1473			if key_ring == 1 then
1474				key_ring = 0
1475			else
1476				key_ring = 1
1477			end
1478			Stuffing_Toggle()
1479			ToggleKeyRing()
1480			Stuffing:Layout()
1481		end
1482		UIDropDownMenu_AddButton(info, level)
1483	end
1484
1485	wipe(info)
1486	info.disabled = nil
1487	info.notCheckable = 1
1488	info.text = CLOSE
1489	info.func = self.HideMenu
1490	info.tooltipTitle = CLOSE
1491	UIDropDownMenu_AddButton(info, level)
1492end