Quantcast

add rbag

rawoil [07-05-21 - 11:33]
add rbag
Filename
rBag/core.lua
rBag/functions.lua
rBag/init.lua
rBag/libs/SortBags.lua
rBag/rBag.toc
rBag/setup.lua
rButtonTemplate/core.lua
rButtonTemplate_Zork/theme.lua
diff --git a/rBag/core.lua b/rBag/core.lua
new file mode 100644
index 0000000..e5e3f12
--- /dev/null
+++ b/rBag/core.lua
@@ -0,0 +1,884 @@
+local A, L = ...
+
+local Noop = function() end
+local ReplaceBags = 0
+local NeedBagRefresh, NeedBankRefresh
+local LastButtonBag, LastButtonBank
+local Token1, Token2, Token3 = BackpackTokenFrameToken1, BackpackTokenFrameToken2, BackpackTokenFrameToken3
+local NUM_CONTAINER_FRAMES = NUM_CONTAINER_FRAMES
+local NUM_BAG_FRAMES = NUM_BAG_FRAMES
+local ContainerFrame_GetOpenFrame = ContainerFrame_GetOpenFrame
+local OriginalToggleBag = ToggleBag
+local BankFrame = BankFrame
+local BagHelpBox = BagHelpBox
+local ButtonSize, ButtonSpacing, ItemsPerRow
+local Bags = CreateFrame("Frame")
+local QuestColor = {1, 1, 0}
+local Bag_Normal = 1
+local Bag_SoulShard = 2
+local Bag_Profession = 3
+local Bag_Quiver = 4
+local KEYRING_CONTAINER = KEYRING_CONTAINER
+local BAGTYPE_QUIVER = 0x0001 + 0x0002
+local BAGTYPE_SOUL = 0x004
+local BAGTYPE_PROFESSION = 0x0008 + 0x0010 + 0x0020 + 0x0040 + 0x0080 + 0x0200 + 0x0400
+local RAID_CLASS_COLORS = RAID_CLASS_COLORS
+
+local BlizzardBags = {
+	CharacterBag0Slot,
+	CharacterBag1Slot,
+	CharacterBag2Slot,
+	CharacterBag3Slot,
+}
+
+local BagProfessions = {
+	[8] = "Leatherworking",
+	[16] = "Inscription",
+	[32] = "Herb",
+	[64] = "Enchanting",
+	[128] = "Engineering",
+	[512] = "Gem",
+	[1024] = "Mining",
+	[32768] = "Fishing",
+}
+
+local BagSize = {}
+
+function Bags:SetTokensPosition()
+	local Money = ContainerFrame1MoneyFrame
+
+	MAX_WATCHED_TOKENS = 2
+
+	-- Set Position
+	Token1:ClearAllPoints()
+	Token1:SetPoint("LEFT", Money, "RIGHT", 0, -2)
+	Token2:ClearAllPoints()
+	Token2:SetPoint("LEFT", Token1, "RIGHT", 0, 0)
+	Token3:SetParent(L.Hider)
+
+	-- Skin Icons
+	Token1.icon:SetTexCoord(0.1, 0.9, 0.1, 0.9)
+	Token2.icon:SetTexCoord(0.1, 0.9, 0.1, 0.9)
+end
+
+function Bags:GetBagProfessionType(bag)
+	local BagType = select(2, GetContainerNumFreeSlots(bag))
+
+	if BagProfessions[BagType] then
+		return BagProfessions[BagType]
+	end
+end
+
+function Bags:GetBagType(bag)
+	local bagType = select(2, GetContainerNumFreeSlots(bag))
+
+	if bit.band(bagType, BAGTYPE_QUIVER) > 0 then
+		return Bag_Quiver
+	elseif bit.band(bagType, BAGTYPE_SOUL) > 0 then
+		return Bag_SoulShard
+	elseif bit.band(bagType, BAGTYPE_PROFESSION) > 0 then
+		return Bag_Profession
+	end
+
+	return Bag_Normal
+end
+
+function Bags:HideBlizzard()
+	local BankPortraitTexture = _G["BankPortraitTexture"]
+	local BankSlotsFrame = _G["BankSlotsFrame"]
+
+	BankPortraitTexture:Hide()
+
+	BankFrame:EnableMouse(false)
+
+	for i = 1, 12 do
+		local CloseButton = _G["ContainerFrame"..i.."CloseButton"]
+		CloseButton:Hide()
+
+		for k = 1, 7 do
+			local Container = _G["ContainerFrame"..i]
+			select(k, Container:GetRegions()):SetAlpha(0)
+		end
+	end
+
+	-- Hide Bank Frame Textures
+	for i = 1, BankFrame:GetNumRegions() do
+		local Region = select(i, BankFrame:GetRegions())
+
+		Region:SetAlpha(0)
+	end
+
+	-- Hide BankSlotsFrame Textures and Fonts
+	for i = 1, BankSlotsFrame:GetNumRegions() do
+		local Region = select(i, BankSlotsFrame:GetRegions())
+
+		Region:SetAlpha(0)
+	end
+end
+
+function Bags:CreateContainer(storagetype, ...)
+	local Container = CreateFrame("Frame", A .. storagetype, UIParent)
+	Container:SetScale(1)
+	Container:SetWidth(((ButtonSize + ButtonSpacing) * ItemsPerRow) + 22 - ButtonSpacing)
+	Container:SetPoint(...)
+	Container:SetFrameStrata("MEDIUM")
+	Container:SetFrameLevel(1)
+	Container:Hide()
+    L.F.CreateBackdrop(Container)
+	Container:EnableMouse(true)
+
+	if (storagetype == "Bag") then
+		local Sort = CreateFrame("Button", nil, Container)
+		local Keys = CreateFrame("Button", nil, Container)
+
+		Sort:SetSize(16, 16)
+		Sort:SetPoint("TOPRIGHT", Container, "TOPRIGHT", -8, -8)
+		Sort.Text = Sort:CreateFontString(nil, "OVERLAY")
+        Sort.Text:SetFont(L.C.font, 12)
+		Sort.Text:SetJustifyH("LEFT")
+		Sort.Text:SetPoint("CENTER")
+		Sort.Text:SetText("S")
+		Sort:SetScript("OnEnter", GameTooltip_Hide)
+		Sort:SetScript("OnClick", function()
+			if InCombatLockdown() then
+				print("You cannot sort your bag in combat")
+				return
+			end
+			SortBags()
+		end)
+
+        Keys:SetSize(16, 16)
+        Keys:SetPoint("RIGHT", Sort, "LEFT", -5, 0)
+        Keys.Text = Keys:CreateFontString(nil, "OVERLAY")
+        Keys.Text:SetFont(L.C.font, 12)
+		Keys.Text:SetJustifyH("LEFT")
+		Keys.Text:SetPoint("CENTER")
+		Keys.Text:SetText("K")
+        Keys:SetScript("OnEnter", GameTooltip_Hide)
+        Keys:SetScript("OnClick", function()
+            if not IsBagOpen(KEYRING_CONTAINER) then
+                ToggleBag(KEYRING_CONTAINER)
+            else
+                ToggleAllBags()
+                ToggleAllBags()
+            end
+        end)
+
+		Container.SortButton = Sort
+		Container.Keys = Keys
+	else
+		local PurchaseButton = BankFramePurchaseButton
+		local CostText = BankFrameSlotCost
+		local TotalCost = BankFrameDetailMoneyFrame
+		local Purchase = BankFramePurchaseInfo
+        local CloseButton = BankCloseButton
+		local BankBagsContainer = CreateFrame("Frame", nil, Container)
+        local ToggleBags = CreateFrame("Button", nil, Container)
+
+		CostText:ClearAllPoints()
+		CostText:SetPoint("BOTTOMLEFT", 60, 10)
+		TotalCost:ClearAllPoints()
+		TotalCost:SetPoint("LEFT", CostText, "RIGHT", 0, 0)
+		PurchaseButton:ClearAllPoints()
+		PurchaseButton:SetPoint("BOTTOMRIGHT", -10, 10)
+
+		local SortButton = CreateFrame("Button", nil, Container)
+		SortButton:SetSize(16, 16)
+		SortButton:SetPoint("TOPRIGHT", Container, "TOPRIGHT", -8, -8)
+
+		SortButton.Text = SortButton:CreateFontString(nil, "OVERLAY")
+		SortButton.Text:SetFont(L.C.font, 12)
+		SortButton.Text:SetJustifyH("LEFT")
+		SortButton.Text:SetPoint("CENTER")
+		SortButton.Text:SetText("S")
+		SortButton:SetScript("OnClick", BankFrame_AutoSortButtonOnClick)
+
+        ToggleBags:SetSize(16, 16)
+		ToggleBags:SetPoint("RIGHT", SortButton, "LEFT", -5, 0)
+        ToggleBags.Text = ToggleBags:CreateFontString(nil, "OVERLAY")
+        ToggleBags.Text:SetFont(L.C.font, 12)
+		ToggleBags.Text:SetJustifyH("LEFT")
+		ToggleBags.Text:SetPoint("CENTER")
+		ToggleBags.Text:SetText("B")
+		ToggleBags:SetScript("OnEnter", GameTooltip_Hide)
+		ToggleBags:SetScript("OnClick", function(self)
+			local BanksContainer = Bags.Bank.BagsContainer
+
+			if (ReplaceBags == 0) then
+				ReplaceBags = 1
+				BanksContainer:Show()
+			else
+				ReplaceBags = 0
+				BanksContainer:Hide()
+			end
+		end)
+
+		Purchase:ClearAllPoints()
+		Purchase:SetWidth(Container:GetWidth() + 50)
+		Purchase:SetHeight(70)
+		Purchase:SetPoint("TOP", UIParent, "TOP", 0, -8)
+
+		BankBagsContainer:SetSize(Container:GetWidth(), BankSlotsFrame.Bag1:GetHeight() + ButtonSpacing + ButtonSpacing)
+        L.F.CreateBackdrop(BankBagsContainer)
+		BankBagsContainer:SetPoint("BOTTOMLEFT", Container, "TOPLEFT", 0, 3)
+		BankBagsContainer:SetFrameLevel(Container:GetFrameLevel())
+		BankBagsContainer:SetFrameStrata(Container:GetFrameStrata())
+
+		for i = 1, 7 do
+			local Bag = BankSlotsFrame["Bag"..i]
+
+			Bag:SetParent(BankBagsContainer)
+			Bag:SetWidth(ButtonSize)
+			Bag:SetHeight(ButtonSize)
+			Bag:ClearAllPoints()
+
+			if i == 1 then
+				Bag:SetPoint("TOPLEFT", BankBagsContainer, "TOPLEFT", ButtonSpacing, -ButtonSpacing)
+			else
+				Bag:SetPoint("LEFT", BankSlotsFrame["Bag"..i-1], "RIGHT", ButtonSpacing, 0)
+			end
+		end
+
+		BankBagsContainer:SetWidth((ButtonSize * 7) + (ButtonSpacing * (7 + 1)))
+		BankBagsContainer:SetHeight(ButtonSize + (ButtonSpacing * 2))
+		BankBagsContainer:Hide()
+
+		BankFrame:EnableMouse(false)
+
+		Container.BagsContainer = BankBagsContainer
+		Container.SortButton = SortButton
+        Container.ToggleBags = ToggleBags
+        CloseButton:Hide()
+	end
+
+	self[storagetype] = Container
+end
+
+function Bags:SlotUpdate(id, button)
+	if not button then
+		return
+	end
+
+	local _, _, _, Rarity, _, _, ItemLink, _, _, ItemID, IsBound = GetContainerItemInfo(id, button:GetID())
+	local QuestItem = false
+	local IsNewItem = C_NewItems.IsNewItem(id, button:GetID())
+
+	if (button.ItemID == ItemID) then
+		return
+	end
+
+	if button.Quest then
+		button.Quest:Hide()
+	end
+
+	button.ItemID = ItemID
+
+	if ItemLink then
+		local itemName, itemString, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, itemEquipLoc, itemTexture = GetItemInfo(ItemLink)
+
+		if itemString then
+			if (itemType == TRANSMOG_SOURCE_2) then
+				QuestItem = true
+			end
+		end
+	end
+
+	if L.C.showQuest and QuestItem then
+		button.Backdrop:SetBackdropBorderColor(1, 1, 0)
+	else
+		if Rarity then
+			button.Backdrop:SetBackdropBorderColor(GetItemQualityColor(Rarity))
+        else
+			button.Backdrop:SetBackdropBorderColor(unpack(L.C.backdrop.edgeColor))
+		end
+	end
+
+	if L.C.flashNew and IsNewItem then
+		if not button.Animation then
+			button.Animation = button:CreateAnimationGroup()
+			button.Animation:SetLooping("BOUNCE")
+
+			button.Animation.FadeOut = button.Animation:CreateAnimation("Alpha")
+			button.Animation.FadeOut:SetFromAlpha(1)
+			button.Animation.FadeOut:SetToAlpha(.3)
+			button.Animation.FadeOut:SetDuration(.3)
+			button.Animation.FadeOut:SetSmoothing("IN_OUT")
+			button:HookScript("OnEnter", function(self)
+				local ItemID = self.ItemID
+				local BagID = self:GetID()
+
+				if ItemID and BagID then
+					local IsNewItem = C_NewItems.IsNewItem(self.ItemID, self:GetID())
+
+					if not IsNewItem and button.Animation:IsPlaying() then
+						button.Animation:Stop()
+					end
+				end
+			end)
+		end
+
+		if not button.Animation:IsPlaying() then
+			button.Animation:Play()
+		end
+	end
+
+	if L.C.showItemLevel then
+		if ItemLink then
+			local Level = GetDetailedItemLevelInfo(ItemLink)
+			local _, _, Rarity, _, _, _, _, _, _, _, _, ClassID = GetItemInfo(ItemLink)
+
+			if (ClassID == LE_ITEM_CLASS_ARMOR or ClassID == LE_ITEM_CLASS_WEAPON) and Level > 1 then
+				if not button.ItemLevel then
+					button.ItemLevel = button:CreateFontString(nil, "ARTWORK")
+					button.ItemLevel:SetPoint("TOPRIGHT", 1, -1)
+					button.ItemLevel:SetFont(L.C.font, 12, "OUTLINE")
+					button.ItemLevel:SetJustifyH("RIGHT")
+				end
+
+				button.ItemLevel:SetText(Level)
+
+				if Rarity then
+					button.ItemLevel:SetTextColor(GetItemQualityColor(Rarity))
+				else
+					button.ItemLevel:SetTextColor(1, 1, 1)
+				end
+			else
+				if button.ItemLevel then
+					button.ItemLevel:SetText("")
+				end
+			end
+		else
+			if button.ItemLevel then
+				button.ItemLevel:SetText("")
+			end
+		end
+	end
+end
+
+function Bags:BagUpdate(id)
+	local Size = GetContainerNumSlots(id)
+	local ContainerNumber = IsBagOpen(KEYRING_CONTAINER) and 1 or id + 1
+
+	for Slot = 1, Size do
+		local Button = _G["ContainerFrame"..ContainerNumber.."Item"..Slot]
+
+		if Button then
+			if not Button:IsShown() then
+				Button:Show()
+			end
+
+			local BagType = Bags:GetBagType(id)
+
+			if (BagType ~= 1) and (not Button.IsTypeStatusCreated) then
+				Button.TypeStatus = CreateFrame("StatusBar", nil, Button)
+				Button.TypeStatus:SetPoint("BOTTOMLEFT", 1, 1)
+				Button.TypeStatus:SetPoint("BOTTOMRIGHT", -1, 1)
+				Button.TypeStatus:SetHeight(3)
+				Button.TypeStatus:SetFrameStrata(Button:GetFrameStrata())
+				Button.TypeStatus:SetFrameLevel(Button:GetFrameLevel())
+				Button.TypeStatus:SetStatusBarTexture(L.C.backdrop.bgFile)
+
+				Button.IsTypeStatusCreated = true
+			end
+
+			if BagType == 2 then
+				-- Warlock Soul Shards Slots
+                local color = RAID_CLASS_COLORS["WARLOCK"]
+				Button.TypeStatus:SetStatusBarColor(color.r, color.g, color.b)
+			elseif BagType == 3 then
+				local ProfessionType = Bags:GetBagProfessionType(id)
+
+				if ProfessionType == "Leatherworking" then
+					Button.TypeStatus:SetStatusBarColor(102/255, 51/255, 0/255)
+				elseif ProfessionType == "Inscription" then
+					Button.TypeStatus:SetStatusBarColor(204/255, 204/255, 0/255)
+				elseif ProfessionType == "Herb" then
+					Button.TypeStatus:SetStatusBarColor(0/255, 153/255, 0/255)
+				elseif ProfessionType == "Enchanting" then
+					Button.TypeStatus:SetStatusBarColor(230/255, 25/255, 128/255)
+				elseif ProfessionType == "Engineering" then
+					Button.TypeStatus:SetStatusBarColor(25/255, 230/255, 230/255)
+				elseif ProfessionType == "Gem" then
+					Button.TypeStatus:SetStatusBarColor(232/255, 252/255, 252/255)
+				elseif ProfessionType == "Mining" then
+					Button.TypeStatus:SetStatusBarColor(138/255, 40/255, 40/255)
+				elseif ProfessionType == "Fishing" then
+					Button.TypeStatus:SetStatusBarColor(54/255, 54/255, 226/255)
+				end
+			elseif BagType == 4 then
+				-- Hunter Quiver Slots
+                local color = RAID_CLASS_COLORS["HUNTER"]
+				Button.TypeStatus:SetStatusBarColor(color.r, color.g, color.b)
+			end
+
+			self:SlotUpdate(id, Button)
+		end
+	end
+end
+
+function Bags:UpdateAllBags()
+	-- check if containers changed
+	if not NeedBagRefresh then
+		for i = 1, 5 do
+			local ContainerSize = _G["ContainerFrame"..i].size
+
+			if ContainerSize ~= BagSize[i] then
+				NeedBagRefresh = true
+
+				BagSize[i] = ContainerSize
+			end
+		end
+
+		if (not NeedBagRefresh) then
+			return
+		end
+	end
+
+	-- Refresh layout if a refresh if found
+	local NumRows, LastRowButton, NumButtons, LastButton = 0, ContainerFrame1Item1, 1, ContainerFrame1Item1
+	local FirstButton
+
+	for Bag = 1, 5 do
+		local ID = Bag - 1
+
+		if IsBagOpen(KEYRING_CONTAINER) then
+			ID = -2
+		end
+
+		local Slots = GetContainerNumSlots(ID)
+
+		for Item = Slots, 1, -1 do
+			local Button = _G["ContainerFrame"..Bag.."Item"..Item]
+			local Money = ContainerFrame1MoneyFrame
+
+			if not FirstButton then
+				FirstButton = Button
+			end
+
+			Button:ClearAllPoints()
+			Button:SetWidth(ButtonSize)
+			Button:SetHeight(ButtonSize)
+			Button:SetScale(1)
+
+			Button.newitemglowAnim:Stop()
+			Button.newitemglowAnim.Play = Noop
+
+			Button.flashAnim:Stop()
+			Button.flashAnim.Play = Noop
+
+			if (Button == FirstButton) then
+				Button:SetPoint("TOPLEFT", Bags.Bag, "TOPLEFT", 10, -30)
+				LastRowButton = Button
+				LastButton = Button
+			elseif (NumButtons == ItemsPerRow) then
+				Button:SetPoint("TOPRIGHT", LastRowButton, "TOPRIGHT", 0, -(ButtonSpacing + ButtonSize))
+				Button:SetPoint("BOTTOMLEFT", LastRowButton, "BOTTOMLEFT", 0, -(ButtonSpacing + ButtonSize))
+				LastRowButton = Button
+				NumRows = NumRows + 1
+				NumButtons = 1
+			else
+				Button:SetPoint("TOPRIGHT", LastButton, "TOPRIGHT", (ButtonSpacing + ButtonSize), 0)
+				Button:SetPoint("BOTTOMLEFT", LastButton, "BOTTOMLEFT", (ButtonSpacing + ButtonSize), 0)
+				NumButtons = NumButtons + 1
+			end
+
+			LastButton = Button
+
+            rButtonTemplate:StyleItemButton(Button, rButtonTemplate_Zork_SlotButtonConfig)
+            Button:SetFrameLevel(0)
+            Button.Backdrop:SetFrameLevel(Button:GetFrameLevel())
+
+			if not Money.IsMoved then
+				Money:ClearAllPoints()
+				Money:Show()
+				Money:SetPoint("TOPLEFT", Bags.Bag, "TOPLEFT", 8, -10)
+				Money:SetScale(1)
+				Money.IsMoved = true
+			end
+		end
+
+		Bags:BagUpdate(ID)
+
+		if IsBagOpen(KEYRING_CONTAINER) then
+			break
+		end
+	end
+
+	NeedBagRefresh = false
+
+	self.Bag:SetHeight(((ButtonSize + ButtonSpacing) * (NumRows + 1) + 26 + (ButtonSpacing * 4)) - ButtonSpacing)
+end
+
+function Bags:UpdateAllBankBags()
+	-- check if containers changed
+	for i = 6, 13 do
+		local ContainerSize = _G["ContainerFrame"..i].size
+
+		if ContainerSize ~= BagSize[i] then
+			NeedBankRefresh = true
+
+			BagSize[i] = ContainerSize
+		end
+	end
+
+	if not NeedBankRefresh then
+		return
+	end
+
+	local NumRows, LastRowButton, NumButtons, LastButton = 0, ContainerFrame1Item1, 1, ContainerFrame1Item1
+	local BankFrameMoneyFrame = BankFrameMoneyFrame
+
+	for Bank = 1, 28 do
+		local Button = _G["BankFrameItem"..Bank]
+		local Money = ContainerFrame2MoneyFrame
+
+		Button:ClearAllPoints()
+		Button:SetWidth(ButtonSize)
+		Button:SetHeight(ButtonSize)
+		Button:SetScale(1)
+		Button.IconBorder:SetAlpha(0)
+
+		if (Bank == 1) then
+			Button:SetPoint("TOPLEFT", Bags.Bank, "TOPLEFT", 10, -30)
+			LastRowButton = Button
+			LastButton = Button
+		elseif (NumButtons == ItemsPerRow) then
+			Button:SetPoint("TOPRIGHT", LastRowButton, "TOPRIGHT", 0, -(ButtonSpacing + ButtonSize))
+			Button:SetPoint("BOTTOMLEFT", LastRowButton, "BOTTOMLEFT", 0, -(ButtonSpacing + ButtonSize))
+			LastRowButton = Button
+			NumRows = NumRows + 1
+			NumButtons = 1
+		else
+			Button:SetPoint("TOPRIGHT", LastButton, "TOPRIGHT", (ButtonSpacing + ButtonSize), 0)
+			Button:SetPoint("BOTTOMLEFT", LastButton, "BOTTOMLEFT", (ButtonSpacing + ButtonSize), 0)
+			NumButtons = NumButtons + 1
+		end
+
+        rButtonTemplate:StyleItemButton(Button, rButtonTemplate_Zork_SlotButtonConfig)
+        Button:SetFrameLevel(0)
+        Button.Backdrop:SetFrameLevel(Button:GetFrameLevel())
+		Bags.SlotUpdate(self, -1, Button)
+
+		LastButton = Button
+	end
+
+	BankFrameMoneyFrame:Hide()
+
+	for Bag = 6, 12 do
+		local Slots = GetContainerNumSlots(Bag - 1)
+
+		for Item = Slots, 1, -1 do
+			local Button = _G["ContainerFrame"..Bag.."Item"..Item]
+
+			Button:ClearAllPoints()
+			Button:SetWidth(ButtonSize)
+			Button:SetHeight(ButtonSize)
+			Button:SetScale(1)
+			Button.IconBorder:SetAlpha(0)
+
+			if (NumButtons == ItemsPerRow) then
+				Button:SetPoint("TOPRIGHT", LastRowButton, "TOPRIGHT", 0, -(ButtonSpacing + ButtonSize))
+				Button:SetPoint("BOTTOMLEFT", LastRowButton, "BOTTOMLEFT", 0, -(ButtonSpacing + ButtonSize))
+				LastRowButton = Button
+				NumRows = NumRows + 1
+				NumButtons = 1
+			else
+				Button:SetPoint("TOPRIGHT", LastButton, "TOPRIGHT", (ButtonSpacing+ButtonSize), 0)
+				Button:SetPoint("BOTTOMLEFT", LastButton, "BOTTOMLEFT", (ButtonSpacing+ButtonSize), 0)
+				NumButtons = NumButtons + 1
+			end
+
+            rButtonTemplate:StyleItemButton(Button, rButtonTemplate_Zork_SlotButtonConfig)
+            Button:SetFrameLevel(0)
+            Button.Backdrop:SetFrameLevel(Button:GetFrameLevel())
+			Bags.SlotUpdate(self, Bag - 1, Button)
+
+			LastButton = Button
+		end
+	end
+
+	NeedBankRefresh = false
+
+	Bags.Bank:SetHeight(((ButtonSize + ButtonSpacing) * (NumRows + 1) + 40) - ButtonSpacing)
+end
+
+function Bags:OpenBag(id)
+	if (not CanOpenPanels()) then
+		if (UnitIsDead("player")) then
+			NotWhileDeadError()
+		end
+
+		return
+	end
+
+	local Size = GetContainerNumSlots(id)
+	local OpenFrame = ContainerFrame_GetOpenFrame()
+
+	for i = 1, 40 do
+		local Index = Size - i + 1
+		local Button = _G[OpenFrame:GetName().."Item"..i]
+
+		if Button then
+			if (i > Size) then
+				Button:Hide()
+			else
+				Button:SetID(Index)
+				Button:Show()
+			end
+		end
+	end
+
+	OpenFrame.size = Size
+	OpenFrame:SetID(id)
+	OpenFrame:Show()
+
+	if (id == 4) then
+		Bags:UpdateAllBags()
+	end
+end
+
+function Bags:CloseBag(id)
+	CloseBag(id)
+end
+
+function Bags:OpenAllBags()
+	self:OpenBag(0)
+
+	for i = 1, 4 do
+		self:OpenBag(i)
+	end
+
+	if IsBagOpen(0) then
+		self.Bag:Show()
+
+		if not self.Bag.MoverAdded then
+            --create drag frame
+            rLib:CreateDragFrame(self.Bag, L.dragFrames, -2, true)
+			self.Bag.MoverAdded = true
+		end
+	end
+end
+
+function Bags:OpenAllBankBags()
+	local Bank = BankFrame
+
+	if Bank:IsShown() then
+		self.Bank:Show()
+
+		if not self.Bank.MoverAdded then
+			--create drag frame
+            rLib:CreateDragFrame(self.Bank, L.dragFrames, -2, true)
+			self.Bank.MoverAdded = true
+		end
+
+		for i = 5, 11 do
+			if (not IsBagOpen(i)) then
+				self:OpenBag(i, 1)
+			end
+		end
+	end
+end
+
+function Bags:CloseAllBags()
+	if MerchantFrame:IsVisible() or InboxFrame:IsVisible() then
+		return
+	end
+
+	CloseAllBags()
+
+	if IsBagOpen(KEYRING_CONTAINER) then
+		CloseBag(KEYRING_CONTAINER)
+	end
+
+	PlaySound(SOUNDKIT.IG_BACKPACK_CLOSE)
+end
+
+function Bags:CloseAllBankBags()
+	local Bank = BankFrame
+
+	if (Bank:IsVisible()) then
+		CloseBankBagFrames()
+		CloseBankFrame()
+	end
+end
+
+function Bags:ToggleBags(id, openonly)
+	if id == KEYRING_CONTAINER then
+		if not IsBagOpen(KEYRING_CONTAINER) then
+			CloseAllBags()
+			CloseBankBagFrames()
+			CloseBankFrame()
+
+			NeedBagRefresh = true
+
+			Bags:OpenBag(id)
+			Bags:UpdateAllBags()
+
+			NeedBagRefresh = true
+		else
+			CloseBag(id)
+		end
+	else
+		if (self.Bag:IsShown() and BankFrame:IsShown()) and (not self.Bank:IsShown()) then
+			self:OpenAllBankBags()
+			return
+		end
+
+		if (not openonly) and (self.Bag:IsShown() or self.Bank:IsShown()) then
+			if MerchantFrame:IsVisible() or InboxFrame:IsVisible() then
+				return
+			end
+
+			self:CloseAllBags()
+			self:CloseAllBankBags()
+
+			return
+		end
+
+		if not self.Bag:IsShown() then
+			self:OpenAllBags()
+		end
+
+		if not self.Bank:IsShown() and BankFrame:IsShown() then
+			self:OpenAllBankBags()
+		end
+	end
+end
+
+function Bags:OnEvent(event, ...)
+	if (event == "BAG_UPDATE") then
+		if not IsBagOpen(KEYRING_CONTAINER) then
+			self:BagUpdate(...)
+		else
+			self:BagUpdate(-2)
+		end
+	elseif (event == "MERCHANT_CLOSED" or event ==  "MAIL_CLOSED") then
+		CloseAllBags()
+	elseif (event == "CURRENCY_DISPLAY_UPDATE") then
+		BackpackTokenFrame_Update()
+	elseif (event == "BAG_CLOSED") then
+		-- This is usually where the client find a bag swap in character or bank slots.
+
+		local Bag = ... + 1
+
+		-- We need to hide buttons from a bag when closing it because they are not parented to the original frame
+		local Container = _G["ContainerFrame"..Bag]
+		local Size = Container.size
+
+		if Size then
+			for i = 1, Size do
+				local Button = _G["ContainerFrame"..Bag.."Item"..i]
+
+				if Button then
+					Button:Hide()
+				end
+			end
+		end
+
+		-- We close to refresh the all in one layout.
+		self:CloseAllBags()
+		self:CloseAllBankBags()
+	elseif (event == "PLAYERBANKSLOTS_CHANGED") then
+		local ID = ...
+		if ID <= 28 then
+			local Button = _G["BankFrameItem"..ID]
+
+			if (Button) then
+				self:SlotUpdate(-1, Button)
+			end
+		end
+	elseif (event == "PLAYERREAGENTBANKSLOTS_CHANGED") then
+		local ID = ...
+		local Button = _G["ReagentBankFrameItem"..ID]
+		if (Button) then
+			self:SlotUpdate(-3, Button)
+		end
+	elseif (event == "BANKFRAME_CLOSED") then
+		local Bank = self.Bank
+		self:CloseAllBags()
+		self:CloseAllBankBags()
+	elseif (event == "BANKFRAME_OPENED") then
+		local Bank = self.Bank
+		Bank:Show()
+		self:UpdateAllBankBags()
+	elseif (event == "SOULBIND_FORGE_INTERACTION_STARTED") then
+		self:OpenAllBags()
+		ItemButtonUtil.OpenAndFilterBags(SoulbindViewer)
+	elseif (event == "SOULBIND_FORGE_INTERACTION_ENDED") then
+		self:CloseAllBags()
+	end
+end
+
+function Bags:Enable()
+	if L.C.sort.sortToBottom then
+		SetSortBagsRightToLeft(false)
+	else
+		SetSortBagsRightToLeft(true)
+	end
+	SetInsertItemsLeftToRight(false)
+
+	-- Bug with mouse click
+	GroupLootContainer:EnableMouse(false)
+
+	ButtonSize = L.C.icon.size
+	ButtonSpacing = L.C.icon.spacing
+	ItemsPerRow = L.C.icon.columns
+
+	local Bag = ContainerFrame1
+	local BankItem1 = BankFrameItem1
+
+	self:CreateContainer("Bag", unpack(L.C.bag.point))
+	self:CreateContainer("Bank", unpack(L.C.bank.point))
+	self:HideBlizzard()
+
+	Bag:SetScript("OnHide", function()
+		self.Bag:Hide()
+	end)
+
+	Bag:HookScript("OnShow", function() -- Cinematic Bug with Bags open.
+		self.Bag:Show()
+	end)
+
+	BankItem1:SetScript("OnHide", function()
+		self.Bank:Hide()
+	end)
+
+	-- Rewrite Blizzard Bags Functions
+	function UpdateContainerFrameAnchors() end
+	function ToggleBag(id) ToggleAllBags(id) end
+	function ToggleBackpack() ToggleAllBags() end
+	function OpenAllBags() ToggleAllBags(1, true) end
+	function OpenBackpack() ToggleAllBags(1, true) end
+	function ToggleAllBags(id, openonly) self:ToggleBags(id, openonly) end
+
+	-- Destroy bubbles help boxes
+	for i = 1, 13 do
+		local HelpBox = _G["ContainerFrame"..i.."ExtraBagSlotsHelpBox"]
+
+		if HelpBox then
+            HelpBox:Hide()
+			HelpBox:SetParent(L.Hider)
+		end
+	end
+
+	OpenAllBagsMatchingContext = function() return 4 end
+
+	-- Register Events for Updates
+	self:RegisterEvent("BAG_UPDATE")
+	self:RegisterEvent("PLAYERBANKSLOTS_CHANGED")
+	self:RegisterEvent("BAG_CLOSED")
+	self:RegisterEvent("BANKFRAME_CLOSED")
+	self:RegisterEvent("BANKFRAME_OPENED")
+	self:RegisterEvent("MERCHANT_CLOSED")
+	self:RegisterEvent("MAIL_CLOSED")
+	self:SetScript("OnEvent", self.OnEvent)
+
+	for i = 1, 13 do
+		_G["ContainerFrame"..i]:EnableMouse(false)
+	end
+
+	ToggleAllBags()
+	ToggleAllBags()
+end
+
+rBag.Bags = Bags
diff --git a/rBag/functions.lua b/rBag/functions.lua
new file mode 100644
index 0000000..2d901ef
--- /dev/null
+++ b/rBag/functions.lua
@@ -0,0 +1,19 @@
+local A, L = ...
+
+local Hider = CreateFrame("Frame", nil, UIParent)
+Hider:Hide()
+L.Hider = Hider
+
+--CreateBackdrop
+local function CreateBackdrop(self,relativeTo)
+  local backdrop = L.C.backdrop
+  local bd = CreateFrame("Frame", nil, self, BackdropTemplateMixin and "BackdropTemplate")
+  bd:SetFrameLevel(self:GetFrameLevel()-1 or 0)
+  bd:SetPoint("TOPLEFT", relativeTo or self, "TOPLEFT", -backdrop.inset, backdrop.inset)
+  bd:SetPoint("BOTTOMRIGHT", relativeTo or self, "BOTTOMRIGHT", backdrop.inset, -backdrop.inset)
+  bd:SetBackdrop(backdrop)
+  bd:SetBackdropColor(unpack(backdrop.bgColor))
+  bd:SetBackdropBorderColor(unpack(backdrop.edgeColor))
+  return bd
+end
+L.F.CreateBackdrop = CreateBackdrop
\ No newline at end of file
diff --git a/rBag/init.lua b/rBag/init.lua
new file mode 100644
index 0000000..ea944c4
--- /dev/null
+++ b/rBag/init.lua
@@ -0,0 +1,62 @@
+local A, L = ...
+
+L.dragFrames        = {}
+L.addonName         = A
+L.addonColor        = "ff1a9fc0"
+L.addonShortcut     = "rbag"
+L.F                 = {}
+
+-----------------------------
+-- rBag Global
+-----------------------------
+
+rBag = {}
+rBag.addonName = A
+
+local mediapath = rLib.mediapath
+
+-----------------------------
+-- Configs
+-----------------------------
+
+local cfg = {}
+
+cfg.icon = {
+    size = 32,
+    spacing = 4,
+    columns = 12,
+}
+
+cfg.sort     = {
+    enabled = true,
+    sortToBottom = false,
+}
+
+cfg.font     = mediapath .. "expressway.ttf"
+cfg.showQuest = true
+cfg.flashNew  = true
+cfg.showItemLevel = true
+
+cfg.backdrop = {
+    bgFile               = "Interface\\Buttons\\WHITE8x8",
+    bgColor              = {0.08, 0.08, 0.1, 0.92},
+    edgeFile             = "Interface\\Tooltips\\UI-Tooltip-Border",
+    edgeColor            = {0.1, 0.1, 0.1, 0.6},
+    tile                 = false,
+    tileEdge             = false,
+    tileSize             = 16,
+    edgeSize             = 16,
+    inset                = 3,
+    insets               = {left = 3, right = 3, top = 3, bottom = 3}
+}
+
+cfg.bag = {
+    point        = {"BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -34, 48},
+    extraHeight  = 16,
+}
+
+cfg.bank = {
+    point        = {"BOTTOMLEFT", UIParent, "BOTTOMLEFT", 34, 48},
+}
+
+L.C = cfg
\ No newline at end of file
diff --git a/rBag/libs/SortBags.lua b/rBag/libs/SortBags.lua
new file mode 100644
index 0000000..654d010
--- /dev/null
+++ b/rBag/libs/SortBags.lua
@@ -0,0 +1,539 @@
+local _G, _M = getfenv(0), {}
+setfenv(1, setmetatable(_M, {__index=_G}))
+
+CreateFrame('GameTooltip', 'SortBagsTooltip', nil, 'GameTooltipTemplate')
+
+BAG_CONTAINERS = {0, 1, 2, 3, 4}
+BANK_BAG_CONTAINERS = {-1, 5, 6, 7, 8, 9, 10, 11}
+
+function _G.SortBags()
+	CONTAINERS = {unpack(BAG_CONTAINERS)}
+	for i = #CONTAINERS, 1, -1 do
+		if GetBagSlotFlag(i - 1, LE_BAG_FILTER_FLAG_IGNORE_CLEANUP) then
+			tremove(CONTAINERS, i)
+		end
+	end
+	Start()
+end
+
+function _G.SortBankBags()
+	CONTAINERS = {unpack(BANK_BAG_CONTAINERS)}
+	for i = #CONTAINERS, 1, -1 do
+		if GetBankBagSlotFlag(i - 1, LE_BAG_FILTER_FLAG_IGNORE_CLEANUP) then
+			tremove(CONTAINERS, i)
+		end
+	end
+	Start()
+end
+
+function _G.GetSortBagsRightToLeft(enabled)
+	return SortBagsRightToLeft
+end
+
+function _G.SetSortBagsRightToLeft(enabled)
+	_G.SortBagsRightToLeft = enabled and 1 or nil
+end
+
+local function set(...)
+	local t = {}
+	local n = select('#', ...)
+	for i = 1, n do
+		t[select(i, ...)] = true
+	end
+	return t
+end
+
+local function arrayToSet(array)
+	local t = {}
+	for i = 1, #array do
+		t[array[i]] = true
+	end
+	return t
+end
+
+local function union(...)
+	local t = {}
+	local n = select('#', ...)
+	for i = 1, n do
+		for k in pairs(select(i, ...)) do
+			t[k] = true
+		end
+	end
+	return t
+end
+
+local SPECIAL = set(5462, 13347, 11511, 38233)
+
+local KEYS = set(9240, 11511, 17191, 13544, 12324, 16309, 12384, 20402)
+
+local TOOLS = set(6218, 6339, 11130, 11145, 16207, 22461, 22462, 22463, 5060, 7005, 12709, 19727, 5956, 2901, 6219, 10498, 9149, 15846, 6256, 6365, 6367, 20815, 20824, 25978)
+
+local CLASSES = {
+	-- soul
+	{
+		containers = {22243, 22244, 21340, 21341, 21342, 21872},
+		items = set(6265),
+	},
+	-- arrow
+	{
+		containers = {2101, 5439, 7278, 11362, 3573, 3605, 7371, 8217, 2662, 19319, 18714, 29143, 29144, 34105, 34100},
+		items = set(2512, 2514, 2515, 3029, 3030, 3031, 3464, 9399, 10579, 11285, 12654, 18042, 19316, 24412, 24417, 28053, 28056, 30319, 30611, 31737, 31949, 32760, 33803, 34581),
+	},
+	-- bullet
+	{
+		containers = {2102, 5441, 7279, 11363, 3574, 3604, 7372, 8218, 2663, 19320, 29118, 34106, 34099},
+		items = set(2516, 2519, 3033, 3465, 4960, 5568, 8067, 8068, 8069, 10512, 10513, 11284, 11630, 13377, 15997, 19317, 23772, 23773, 28060, 28061, 30612, 31735, 32761, 32882, 32883, 34582),
+	},
+	-- ench
+	{
+		containers = {22246, 22248, 22249, 22249, 21858},
+		items = arrayToSet({6218, 6222, 6339, 6342, 6343, 6344, 6345, 6346, 6347, 6348, 6349, 6375, 6376, 6377, 10938, 10939, 10940, 10978, 10998, 11038, 11039, 11081, 11082, 11083, 11084, 11098, 11101, 11130, 11134, 11135, 11137, 11138, 11139, 11145, 11150, 11151, 11152, 11163, 11164, 11165, 11166, 11167, 11168, 11174, 11175, 11176, 11177, 11178, 11202, 11203, 11204, 11205, 11206, 11207, 11208, 11223, 11224, 11225, 11226, 11813, 14343, 14344, 16202, 16203, 16204, 16207, 16214, 16215, 16216, 16217, 16218, 16219, 16220, 16221, 16222, 16223, 16224, 16242, 16243, 16244, 16245, 16246, 16247, 16248, 16249, 16250, 16251, 16252, 16253, 16254, 16255, 17725, 18259, 18260, 19444, 19445, 19446, 19447, 19448, 19449, 20725, 20726, 20727, 20728, 20729, 20730, 20731, 20732, 20733, 20734, 20735, 20736, 20752, 20753, 20754, 20755, 20756, 20757, 20758, 22392, 22445, 22446, 22447, 22448, 22449, 22450, 22461, 22462, 22463, 22530, 22531, 22532, 22533, 22534, 22535, 22536, 22537, 22538, 22539, 22540, 22541, 22542, 22543, 22544, 22545, 22546, 22547, 22548, 22551, 22552, 22553, 22554, 22555, 22556, 22557, 22558, 22559, 22560, 22561, 22562, 22563, 22564, 22565, 24000, 24003, 25848, 25849, 28270, 28271, 28272, 28273, 28274, 28276, 28277, 28279, 28280, 28281, 28282, 33148, 33149, 33150, 33151, 33152, 33153, 33165, 33307, 34872, 35297, 35298, 35299, 35498, 35500, 35756, 186683, 7081, 12810, 7068, 7972, 12808, 7067, 7075, 7076, 7077, 7078, 7080, 7082, 12803}),
+	},
+	-- herb
+	{
+		containers = {22250, 22251, 22252, 38225},
+		items = arrayToSet({765, 785, 1401, 2263, 2447, 2449, 2450, 2452, 2453, 3355, 3356, 3357, 3358, 3369, 3818, 3819, 3820, 3821, 4625, 5013, 5056, 5168, 8831, 8836, 8838, 8839, 8845, 8846, 11018, 11020, 11022, 11024, 11040, 11514, 11951, 11952, 13463, 13464, 13465, 13466, 13467, 13468, 16205, 16208, 17034, 17035, 17036, 17037, 17038, 17760, 18297, 19727, 22094, 22147, 22710, 22785, 22786, 22787, 22788, 22789, 22790, 22791, 22792, 22793, 22794, 22795, 22797, 23329, 23501, 23788, 24245, 24246, 24401, 31300, 32468, 34465, 8153, 10286, 19726}),
+	},
+	-- mining
+	{
+		containers = {29540, 30746},
+		items = arrayToSet({756, 778, 1819, 1893, 1959, 2770, 2771, 2772, 2775, 2776, 2835, 2836, 2838, 2840, 2841, 2842, 2901, 3575, 3576, 3577, 3858, 3859, 3860, 3861, 6037, 7911, 7912, 10620, 11370, 11371, 12359, 12360, 12365, 12655, 17771, 18562, 20723, 22202, 22203, 23424, 23425, 23426, 23427, 23445, 23446, 23447, 23448, 23449, 23573, 32464, 35128, 5956, 24186, 24188, 24190, 24234, 24235, 24242, 24243}),
+	},
+	-- leather
+	{
+		containers = {34482, 34490},
+		items = arrayToSet({783, 2304, 2313, 2318, 2319, 2320, 2321, 2324, 2325, 2406, 2407, 2408, 2409, 2604, 2605, 2934, 3182, 3824, 4096, 4231, 4232, 4233, 4234, 4235, 4236, 4265, 4289, 4291, 4293, 4294, 4295, 4296, 4297, 4298, 4299, 4300, 4301, 4304, 4337, 4340, 4341, 4342, 4461, 5082, 5083, 5116, 5373, 5637, 5784, 5785, 5786, 5787, 5788, 5789, 5972, 5973, 5974, 6260, 6261, 6470, 6471, 6474, 6475, 6476, 6710, 7005, 7070, 7071, 7286, 7287, 7288, 7289, 7290, 7360, 7361, 7362, 7363, 7364, 7392, 7428, 7449, 7450, 7451, 7452, 7453, 7613, 8146, 8150, 8151, 8154, 8165, 8167, 8168, 8169, 8170, 8171, 8172, 8173, 8343, 8368, 8384, 8385, 8386, 8387, 8388, 8389, 8390, 8395, 8397, 8398, 8399, 8400, 8401, 8402, 8403, 8404, 8405, 8406, 8407, 8408, 8409, 10290, 11512, 12607, 12709, 12731, 12753, 13287, 13288, 14341, 14635, 15407, 15408, 15409, 15410, 15412, 15414, 15415, 15416, 15417, 15419, 15420, 15422, 15423, 15564, 15725, 15726, 15727, 15728, 15729, 15730, 15731, 15732, 15733, 15734, 15735, 15737, 15738, 15739, 15740, 15741, 15742, 15743, 15744, 15745, 15746, 15747, 15748, 15749, 15751, 15752, 15753, 15754, 15755, 15756, 15757, 15758, 15759, 15760, 15761, 15762, 15763, 15764, 15765, 15768, 15769, 15770, 15771, 15772, 15773, 15774, 15775, 15776, 15777, 15779, 15781, 17012, 17022, 17023, 17025, 17056, 17722, 17967, 17968, 18239, 18240, 18251, 18252, 18512, 18514, 18515, 18516, 18517, 18518, 18519, 18662, 18731, 18949, 19326, 19327, 19328, 19329, 19330, 19331, 19332, 19333, 19767, 19768, 19769, 19770, 19771, 19772, 19773, 19901, 20253, 20254, 20381, 20382, 20498, 20499, 20500, 20501, 20506, 20507, 20508, 20509, 20510, 20511, 20576, 21548, 21887, 22692, 22694, 22695, 22696, 22697, 22698, 22769, 22770, 22771, 23793, 25649, 25650, 25651, 25652, 25699, 25700, 25707, 25708, 25720, 25721, 25722, 25725, 25726, 25728, 25729, 25730, 25731, 25732, 25733, 25734, 25735, 25736, 25737, 25738, 25739, 25740, 25741, 25742, 25743, 29213, 29214, 29215, 29217, 29218, 29219, 29483, 29485, 29486, 29487, 29488, 29528, 29529, 29530, 29531, 29532, 29533, 29534, 29535, 29536, 29539, 29547, 29548, 29664, 29669, 29672, 29673, 29674, 29675, 29677, 29682, 29684, 29689, 29691, 29693, 29698, 29700, 29701, 29702, 29703, 29704, 29713, 29714, 29717, 29718, 29719, 29720, 29721, 29722, 29723, 29724, 29725, 29726, 29727, 29728, 29729, 29730, 29731, 29732, 29733, 29734, 30183, 30301, 30302, 30303, 30304, 30305, 30306, 30307, 30308, 30444, 31361, 31362, 32428, 32429, 32430, 32431, 32432, 32433, 32434, 32435, 32436, 32470, 32744, 32745, 32746, 32747, 32748, 32749, 32750, 32751, 33124, 33205, 34172, 34173, 34174, 34175, 34200, 34201, 34207, 34218, 34262, 34330, 34491, 34664, 35212, 35213, 35214, 35215, 35216, 35217, 35218, 35219, 35300, 35301, 35302, 35303, 35517, 35519, 35520, 35521, 35523, 35524, 35527, 35528, 35539, 35540, 35541, 35542, 35545, 35546, 35549, 35550, 185848, 185849, 185850, 185851, 185852, 185922, 185923, 185924, 185925, 185926, 187048, 187049, 8153, 7081, 12810, 15846, 19726, 7067, 7075, 7076, 7077, 7078, 7080, 7082, 12803}),
+	},
+	-- gems
+	{
+		containers = {24270, 30747},
+		items = arrayToSet({774, 818, 1206, 1210, 1529, 1705, 3864, 5498, 5500, 5513, 5514, 7909, 7910, 7971, 8007, 8008, 11382, 11754, 12361, 12363, 12364, 12799, 12800, 13926, 18335, 19774, 20815, 20824, 21929, 22044, 22459, 22460, 23077, 23079, 23094, 23095, 23096, 23097, 23098, 23099, 23100, 23101, 23103, 23104, 23105, 23106, 23107, 23108, 23109, 23110, 23111, 23112, 23113, 23114, 23115, 23116, 23117, 23118, 23119, 23120, 23121, 23158, 23234, 23364, 23366, 23436, 23437, 23438, 23439, 23440, 23441, 24027, 24028, 24029, 24030, 24031, 24032, 24033, 24035, 24036, 24037, 24039, 24047, 24048, 24050, 24051, 24052, 24053, 24054, 24055, 24056, 24057, 24058, 24059, 24060, 24061, 24062, 24065, 24066, 24067, 24478, 24479, 25867, 25868, 25890, 25893, 25894, 25895, 25896, 25897, 25898, 25899, 25901, 27679, 27774, 27777, 27785, 27786, 27809, 27811, 27812, 27820, 27863, 27864, 28117, 28118, 28119, 28120, 28122, 28123, 28290, 28360, 28361, 28362, 28363, 28458, 28459, 28460, 28461, 28462, 28463, 28464, 28465, 28466, 28467, 28468, 28469, 28470, 28556, 28557, 28595, 30546, 30547, 30548, 30549, 30550, 30551, 30552, 30553, 30554, 30555, 30556, 30558, 30559, 30560, 30563, 30564, 30565, 30566, 30571, 30572, 30573, 30574, 30575, 30581, 30582, 30583, 30584, 30585, 30586, 30587, 30588, 30589, 30590, 30591, 30592, 30593, 30594, 30598, 30600, 30601, 30602, 30603, 30604, 30605, 30606, 30607, 30608, 31079, 31080, 31116, 31117, 31118, 31860, 31861, 31862, 31863, 31864, 31865, 31866, 31867, 31868, 31869, 32193, 32194, 32195, 32196, 32197, 32198, 32199, 32200, 32201, 32202, 32203, 32204, 32205, 32206, 32207, 32208, 32209, 32210, 32211, 32212, 32213, 32214, 32215, 32216, 32217, 32218, 32219, 32220, 32221, 32222, 32223, 32224, 32225, 32226, 32227, 32228, 32229, 32230, 32231, 32249, 32409, 32410, 32634, 32635, 32636, 32637, 32638, 32639, 32640, 32641, 32735, 32775, 32833, 32836, 33131, 33132, 33133, 33134, 33135, 33137, 33138, 33139, 33140, 33141, 33142, 33143, 33144, 33633, 33782, 34220, 34256, 34831, 35315, 35316, 35318, 35487, 35488, 35489, 35501, 35503, 35707, 35758, 35759, 35760, 35761, 37503, 38545, 38546, 38547, 38548, 38549, 38550, 24186, 24188, 24190, 24234, 24235, 24242, 24243}),
+	},
+	-- engineering
+	{
+		containers = {23774, 23775, 30745},
+		items = arrayToSet({814, 4357, 4358, 4359, 4360, 4361, 4363, 4364, 4365, 4366, 4367, 4368, 4370, 4371, 4373, 4374, 4375, 4376, 4377, 4378, 4380, 4381, 4382, 4384, 4385, 4386, 4387, 4388, 4389, 4390, 4391, 4392, 4393, 4394, 4395, 4396, 4397, 4398, 4399, 4400, 4403, 4404, 4405, 4406, 4407, 4408, 4409, 4410, 4411, 4412, 4413, 4414, 4415, 4416, 4417, 4852, 5507, 6219, 6672, 6712, 6714, 6715, 6716, 7069, 7148, 7189, 7190, 7191, 7192, 7506, 7560, 7561, 7742, 9060, 9061, 9312, 9313, 9318, 10498, 10499, 10500, 10501, 10502, 10503, 10504, 10505, 10506, 10507, 10514, 10518, 10542, 10543, 10545, 10546, 10548, 10558, 10559, 10560, 10561, 10562, 10576, 10577, 10580, 10585, 10586, 10587, 10588, 10601, 10602, 10603, 10604, 10605, 10606, 10607, 10608, 10609, 10645, 10646, 10647, 10648, 10716, 10720, 10721, 10723, 10724, 10725, 10726, 10727, 10790, 10791, 11590, 11827, 11828, 13308, 13309, 13310, 13311, 14639, 15992, 15993, 15994, 15999, 16000, 16005, 16006, 16008, 16009, 16022, 16023, 16040, 16041, 16042, 16043, 16044, 16045, 16046, 16047, 16048, 16049, 16050, 16051, 16052, 16053, 16054, 16055, 16056, 17716, 17720, 18232, 18235, 18283, 18290, 18291, 18292, 18587, 18588, 18594, 18631, 18634, 18636, 18637, 18638, 18639, 18641, 18645, 18647, 18648, 18649, 18650, 18651, 18652, 18653, 18654, 18655, 18656, 18657, 18658, 18660, 18661, 18984, 18986, 19026, 19027, 19998, 19999, 20000, 20001, 20475, 20816, 20834, 21557, 21558, 21559, 21571, 21574, 21576, 21589, 21590, 21592, 21714, 21716, 21718, 21724, 21725, 21726, 21727, 21728, 21729, 21730, 21731, 21732, 21733, 21734, 21735, 21737, 21738, 22728, 22729, 23736, 23737, 23758, 23761, 23762, 23763, 23764, 23765, 23766, 23768, 23769, 23770, 23771, 23781, 23782, 23783, 23784, 23785, 23786, 23787, 23799, 23800, 23802, 23803, 23804, 23805, 23806, 23807, 23808, 23809, 23810, 23811, 23812, 23813, 23814, 23815, 23816, 23817, 23819, 23820, 23821, 23822, 23823, 23824, 23825, 23826, 23827, 23828, 23829, 23831, 23832, 23835, 23836, 23838, 23839, 23840, 23841, 23874, 23882, 23883, 23884, 23887, 23888, 25886, 25887, 30542, 30544, 31666, 32381, 32413, 32423, 32461, 32472, 32473, 32474, 32475, 32476, 32478, 32479, 32480, 32494, 32495, 33092, 33093, 33804, 34060, 34061, 34113, 34114, 34353, 34354, 34355, 34356, 34357, 34467, 34503, 34504, 34626, 34627, 34847, 35181, 35182, 35183, 35184, 35185, 35186, 35187, 35189, 35190, 35191, 35192, 35193, 35194, 35195, 35196, 35197, 35310, 35311, 35485, 35581, 35582, 37567, 15846, 10286, 19726, 7068, 7972, 12808, 7067, 7075, 7076, 7077, 7078, 7080, 7082, 12803, 5956, 22574, 4401, 11825, 11826, 15996, 21277, 23767, 37710}),
+	},
+}
+
+do
+	local f = CreateFrame'Frame'
+	local lastUpdate = 0
+	local function updateHandler()
+		if GetTime() - lastUpdate > 1 then
+			for _, container in pairs(BAG_CONTAINERS) do
+				for position = 1, GetContainerNumSlots(container) do
+					SetScanTooltip(container, position)
+				end
+			end
+			for _, container in pairs(BANK_BAG_CONTAINERS) do
+				for position = 1, GetContainerNumSlots(container) do
+					SetScanTooltip(container, position)
+				end
+			end
+			f:SetScript('OnUpdate', nil)
+		end
+	end
+	f:SetScript('OnEvent', function()
+		lastUpdate = GetTime()
+		f:SetScript('OnUpdate', updateHandler)
+	end)
+	f:RegisterEvent'BAG_UPDATE'
+	f:RegisterEvent'BANKFRAME_OPENED'
+end
+
+local model, itemStacks, itemClasses, itemSortKeys
+
+do
+	local f = CreateFrame'Frame'
+
+	local process = coroutine.create(function() end);
+
+	local suspended
+
+	function Start()
+		process = coroutine.create(function()
+			while not Initialize() do
+				coroutine.yield()
+			end
+			while true do
+				suspended = false
+				if InCombatLockdown() then
+					return
+				end
+				local complete = Sort()
+				if complete then
+					return
+				end
+				Stack()
+				if not suspended then
+					coroutine.yield()
+				end
+			end
+		end)
+		f:Show()
+	end
+
+	f:SetScript('OnUpdate', function(_, arg1)
+		if coroutine.status(process) == 'suspended' then
+			suspended = true
+			coroutine.resume(process)
+		end
+		if coroutine.status(process) == 'dead' then
+			f:Hide()
+		end
+	end)
+end
+
+function LT(a, b)
+	local i = 1
+	while true do
+		if a[i] and b[i] and a[i] ~= b[i] then
+			return a[i] < b[i]
+		elseif not a[i] and b[i] then
+			return true
+		elseif not b[i] then
+			return false
+		end
+		i = i + 1
+	end
+end
+
+function Move(src, dst)
+	local texture, _, srcLocked = GetContainerItemInfo(src.container, src.position)
+	local _, _, dstLocked = GetContainerItemInfo(dst.container, dst.position)
+
+	if texture and not srcLocked and not dstLocked then
+		ClearCursor()
+		PickupContainerItem(src.container, src.position)
+		PickupContainerItem(dst.container, dst.position)
+
+		if src.item == dst.item then
+			local count = min(src.count, itemStacks[dst.item] - dst.count)
+			src.count = src.count - count
+			dst.count = dst.count + count
+			if src.count == 0 then
+				src.item = nil
+			end
+		else
+			src.item, dst.item = dst.item, src.item
+			src.count, dst.count = dst.count, src.count
+		end
+
+		coroutine.yield()
+		return true
+	end
+end
+
+do
+	local patterns = {}
+	for i = 1, 10 do
+		local text = gsub(format(ITEM_SPELL_CHARGES, i), '(-?%d+)(.-)|4([^;]-);', function(numberString, gap, numberForms)
+			local singular, dual, plural
+			_, _, singular, dual, plural = strfind(numberForms, '(.+):(.+):(.+)');
+			if not singular then
+				_, _, singular, plural = strfind(numberForms, '(.+):(.+)')
+			end
+			local i = abs(tonumber(numberString))
+			local numberForm
+			if i == 1 then
+				numberForm = singular
+			elseif i == 2 then
+				numberForm = dual or plural
+			else
+				numberForm = plural
+			end
+			return numberString .. gap .. numberForm
+		end)
+		patterns[text] = i
+	end
+
+	function itemCharges(text)
+		return patterns[text]
+	end
+end
+
+function TooltipInfo(container, position)
+	SetScanTooltip(container, position)
+
+	local charges, usable, soulbound, quest, conjured, mount
+	for i = 1, SortBagsTooltip:NumLines() do
+		local text = getglobal('SortBagsTooltipTextLeft' .. i):GetText()
+
+		local extractedCharges = itemCharges(text)
+		if extractedCharges then
+			charges = extractedCharges
+		elseif strfind(text, '^' .. ITEM_SPELL_TRIGGER_ONUSE) then
+			usable = true
+		elseif text == ITEM_SOULBOUND then
+			soulbound = true
+		elseif text == ITEM_BIND_QUEST then -- TODO retail can maybe use GetItemInfo bind info instead
+			quest = true
+		elseif text == ITEM_CONJURED then
+			conjured = true
+		elseif text == MOUNT then
+			mount = true
+		end
+	end
+
+	return charges or 1, usable, soulbound, quest, conjured, mount
+end
+
+function SetScanTooltip(container, position)
+	SortBagsTooltip:SetOwner(UIParent, 'ANCHOR_NONE')
+	SortBagsTooltip:ClearLines()
+
+	if container == BANK_CONTAINER then
+		SortBagsTooltip:SetInventoryItem('player', BankButtonIDToInvSlotID(position))
+	else
+		SortBagsTooltip:SetBagItem(container, position)
+	end
+end
+
+function Sort()
+	local complete, moved
+	repeat
+		complete, moved = true, false
+		for _, dst in ipairs(model) do
+			if dst.targetItem and (dst.item ~= dst.targetItem or dst.count < dst.targetCount) then
+				complete = false
+
+				local sources, rank = {}, {}
+
+				for _, src in ipairs(model) do
+					if src.item == dst.targetItem
+						and src ~= dst
+						and not (dst.item and src.class and src.class ~= itemClasses[dst.item])
+						and not (src.targetItem and src.item == src.targetItem and src.count <= src.targetCount)
+					then
+						rank[src] = abs(src.count - dst.targetCount + (dst.item == dst.targetItem and dst.count or 0))
+						tinsert(sources, src)
+					end
+				end
+
+				sort(sources, function(a, b) return rank[a] < rank[b] end)
+
+				for _, src in ipairs(sources) do
+					if Move(src, dst) then
+						moved = true
+						break
+					end
+				end
+			end
+		end
+	until complete or not moved
+	return complete
+end
+
+function Stack()
+	for _, src in ipairs(model) do
+		if src.item and src.count < itemStacks[src.item] and src.item ~= src.targetItem then
+			for _, dst in ipairs(model) do
+				if dst ~= src and dst.item and dst.item == src.item and dst.count < itemStacks[dst.item] and dst.item ~= dst.targetItem then
+					if Move(src, dst) then
+						return
+					end
+				end
+			end
+		end
+	end
+end
+
+do
+	local counts
+
+	local function insert(t, v)
+		if SortBagsRightToLeft then
+			tinsert(t, v)
+		else
+			tinsert(t, 1, v)
+		end
+	end
+
+	local function assign(slot, item)
+		if counts[item] > 0 then
+			local count
+			if SortBagsRightToLeft and mod(counts[item], itemStacks[item]) ~= 0 then
+				count = mod(counts[item], itemStacks[item])
+			else
+				count = min(counts[item], itemStacks[item])
+			end
+			slot.targetItem = item
+			slot.targetCount = count
+			counts[item] = counts[item] - count
+			return true
+		end
+	end
+
+	function Initialize()
+		model, counts, itemStacks, itemClasses, itemSortKeys = {}, {}, {}, {}, {}
+
+		for _, container in ipairs(CONTAINERS) do
+			local class = ContainerClass(container)
+			for position = 1, GetContainerNumSlots(container) do
+				local slot = {container=container, position=position, class=class}
+				local item = Item(container, position)
+				if item then
+					local _, count, locked = GetContainerItemInfo(container, position)
+					if locked then
+						return false
+					end
+					slot.item = item
+					slot.count = count
+					counts[item] = (counts[item] or 0) + count
+				end
+				insert(model, slot)
+			end
+		end
+
+		local free = {}
+		for item, count in pairs(counts) do
+			local stacks = ceil(count / itemStacks[item])
+			free[item] = stacks
+			if itemClasses[item] then
+				free[itemClasses[item]] = (free[itemClasses[item]] or 0) + stacks
+			end
+		end
+		for _, slot in ipairs(model) do
+			if slot.class and free[slot.class] then
+				free[slot.class] = free[slot.class] - 1
+			end
+		end
+
+		local items = {}
+		for item in pairs(counts) do
+			tinsert(items, item)
+		end
+		sort(items, function(a, b) return LT(itemSortKeys[a], itemSortKeys[b]) end)
+
+		for _, slot in ipairs(model) do
+			if slot.class then
+				for _, item in ipairs(items) do
+					if itemClasses[item] == slot.class and assign(slot, item) then
+						break
+					end
+				end
+			else
+				for _, item in ipairs(items) do
+					if (not itemClasses[item] or free[itemClasses[item]] > 0) and assign(slot, item) then
+						if itemClasses[item] then
+							free[itemClasses[item]] = free[itemClasses[item]] - 1
+						end
+						break
+					end
+				end
+			end
+		end
+		return true
+	end
+end
+
+function ContainerClass(container)
+	if container ~= 0 and container ~= BANK_CONTAINER then
+		local name = GetBagName(container)
+		if name then
+			for class, info in pairs(CLASSES) do
+				for _, itemID in pairs(info.containers) do
+					if name == GetItemInfo(itemID) then
+						return class
+					end
+				end
+			end
+		end
+	end
+end
+
+function Item(container, position)
+	local link = GetContainerItemLink(container, position)
+	if link then
+		local _, _, itemID, enchantID, suffixID, uniqueID = strfind(link, 'item:(%d+):(%d*):%d*:%d*:%d*:%d*:(%-?%d*):(%-?%d*)')
+		itemID = tonumber(itemID)
+		local itemName, _, quality, _, _, _, _, stack, slot, _, sellPrice, classId, subClassId = GetItemInfo('item:' .. itemID)
+		local charges, usable, soulbound, quest, conjured, mount = TooltipInfo(container, position)
+		local sortKey = {}
+
+		-- hearthstone
+		if itemID == 6948 or itemID == 184871 then
+			tinsert(sortKey, 1)
+
+		-- mounts
+		elseif mount then
+			tinsert(sortKey, 2)
+
+		-- special items
+		elseif SPECIAL[itemID] then
+			tinsert(sortKey, 3)
+
+		-- key items
+		elseif KEYS[itemID] then
+			tinsert(sortKey, 4)
+
+		-- tools
+		elseif TOOLS[itemID] then
+			tinsert(sortKey, 5)
+
+		-- soul shards
+		elseif itemID == 6265 then
+			tinsert(sortKey, 13)
+
+		-- conjured items
+		elseif conjured then
+			tinsert(sortKey, 14)
+
+		-- soulbound items
+		elseif soulbound then
+			tinsert(sortKey, 6)
+
+		-- reagents
+		elseif classId == 9 then
+			tinsert(sortKey, 7)
+
+		-- quest items
+		elseif quest then
+			tinsert(sortKey, 9)
+
+		-- consumables
+		elseif usable and classId ~= 1 and classId ~= 2 and classId ~= 8 or classId == 4 then
+			tinsert(sortKey, 8)
+
+		-- higher quality
+		elseif quality > 1 then
+			tinsert(sortKey, 10)
+
+		-- common quality
+		elseif quality == 1 then
+			tinsert(sortKey, 11)
+			tinsert(sortKey, -sellPrice)
+
+		-- junk
+		elseif quality == 0 then
+			tinsert(sortKey, 12)
+			tinsert(sortKey, sellPrice)
+		end
+
+		tinsert(sortKey, classId)
+		tinsert(sortKey, slot)
+		tinsert(sortKey, subClassId)
+		tinsert(sortKey, -quality)
+		tinsert(sortKey, itemName)
+		tinsert(sortKey, itemID)
+		tinsert(sortKey, (SortBagsRightToLeft and 1 or -1) * charges)
+		tinsert(sortKey, suffixID)
+		tinsert(sortKey, enchantID)
+		tinsert(sortKey, uniqueID)
+
+		local key = format('%s:%s:%s:%s:%s:%s', itemID, enchantID, suffixID, uniqueID, charges, (soulbound and 1 or 0))
+
+		itemStacks[key] = stack
+		itemSortKeys[key] = sortKey
+
+		for class, info in pairs(CLASSES) do
+			if info.items[itemID] then
+				itemClasses[key] = class
+				break
+			end
+		end
+
+		return key
+	end
+end
diff --git a/rBag/rBag.toc b/rBag/rBag.toc
new file mode 100644
index 0000000..f8d5279
--- /dev/null
+++ b/rBag/rBag.toc
@@ -0,0 +1,12 @@
+## Interface: 20501
+## Author: rawoil
+## Title: rBag |cff1a9fc0BCC|r
+## Notes: Inventory enhancements
+## RequiredDeps: rLib, rButtonTemplate_Zork
+
+libs/SortBags.lua
+
+init.lua
+functions.lua
+core.lua
+setup.lua
\ No newline at end of file
diff --git a/rBag/setup.lua b/rBag/setup.lua
new file mode 100644
index 0000000..cbb41b2
--- /dev/null
+++ b/rBag/setup.lua
@@ -0,0 +1,13 @@
+local A, L = ...
+
+local frame = CreateFrame("Frame")
+
+local function OnEvent(event)
+    rBag.Bags:Enable()
+
+    --create slash commands
+    rLib:CreateSlashCmd(L.addonName, L.addonShortcut, L.dragFrames, L.addonColor)
+end
+
+frame:RegisterEvent("PLAYER_LOGIN")
+frame:SetScript("OnEvent", OnEvent)
\ No newline at end of file
diff --git a/rButtonTemplate/core.lua b/rButtonTemplate/core.lua
index 41ce298..df4ffc1 100644
--- a/rButtonTemplate/core.lua
+++ b/rButtonTemplate/core.lua
@@ -164,6 +164,7 @@ local function SetupBackdrop(button,backdrop)
   if backdrop.borderColor then
     bg:SetBackdropBorderColor(unpack(backdrop.borderColor))
   end
+  return bg
 end

 local function FormatHotkey(hotkey)
@@ -326,7 +327,7 @@ function rButtonTemplate:StyleItemButton(button,cfg)
   if button.GetCheckedTexture then checkedTexture = button:GetCheckedTexture() end

   --backdrop
-  SetupBackdrop(button,cfg.backdrop)
+  button.Backdrop = SetupBackdrop(button,cfg.backdrop)

   --textures
   SetupTexture(icon,cfg.icon,"SetTexture",icon)
diff --git a/rButtonTemplate_Zork/theme.lua b/rButtonTemplate_Zork/theme.lua
index cfcddc1..add0c7b 100644
--- a/rButtonTemplate_Zork/theme.lua
+++ b/rButtonTemplate_Zork/theme.lua
@@ -160,7 +160,7 @@ local itemButtonConfig = {}
 itemButtonConfig.backdrop = copyTable(actionButtonConfig.backdrop)
 itemButtonConfig.icon = copyTable(actionButtonConfig.icon)
 itemButtonConfig.count = copyTable(actionButtonConfig.count)
-itemButtonConfig.stock = copyTable(actionButtonConfig.name)
+itemButtonConfig.stock = copyTable(actionButtonConfig.hotkey)
 itemButtonConfig.stock.alpha = 1
 itemButtonConfig.border = copyTable(actionButtonConfig.border)
 itemButtonConfig.normalTexture = copyTable(actionButtonConfig.normalTexture)
@@ -171,6 +171,18 @@ for i, button in next, itemButtons do
   rButtonTemplate:StyleItemButton(button, itemButtonConfig)
 end

+--make item config global for rBag
+rButtonTemplate_Zork_SlotButtonConfig = itemButtonConfig
+rButtonTemplate_Zork_SlotButtonConfig.backdrop.points = {
+  {"TOPLEFT", 0, 0 },
+  {"BOTTOMRIGHT", 0, 0 },
+}
+rButtonTemplate_Zork_SlotButtonConfig.backdrop.edgeSize = 1
+rButtonTemplate_Zork_SlotButtonConfig.backdrop.insets = {left = 0,right = 0,top = 0,bottom = 0}
+rButtonTemplate_Zork_SlotButtonConfig.border.alpha = 0
+rButtonTemplate_Zork_SlotButtonConfig.normalTexture.file = ""
+rButtonTemplate_Zork_SlotButtonConfig.pushedTexture = {file = ""}
+
 -----------------------------
 -- extraButtonConfig
 -----------------------------
@@ -211,22 +223,4 @@ debuffButtonConfig.count.font = { fontExpressway, 12.5, "OUTLINE"}
 debuffButtonConfig.duration.font = { fontExpressway, 12.5, "OUTLINE"}

 --rButtonTemplate:StyleDebuffButtons
-rButtonTemplate:StyleDebuffButtons(debuffButtonConfig)
-
------------------------------
--- bagButtonConfig
------------------------------
-
-local bagButtonConfig = copyTable(auraButtonConfig)
---change the backdrop a bit
-bagButtonConfig.backdrop.bgFile = "Interface\\Buttons\\WHITE8x8"
-bagButtonConfig.backdrop.edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border"
-bagButtonConfig.backdrop.tileSize = 16
-bagButtonConfig.backdrop.edgeSize = 16
-bagButtonConfig.backdrop.insets = {left=3,right=3,top=3,bottom=3}
-bagButtonConfig.backdrop.backgroundColor = {0.08,0.08,0.1,0.92}
-bagButtonConfig.backdrop.borderColor = {0.1,0.1,0.1,0.6}
-
---rButtonTemplate:StyleAllSlotButtons
--- rButtonTemplate:StyleAllSlotButtons(bagButtonConfig)
-rButtonTemplate_Zork_SlotButtonConfig = bagButtonConfig
\ No newline at end of file
+rButtonTemplate:StyleDebuffButtons(debuffButtonConfig)
\ No newline at end of file