Quantcast

Major refactor in progress

Brandon Talbot [07-18-16 - 19:01]
Major refactor in progress

* Adding locale
* Fixing setting to not lag
* Adding better tooling for efficiency
* Getting layout formatters working
* TODO: Bank, linking to UI keybinding calls
Filename
DJBags.toc
src/lua/cache/cache.lua
src/lua/constants/contstants.lua
src/lua/controller/bag.lua
src/lua/controller/bank.lua
src/lua/controllers/bag.lua
src/lua/controllers/bank.lua
src/lua/core.lua
src/lua/element/bagItem.lua
src/lua/element/container.lua
src/lua/element/item.lua
src/lua/element/itemContainer.lua
src/lua/element/tooltip.lua
src/lua/elements/bagBar.lua
src/lua/elements/bagItem.lua
src/lua/elements/categoryContainer.lua
src/lua/elements/categoryDialog.lua
src/lua/elements/container.lua
src/lua/elements/item.lua
src/lua/elements/itemContainer.lua
src/lua/elements/mainBar.lua
src/lua/event/eventManager.lua
src/lua/events/events.lua
src/lua/formatters/horizontal.lua
src/lua/formatters/vertical.lua
src/lua/settings/defaults/auto.lua
src/lua/settings/defaults/bagItem.lua
src/lua/settings/defaults/category.lua
src/lua/settings/defaults/categoryContainer.lua
src/lua/settings/defaults/container.lua
src/lua/settings/defaults/formatter.lua
src/lua/settings/defaults/item.lua
src/lua/settings/defaults/itemContainer.lua
src/lua/settings/defaults/mainBar.lua
src/lua/settings/editor.lua
src/lua/settings/settings.lua
src/lua/settings/settingsController.lua
src/lua/settings/settingsElements.lua
src/lua/sorters/containers.lua
src/lua/sorters/items.lua
src/lua/tools/boxFormatter.lua
src/lua/tools/itemFormatter.lua
src/lua/tools/masonryFormatter.lua
src/lua/utils/utils.lua
src/manifest.xml
src/xml/element/bankBar.xml
src/xml/element/container.xml
src/xml/element/itemContainer.xml
src/xml/element/mainBar.xml
src/xml/element/tooltip.xml
src/xml/settings/colorPicker.xml
src/xml/settings/itemContainerSettings.xml
src/xml/settings/slider.xml
diff --git a/DJBags.toc b/DJBags.toc
index 306eddc..ac915cc 100644
--- a/DJBags.toc
+++ b/DJBags.toc
@@ -2,7 +2,7 @@
 ## Title: DJBags
 ## Author: DarkJaguar91
 ## Notes: BagAddon - BETA
-## Version: 0.5.1
-## SavedVariables: DJBagsConfig
+## Version: 0.6.0
+## SavedVariables: DJBags_DB

 src/manifest.xml
\ No newline at end of file
diff --git a/src/lua/cache/cache.lua b/src/lua/cache/cache.lua
index 8b79663..427e277 100644
--- a/src/lua/cache/cache.lua
+++ b/src/lua/cache/cache.lua
@@ -11,38 +11,22 @@ cache.reagentContainers = {}

 function cache:GetItem(bag, slot)
     self.items[bag] = self.items[bag] or {}
-    self.items[bag][slot] = self.items[bag][slot] or ADDON.item(bag, slot)
+    self.items[bag][slot] = self.items[bag][slot] or ADDON:NewItem(bag, slot)
     return self.items[bag][slot]
 end

-function cache:GetBagItemContainer(name)
-    self.bagContainers[name] = self.bagContainers[name] or ADDON.itemContainer(name, nil, nil, name == EMPTY)
-    return self.bagContainers[name]
-end
-
-function cache:GetBankItemContainer(name)
-    self.bankContainers[name] = self.bankContainers[name] or ADDON.itemContainer(name, nil, nil, name == EMPTY)
-    return self.bankContainers[name]
-end
-
-function cache:GetReagentItemContainer(name)
-    self.reagentContainers[name] = self.reagentContainers[name] or ADDON.itemContainer(name, nil, nil, name == EMPTY)
-    return self.reagentContainers[name]
-end
-
-function cache:UpdateSettings()
-    for _, slots in pairs(self.items) do
-        for _, item in pairs(slots) do
-            item:Setup()
-        end
-    end
-    for _, container in pairs(cache.bagContainers) do
-        container:Setup()
-    end
-    for _, container in pairs(cache.bankContainers) do
-        container:Setup()
-    end
-    for _, container in pairs(cache.reagentContainers) do
-        container:Setup()
+function cache:GetItemContainer(bag, name)
+    if bag == BANK_CONTAINER or bag > NUM_BAG_SLOTS then
+        self.bankContainers[name] = self.bankContainers[name] or ADDON:NewItemContainer(name)
+        DJBagsBankContainer:AddItem(self.bankContainers[name])
+        return self.bankContainers[name]
+    elseif bag == REAGENTBANK_CONTAINER then
+        self.reagentContainers[name] = self.reagentContainers[name] or ADDON:NewItemContainer(name)
+        DJBagsReagentContainer:AddItem(self.reagentContainers[name])
+        return self.reagentContainers[name]
+    else
+        self.bagContainers[name] = self.bagContainers[name] or ADDON:NewItemContainer(name)
+        DJBagsBagContainer:AddItem(self.bagContainers[name])
+        return self.bagContainers[name]
     end
 end
\ No newline at end of file
diff --git a/src/lua/constants/contstants.lua b/src/lua/constants/contstants.lua
new file mode 100644
index 0000000..d64348c
--- /dev/null
+++ b/src/lua/constants/contstants.lua
@@ -0,0 +1,47 @@
+local NAME, ADDON = ...
+
+--region Types
+
+DJBags_TYPE_CONTAINER = 'container'
+DJBags_TYPE_ITEM_CONTAINER = 'itemContainer'
+
+--endregion
+
+--region Settings
+
+DJBags_SETTING_BACKGROUND_COLOR = 'djbags_background_color'
+DJBags_SETTING_BORDER_COLOR = 'djbags_border_color'
+DJBags_SETTING_TEXT_COLOR = 'djbags_text_color'
+DJBags_SETTING_PADDING = 'djbags_padding'
+DJBags_SETTING_SPACING = 'djbags_spacing'
+DJBags_SETTING_SCALE = 'djbags_scale'
+DJBags_SETTING_FORMATTER = 'djbags_formatter'
+DJBags_SETTING_FORMATTER_VERT = 'djbags_formatter_vert'
+DJBags_SETTING_FORMATTER_MAX_ITEMS = 'djbags_formatter_max_items'
+DJBags_SETTING_FORMATTER_MAX_HEIGHT = 'djbags_formatter_max_height'
+DJBags_SETTING_TRUNCATE_SUB_CLASS = 'djbags_truncate_sub_class'
+DJBags_SETTING_TEXT_SIZE = 'djbags_truncate_text_size'
+
+--endregion
+
+--region Locale
+
+local localeText= {}
+localeText['enUS'] = function()
+    DJBags_LOCALE_ITEM_CONTAINER_SETTINGS = 'Item Container Settings:'
+    DJBags_LOCALE_CLEAR_NEW_ITEMS = 'Clear new items'
+    DJBags_LOCALE_BACKGROUND_COLOR = 'Background color'
+    DJBags_LOCALE_BORDER_COLOR = 'Border color'
+    DJBags_LOCALE_TEXT_COLOR = 'Text color'
+    DJBags_LOCALE_PADDING = 'Padding'
+    DJBags_LOCALE_SPACING = 'Spacing'
+    DJBags_LOCALE_TEXT_SIZE = 'Text size'
+end
+
+if localeText[GetLocale()] then
+    localeText[GetLocale()]()
+else
+    localeText['enUS']()
+end
+
+--endregion
\ No newline at end of file
diff --git a/src/lua/controller/bag.lua b/src/lua/controller/bag.lua
new file mode 100644
index 0000000..b19dbb4
--- /dev/null
+++ b/src/lua/controller/bag.lua
@@ -0,0 +1,147 @@
+local NAME, ADDON = ...
+
+ADDON.bagController = {}
+ADDON.bagController.__index = ADDON.bagController
+
+local controller = ADDON.bagController
+
+function controller:Init()
+    ADDON.events:Add('MERCHANT_SHOW', self)
+end
+
+function DJBagsBagContainer_OnShow()
+    ADDON.events:Add('INVENTORY_SEARCH_UPDATE', controller)
+    ADDON.events:Add('BAG_UPDATE', controller)
+    ADDON.events:Add('BAG_UPDATE_COOLDOWN', controller)
+    ADDON.events:Add('ITEM_LOCK_CHANGED', controller)
+    ADDON.events:Add('BAG_UPDATE_DELAYED', controller)
+    ADDON.events:Add('DJBAGS_BAG_HOVER', controller)
+end
+
+function DJBagsBagContainer_OnHide()
+    ADDON.events:Remove('INVENTORY_SEARCH_UPDATE', controller)
+    ADDON.events:Remove('BAG_UPDATE', controller)
+    ADDON.events:Remove('BAG_UPDATE_COOLDOWN', controller)
+    ADDON.events:Remove('ITEM_LOCK_CHANGED', controller)
+    ADDON.events:Remove('BAG_UPDATE_DELAYED', controller)
+    ADDON.events:Remove('DJBAGS_BAG_HOVER', controller)
+end
+
+function DJDBagsBagsButton_OnClick(self)
+    if self:GetChecked() then
+        controller:ShowBagBar()
+    else
+        controller:HideBagBar()
+    end
+end
+
+function controller:Open()
+    ADDON:UpdateBags({0, 1, 2, 3, 4})
+    DJBagsBagContainer:Arrange()
+    DJBagsBagContainer:Show()
+end
+
+function controller:Close()
+
+end
+
+function controller:BAG_UPDATE(bag)
+    ADDON:UpdateBags({bag})
+    DJBagsBagContainer:Arrange()
+end
+
+function controller:MERCHANT_SHOW()
+    local price = 0
+    for bag = 0, NUM_BAG_SLOTS do
+        for slot = 1 , GetContainerNumSlots(bag) do
+            if select(4, GetContainerItemInfo(bag, slot)) == LE_ITEM_QUALITY_POOR then
+                ShowMerchantSellCursor(1)
+                UseContainerItem(bag, slot)
+                price = price + select(11, GetItemInfo(GetContainerItemID(bag, slot)))
+            end
+        end
+    end
+    ResetCursor()
+    if price ~= 0 then
+        DEFAULT_CHAT_FRAME:AddMessage("Sold junk for: " .. GetCoinTextureString(price))
+    end
+end
+
+function controller:INVENTORY_SEARCH_UPDATE()
+    for bag = 0, NUM_BAG_SLOTS do
+        for slot = 1, GetContainerNumSlots(bag) do
+            ADDON.cache:GetItem(bag, slot):UpdateSearch()
+        end
+    end
+end
+
+function controller:BAG_UPDATE_COOLDOWN()
+    for bag = 0, NUM_BAG_SLOTS do
+        for slot = 1, GetContainerNumSlots(bag) do
+            ADDON.cache:GetItem(bag, slot):UpdateCooldown()
+        end
+    end
+end
+
+function controller:ITEM_LOCK_CHANGED(bag, slot)
+    if bag then
+        if bag >= 0 and bag <= NUM_BAG_SLOTS and slot then
+            ADDON.cache:GetItem(bag, slot):UpdateLock()
+        end
+        if DJBagsBagContainer.mainBar.bagBar and DJBagsBagContainer.mainBar.bagBar.bags[bag] then
+            DJBagsBagContainer.mainBar.bagBar.bags[bag]:UpdateLock()
+        end
+    end
+end
+
+function controller:DJBAGS_BAG_HOVER(bag, locked)
+    if bag and bag >= 0 and bag <= NUM_BAG_SLOTS then
+        for bagSlot = 0, NUM_BAG_SLOTS do
+            if bagSlot ~= bag then
+                for slot = 1, GetContainerNumSlots(bagSlot) do
+                    ADDON.cache:GetItem(bagSlot, slot):SetFiltered(locked)
+                end
+            end
+        end
+    end
+end
+
+function controller:BAG_UPDATE_DELAYED()
+    if DJBagsBagContainer.mainBar.bagBar then
+        for _, bagItem in pairs(DJBagsBagContainer.mainBar.bagBar.bags) do
+            bagItem:Update()
+        end
+    end
+end
+
+function controller:ShowBagBar()
+    self:GetBagBar():Show()
+end
+
+function controller:HideBagBar()
+    self:GetBagBar():Hide()
+end
+
+function controller:GetBagBar()
+    if not DJBagsBagContainer.mainBar.bagBar then
+        local bagBar = CreateFrame('Frame', 'DJBagsBagBar', DJBagsBagContainer.mainBar, 'DJBagsContainerTemplate')
+        bagBar.bags = {}
+
+        local prevBag
+        for bag = 1, NUM_BAG_SLOTS do
+            local bagItem = ADDON:NewBagItem('DJBagsBag_' .. bag, bag, GetInventorySlotInfo("Bag" .. (bag-1) .. "Slot"))
+            bagItem:SetParent(bagBar.container)
+            bagItem:SetPoint('TOPRIGHT', prevBag or bagBar.container, prevBag and 'TOPLEFT' or 'TOPRIGHT', prevBag and -5 or 0, 0)
+            bagItem:Update()
+            bagItem:Show()
+            prevBag = bagItem
+            bagBar.bags[bagItem:GetID()] = bagItem
+        end
+
+        bagBar:SetSize((prevBag:GetWidth() + 5) * NUM_BAG_SLOTS - 5 + bagBar.padding * 2, prevBag:GetHeight() + bagBar.padding * 2)
+        bagBar:SetPoint('TOPRIGHT', DJBagsBagContainer.mainBar, 'BOTTOMRIGHT', 0, -5)
+
+        DJBagsBagContainer.mainBar.bagBar = bagBar
+    end
+    return DJBagsBagContainer.mainBar.bagBar
+end
\ No newline at end of file
diff --git a/src/lua/controller/bank.lua b/src/lua/controller/bank.lua
new file mode 100644
index 0000000..5825d60
--- /dev/null
+++ b/src/lua/controller/bank.lua
@@ -0,0 +1,8 @@
+--
+-- Created by IntelliJ IDEA.
+-- User: bjtal
+-- Date: 2016/07/17
+-- Time: 8:38 AM
+-- To change this template use File | Settings | File Templates.
+--
+
diff --git a/src/lua/controllers/bag.lua b/src/lua/controllers/bag.lua
deleted file mode 100644
index 43ca673..0000000
--- a/src/lua/controllers/bag.lua
+++ /dev/null
@@ -1,164 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.bag = {}
-ADDON.bag.__index = ADDON.bag
-
-local bag = ADDON.bag
-
-function bag:Init()
-    self.frame = ADDON.categoryContainer('DJBagsBagCategoryContainer', UIParent)
-    self.frame:SetPoint('BOTTOMRIGHT', -200, 200)
-    self.frame:SetUserPlaced(true)
-    self.frame:Hide()
-    self.frame.mainBar = ADDON.mainBar(self.frame)
-    self.frame.mainBar:SetPoint('TOPRIGHT', self.frame, 'BOTTOMRIGHT', 0, -2)
-    self.frame.mainBar:Show()
-    self.frame.bagBar = ADDON.bagBar(self.frame)
-    self.frame.bagBar:SetPoint('TOPRIGHT', self.frame.mainBar, 'BOTTOMRIGHT', 0, -3)
-    self.frame.mainBar:SetBagFrame(self.frame.bagBar)
-
-    self.frame:HookScript('OnShow', function()
-        self:Register()
-    end)
-    self.frame:HookScript('OnHide', function()
-        self:UnRegister()
-        if ADDON.settings.auto.clearNewItems then
-            C_NewItems.ClearAll()
-        end
-    end)
-
-    ADDON.eventManager:AddEvent(self, 'MERCHANT_SHOW')
-end
-
-function bag:MERCHANT_SHOW()
-    if ADDON.settings.auto.sellJunk then
-        local price = 0
-        for bag = 0, NUM_BAG_SLOTS do
-            for slot = 1 , GetContainerNumSlots(bag) do
-                if select(4, GetContainerItemInfo(bag, slot)) == LE_ITEM_QUALITY_POOR then
-                    ShowMerchantSellCursor(1)
-                    UseContainerItem(bag, slot)
-                    price = price + select(11, GetItemInfo(GetContainerItemID(bag, slot)))
-                end
-            end
-        end
-        ResetCursor()
-        DEFAULT_CHAT_FRAME:AddMessage("Sold junk for: " .. GetCoinTextureString(price))
-    end
-end
-
-function bag:Open()
-    self:UpdateAllItems()
-    self.frame.mainBar:Update()
-    self.frame.bagBar:Update()
-    self.frame:Show()
-end
-
-function bag:Close()
-    self.frame:Hide()
-end
-
-function bag:Toggle()
-    if self.frame:IsVisible() then
-        self:Close()
-    else
-        self:Open()
-    end
-end
-
-function bag:NewItemsUpdated()
-    if self.frame:IsVisible() then
-        self:UpdateAllItems()
-    end
-end
-
-function bag:UpdateAllItems()
-    for bag = 0, NUM_BAG_SLOTS do
-        ADDON.utils:UpdateItemsForBag(self.frame, bag, ADDON.cache.GetBagItemContainer)
-    end
-    self:CheckForRemovedItems()
-    self.frame:Arrange()
-end
-
-function bag:UpdateAllItemsForBag(bag)
-    ADDON.utils:UpdateItemsForBag(self.frame, bag, ADDON.cache.GetBagItemContainer)
-    self:CheckForRemovedItems()
-    self.frame:Arrange()
-end
-
-function bag:Register()
-    ADDON.eventManager:AddEvent(self, 'INVENTORY_SEARCH_UPDATE')
-    ADDON.eventManager:AddEvent(self, 'BAG_UPDATE')
-    ADDON.eventManager:AddEvent(self, 'BAG_UPDATE_COOLDOWN')
-    ADDON.eventManager:AddEvent(self, 'ITEM_LOCK_CHANGED')
-    ADDON.eventManager:AddEvent(self, 'PLAYER_MONEY')
-    ADDON.eventManager:AddEvent(self, 'BAG_UPDATE_DELAYED')
-end
-
-function bag:UnRegister()
-    ADDON.eventManager:RemoveEvent(self, 'INVENTORY_SEARCH_UPDATE')
-    ADDON.eventManager:RemoveEvent(self, 'BAG_UPDATE')
-    ADDON.eventManager:RemoveEvent(self, 'BAG_UPDATE_COOLDOWN')
-    ADDON.eventManager:RemoveEvent(self, 'ITEM_LOCK_CHANGED')
-    ADDON.eventManager:RemoveEvent(self, 'PLAYER_MONEY')
-    ADDON.eventManager:RemoveEvent(self, 'BAG_UPDATE_DELAYED')
-end
-
-function bag:UpdateSettings(arrange)
-    self.frame:Setup()
-    self.frame.mainBar:Setup()
-    self.frame.mainBar:Update()
-    self.frame.bagBar:Setup()
-    if self.frame:IsVisible() and arrange then
-        self:Open()
-    end
-end
-
-function bag:PLAYER_MONEY()
-    self.frame.mainBar:Update()
-end
-
-function bag:BAG_UPDATE(bag)
-    if bag >= 0 and bag <= NUM_BAG_SLOTS then
-        self:UpdateAllItemsForBag(bag)
-    end
-end
-
-function bag:INVENTORY_SEARCH_UPDATE()
-    for bag = 0, NUM_BAG_SLOTS do
-        for slot = 1, GetContainerNumSlots(bag) do
-            local item = ADDON.cache:GetItem(bag, slot)
-            item:UpdateSearch()
-        end
-    end
-end
-
-function bag:BAG_UPDATE_COOLDOWN()
-    for bag = 0, NUM_BAG_SLOTS do
-        for slot = 1, GetContainerNumSlots(bag) do
-            local item = ADDON.cache:GetItem(bag, slot)
-            item:UpdateCooldown()
-        end
-    end
-end
-
-function bag:ITEM_LOCK_CHANGED(bag, slot)
-    if bag then
-        if bag >= 0 and bag <= NUM_BAG_SLOTS and slot then
-            ADDON.cache:GetItem(bag, slot):UpdateLock()
-        end
-        self.frame.bagBar:UpdateLock(bag)
-    end
-end
-
-function bag:BAG_UPDATE_DELAYED()
-    self.frame.bagBar:Update()
-end
-
-function bag:CheckForRemovedItems()
-    for bag = 1, NUM_BAG_SLOTS do
-        if GetContainerNumSlots(bag) == 0 and ADDON.cache.items[bag] then
-            ADDON.utils:UpdateItemsForBag(self.frame, bag, ADDON.cache.GetBagItemContainer)
-        end
-    end
-end
\ No newline at end of file
diff --git a/src/lua/controllers/bank.lua b/src/lua/controllers/bank.lua
deleted file mode 100644
index 732648c..0000000
--- a/src/lua/controllers/bank.lua
+++ /dev/null
@@ -1,324 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.bank = {}
-ADDON.bank.__index = ADDON.bank
-
-local bank = ADDON.bank
-
-function bank:Init()
-    self.frame = ADDON.container('DJBagsBankMainBar')
-    self:InitMainBar()
-
-    self.bankContainer = ADDON.categoryContainer('DJBagsBankCategoryContainer', self.frame)
-    self.bankContainer:SetPoint('TOPLEFT', self.frame, 'BOTTOMLEFT', 0, -5)
-    self.bankContainer:SetScript("OnDragStart", function(_, ...)
-        self.frame:StartMoving(...)
-    end)
-    self.bankContainer:SetScript("OnDragStop", function(_, ...)
-        self.frame:StopMovingOrSizing(...)
-    end)
-
-    self.reagentContainer = ADDON.categoryContainer('DJBagsReagentBankCategoryContainer', self.frame)
-    self.reagentContainer:SetSize(10, 10)
-    self.reagentContainer:SetPoint('TOPLEFT', self.frame, 'BOTTOMLEFT', 0, -34)
-    self.reagentContainer:SetScript("OnDragStart", function(_, ...)
-        self.frame:StartMoving(...)
-    end)
-    self.reagentContainer:SetScript("OnDragStop", function(_, ...)
-        self.frame:StopMovingOrSizing(...)
-    end)
-    self.reagentButton = CreateFrame('BUTTON', 'DJBagsBankBarReagentDepositButton', self.reagentContainer, 'UIPanelButtonTemplate')
-    self.reagentButton:SetScript('OnClick', bank.ReagentButtonClick)
-    self.reagentButton:SetHeight(24)
-    self.reagentButton:SetPoint('BOTTOMLEFT', self.reagentContainer, 'TOPLEFT', 0, 5)
-
-    self.frame:HookScript('OnShow', self.OnShow)
-    self.frame:HookScript('OnHide', self.OnHide)
-
-    ADDON.eventManager:AddEvent(self, "BANKFRAME_OPENED")
-    ADDON.eventManager:AddEvent(self, "BANKFRAME_CLOSED")
-    BankFrame:UnregisterAllEvents()
-end
-
-function bank:UpdateSettings(arrange)
-    self.frame:Setup()
-    self.bankContainer:Setup()
-    self.reagentContainer:Setup()
-    if self.frame:IsVisible() and arrange then
-        self:UpdateAllItems()
-    end
-end
-
-function bank:BANKFRAME_OPENED()
-    self.frame:Show()
-end
-
-function bank:BANKFRAME_CLOSED()
-    self.frame:Hide()
-end
-
-function bank:ReagentButtonClick()
-    if IsReagentBankUnlocked() then
-        PlaySound("igMainMenuOption");
-        DepositReagentBank();
-    else
-        PlaySound("igMainMenuOption");
-        StaticPopup_Show("CONFIRM_BUY_REAGENTBANK_TAB");
-    end
-end
-
-function bank:OnShow()
-    PlaySound("igMainMenuOpen")
-    ADDON.bag:Open()
-    bank:Register()
-    bank:UpdateAllItems()
-    bank:UpdateBags()
-    PanelTemplates_SetTab(self, 1)
-    bank.bankContainer:Show()
-    bank.reagentContainer:Hide()
-
-    if ADDON.settings.auto.depositReagents and IsReagentBankUnlocked() then
-        DepositReagentBank();
-    end
-end
-
-function bank:OnHide()
-    PlaySound("igMainMenuClose")
-    CloseAllBags(self);
-    CloseBankBagFrames();
-    CloseBankFrame();
-    StaticPopup_Hide("CONFIRM_BUY_BANK_SLOT")
-    bank:UnRegister()
-end
-
-function bank:UpdateAllItems()
-    ADDON.utils:UpdateItemsForBag(self.bankContainer, BANK_CONTAINER, ADDON.cache.GetBankItemContainer)
-    for bag = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + GetNumBankSlots() do
-        ADDON.utils:UpdateItemsForBag(self.bankContainer, bag, ADDON.cache.GetBankItemContainer)
-    end
-    self.bankContainer:Arrange()
-
-    self:UpdateReagentBank()
-end
-
-function bank:UpdateReagentBank()
-    if IsReagentBankUnlocked() then
-        ADDON.utils:UpdateItemsForBag(self.reagentContainer, REAGENTBANK_CONTAINER, ADDON.cache.GetReagentItemContainer)
-        self.reagentContainer:Arrange()
-        self.reagentButton:SetText(REAGENTBANK_DEPOSIT)
-        self.reagentButton:SetWidth(self.reagentButton:GetFontString():GetStringWidth() + 31)
-    else
-        self.reagentButton:SetText(BANKSLOTPURCHASE)
-        self.reagentButton:SetWidth(self.reagentButton:GetFontString():GetStringWidth() + 31)
-    end
-end
-
-function bank:UpdateAllItemsForBag(bag)
-    ADDON.utils:UpdateItemsForBag(self.bankContainer, bag, ADDON.cache.GetBankItemContainer)
-    self.bankContainer:Arrange()
-end
-
-function bank:Register()
-    ADDON.eventManager:AddEvent(self, 'PLAYERBANKSLOTS_CHANGED')
-    ADDON.eventManager:AddEvent(self, 'BAG_UPDATE')
-    ADDON.eventManager:AddEvent(self, 'INVENTORY_SEARCH_UPDATE')
-    ADDON.eventManager:AddEvent(self, 'BAG_UPDATE_COOLDOWN')
-    ADDON.eventManager:AddEvent(self, 'ITEM_LOCK_CHANGED')
-    ADDON.eventManager:AddEvent(self, 'PLAYERREAGENTBANKSLOTS_CHANGED')
-    ADDON.eventManager:AddEvent(self, 'PLAYERBANKBAGSLOTS_CHANGED')
-    ADDON.eventManager:AddEvent(self, 'REAGENTBANK_PURCHASED')
-    ADDON.eventManager:AddEvent(self, 'BAG_UPDATE_DELAYED')
-end
-
-function bank:UnRegister()
-    ADDON.eventManager:RemoveEvent(self, 'PLAYERBANKSLOTS_CHANGED')
-    ADDON.eventManager:RemoveEvent(self, 'BAG_UPDATE')
-    ADDON.eventManager:RemoveEvent(self, 'INVENTORY_SEARCH_UPDATE')
-    ADDON.eventManager:RemoveEvent(self, 'BAG_UPDATE_COOLDOWN')
-    ADDON.eventManager:RemoveEvent(self, 'ITEM_LOCK_CHANGED')
-    ADDON.eventManager:RemoveEvent(self, 'PLAYERREAGENTBANKSLOTS_CHANGED')
-    ADDON.eventManager:RemoveEvent(self, 'PLAYERBANKBAGSLOTS_CHANGED')
-    ADDON.eventManager:RemoveEvent(self, 'REAGENTBANK_PURCHASED')
-    ADDON.eventManager:RemoveEvent(self, 'BAG_UPDATE_DELAYED')
-end
-
-function bank:PLAYERBANKBAGSLOTS_CHANGED()
-    self:UpdateBags()
-end
-
-function bank:BAG_UPDATE_DELAYED()
-    self:UpdateBags()
-end
-
-function bank:BAG_UPDATE(bag)
-    if bag > NUM_BAG_SLOTS then
-        self:UpdateAllItemsForBag(bag)
-    end
-end
-
-function bank:PLAYERBANKSLOTS_CHANGED(slot)
-    if slot <= NUM_BANKGENERIC_SLOTS then
-        self:UpdateAllItemsForBag(BANK_CONTAINER)
-    else
-        self.bags[slot-NUM_BANKGENERIC_SLOTS]:Update()
-    end
-end
-
-function bank:PLAYERREAGENTBANKSLOTS_CHANGED()
-    self:UpdateReagentBank()
-end
-
-function bank:REAGENTBANK_PURCHASED()
-    self:UpdateReagentBank()
-end
-
-function bank:INVENTORY_SEARCH_UPDATE()
-    for bag = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + GetNumBankSlots() do
-        for slot = 1, GetContainerNumSlots(bag) do
-            ADDON.cache:GetItem(bag, slot):UpdateSearch()
-        end
-    end
-    for slot = 1, GetContainerNumSlots(BANK_CONTAINER) do
-        ADDON.cache:GetItem(BANK_CONTAINER, slot):UpdateSearch()
-    end
-    if IsReagentBankUnlocked() then
-        for slot = 1, GetContainerNumSlots(REAGENTBANK_CONTAINER) do
-            ADDON.cache:GetItem(REAGENTBANK_CONTAINER, slot):UpdateSearch()
-        end
-    end
-end
-
-function bank:BAG_UPDATE_COOLDOWN()
-    for bag = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + GetNumBankSlots() do
-        for slot = 1, GetContainerNumSlots(bag) do
-            ADDON.cache:GetItem(bag, slot):UpdateCooldown()
-        end
-    end
-    for slot = 1, GetContainerNumSlots(BANK_CONTAINER) do
-        ADDON.cache:GetItem(BANK_CONTAINER, slot):UpdateCooldown()
-    end
-    if IsReagentBankUnlocked() then
-        for slot = 1, GetContainerNumSlots(REAGENTBANK_CONTAINER) do
-            ADDON.cache:GetItem(REAGENTBANK_CONTAINER, slot):UpdateCooldown()
-        end
-    end
-end
-
-function bank:ITEM_LOCK_CHANGED(bag, slot)
-    if bag ~= BANK_CONTAINER and bag ~= REAGENTBANK_CONTAINER and bag <= NUM_BAG_SLOTS then return end
-
-    if bag == BANK_CONTAINER and slot > NUM_BANKGENERIC_SLOTS then
-        self.bags[slot-NUM_BANKGENERIC_SLOTS]:UpdateLock()
-    elseif slot then
-        ADDON.cache:GetItem(bag, slot):UpdateLock()
-    end
-end
-
-function bank:InitMainBar()
-    table.insert(UISpecialFrames, self.frame:GetName())
-    self.frame:SetMovable(true)
-    self.frame:EnableMouse(true)
-    self.frame:RegisterForDrag("LeftButton")
-    self.frame:SetScript("OnDragStart", self.frame.StartMoving)
-    self.frame:SetScript("OnDragStop", self.frame.StopMovingOrSizing)
-    self.frame:SetPoint('TOPLEFT', 200, -100)
-    self.frame:SetUserPlaced(true)
-    self.frame:Hide()
-    self.bags = {}
-
-    self.emptyBag = CreateFrame('BUTTON', 'DJBagsBankEmptyContainer', self.frame)
-    self.emptyBag:SetBackdrop({
-        bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
-        edgeFile = "Interface\\Buttons\\WHITE8x8",
-        tile = true,
-        tileSize = 16,
-        edgeSize = 1,
-    })
-    self.emptyBag:SetBackdropBorderColor(1, 0, 0, 1)
-    self.emptyBag:SetBackdropColor(0, 0, 0, 0)
-    self.emptyBag.money = CreateFrame('Frame', 'DJBagsBankBagBost', self.emptyBag, 'SmallMoneyFrameTemplate')
-    self.emptyBag.money:SetPoint('CENTER', 6, 0)
-    self.emptyBag:SetPoint("TOPRIGHT", -5, -5)
-    self.emptyBag:SetScript('OnClick', function()
-        PlaySound("igMainMenuOption");
-        StaticPopup_Show("CONFIRM_BUY_BANK_SLOT");
-    end)
-    SmallMoneyFrame_OnLoad(self.emptyBag.money)
-    MoneyFrame_SetType(self.emptyBag.money, "STATIC")
-
-    self.searchBar = CreateFrame('EDITBOX', 'DJBagsBankSearch', self.frame, 'BagSearchBoxTemplate')
-    self.searchBar:SetPoint('BOTTOMLEFT', 10, 5)
-    self.searchBar:SetPoint('BOTTOMRIGHT', -5, 5)
-    self.searchBar:SetHeight(25)
-
-    self.bagBtn = CreateFrame('BUTTON', self.frame:GetName()..'Tab1', self.frame, 'TabButtonTemplate')
-    self.bagBtn.tab = 1
-    self.bagBtn:SetPoint('BOTTOMLEFT', self.frame, 'TOPLEFT')
-    self.bagBtn:SetText(BANK)
-    self.bagBtn:SetScript('OnClick', self.TabClick)
-    PanelTemplates_TabResize(self.bagBtn, 0)
-    _G[self.bagBtn:GetName().."HighlightTexture"]:SetWidth(self.bagBtn:GetTextWidth() + 31)
-
-    self.reagentBtn = CreateFrame('BUTTON', self.frame:GetName()..'Tab2', self.frame, 'TabButtonTemplate')
-    self.reagentBtn.tab = 2
-    self.reagentBtn:SetPoint('BOTTOMLEFT', self.bagBtn, 'BOTTOMRIGHT', 0, 0)
-    self.reagentBtn:SetText(REAGENT_BANK)
-    self.reagentBtn:SetScript('OnClick', self.TabClick)
-    PanelTemplates_TabResize(self.reagentBtn, 0)
-    _G[self.reagentBtn:GetName().."HighlightTexture"]:SetWidth(self.reagentBtn:GetTextWidth() + 31)
-    PanelTemplates_SetNumTabs(self.frame, 2)
-end
-
-function bank:TabClick()
-    PlaySound("igMainMenuOpen")
-    PanelTemplates_SetTab(self:GetParent(), self.tab)
-    if self.tab == 1 then
-        bank.bankContainer:Show()
-        bank.reagentContainer:Hide()
-    else
-        bank.bankContainer:Hide()
-        bank.reagentContainer:Show()
-    end
-end
-
-function bank:UpdateBags()
-    local numBankslots, full = GetNumBankSlots()
-    for bag = #self.bags+1, numBankslots do
-        local item = ADDON.bagItem('DJBagsBankBagItem' .. bag, NUM_BAG_SLOTS + bag, BankButtonIDToInvSlotID(bag, 1))
-        item:SetParent(self.frame)
-        tinsert(self.bags, item)
-    end
-
-    if not full then
-        self.emptyBag:Show()
-        local cost = GetBankSlotCost(numSlots);
-        BankFrame.nextSlotCost = cost;
-        if( GetMoney() >= cost ) then
-            SetMoneyFrameColor(self.emptyBag.money, "white");
-        else
-            SetMoneyFrameColor(self.emptyBag.money, "red")
-        end
-        MoneyFrame_Update(self.emptyBag.money, cost);
-    else
-        self.emptyBag:Hide()
-    end
-    self:ArrangeBags()
-end
-
-function bank:ArrangeBags()
-    local x = 5
-    local y = ADDON.settings.bagItem.size
-
-    for _, bag in pairs(self.bags) do
-        bag:Update()
-        bag:SetPoint('TOPLEFT', x, -5)
-        x = x + 5 + bag:GetWidth()
-    end
-
-    if self.emptyBag:IsVisible() then
-        self.emptyBag:SetSize(math.max(y, self.emptyBag.money:GetWidth() - 10), y)
-        x = x + 5 + self.emptyBag:GetWidth()
-    end
-
-    self.frame:SetSize(math.max(x, 175), y + 12 + self.searchBar:GetHeight())
-end
\ No newline at end of file
diff --git a/src/lua/core.lua b/src/lua/core.lua
index 33f35bf..b45c8d0 100644
--- a/src/lua/core.lua
+++ b/src/lua/core.lua
@@ -1,80 +1,24 @@
 local NAME, ADDON = ...

-ADDON.core = {}
-ADDON.core.__index = ADDON.core
-local core = ADDON.core
-
---region Events
+local core = {}

 function core:ADDON_LOADED(name)
     if name ~= NAME then return end

-    ADDON.settingsController:Init()
-
-    ADDON.bag:Init()
-    ADDON.bank:Init()
-
-    ADDON.eventManager:AddEvent(self, "SETTINGS_UPDATE")
-    ADDON.eventManager:RemoveEvent(self, 'ADDON_LOADED')
-end
+    ADDON.settings:Init()
+    ADDON.bagController:Init()

-function core:SETTINGS_UPDATE(arrange)
-    ADDON.cache:UpdateSettings(arrange)
-    ADDON.bag:UpdateSettings(arrange)
-    ADDON.bank:UpdateSettings(arrange)
-    ADDON.categoryDialog:Setup()
+    ADDON.events:Remove('ADDON_LOADED', self)
 end

-ADDON.eventManager:AddEvent(core, 'ADDON_LOADED')
-
---region Bag commands
-
-ToggleAllBags = function()
-    ADDON.bag:Toggle()
-end
-
-ToggleBag = function(id)
-    if id < 5 and id > -1 then
-        ADDON.bag:Toggle()
-    end
-end
-
-ToggleBackpack = function()
-    ADDON.bag:Toggle()
-end
-
-OpenAllBags = function()
-    ADDON.bag:Open()
-end
+ADDON.events:Add('ADDON_LOADED', core)

-OpenBackpack = function()
-    ADDON.bag:Open()
-end
-
-CloseAllBags = function()
-    ADDON.bag:Close()
-end
-
-CloseBackpack = function()
-    ADDON.bag:Close()
-end
-
---endregion
-
---region Slash Commands
-
-SLASH_DJBAGS1, SLASH_DJBAGS2 = '/db', '/djbags';
+SLASH_DJBAGS1 = '/djb';
 function SlashCmdList.DJBAGS(msg, editbox)
-    ADDON.settingsController:ShowSettings()
-end
-
-SLASH_TDJBAGS1, SLASH_TDJBAGS2 = '/tt', '/ttt';
-function SlashCmdList.TDJBAGS(msg, editbox)
+    ADDON.bagController:Open()
 end

-SLASH_RELOAD1 = '/rl'
-function SlashCmdList.RELOAD(msg, editbox)
+SLASH_RL1 = '/rl';
+function SlashCmdList.RL(msg, editbox)
     ReloadUI()
-end
-
---endregion
\ No newline at end of file
+end
\ No newline at end of file
diff --git a/src/lua/element/bagItem.lua b/src/lua/element/bagItem.lua
new file mode 100644
index 0000000..4bb2445
--- /dev/null
+++ b/src/lua/element/bagItem.lua
@@ -0,0 +1,80 @@
+local NAME, ADDON = ...
+
+local item = {}
+
+function ADDON:NewBagItem(name, slot, id)
+    local frame = CreateFrame('Button', name, UIParent, 'ItemButtonTemplate')
+
+    ADDON:CreateAddon(frame, item, id, slot)
+
+    return frame
+end
+
+function item:Init(id, slot)
+    self:SetID(id)
+    self.slot = slot
+
+    self:SetScript('OnDragStart', self.DragItem)
+    self:SetScript('OnReceiveDrag', self.PlaceOrPickup)
+    self:SetScript('OnClick', self.PlaceOrPickup)
+    self:SetScript('OnEnter', self.OnEnter)
+    self:SetScript('OnLeave', self.OnLeave)
+end
+
+function item:Update()
+    PaperDollItemSlotButton_Update(self)
+    local slotcount = GetContainerNumSlots(self.slot)
+    if slotcount > 0 then
+        self.Count:SetText(tostring(slotcount))
+        self.Count:Show()
+    else
+        self.Count:Hide()
+    end
+end
+
+function item:UpdateLock()
+    PaperDollItemSlotButton_UpdateLock(self)
+end
+
+function item:PlaceOrPickup()
+    local placed = PutItemInBag(self:GetID())
+    if not placed then
+        PickupBagFromSlot(self:GetID())
+    end
+end
+
+function item:OnEnter()
+    if self:GetRight() >= (GetScreenWidth() / 2) then
+        GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
+    else
+        GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
+    end
+
+    local hasItem, hasCooldown, repairCost, speciesID, level, breedQuality, maxHealth, power, speed, name = GameTooltip:SetInventoryItem("player", self:GetID());
+    if(speciesID and speciesID > 0) then
+        BattlePetToolTip_Show(speciesID, level, breedQuality, maxHealth, power, speed, name);
+        CursorUpdate(self);
+        return;
+    end
+
+    if (not IsInventoryItemProfessionBag("player", self:GetID())) then
+        for i = LE_BAG_FILTER_FLAG_EQUIPMENT, NUM_LE_BAG_FILTER_FLAGS do
+            if ( GetBankBagSlotFlag(self:GetID(), i) ) then
+                GameTooltip:AddLine(BAG_FILTER_ASSIGNED_TO:format(BAG_FILTER_LABELS[i]));
+                break;
+            end
+        end
+    end
+
+    GameTooltip:Show();
+    CursorUpdate(self);
+
+    ADDON.events:Fire('DJBAGS_BAG_HOVER', self.slot, true)
+end
+
+function item:OnLeave()
+    GameTooltip_Hide();
+    ResetCursor();
+
+    ADDON.events:Fire('DJBAGS_BAG_HOVER', self.slot, false)
+end
\ No newline at end of file
diff --git a/src/lua/element/container.lua b/src/lua/element/container.lua
new file mode 100644
index 0000000..23c0e30
--- /dev/null
+++ b/src/lua/element/container.lua
@@ -0,0 +1,75 @@
+local NAME, ADDON = ...
+
+
+local container = {}
+
+function DJBagsContainerLoad(self)
+    ADDON:CreateAddon(self, container)
+end
+
+function container:Init()
+    self.__type = DJBags_TYPE_CONTAINER
+
+    table.insert(UISpecialFrames, self:GetName())
+    self:RegisterForDrag("LeftButton")
+    self:SetScript("OnDragStart", self.StartMoving)
+    self:SetScript("OnDragStop", self.StopMovingOrSizing)
+    self:SetUserPlaced(true)
+
+    self:SetColors(
+        {0, 0, 0, 0.6},
+        {0.3, 0.3, 0.3, 1}
+    )
+
+    self:SetPadding(5)
+    self:SetSpacing(5)
+
+    self.items = {}
+end
+
+function container:UpdateFromSettings()
+    local settings = ADDON.settings:GetSettings(self.__type)
+
+    self:SetColors(
+        settings[DJBags_SETTING_BACKGROUND_COLOR],
+        settings[DJBags_SETTING_BORDER_COLOR]
+    )
+    self:SetPadding(settings[DJBags_SETTING_PADDING])
+    self:SetSpacing(settings[DJBags_SETTING_SPACING])
+    self:SetScale(settings[DJBags_SETTING_SCALE])
+end
+
+function container:SetPadding(padding)
+    self.container:ClearAllPoints()
+    self.padding = padding
+
+    self.container:SetPoint('TOPLEFT', padding, -padding)
+    self.container:SetPoint('BOTTOMRIGHT', -padding, padding)
+end
+
+function container:SetSpacing(spacing)
+    self.spacing = spacing
+end
+
+function container:SetColors(background, border)
+    self:SetBackdropColor(unpack(background))
+    self:SetBackdropBorderColor(unpack(border))
+end
+
+function container:AddItem(item)
+    self.items[item] = true
+
+    if item:GetParent() ~= self.container then
+        item:SetParent(self.container)
+    end
+end
+
+function container:Arrange(override)
+    ADDON.format['massonry'](
+        self,
+        ADDON.settings:GetSettings(self.__type)[DJBags_SETTING_FORMATTER_MAX_ITEMS],
+        ADDON.settings:GetSettings(self.__type)[DJBags_SETTING_FORMATTER_MAX_HEIGHT],
+        ADDON.settings:GetSettings(self.__type)[DJBags_SETTING_FORMATTER_VERT],
+        override
+    )
+end
\ No newline at end of file
diff --git a/src/lua/element/item.lua b/src/lua/element/item.lua
new file mode 100644
index 0000000..e12280e
--- /dev/null
+++ b/src/lua/element/item.lua
@@ -0,0 +1,293 @@
+local NAME, ADDON = ...
+
+local item = {}
+
+function ADDON:NewItem(bag, slot)
+    local frame = CreateFrame('Frame', string.format('DJBagsItem_%d_%d', bag, slot))
+    frame.button = CreateFrame('Button', string.format('DJBagsItemButton_%d_%d', bag, slot), frame,
+                bag == BANK_CONTAINER and 'BankItemButtonGenericTemplate' or
+                bag == REAGENTBANK_CONTAINER and 'ReagentBankItemButtonGenericTemplate' or
+                'ContainerFrameItemButtonTemplate'
+    )
+
+    ADDON:CreateAddon(frame, item, bag, slot)
+
+    return frame
+end
+
+function item:Init(bag, slot)
+    self:SetID(bag)
+    self.button:SetID(slot)
+
+    self.button:SetPoint('CENTER')
+
+    self.button.quest = _G[self.button:GetName() .. "IconQuestTexture"]
+    self.button.cooldown = _G[self.button:GetName() .. "Cooldown"]
+    self.button.itemLevel = self.button:CreateFontString(self.button:GetName() .. 'ItemLevel', 'ARTWORK', 'NumberFontNormal')
+    self.button.itemLevel:SetPoint('TOPLEFT', 2, -2)
+
+    self.button:Show()
+    self:SetSize(self.button:GetSize())
+
+    self.button:HookScript('OnClick', self.OnClick)
+end
+
+function item:OnClick(button)
+    if self:GetParent().id then
+        if IsAltKeyDown() and button == 'LeftButton' then
+--            ADDON.categoryDialog(self:GetParent().id)
+        end
+    end
+end
+
+function item:GetContainerName()
+    if self.id then
+        local isInSet, setName = GetContainerItemEquipmentSetInfo(self:GetID(), self.button:GetID())
+
+        if self.quality == LE_ITEM_QUALITY_POOR then
+            return BAG_FILTER_JUNK
+        end
+
+        if isInSet then
+            return setName
+        end
+
+        if self:GetID() >= 0 and self:GetID() <= NUM_BAG_SLOTS and C_NewItems.IsNewItem(self:GetID(), self.button:GetID()) then
+            return NEW
+        end
+
+        local userDefinedList = ADDON.settings:GetUserDefinedList()
+        if userDefinedList[self.id] then
+            return userDefinedList[self.id] .. '*'
+        end
+
+        local globalDefinedList = ADDON.settings:GetGlobalUserDefinedList()
+        if globalDefinedList[self.id] then
+            return globalDefinedList[self.id] .. '**'
+        end
+
+        local subClassSplitList = ADDON.settings:GetSubClassList()
+        if subClassSplitList[self.classId] then
+            return self.class .. (self.subClass == BAG_FILTER_JUNK and '' or '_' .. self.subClass)
+        end
+
+        return self.class
+    end
+    return EMPTY
+end
+
+--region Update Magic
+
+local function UpdateQuest(self, isQuestItem, questId, isActive)
+    if (questId and not isActive) then
+        self.button.quest:SetTexture(TEXTURE_ITEM_QUEST_BANG)
+        self.button.quest:Show()
+    elseif (questId or isQuestItem) then
+        self.button.quest:SetTexture(TEXTURE_ITEM_QUEST_BORDER)
+        self.button.quest:Show()
+    else
+        self.button.quest:Hide()
+    end
+end
+
+local function UpdateNewItemAnimations(self, isNewItem, isBattlePayItem, quality)
+    if (isNewItem) then
+        if (isBattlePayItem) then
+            self.button.NewItemTexture:Hide()
+            self.button.BattlepayItemTexture:Show()
+        else
+            if (quality and NEW_ITEM_ATLAS_BY_QUALITY[quality]) then
+                self.button.NewItemTexture:SetAtlas(NEW_ITEM_ATLAS_BY_QUALITY[quality]);
+            else
+                self.button.NewItemTexture:SetAtlas("bags-glow-white");
+            end
+            self.button.BattlepayItemTexture:Hide();
+            self.button.NewItemTexture:Show();
+        end
+        if (not self.button.flashAnim:IsPlaying() and not self.button.newitemglowAnim:IsPlaying()) then
+            self.button.flashAnim:Play();
+            self.button.newitemglowAnim:Play();
+        end
+    else
+        self.button.BattlepayItemTexture:Hide();
+        self.button.NewItemTexture:Hide();
+        if (self.button.flashAnim:IsPlaying() or self.button.newitemglowAnim:IsPlaying()) then
+            self.button.flashAnim:Stop();
+            self.button.newitemglowAnim:Stop();
+        end
+    end
+end
+
+local function UpdateFiltered(self, filtered, shouldDoRelicChecks, itemID)
+    if (filtered) then
+        self.button.searchOverlay:Show();
+    else
+        self.button.searchOverlay:Hide();
+        if shouldDoRelicChecks then
+            ContainerFrame_ConsiderItemButtonForRelicTutorial(self.button, itemID);
+        end
+    end
+end
+
+local function UpdateILevel(self, equipable, quality, level)
+    if equipable then
+        if quality and quality >= LE_ITEM_QUALITY_COMMON then
+            self.button.itemLevel:SetVertexColor(BAG_ITEM_QUALITY_COLORS[quality].r, BAG_ITEM_QUALITY_COLORS[quality].g, BAG_ITEM_QUALITY_COLORS[quality].b)
+        else
+            self.button.itemLevel:SetVertexColor(1, 1, 1, 1)
+        end
+        self.button.itemLevel:SetText(level)
+        self.button.itemLevel:Show()
+    else
+        self.button.itemLevel:Hide()
+    end
+end
+
+local function UpdateCooldown(self)
+    if not GetContainerItemID(self:GetID(), self.button:GetID()) then
+        self.button.cooldown:Hide()
+        return
+    end
+
+    local start, duration, enable = GetContainerItemCooldown(self:GetID(), self.button:GetID());
+    CooldownFrame_Set(self.button.cooldown, start, duration, enable);
+    if (duration > 0 and enable == 0) then
+        SetItemButtonTextureVertexColor(self.button, 0.4, 0.4, 0.4);
+    else
+        SetItemButtonTextureVertexColor(self.button, 1, 1, 1);
+    end
+end
+
+function item:Update()
+    local texture, count, locked, quality, _, _, link, filtered, _, id = GetContainerItemInfo(self:GetID(), self.button:GetID())
+    local equipable = IsEquippableItem(id)
+
+    local name, level, classId, class, subClass
+    if id then
+        name, _, _, level, _, class, subClass, _, _, _, _, classId = GetItemInfo(id)
+    end
+    local isEquipment = equipable or classId == LE_ITEM_CLASS_ARMOR or classId == LE_ITEM_CLASS_WEAPON
+
+    self.id = id
+    self.name = name or ''
+    self.quality = quality or 0
+    self.ilevel = level or 0
+    self.link = link
+    self.classId = classId
+    self.class = class
+    self.subClass = subClass
+    self.button.hasItem = nil
+
+    if isEquipment then
+        level = DJBagsTooltip:GetItemLevel(link) or level
+    elseif classId == LE_ITEM_CLASS_CONTAINER then
+        -- TODO set count to number of slots
+    end
+
+    UpdateILevel(self, equipable, quality, level)
+    if ADDON:IsBankBag(self:GetID()) then
+        BankFrameItemButton_Update(self.button)
+    else
+        local isQuestItem, questId, isActive = GetContainerItemQuestInfo(self:GetID(), self.button:GetID())
+        local isNewItem = C_NewItems.IsNewItem(self:GetID(), self.button:GetID())
+        local isBattlePayItem = IsBattlePayItem(self:GetID(), self.button:GetID())
+        local shouldDoRelicChecks = not BagHelpBox:IsShown() and not GetCVarBitfield("closedInfoFrames", LE_FRAME_TUTORIAL_ARTIFACT_RELIC_MATCH)
+
+        self.button.hasItem = true
+
+        SetItemButtonTexture(self.button, texture)
+        SetItemButtonQuality(self.button, quality, id)
+        SetItemButtonCount(self.button, count)
+        SetItemButtonDesaturated(self.button, locked)
+        UpdateQuest(self, isQuestItem, questId, isActive)
+        UpdateNewItemAnimations(self, isNewItem, isBattlePayItem, quality)
+        UpdateFiltered(self, filtered, shouldDoRelicChecks, id)
+        UpdateCooldown(self)
+    end
+end
+
+function item:UpdateCooldown()
+    UpdateCooldown(self)
+end
+
+function item:UpdateSearch()
+    local _, _, _, _, _, _, _, filtered, _, id = GetContainerItemInfo(self:GetID(), self.button:GetID())
+    local shouldDoRelicChecks = not BagHelpBox:IsShown() and not GetCVarBitfield("closedInfoFrames", LE_FRAME_TUTORIAL_ARTIFACT_RELIC_MATCH)
+    self:SetFiltered(filtered, shouldDoRelicChecks)
+end
+
+function item:UpdateLock()
+    local locked = select(3, GetContainerItemInfo(self:GetID(), self.button:GetID()))
+    SetItemButtonDesaturated(self.button, locked);
+end
+
+function item:SetFiltered(filtered, shouldDoRelicChecks)
+    UpdateFiltered(self, filtered, shouldDoRelicChecks, self.id)
+end
+
+function item:SetItemCount(count)
+    SetItemButtonCount(self.button, count)
+end
+
+--endregion
+
+--region Override UI code
+
+function ContainerFrameItemButton_OnEnter(self)
+    GameTooltip:SetOwner(self, "ANCHOR_NONE")
+
+    local newItemTexture = self.NewItemTexture
+    local battlepayItemTexture = self.BattlepayItemTexture
+    local flash = self.flashAnim
+    local newItemGlowAnim = self.newitemglowAnim
+
+    newItemTexture:Hide()
+    battlepayItemTexture:Hide()
+
+    if (flash:IsPlaying() or newItemGlowAnim:IsPlaying()) then
+        flash:Stop()
+        newItemGlowAnim:Stop()
+    end
+
+    local showSell
+    local _, repairCost, speciesID, level, breedQuality, maxHealth, power, speed, name = GameTooltip:SetBagItem(self:GetParent():GetID(), self:GetID())
+    if(speciesID and speciesID > 0) then
+        ContainerFrameItemButton_CalculateItemTooltipAnchors(self, GameTooltip)
+        BattlePetToolTip_Show(speciesID, level, breedQuality, maxHealth, power, speed, name)
+        return;
+    else
+        if (BattlePetTooltip) then
+            BattlePetTooltip:Hide()
+        end
+    end
+
+    local requiresCompareTooltipReanchor = ContainerFrameItemButton_CalculateItemTooltipAnchors(self, GameTooltip)
+
+    if ( requiresCompareTooltipReanchor and (IsModifiedClick("COMPAREITEMS") or GetCVarBool("alwaysCompareItems")) ) then
+        GameTooltip_ShowCompareItem(GameTooltip)
+    end
+
+    if ( InRepairMode() and (repairCost and repairCost > 0) ) then
+        GameTooltip:AddLine(REPAIR_COST, nil, nil, nil, true)
+        SetTooltipMoney(GameTooltip, repairCost)
+        GameTooltip:Show()
+    elseif ( MerchantFrame:IsShown() and MerchantFrame.selectedTab == 1 ) then
+        showSell = 1
+    end
+
+    if ( IsModifiedClick("DRESSUP") and self.hasItem ) then
+        ShowInspectCursor()
+    elseif ( showSell ) then
+        ShowContainerSellCursor(self:GetParent():GetID(),self:GetID())
+    elseif ( self.readable ) then
+        ShowInspectCursor()
+    else
+        ResetCursor()
+    end
+
+    if ArtifactFrame and self.hasItem then
+        ArtifactFrame:OnInventoryItemMouseEnter(self:GetParent():GetID(), self:GetID())
+    end
+end
+
+--endregion
\ No newline at end of file
diff --git a/src/lua/element/itemContainer.lua b/src/lua/element/itemContainer.lua
new file mode 100644
index 0000000..a4b2fec
--- /dev/null
+++ b/src/lua/element/itemContainer.lua
@@ -0,0 +1,100 @@
+local NAME, ADDON = ...
+
+
+local container = {}
+
+function ADDON:NewItemContainer(name, parent)
+    local frame = CreateFrame('Frame', 'DJBagsItemContainer_' .. name, parent or UIParent, 'DJBagsItemContainerTemplate')
+
+    ADDON:CreateAddon(frame, container, name)
+
+    return frame
+end
+
+function container:Init(name)
+    self.__type = DJBags_TYPE_ITEM_CONTAINER
+
+    self:SetMovable(false)
+
+    if string.match(name, '%a*_%a*') then
+        local txt = string.match(name, '%a*_(%a*)')
+        self.name:SetText(txt)
+    else
+        self.name:SetText(name)
+    end
+    self.name:SetMaxLines(1)
+    self.name.text = name
+    self.items = {}
+
+    self:UpdateFromSettings()
+end
+
+function container:UpdateFromSettings()
+    local settings = ADDON.settings:GetSettings(self.__type)
+
+    self:SetTitleSize(settings[DJBags_SETTING_TEXT_SIZE])
+    self:SetColors(
+        settings[DJBags_SETTING_BACKGROUND_COLOR],
+        settings[DJBags_SETTING_BORDER_COLOR]
+    )
+    self:SetTextColor(settings[DJBags_SETTING_TEXT_COLOR])
+    self:SetPadding(settings[DJBags_SETTING_PADDING])
+    self:SetSpacing(settings[DJBags_SETTING_SPACING])
+end
+
+function container:SetTitleSize(size)
+    local font, _, outline = self.name:GetFont()
+    self.name:SetFont(font, size, outline)
+    self.name:SetHeight(size)
+end
+
+function container:SetPadding(padding)
+    self.container:ClearAllPoints()
+    self.padding = padding
+
+    self.container:SetPoint('TOPLEFT', self.name, 'BOTTOMLEFT', padding, -5)
+    self.container:SetPoint('BOTTOMRIGHT', -padding, padding)
+end
+
+function container:SetTextColor(color)
+    self.name:SetVertexColor(unpack(color))
+end
+
+function container:SetSize(width, height)
+    local index = getmetatable(self).__index
+
+    height = height + self.name:GetHeight() + 10
+
+    index.SetSize(self, width, height)
+end
+
+function container:AddItem(item)
+    self.items[item] = true
+    if item:GetParent() ~= self.container then
+        item:SetParent(self.container)
+    end
+
+    self.arranged = nil
+end
+
+function container:RemoveItem(item)
+    self.items[item] = nil
+    item:SetParent(nil)
+
+    self.arranged = nil
+end
+
+function container:IsEmpty()
+    return next(self.items) == nil
+end
+
+function container:GetCount()
+    return ADDON:Count(self.items)
+end
+
+function container:Arrange(max, vert, maxCnt, override)
+    if override then
+        self.arrange = nil
+    end
+    ADDON:ArrangeItemContainer(self, max, vert, maxCnt)
+end
\ No newline at end of file
diff --git a/src/lua/element/tooltip.lua b/src/lua/element/tooltip.lua
new file mode 100644
index 0000000..a6e9609
--- /dev/null
+++ b/src/lua/element/tooltip.lua
@@ -0,0 +1,19 @@
+local NAME, ADDON = ...
+
+function DJBagsTooltip:GetItemLevel(link)
+    self:SetOwner(UIParent, "ANCHOR_NONE")
+    self:SetHyperlink(link)
+
+    for i = 2, self:NumLines() do
+        local text = _G[self:GetName() .. "TextLeft"..i]:GetText()
+        local UPGRADE_LEVEL = gsub(ITEM_LEVEL," %d","")
+
+        if text and text:find(UPGRADE_LEVEL) then
+            local itemLevel = string.match(text,"%d+")
+
+            if itemLevel then
+                return tonumber(itemLevel)
+            end
+        end
+    end
+end
\ No newline at end of file
diff --git a/src/lua/elements/bagBar.lua b/src/lua/elements/bagBar.lua
deleted file mode 100644
index b1d0e32..0000000
--- a/src/lua/elements/bagBar.lua
+++ /dev/null
@@ -1,61 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.bagBar = {}
-ADDON.bagBar.__index = ADDON.bagBar
-
-local bar = ADDON.bagBar
-setmetatable(bar, {
-    __call = function(self, parent)
-        local frame = ADDON.container('DJBagsBagBar', parent)
-
-        for k, v in pairs(self) do
-            frame[k] = v
-        end
-
-        frame:Init()
-        frame:Setup()
-
-        return frame
-    end
-})
-
-function bar:Init()
-    self.bag1 = ADDON.bagItem('DJBagsBag0', 1, GetInventorySlotInfo("Bag0Slot"))
-    self.bag1:SetParent(self)
-    self.bag2 = ADDON.bagItem('DJBagsBag1', 2, GetInventorySlotInfo("Bag1Slot"))
-    self.bag2:SetParent(self)
-    self.bag3 = ADDON.bagItem('DJBagsBag2', 3, GetInventorySlotInfo("Bag2Slot"))
-    self.bag3:SetParent(self)
-    self.bag4 = ADDON.bagItem('DJBagsBag3', 4, GetInventorySlotInfo("Bag3Slot"))
-    self.bag4:SetParent(self)
-end
-
-function bar:Setup()
-    ADDON.container.Setup(self)
-
-    self.bag1:SetPoint("TOPRIGHT", -5, -5)
-    self.bag2:SetPoint("TOPRIGHT", self.bag1, 'TOPLEFT', -5, 0)
-    self.bag3:SetPoint("TOPRIGHT", self.bag2, 'TOPLEFT', -5, 0)
-    self.bag4:SetPoint("TOPRIGHT", self.bag3, 'TOPLEFT', -5, 0)
-
-    self:SetSize(self.bag1:GetWidth() * 4 + 25, 10 + self.bag1:GetHeight())
-end
-
-function bar:Update()
-    self.bag1:Update()
-    self.bag2:Update()
-    self.bag3:Update()
-    self.bag4:Update()
-end
-
-function bar:UpdateLock(bag)
-    if bag == self.bag1:GetID() then
-        self.bag1:UpdateLock()
-    elseif bag == self.bag2:GetID() then
-        self.bag2:UpdateLock()
-    elseif bag == self.bag3:GetID() then
-        self.bag3:UpdateLock()
-    elseif bag == self.bag4:GetID() then
-        self.bag4:UpdateLock()
-    end
-end
\ No newline at end of file
diff --git a/src/lua/elements/bagItem.lua b/src/lua/elements/bagItem.lua
deleted file mode 100644
index 90ebbd4..0000000
--- a/src/lua/elements/bagItem.lua
+++ /dev/null
@@ -1,101 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.bagItem = {}
-ADDON.bagItem.__index = ADDON.bagItem
-
-local item = ADDON.bagItem
-setmetatable(item, {
-    __call = function(tbl, name, slot, id)
-        local frame = CreateFrame('BUTTON', name, nil, 'ItemButtonTemplate')
-        frame:SetID(id)
-        frame.slot = slot
-
-        for k, v in pairs(tbl) do
-            frame[k] = v
-        end
-
-        frame:Init()
-        frame:Setup()
-
-        return frame
-    end
-})
-
-function item:Init()
-    self:SetScript('OnDragStart', self.DragItem)
-    self:SetScript('OnReceiveDrag', self.PlaceOrPickup)
-    self:SetScript('OnClick', self.PlaceOrPickup)
-    self:SetScript('OnEnter', self.OnEnter)
-    self:SetScript('OnLeave', self.OnLeave)
-
-    self.IconBorder:ClearAllPoints()
-    self.IconBorder:SetAllPoints()
-
-    self:SetNormalTexture([[Interface\Common\WhiteIconFrame]])
-    self:GetNormalTexture():ClearAllPoints()
-    self:GetNormalTexture():SetAllPoints()
-end
-
-function item:Setup()
-    local settings = ADDON.settings.bagItem or {size = 26}
-
-    self:SetSize(settings.size, settings.size)
-end
-
-function item:Update()
-    PaperDollItemSlotButton_Update(self)
-    local slotcount = GetContainerNumSlots(self.slot)
-    if slotcount > 0 then
-        self.Count:SetText(tostring(slotcount))
-        self.Count:Show()
-    else
-        self.Count:Hide()
-    end
-end
-
-function item:UpdateLock()
-    PaperDollItemSlotButton_UpdateLock(self)
-end
-
-function item:PlaceOrPickup()
-    local placed = PutItemInBag(self:GetID())
-    if not placed then
-        PickupBagFromSlot(self:GetID())
-    end
-end
-
-function item:DragItem()
-    PickupBagFromSlot(self:GetID())
-end
-
-function item:OnEnter()
-    if self:GetRight() >= (GetScreenWidth() / 2) then
-        GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
-    else
-        GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
-    end
-
-    local hasItem, hasCooldown, repairCost, speciesID, level, breedQuality, maxHealth, power, speed, name = GameTooltip:SetInventoryItem("player", self:GetID());
-    if(speciesID and speciesID > 0) then
-        BattlePetToolTip_Show(speciesID, level, breedQuality, maxHealth, power, speed, name);
-        CursorUpdate(self);
-        return;
-    end
-
-    if (not IsInventoryItemProfessionBag("player", self:GetID())) then
-        for i = LE_BAG_FILTER_FLAG_EQUIPMENT, NUM_LE_BAG_FILTER_FLAGS do
-            if ( GetBankBagSlotFlag(self:GetID(), i) ) then
-                GameTooltip:AddLine(BAG_FILTER_ASSIGNED_TO:format(BAG_FILTER_LABELS[i]));
-                break;
-            end
-        end
-    end
-
-    GameTooltip:Show();
-    CursorUpdate(self);
-end
-
-function item:OnLeave()
-    GameTooltip_Hide();
-    ResetCursor();
-end
\ No newline at end of file
diff --git a/src/lua/elements/categoryContainer.lua b/src/lua/elements/categoryContainer.lua
deleted file mode 100644
index ae8049e..0000000
--- a/src/lua/elements/categoryContainer.lua
+++ /dev/null
@@ -1,68 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.categoryContainer = {}
-ADDON.categoryContainer.__index = ADDON.categoryContainer
-
-local container = ADDON.categoryContainer
-setmetatable(container, {
-    __call = function(tbl, name, parent)
-        local frame = ADDON.container(name, parent)
-
-        for k, v in pairs(tbl) do
-            frame[k] = v
-        end
-
-        frame:Init()
-        frame:Setup()
-
-        return frame
-    end
-})
-
-function container:Init()
-    table.insert(UISpecialFrames, self:GetName())
-    self:SetMovable(true)
-    self:EnableMouse(true)
-    self:RegisterForDrag("LeftButton")
-    self:SetScript("OnDragStart", self.StartMoving)
-    self:SetScript("OnDragStop", self.StopMovingOrSizing)
-    self.containers = {}
-
-    self.closeBtn = CreateFrame('Button', self:GetName() .. 'CloseButton', self)
-    self.closeBtn:SetNormalTexture([[Interface\Buttons\UI-Panel-MinimizeButton-Disabled]])
-    self.closeBtn:SetPushedTexture([[Interface\Buttons\UI-Panel-MinimizeButton-Down]])
-    self.closeBtn:SetHighlightTexture([[Interface\Buttons\UI-Panel-MinimizeButton-Up]])
-    self.closeBtn:SetScript('OnClick', function()
-        if self:GetParent() == UIParent then
-            self:Hide()
-        else
-            self:GetParent():Hide()
-        end
-    end)
-end
-
-function container:Setup()
-    ADDON.container.Setup(self)
-
-    local settings = ADDON.settings.categoryContainer
-
-    self.padding = settings.padding
-    self.spacing = settings.spacing
-    self.formatter = ADDON.formatters[settings.formatter]
-    self.maxHeight = settings.maxHeight
-    if settings.closeVisible then
-        self.closeBtn:Show()
-    else
-        self.closeBtn:Hide()
-    end
-    self.closeBtn:SetPoint('Topright', self, 'TOPRIGHT', settings.closeSize / 5, settings.closeSize / 5)
-    self.closeBtn:SetSize(settings.closeSize, settings.closeSize)
-end
-
-function container:AddContainer(container)
-    self.containers[container] = true
-end
-
-function container:Arrange()
-    self.formatter:Format(self)
-end
\ No newline at end of file
diff --git a/src/lua/elements/categoryDialog.lua b/src/lua/elements/categoryDialog.lua
deleted file mode 100644
index c532c0b..0000000
--- a/src/lua/elements/categoryDialog.lua
+++ /dev/null
@@ -1,213 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.categoryDialog = {}
-ADDON.categoryDialog.__index = ADDON.categoryDialog
-
-local dialog = ADDON.categoryDialog
-setmetatable(dialog, {
-    __call = function(self, id)
-        self:Show(id)
-    end
-})
-
-function dialog:Show(id)
-    if not id then return end
-
-    local frame = self:GetFrame(id)
-    self.id = id
-    frame:Show()
-    self.editBox:SetFocus()
-end
-
-function dialog:GetFrame(id)
-    if not self.frame then
-        self:CreateFrame()
-    end
-
-    self.frame:Setup()
-
-    self:Init(id)
-    return self.frame
-end
-
-function OnDropDownClick(self)
-    UIDropDownMenu_SetSelectedID(dialog.dropDown, self:GetID())
-    dialog:SetText(self.value)
-end
-
-function InitDropDown(self, level)
-    local unique = {}
-    for _, v in pairs(ADDON.settings.categories.userDefined) do
-        unique[v] = true
-    end
-    for _, v in pairs(ADDON.globalCategories) do
-        unique[v] = {}
-    end
-
-    if next(unique) ~= nil then
-        local info
-        for k, _ in pairs(unique) do
-            info = UIDropDownMenu_CreateInfo()
-            info.text = k
-            info.value = k
-            info.func = OnDropDownClick
-            UIDropDownMenu_AddButton(info, level)
-        end
-    end
-end
-
-function dialog:Init(id)
-        local name, link, quality, iLevel, reqLevel, class, subclass, maxStack, equipSlot, texture, vendorPrice = GetItemInfo(id)
-
-    self.title:SetText(string.format('Change %s\'s category?', name))
-    -- TODO add texture
-
-    UIDropDownMenu_Initialize(self.dropDown, InitDropDown)
-    self.errorText:Hide()
-    local text = ''
-    if ADDON.settings.categories.userDefined[id] then
-        text = ADDON.settings.categories.userDefined[id]
-        self.globalCheckbox:SetChecked(false)
-    elseif ADDON.globalCategories[id] then
-        text = ADDON.globalCategories[id]
-        self.globalCheckbox:SetChecked(true)
-    end
-    self:SetText(text)
-
-    self.frame:SetHeight(75 + self.title:GetStringHeight())
-end
-
-function dialog:Setup()
-    if self.frame then
-        self.frame:Setup()
-    end
-end
-
-function dialog:SetText(text)
-    self.editBox:SetText(text)
-end
-
-function dialog:CreateFrame()
-    self.frame = ADDON.container('DJBagsCategoryDialog')
-    self.frame:SetPoint('CENTER')
-    table.insert(UISpecialFrames, self.frame:GetName())
-
-    self.title = self.frame:CreateFontString('DJBagsCategoryDialogTitle', 'OVERLAY', 'GameFontNormal')
-    self.title:SetFont(select(1, self.title:GetFont()), 18, 'OUTLINE')
-    self.title:SetTextColor(1, 1, 1, 1)
-    self.title:SetPoint("TOPLEFT", 5, -5)
-    self.title:SetPoint("TOPRIGHT", -5, -5)
-
-    self.editBox = CreateFrame('EDITBOX', 'DJBagsCategoryDialogEdit', self.frame)
-    self.editBox:SetHeight(20)
-    self.editBox:SetFontObject("GameFontHighlight")
-    self.editBox:SetPoint('TOPLEFT', self.title, 'BOTTOMLEFT', 0, -15)
-    self.editBox:SetPoint('TOPRIGHT', self.frame, 'RIGHT', -140, 0)
-    self.editBox:SetBackdrop({
-        bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
-        edgeFile = "Interface\\Buttons\\WHITE8x8",
-        tile = true,
-        tileSize = 16,
-        edgeSize = 1,
-    })
-    self.editBox:SetBackdropBorderColor(0.3, 0.3, 0.3, 1)
-    self.editBox:SetBackdropColor(0, 0, 0, 0)
-    self.editBox:SetScript('OnEnterPressed', function()
-        dialog.okBtn:Click()
-    end)
-    self.editBox:SetScript('OnEscapePressed', function()
-        dialog.frame:Hide()
-    end)
-
-    self.errorText = self.frame:CreateFontString('DJBagsCategoryDialogTitle', 'OVERLAY', 'GameFontNormal')
-    self.errorText:SetFont(select(1, self.errorText:GetFont()), 18, 'OUTLINE')
-    self.errorText:SetTextColor(1, 0, 0, 1)
-    self.errorText:SetPoint("TOPRIGHT", self.editBox, 'TOPLEFT', -5, 0)
-    self.errorText:SetText('A Category name needs to be entered!')
-    self.errorText:Hide()
-
-    self.dropDown = CreateFrame("Button", "DJBagsCategoryDialogDropDown", self.frame, "UIDropDownMenuTemplate")
-    self.dropDown:SetPoint('LEFT', self.editBox, 'RIGHT')
-    UIDropDownMenu_SetWidth(self.dropDown, 100);
-    UIDropDownMenu_SetButtonWidth(self.dropDown, 124)
-    UIDropDownMenu_JustifyText(self.dropDown, "LEFT")
-
-    self.resetBtn = CreateFrame('BUTTON', 'DJBagsCategoryDialogResetButton', self.frame)
-    self.resetBtn:SetNormalFontObject("GameFontHighlight")
-    self.resetBtn:SetSize(75, 20)
-    self.resetBtn:SetText(RESET)
-    self.resetBtn:SetBackdrop({
-        bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
-        edgeFile = "Interface\\Buttons\\WHITE8x8",
-        tile = true,
-        tileSize = 16,
-        edgeSize = 1,
-    })
-    self.resetBtn:SetBackdropBorderColor(0.3, 0.3, 0.3, 1)
-    self.resetBtn:SetBackdropColor(0, 0, 0, 0)
-    self.resetBtn:SetPoint('BOTTOMLEFT', self.frame, 'BOTTOMLEFT', 5, 5)
-    self.resetBtn:SetScript('OnClick', function()
-        if self.globalCheckbox:GetChecked() then
-            ADDON.globalCategories[dialog.id] = nil
-        else
-            ADDON.settings.categories.userDefined[dialog.id] = nil
-        end
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-        dialog.frame:Hide()
-    end)
-
-    self.globalCheckbox = CreateFrame("CheckButton", 'DJBagsCategoryDialogGlobalCheckbox', self.frame, 'OptionsSmallCheckButtonTemplate')
-    self.globalCheckbox:SetPoint('LEFT', self.resetBtn, 'RIGHT', 5, 0)
-    _G[self.globalCheckbox:GetName().."Text"]:SetText(ALL)
-
-    self.okBtn = CreateFrame('BUTTON', 'DJBagsCategoryDialogOkButton', self.frame)
-    self.okBtn:SetNormalFontObject("GameFontHighlight")
-    self.okBtn:SetSize(75, 20)
-    self.okBtn:SetText(DONE)
-    self.okBtn:SetBackdrop({
-        bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
-        edgeFile = "Interface\\Buttons\\WHITE8x8",
-        tile = true,
-        tileSize = 16,
-        edgeSize = 1,
-    })
-    self.okBtn:SetBackdropBorderColor(0.3, 0.3, 0.3, 1)
-    self.okBtn:SetBackdropColor(0, 0, 0, 0)
-    self.okBtn:SetPoint('BOTTOMRIGHT', self.frame, 'BOTTOMRIGHT', -5, 5)
-    self.okBtn:SetScript('OnClick', function()
-        local text = dialog.editBox:GetText()
-        dialog.errorText:Hide()
-        if not text or text ~= '' then
-            if self.globalCheckbox:GetChecked() then
-                ADDON.globalCategories[dialog.id] = text
-            else
-                ADDON.settings.categories.userDefined[dialog.id] = text
-            end
-            ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-            dialog.frame:Hide()
-        else
-            dialog.errorText:Show()
-        end
-    end)
-
-    self.cancelBtn = CreateFrame('BUTTON', 'DJBagsCategoryDialogCancelButton', self.frame)
-    self.cancelBtn:SetNormalFontObject("GameFontHighlight")
-    self.cancelBtn:SetSize(75, 20)
-    self.cancelBtn:SetText(CANCEL)
-    self.cancelBtn:SetBackdrop({
-        bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
-        edgeFile = "Interface\\Buttons\\WHITE8x8",
-        tile = true,
-        tileSize = 16,
-        edgeSize = 1,
-    })
-    self.cancelBtn:SetBackdropBorderColor(0.3, 0.3, 0.3, 1)
-    self.cancelBtn:SetBackdropColor(0, 0, 0, 0)
-    self.cancelBtn:SetPoint('TOPRIGHT', self.okBtn, 'TOPLEFT', -5, 0)
-    self.cancelBtn:SetScript('OnClick', function()
-        dialog.frame:Hide()
-    end)
-
-    self.frame:SetSize(350, 90)
-end
-
diff --git a/src/lua/elements/container.lua b/src/lua/elements/container.lua
deleted file mode 100644
index 8bbf102..0000000
--- a/src/lua/elements/container.lua
+++ /dev/null
@@ -1,35 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.container = {}
-ADDON.container.__index = ADDON.container
-
-local container = ADDON.container
-setmetatable(container, {
-    __call = function(tbl, name, parent)
-        local frame = CreateFrame('FRAME', 'DJBagContainer_' .. (name or ADDON.uuid()), parent or UIParent)
-        frame.name = name
-
-        for key, value in pairs(tbl) do
-            frame[key] = value
-        end
-
-        frame:Setup()
-
-        return frame
-    end
-})
-
-function container:Setup()
-    local settings = ADDON.settings.container
-
-    self:SetBackdrop({
-        -- TODO remove all hardcoded shit
-        bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
-        edgeFile = "Interface\\Buttons\\WHITE8x8",
-        tile = true,
-        tileSize = 16,
-        edgeSize = settings.borderWidth,
-    })
-    self:SetBackdropColor(unpack(settings.backgroundColor))
-    self:SetBackdropBorderColor(unpack(settings.borderColor))
-end
\ No newline at end of file
diff --git a/src/lua/elements/item.lua b/src/lua/elements/item.lua
deleted file mode 100644
index b724be5..0000000
--- a/src/lua/elements/item.lua
+++ /dev/null
@@ -1,314 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.item = {}
-ADDON.item.__index = ADDON.item
-
-local item = ADDON.item
-setmetatable(item, {
-    __call = function(tbl, bag, slot)
-        local parent = CreateFrame('FRAME', string.format('DJBagsItemParent%d_%d', bag, slot))
-        local inherit = bag == BANK_CONTAINER and 'BankItemButtonGenericTemplate' or
-                bag == REAGENTBANK_CONTAINER and 'ReagentBankItemButtonGenericTemplate' or 'ContainerFrameItemButtonTemplate'
-        parent.button = CreateFrame('BUTTON', string.format('DJBagsItem%d_%d', bag, slot), parent, inherit)
-
-        parent:SetID(bag)
-        parent.button:SetID(slot)
-
-        for key, value in pairs(tbl) do
-            parent[key] = value
-        end
-
-        parent:Init()
-        parent:Setup()
-
-        return parent
-    end
-})
-
-function item:Init()
-    self.button:ClearAllPoints()
-    self.button:SetAllPoints()
-
-    self.button.IconBorder:ClearAllPoints()
-    self.button.IconBorder:SetAllPoints()
-
-    self.button:SetNormalTexture([[Interface\Common\WhiteIconFrame]])
-    self.button:GetNormalTexture():ClearAllPoints()
-    self.button:GetNormalTexture():SetAllPoints()
-
-    if self.button.NewItemTexture then
-        self.button.NewItemTexture:ClearAllPoints()
-        self.button.NewItemTexture:SetAllPoints()
-    end
-
-    if self.button.flash then
-        self.button.flash:ClearAllPoints()
-        self.button.flash:SetAllPoints()
-    end
-
-    self.button.quest = _G[self.button:GetName() .. "IconQuestTexture"]
-    if self.button.quest then
-        self.button.quest:ClearAllPoints()
-        self.button.quest:SetAllPoints()
-    end
-
-    self.button.cooldown = _G[self.button:GetName() .. "Cooldown"]
-
-    self.button.Count:ClearAllPoints()
-    self.button.Count:SetJustifyH('LEFT')
-    self.button.Count:SetPoint('BOTTOMRIGHT', -1, 3)
-
-    self.button:Show()
-
-    self.button:HookScript('OnClick', self.OnClick)
-end
-
-function item:ShowCountText(text)
-    SetItemButtonCount(self.button, text)
-end
-
-function item:Setup()
-    local settings = ADDON.settings.item
-    self:SetSize(settings.size, settings.size)
-    local name, _, outline = self.button.Count:GetFont()
-    self.button.Count:SetFont(name, math.min(settings.size / 3, 13), outline)
-end
-
-function item:OnEnter(...)
-    local bag = self:GetParent():GetID()
-
-    if bag == BANK_CONTAINER or bag == REAGENTBANK_CONTAINER then
-        BankFrameItemButton_OnEnter(self, ...)
-    else
-        self:GetParent().OnEnterBag(self)
-    end
-end
-
-function ContainerFrameItemButton_OnEnter(self)
-    GameTooltip:SetOwner(self, "ANCHOR_NONE")
-
-    local newItemTexture = self.NewItemTexture
-    local battlepayItemTexture = self.BattlepayItemTexture
-    local flash = self.flashAnim
-    local newItemGlowAnim = self.newitemglowAnim
-
-    newItemTexture:Hide()
-    battlepayItemTexture:Hide()
-
-    if (flash:IsPlaying() or newItemGlowAnim:IsPlaying()) then
-        flash:Stop()
-        newItemGlowAnim:Stop()
-    end
-
-    local showSell
-    local _, repairCost, speciesID, level, breedQuality, maxHealth, power, speed, name = GameTooltip:SetBagItem(self:GetParent():GetID(), self:GetID())
-    if(speciesID and speciesID > 0) then
-        ContainerFrameItemButton_CalculateItemTooltipAnchors(self, GameTooltip)
-        BattlePetToolTip_Show(speciesID, level, breedQuality, maxHealth, power, speed, name)
-        return;
-    else
-        if (BattlePetTooltip) then
-            BattlePetTooltip:Hide()
-        end
-    end
-
-    local requiresCompareTooltipReanchor = ContainerFrameItemButton_CalculateItemTooltipAnchors(self, GameTooltip)
-
-    if ( requiresCompareTooltipReanchor and (IsModifiedClick("COMPAREITEMS") or GetCVarBool("alwaysCompareItems")) ) then
-        GameTooltip_ShowCompareItem(GameTooltip)
-    end
-
-    if ( InRepairMode() and (repairCost and repairCost > 0) ) then
-        GameTooltip:AddLine(REPAIR_COST, nil, nil, nil, true)
-        SetTooltipMoney(GameTooltip, repairCost)
-        GameTooltip:Show()
-    elseif ( MerchantFrame:IsShown() and MerchantFrame.selectedTab == 1 ) then
-        showSell = 1
-    end
-
-    if ( IsModifiedClick("DRESSUP") and self.hasItem ) then
-        ShowInspectCursor()
-    elseif ( showSell ) then
-        ShowContainerSellCursor(self:GetParent():GetID(),self:GetID())
-    elseif ( self.readable ) then
-        ShowInspectCursor()
-    else
-        ResetCursor()
-    end
-
-    if ArtifactFrame and self.hasItem then
-        ArtifactFrame:OnInventoryItemMouseEnter(self:GetParent():GetID(), self:GetID())
-    end
-end
-
---region Update Events
-
-local function UpdateQuest(self, isQuestItem, questId, isActive)
-    if (questId and not isActive) then
-        self.button.quest:SetTexture(TEXTURE_ITEM_QUEST_BANG)
-        self.button.quest:Show()
-    elseif (questId or isQuestItem) then
-        self.button.quest:SetTexture(TEXTURE_ITEM_QUEST_BORDER)
-        self.button.quest:Show()
-    else
-        self.button.quest:Hide()
-    end
-end
-
-local function UpdateNewItemAnimations(self, isNewItem, isBattlePayItem, quality)
-    if (isNewItem) then
-        if (isBattlePayItem) then
-            self.button.NewItemTexture:Hide()
-            self.button.BattlepayItemTexture:Show()
-        else
-            if (quality and NEW_ITEM_ATLAS_BY_QUALITY[quality]) then
-                self.button.NewItemTexture:SetAtlas(NEW_ITEM_ATLAS_BY_QUALITY[quality]);
-            else
-                self.button.NewItemTexture:SetAtlas("bags-glow-white");
-            end
-            self.button.BattlepayItemTexture:Hide();
-            self.button.NewItemTexture:Show();
-        end
-        if (not self.button.flashAnim:IsPlaying() and not self.button.newitemglowAnim:IsPlaying()) then
-            self.button.flashAnim:Play();
-            self.button.newitemglowAnim:Play();
-        end
-    else
-        self.button.BattlepayItemTexture:Hide();
-        self.button.NewItemTexture:Hide();
-        if (self.button.flashAnim:IsPlaying() or self.button.newitemglowAnim:IsPlaying()) then
-            self.button.flashAnim:Stop();
-            self.button.newitemglowAnim:Stop();
-        end
-    end
-end
-
-local function UpdateFiltered(self, filtered, shouldDoRelicChecks, itemID)
-    if (filtered) then
-        self.button.searchOverlay:Show();
-    else
-        self.button.searchOverlay:Hide();
-        if shouldDoRelicChecks then
-            ContainerFrame_ConsiderItemButtonForRelicTutorial(self.button, itemID);
-        end
-    end
-end
-
-local function UpdateCountcolour(self, equipable, quality)
-    if equipable and quality and quality >= LE_ITEM_QUALITY_COMMON then
-        self.button.Count:SetVertexColor(BAG_ITEM_QUALITY_COLORS[quality].r, BAG_ITEM_QUALITY_COLORS[quality].g, BAG_ITEM_QUALITY_COLORS[quality].b)
-    else
-        self.button.Count:SetVertexColor(1, 1, 1)
-    end
-end
-
-local function UpdateCooldown(self)
-    if not GetContainerItemID(self:GetID(), self.button:GetID()) then
-        self.button.cooldown:Hide()
-        return
-    end
-
-    local start, duration, enable = GetContainerItemCooldown(self:GetID(), self.button:GetID());
-    CooldownFrame_Set(self.button.cooldown, start, duration, enable);
-    if (duration > 0 and enable == 0) then
-        SetItemButtonTextureVertexColor(self.button, 0.4, 0.4, 0.4);
-    else
-        SetItemButtonTextureVertexColor(self.button, 1, 1, 1);
-    end
-end
-
-function item:Update()
-    local texture, count, locked, quality, _, _, link, filtered, _, id = GetContainerItemInfo(self:GetID(), self.button:GetID())
-    local equipable = IsEquippableItem(id)
-    local name, level, classId
-    if id then
-        name, _, _, level, _, _, _, _, _, _, _, classId = GetItemInfo(id)
-    end
-    self.id = id
-    self.name = name or ''
-    self.quality = quality or 0
-    self.ilevel = level or 0
-    self.button.hasItem = nil
-
-    local isEquipment = equipable or classId == LE_ITEM_CLASS_ARMOR or classId == LE_ITEM_CLASS_WEAPON
-    if isEquipment then
-        count = count > 1 and count or (self:GetItemLevel(link) or level)
-    end
-
-    if self:GetID() == BANK_CONTAINER or self:GetID() == REAGENTBANK_CONTAINER then
-        BankFrameItemButton_Update(self.button)
-        if isEquipment then
-            SetItemButtonCount(self.button, count)
-            UpdateCountcolour(self, equipable, quality)
-        end
-    else
-        local isQuestItem, questId, isActive = GetContainerItemQuestInfo(self:GetID(), self.button:GetID())
-        local isNewItem = C_NewItems.IsNewItem(self:GetID(), self.button:GetID())
-        local isBattlePayItem = IsBattlePayItem(self:GetID(), self.button:GetID())
-        local shouldDoRelicChecks = not BagHelpBox:IsShown() and not GetCVarBitfield("closedInfoFrames", LE_FRAME_TUTORIAL_ARTIFACT_RELIC_MATCH)
-
-        self.button.hasItem = true
-
-        SetItemButtonTexture(self.button, texture)
-        SetItemButtonQuality(self.button, quality, id)
-        SetItemButtonCount(self.button, count)
-        SetItemButtonDesaturated(self.button, locked)
-        UpdateQuest(self, isQuestItem, questId, isActive)
-        UpdateNewItemAnimations(self, isNewItem, isBattlePayItem, quality)
-        UpdateFiltered(self, filtered, shouldDoRelicChecks, id)
-        UpdateCountcolour(self, equipable, quality)
-        UpdateCooldown(self)
-    end
-end
-
-function item:UpdateCooldown()
-    UpdateCooldown(self)
-end
-
-function item:UpdateSearch()
-    local _, _, _, _, _, _, _, filtered, _, id = GetContainerItemInfo(self:GetID(), self.button:GetID())
-    local shouldDoRelicChecks = not BagHelpBox:IsShown() and not GetCVarBitfield("closedInfoFrames", LE_FRAME_TUTORIAL_ARTIFACT_RELIC_MATCH)
-    UpdateFiltered(self, filtered, shouldDoRelicChecks, id)
-end
-
-function item:UpdateLock()
-    local locked = select(3, GetContainerItemInfo(self:GetID(), self.button:GetID()))
-    SetItemButtonDesaturated(self.button, locked);
-end
-
-function item:OnClick(button)
-    if self:GetParent().id then
-        if IsAltKeyDown() and button == 'LeftButton' then
-            ADDON.categoryDialog(self:GetParent().id)
-        end
-    end
-end
-
-function item:GetItemLevel(link)
-    local tooltip = self:GetTooltip()
-
-    tooltip:SetOwner(UIParent, "ANCHOR_NONE")
-    tooltip:SetHyperlink(link)
-
-    for i = 2, tooltip:NumLines() do
-        local text = _G[tooltip:GetName() .. "TextLeft"..i]:GetText()
-        local UPGRADE_LEVEL = gsub(ITEM_LEVEL," %d","")
-
-        if text and text:find(UPGRADE_LEVEL) then
-            local itemLevel = string.match(text,"%d+")
-
-            if itemLevel then
-                return tonumber(itemLevel)
-            end
-        end
-    end
-end
-
-function item:GetTooltip()
-    if not ADDON.DJTooltip then
-        ADDON.DJTooltip = CreateFrame('GameTooltip', 'DJBagsTooltip', UIParent, 'GameTooltipTemplate')
-    end
-    return ADDON.DJTooltip
-end
-
---endregion
\ No newline at end of file
diff --git a/src/lua/elements/itemContainer.lua b/src/lua/elements/itemContainer.lua
deleted file mode 100644
index 321c7ae..0000000
--- a/src/lua/elements/itemContainer.lua
+++ /dev/null
@@ -1,140 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.itemContainer = {}
-ADDON.itemContainer.__index = ADDON.itemContainer
-ADDON.itemContainer.__class = 'ItemContainer'
-
-local container = ADDON.itemContainer
-setmetatable(container, {
-    __call = function(tbl, name, hasTitle, parent, max)
-        local frame = ADDON.container(name, parent)
-        frame.max = max
-
-        for k, v in pairs(tbl) do
-            frame[k] = v
-        end
-
-        frame:Init(hasTitle)
-        frame:Setup()
-
-        return frame
-    end
-})
-
-function container:Init(hasTitle)
-    self.items = {}
-    if hasTitle == nil or hasTitle then
-        self.title = self:CreateFontString(self:GetName() .. 'Title', 'OVERLAY', 'GameFontNormal')
-        self.title.scriptHandler = CreateFrame('FRAME', 'DJBagsScriptHandler' .. self.name, self)
-        self.title.scriptHandler:SetPoint('TOPLEFT')
-        self.title.scriptHandler:SetPoint('TOPRight')
-        self.title.scriptHandler:SetScript('OnEnter', self.TitleEnter)
-        self.title.scriptHandler:SetScript('OnLeave', self.TitleLeave)
-    end
-end
-
-function container:Setup()
-    ADDON.container.Setup(self)
-
-    local settings = ADDON.settings.itemContainer
-
-    self.padding = settings.padding
-    self.spacing = settings.spacing
-    self.sortFunction = ADDON.sorters.items[settings.sortFunction]
-    self.fontSize = settings.fontSize
-
-    if self.title then
-        local font, _, outline = self.title:GetFont()
-        self.title:SetFont(font, settings.fontSize, outline)
-        if not settings.showClassWithSub and string.match(self.name, '%a*_%a*') then
-            local name = string.match(self.name, '%a*_(%a*)')
-            self.title:SetText(name)
-        else
-            self.title:SetText(self.name)
-        end
-        self.title:SetMaxLines(1)
-        self.title:SetTextColor(unpack(settings.fontColor))
-        self.title:ClearAllPoints()
-        self.title:SetPoint('TOPLEFT', 0, -self.padding)
-        self.title.margin = settings.titleMargin
-        self.title.scriptHandler:SetHeight(self.fontSize)
-    end
-end
-
-function container:AddItem(item)
-    self.items[item] = true
-end
-
-function container:RemoveItem(item)
-    self.items[item] = nil
-end
-
-function container:Arrange(cols)
-    local list = self.items
-
-    local x = self.padding
-    local y = -self.padding - (self.title and (self.fontSize + self.title.margin) or 0)
-    local width
-    local height = 0
-
-    local cnt = 0
-
-    for item, _ in ADDON.utils:PairsByKey(list, self.sortFunction) do
-        item:ClearAllPoints()
-        item:SetParent(self)
-
-        if self.max and cnt >= cols then
-            item:Hide()
-        else
-            item:SetPoint('TOPLEFT', x, y)
-            item:Show()
-
-            width = width or cols * (self.spacing + item:GetWidth()) - self.spacing + self.padding * 2
-            height = math.max(height, -y + item:GetHeight() + self.padding)
-
-            cnt = cnt + 1
-
-            if cnt % cols == 0 then
-                y = y - self.spacing - item:GetHeight()
-                x = self.padding
-            else
-                x = x + self.spacing + item:GetWidth()
-            end
-            if self.max and cnt == cols then
-                item:ShowCountText(self:Count() - cnt + 1)
-            end
-        end
-    end
-    if width then
-        self:SetSize(width, height)
-        if self.title then
-            self.title:SetWidth(width)
-        end
-    end
-end
-
-function container:Count()
-    local count = 0
-    for _, v in pairs(self.items) do
-        if v and v ~= nil then
-            count = count + 1
-        end
-    end
-    return count
-end
-
-function container:IsEmpty()
-    return next(self.items) == nil
-end
-
-function container:TitleEnter()
-    if (self:GetParent().title:IsTruncated() or self:GetParent().title:GetText() ~= self:GetParent().name) then
-        GameTooltip:SetOwner(self, 'ANCHOR_CURSOR')
-        GameTooltip:SetText(self:GetParent().name)
-        GameTooltip:Show()
-    end
-end
-
-function container:TitleLeave()
-    GameTooltip:Hide()
-end
\ No newline at end of file
diff --git a/src/lua/elements/mainBar.lua b/src/lua/elements/mainBar.lua
deleted file mode 100644
index 1b4f27a..0000000
--- a/src/lua/elements/mainBar.lua
+++ /dev/null
@@ -1,137 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.mainBar = {}
-ADDON.mainBar.__index = ADDON.mainBar
-
-local bar = ADDON.mainBar
-setmetatable(bar, {
-    __call = function(tbl, parent)
-        local container = ADDON.container('DJBagsMoneyBar', parent)
-
-        for k, v in pairs(tbl) do
-            container[k] = v
-        end
-
-        container:Init()
-        container:Setup()
-
-        return container
-    end
-})
-
-function bar:Init()
-    self:SetMovable(true)
-    self:EnableMouse(true)
-    self:RegisterForDrag("LeftButton")
-    self:SetScript("OnDragStart", function(self, ...)
-        if self:GetParent() then
-            self:GetParent():StartMoving(...)
-        end
-    end)
-    self:SetScript("OnDragStop", function(self, ...)
-        if self:GetParent() then
-            self:GetParent():StopMovingOrSizing(...)
-        end
-    end)
-
-    self.currencyBox = CreateFrame('FRAME', 'DJBagsMainBarCurrencyBox', self)
-    self.currency = self.currencyBox:CreateFontString('DJBagMainBarCurrencyText', 'OVERLAY', 'GameFontNormal')
-    self.currency:SetAllPoints()
-    self.currencyBox:SetPoint('TOPLEFT', 5, -5)
-    self.currencyBox:SetPoint('BOTTOMLEFT', 5, 5)
-    self.searchBox = CreateFrame('EDITBOX', 'DJBagsMainBarSearch', self, 'BagSearchBoxTemplate')
-    self.searchBox:SetPoint('TOPLEFT', self.currencyBox, 'TOPRIGHT', 10, 0)
-    self.searchBox:SetPoint('BOTTOMLEFT', self.currencyBox, 'BOTTOMRIGHT', 10, 0)
-    self.searchBox:SetWidth(125)
-    self.slots = self:CreateFontString('DJBagMainBarSlotsText', 'OVERLAY', 'GameFontNormal')
-    self.slots:SetPoint('TOPLEFT', self.searchBox, 'TOPRIGHT', 5, 0)
-    self.slots:SetPoint('BOTTOMLEFT', self.searchBox, 'BOTTOMRIGHT', 5, 0)
-
-    self.bagBtn = CreateFrame("CheckButton", 'DJMainBarBagBtn', self, 'UIRadioButtonTemplate')
-    self.bagBtn:SetPoint('RIGHT', -5, 0)
-    self.bagBtn:SetScript('OnClick', function()
-        if self.bagFrame then
-            if self.bagBtn:GetChecked() then
-                self.bagFrame:Show()
-            else
-                self.bagFrame:Hide()
-            end
-        end
-    end)
-
-    self.clearBtn = CreateFrame('Button', 'DJMainBarClearBtn', self)
-    self.clearBtn:SetNormalTexture([[Interface\Buttons\UI-RotationLeft-Button-Up]])
-    self.clearBtn:SetPushedTexture([[Interface\Buttons\UI-RotationLeft-Button-Down]])
-    self.clearBtn:SetHighlightTexture([[Interface\Buttons\ButtonHilight-Square]])
-    self.clearBtn:GetHighlightTexture():ClearAllPoints()
-    self.clearBtn:GetHighlightTexture():SetPoint('TOPLEFT', 3, -3)
-    self.clearBtn:GetHighlightTexture():SetPoint('BOTTOMRIGHT', -3, 3)
-    self.clearBtn:SetPoint('RIGHT', self.bagBtn, 'LEFT', -1, 0)
-    self.clearBtn:SetSize(25, 25)
-    self.clearBtn:SetScript('OnEnter', function(self)
-        GameTooltip:SetOwner(self, 'TOPRIGHT')
-        GameTooltip:SetText('Clear New Items')
-        GameTooltip:Show()
-    end)
-    self.clearBtn:SetScript('OnLeave', function(self)
-        GameTooltip:Hide()
-    end)
-    self.clearBtn:SetScript('OnClick', function(self)
-        C_NewItems:ClearAll()
-        ADDON.bag:NewItemsUpdated()
-    end)
-
-    self.currencyBox:SetScript('OnEnter', function()
-        local cnt = GetCurrencyListSize()
-        GameTooltip:SetOwner(self.currencyBox, "ANCHOR_NONE")
-        GameTooltip:SetPoint("BOTTOMLEFT", self.currencyBox, "TOPLEFT")
-        GameTooltip:SetText("Currency")
-        for index = 1, cnt do
-            local name, _, _, _, _, count, texture, _, _, _, _ = GetCurrencyListInfo(index)
-            if count ~= 0 and texture ~= nil then
-                GameTooltip:AddDoubleLine(name, count .. " |T" .. texture .. ":16|t", 1, 1, 1, 1, 1, 1)
-            end
-        end
-        GameTooltip:Show()
-    end)
-
-    self.currencyBox:SetScript('OnLeave', function()
-        GameTooltip:Hide()
-    end)
-end
-
-function bar:SetBagFrame(frame)
-    self.bagFrame = frame
-    if self.bagBtn:GetChecked() then
-        frame:Show()
-    else
-        frame:Hide()
-    end
-end
-
-function bar:Setup()
-    ADDON.container.Setup(self)
-
-    local settings = ADDON.settings.mainBar
-    local font, _, outline = self.currency:GetFont()
-    self.currency:SetFont(font, settings.currencyFontSize, outline)
-    self.currency:SetTextColor(unpack(settings.currencyFontColor))
-
-    font, _, outline = self.slots:GetFont()
-    self.slots:SetFont(font, settings.slotsFontSize, outline)
-    self.slots:SetTextColor(unpack(settings.slotsFontColor))
-end
-
-function bar:Update()
-    self.currency:SetText(GetCoinTextureString(GetMoney()))
-
-    local total, free = 0, 0
-    for bag = 0, NUM_BAG_SLOTS do
-        total = total + GetContainerNumSlots(bag)
-        free = free + GetContainerNumFreeSlots(bag)
-    end
-    self.slots:SetText(string.format("%d/%d", total - free, total))
-
-    self.currencyBox:SetWidth(self.currency:GetStringWidth())
-    self:SetSize(self.currency:GetStringWidth() + self.slots:GetStringWidth() + 190, math.max(self.currency:GetStringHeight(), self.slots:GetStringHeight()) + 12)
-end
diff --git a/src/lua/event/eventManager.lua b/src/lua/event/eventManager.lua
deleted file mode 100644
index 6d4b442..0000000
--- a/src/lua/event/eventManager.lua
+++ /dev/null
@@ -1,37 +0,0 @@
-local NAME, ADDON = ...
-
-local eventFrame = CreateFrame("FRAME", "DJBagsEventsFrame", nil)
-eventFrame:Hide()
-
-eventFrame.types = {}
-
-function eventFrame:FireEvent(event, ...)
-    if not self.types[event] then return end
-
-    for k, _ in pairs(self.types[event]) do
-        if k[event] then
-            k[event](k, ...)
-        end
-    end
-end
-
-eventFrame:SetScript("OnEvent", eventFrame.FireEvent)
-
-function eventFrame:AddEvent(obj, event)
-    if not obj[event] then return end
-
-    if not self.types[event] then
-        self.types[event] = {}
-        self:RegisterEvent(event)
-    end
-
-    self.types[event][obj] = true
-end
-
-function eventFrame:RemoveEvent(obj, event)
-    if not self.types[event] and not self.types[event][obj] then return end
-
-    self.types[event][obj] = nil
-end
-
-ADDON.eventManager = eventFrame
\ No newline at end of file
diff --git a/src/lua/events/events.lua b/src/lua/events/events.lua
new file mode 100644
index 0000000..cbf51ee
--- /dev/null
+++ b/src/lua/events/events.lua
@@ -0,0 +1,41 @@
+local NAME, ADDON = ...
+
+ADDON.events = CreateFrame('FRAME')
+
+local events = ADDON.events
+events.list = {}
+
+events:SetScript('OnEvent', function(self, event, ...)
+    self:Fire(event, ...)
+end)
+
+function events:Fire(event, ...)
+    if not event or not self.list[event] then return end
+
+    for obj in pairs(self.list[event]) do
+        obj[event](obj, ...)
+    end
+end
+
+function events:Add(event, obj)
+    if not event or not obj or not obj[event] then return end
+
+    if not self.list[event] then
+        self.list[event] = {}
+
+        self:RegisterEvent(event)
+    end
+
+    self.list[event][obj] = true
+end
+
+function events:Remove(event, obj)
+    if not event or not obj or not self.list[event] or not self.list[event][obj] then return end
+
+    self.list[event][obj] = nil
+
+    if next(self.list[event]) == nil and ADDON:Count(self.list[event]) == 0 then
+        self.list[event] = nil
+        self:UnregisterEvent(event)
+    end
+end
\ No newline at end of file
diff --git a/src/lua/formatters/horizontal.lua b/src/lua/formatters/horizontal.lua
deleted file mode 100644
index fc20d81..0000000
--- a/src/lua/formatters/horizontal.lua
+++ /dev/null
@@ -1,61 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.formatters = ADDON.formatters or {}
-
-ADDON.formatters['horizontal'] = {}
-
-local formatter = ADDON.formatters['horizontal']
-formatter.__index = formatter
-
-function formatter:Format(container)
-    local settings = ADDON.settings.formatter.horizontal
-
-    local list = container.containers
-
-    local maxCols = settings.cols
-    local h = container.padding
-
-    local x = container.padding
-    local mH = 0
-    local mW = 0
-    local cnt = 0
-    local lastH = 0
-
-    for v in ADDON.utils:PairsByKey(list, ADDON.sorters.containers[settings.sorter]) do
-        if v:IsEmpty() then
-            v:Hide()
-        else
-            v:Show()
-            local numItems = v.name == EMPTY and 1 or v:Count()
-
-            if cnt ~= 0 and (cnt + numItems) > maxCols then
-                x = container.padding
-                h = h + mH + container.spacing
-                cnt = 0
-                mH = 0
-            end
-
-            if numItems > maxCols then
-                v:Arrange(maxCols)
-            else
-                v:Arrange(numItems)
-            end
-
-            v:SetParent(container)
-            v:ClearAllPoints()
-            v:SetPoint('TOPLEFT', x, -h)
-
-            mH = math.max(mH, v:GetHeight())
-            mW = math.max(mW, x + v:GetWidth())
-            x = x + container.spacing + v:GetWidth()
-
-            cnt = cnt + numItems
-            lastH = v:GetHeight()
-        end
-    end
-
-    container:SetSize(
-        mW + container.padding,
-        h + container.padding + lastH
-    )
-end
\ No newline at end of file
diff --git a/src/lua/formatters/vertical.lua b/src/lua/formatters/vertical.lua
deleted file mode 100644
index 92e32cb..0000000
--- a/src/lua/formatters/vertical.lua
+++ /dev/null
@@ -1,43 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.formatters = ADDON.formatters or {}
-
-ADDON.formatters['vertical'] = {}
-
-local formatter = ADDON.formatters['vertical']
-formatter.__index = formatter
-
-function formatter:Format(container)
-    local settings = ADDON.settings.formatter.vertical
-
-    local list = container.containers
-
-    local x = -container.padding
-    local y = container.padding
-    local width = 0
-    local height = 0
-
-    for item in ADDON.utils:PairsByKey(list, ADDON.sorters.containers[settings.sorter]) do
-        item:Arrange(settings.cols)
-        item:ClearAllPoints()
-        item:SetParent(container)
-
-        if item:IsEmpty() then
-            item:Hide()
-        else
-            item:Show()
-            if (y + item:GetHeight() + container.spacing) > (settings.maxHeight / 100 * GetScreenHeight()) then
-                y = container.padding
-                x = x - item:GetWidth() - container.spacing
-            end
-
-            item:SetPoint('BOTTOMRIGHT', x, y)
-
-            height = math.max(height, y + item:GetHeight() + container.padding)
-            width = math.max(width, -x + container.padding + item:GetWidth())
-            y = y + container.spacing + item:GetHeight()
-        end
-    end
-
-    container:SetSize(width, height)
-end
\ No newline at end of file
diff --git a/src/lua/settings/defaults/auto.lua b/src/lua/settings/defaults/auto.lua
deleted file mode 100644
index d882405..0000000
--- a/src/lua/settings/defaults/auto.lua
+++ /dev/null
@@ -1,9 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.settings = ADDON.settings or {}
-
-ADDON.settings.auto = {
-    depositReagents = false,
-    sellJunk = false,
-    clearNewItems = false,
-}
\ No newline at end of file
diff --git a/src/lua/settings/defaults/bagItem.lua b/src/lua/settings/defaults/bagItem.lua
deleted file mode 100644
index af69a5d..0000000
--- a/src/lua/settings/defaults/bagItem.lua
+++ /dev/null
@@ -1,7 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.settings = ADDON.settings or {}
-
-ADDON.settings.bagItem = {
-    size = 32,
-}
\ No newline at end of file
diff --git a/src/lua/settings/defaults/category.lua b/src/lua/settings/defaults/category.lua
deleted file mode 100644
index 482757b..0000000
--- a/src/lua/settings/defaults/category.lua
+++ /dev/null
@@ -1,20 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.settings = ADDON.settings or {}
-
-ADDON.settings.categories = {
-    subClass = {
-        [LE_ITEM_CLASS_ARMOR] = false,
-        [LE_ITEM_CLASS_CONSUMABLE] = true,
-        [LE_ITEM_CLASS_GEM] = false,
-        [LE_ITEM_CLASS_GLYPH] = false,
-        [LE_ITEM_CLASS_ITEM_ENHANCEMENT] = false,
-        [LE_ITEM_CLASS_MISCELLANEOUS] = true,
-        [LE_ITEM_CLASS_RECIPE] = false,
-        [LE_ITEM_CLASS_TRADEGOODS] = true,
-        [LE_ITEM_CLASS_WEAPON] = false,
-    },
-    userDefined = {
-    }
-}
-
diff --git a/src/lua/settings/defaults/categoryContainer.lua b/src/lua/settings/defaults/categoryContainer.lua
deleted file mode 100644
index 55df250..0000000
--- a/src/lua/settings/defaults/categoryContainer.lua
+++ /dev/null
@@ -1,12 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.settings = ADDON.settings or {}
-
-ADDON.settings.categoryContainer = {
-    padding = 5,
-    spacing = 3,
-    formatter = 'vertical',
-    closeVisible = false,
-    closeSize = 25,
-}
-
diff --git a/src/lua/settings/defaults/container.lua b/src/lua/settings/defaults/container.lua
deleted file mode 100644
index 8b57935..0000000
--- a/src/lua/settings/defaults/container.lua
+++ /dev/null
@@ -1,9 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.settings = ADDON.settings or {}
-
-ADDON.settings.container = {
-    borderColor = { 0.3, 0.3, 0.3, 0.9 },
-    borderWidth = 1,
-    backgroundColor = { 0, 0, 0, 0.6 },
-}
\ No newline at end of file
diff --git a/src/lua/settings/defaults/formatter.lua b/src/lua/settings/defaults/formatter.lua
deleted file mode 100644
index c9ecae2..0000000
--- a/src/lua/settings/defaults/formatter.lua
+++ /dev/null
@@ -1,16 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.settings = ADDON.settings or {}
-
-ADDON.settings.formatter = {
-    vertical = {
-        sorter = 'defaultVertical',
-        cols = 4,
-        maxHeight = 50,
-    },
-    horizontal = {
-        sorter = 'defaultHorizontal',
-        cols = 12,
-    },
-}
-
diff --git a/src/lua/settings/defaults/item.lua b/src/lua/settings/defaults/item.lua
deleted file mode 100644
index 29c84f9..0000000
--- a/src/lua/settings/defaults/item.lua
+++ /dev/null
@@ -1,8 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.settings = ADDON.settings or {}
-
-ADDON.settings.item = {
-    size = 32,
-}
-
diff --git a/src/lua/settings/defaults/itemContainer.lua b/src/lua/settings/defaults/itemContainer.lua
deleted file mode 100644
index b2ebaa0..0000000
--- a/src/lua/settings/defaults/itemContainer.lua
+++ /dev/null
@@ -1,14 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.settings = ADDON.settings or {}
-
-ADDON.settings.itemContainer = {
-    spacing = 3,
-    padding = 5,
-    cols = 5,
-    fontSize = 13,
-    fontColor = { 0.5, 1, 0.5, 1 },
-    titleMargin = 5,
-    sortFunction = 'default',
-    showClassWithSub = true,
-}
\ No newline at end of file
diff --git a/src/lua/settings/defaults/mainBar.lua b/src/lua/settings/defaults/mainBar.lua
deleted file mode 100644
index b063dca..0000000
--- a/src/lua/settings/defaults/mainBar.lua
+++ /dev/null
@@ -1,10 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.settings = ADDON.settings or {}
-
-ADDON.settings.mainBar = {
-    currencyFontSize = 12,
-    currencyFontColor = { 1, 1, 1, 1 },
-    slotsFontSize = 12,
-    slotsFontColor = { 1, 1, 1, 1 },
-}
\ No newline at end of file
diff --git a/src/lua/settings/editor.lua b/src/lua/settings/editor.lua
deleted file mode 100644
index 76c6346..0000000
--- a/src/lua/settings/editor.lua
+++ /dev/null
@@ -1,529 +0,0 @@
-local NAME, ADDON = ...
-
-local STEP = 1
-local SCROLL = 20
-local MAX = 1
-
-ADDON.settingsEditor = {}
-ADDON.settingsEditor.__index = ADDON.settingsEditor
-
-local settings = ADDON.settingsEditor
-setmetatable(settings, {
-    __call = function(self)
-        return self.frame or self:CreateFrame()
-    end
-})
-
-function settings:UpdateSettings()
-    if self.frame then
-        self.frame:Setup()
-        if self.containers then
-            for _, v in pairs(self.containers) do
-                v:Setup()
-            end
-        end
-    end
-end
-
-function settings:CreateFrame()
-    self.frame = ADDON.container('DJBagsSettingsScreen')
-    self.frame:SetSize(520, 0.5 * GetScreenHeight())
-    self.frame:SetPoint("TOPLEFT", 200, -200)
-    self.frame:Hide()
-    table.insert(UISpecialFrames, self.frame:GetName())
-
-    self.title = self.frame:CreateFontString('DJBagsSettingsScreenTitle', nil, 'GameFontNormal')
-    self.title:SetText('DJBags Settings')
-    self.title:SetPoint('TOPLEFT', 5, -5)
-
-    self.exitBtn = CreateFrame('BUTTON', 'DJBagsSettingsScreenExitButton', self.frame, 'UIPanelCloseButton')
-    self.exitBtn:SetPoint('TOPRIGHT')
-
-    self.scrollBar = CreateFrame("Slider", 'DJBagsSettingsScreenScrollBar', self.frame, "UIPanelScrollBarTemplate")
-    self.scrollBar:SetPoint('TOPRIGHT', -5, -50)
-    self.scrollBar:SetPoint('BOTTOMRIGHT', -5, 25)
-    self.scrollBar:SetMinMaxValues(1, MAX)
-    self.scrollBar:SetValueStep(STEP)
-    self.scrollBar.scrollStep = SCROLL
-    self.scrollBar:SetScript("OnValueChanged",
-        function(self, value)
-            settings.scrollFrame:SetVerticalScroll(value)
-        end)
-
-    self.scrollFrame = CreateFrame("ScrollFrame", 'DJBagsSettingsScreenScrollFrame', self.frame)
-    self.scrollFrame:SetPoint('TOPLEFT', 5, -30)
-    self.scrollFrame:SetPoint('BOTTOMRIGHT', self.scrollBar, 'BOTTOMLEFT', -5, -15)
-    self.scrollBar:SetValue(1)
-
-    self.scrollFrame:EnableMouseWheel(true)
-    self.scrollFrame:SetScript("OnMouseWheel", function(self, delta)
-        local current = settings.scrollBar:GetValue()
-
-        if IsShiftKeyDown() and (delta > 0) then
-            settings.scrollBar:SetValue(0)
-        elseif IsShiftKeyDown() and (delta < 0) then
-            settings.scrollBar:SetValue(MAX)
-        elseif (delta < 0) and (current < MAX) then
-            settings.scrollBar:SetValue(math.min(current + 20, MAX))
-        elseif (delta > 0) and (current > 1) then
-            settings.scrollBar:SetValue(math.max(current - 20, 1))
-        end
-    end)
-
-    self.content = CreateFrame("Frame", 'DJBagsSettingsScreenContent', self.scrollFrame)
-    self.content:SetSize(self.scrollFrame:GetWidth(), 0)
-
-    self.scrollFrame:SetScrollChild(self.content)
-
-    self:CreateAutoSettings()
-    self:CreateCategorySettings()
-    self:CreateFormatterSettings()
-    self:CreateItemSettings()
-    self:CreateContainerSettings()
-    self:CreateItemContainerSettings()
-    self:CreateCategoryContainerSettings()
-    self:CreateMainBarSettings()
-
-    self.settingsFrame = CreateFrame('FRAME', 'DJBagsSettingsOpenFrame', UIParent)
-    self.settingsFrame.name = 'DJBags'
-    self.settingsTextInfo = self.settingsFrame:CreateFontString('DJBagsSettingsInfo', 'OVERLAY', 'GameFontNormal')
-    self.settingsTextInfo:SetPoint('CENTER')
-    self.settingsTextInfo:SetText('In order to access DJBag\'s settings, please type:\n\n/db\n\nor\n\n/djbags\n\nin the game chat window.')
-    InterfaceOptions_AddCategory(self.settingsFrame);
-
-    return self.frame
-end
-
-function settings:AddSettingsPanel(panel)
-    self.containers = self.containers or {}
-    tinsert(self.containers, panel)
-    panel:SetParent(self.content)
-    panel:SetPoint('TOPLEFT', 0, -5 - self.content:GetHeight())
-    panel:SetPoint('TOPRIGHT', 0, -5 - self.content:GetHeight())
-    self.content:SetHeight(self.content:GetHeight() + panel:GetHeight() + 5)
-
-    MAX = math.max(MAX, self.content:GetHeight() - self.scrollFrame:GetHeight())
-    self.scrollBar:SetMinMaxValues(1, MAX)
-end
-
-local function CreateColorSelector(name, parent, getColor, callBack)
-    local colourSelector = CreateFrame('BUTTON', 'DJBagsSettingsColourSelector' .. name .. ADDON.uuid(), parent)
-    colourSelector:SetNormalFontObject("GameFontHighlight")
-    colourSelector:SetText(name)
-    colourSelector:SetBackdrop({
-        bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
-        edgeFile = "Interface\\Buttons\\WHITE8x8",
-        tile = true,
-        tileSize = 16,
-        edgeSize = 2,
-    })
-    colourSelector:SetBackdropBorderColor(unpack(getColor()))
-    colourSelector:SetBackdropColor(0, 0, 0, 1)
-    colourSelector.call = callBack
-
-    colourSelector:SetScript('OnClick', function(self)
-        local r, g, b, a = unpack(getColor())
-
-        local function callback(restore)
-            local newR, newG, newB, newA = r, g, b, a;
-            if not restore then
-                newA, newR, newG, newB = OpacitySliderFrame:GetValue(), ColorPickerFrame:GetColorRGB();
-            end
-
-            self:SetBackdropBorderColor(newR, newG, newB, newA)
-            self.call(newR, newG, newB, newA)
-        end
-
-        ColorPickerFrame.func, ColorPickerFrame.opacityFunc, ColorPickerFrame.cancelFunc = callback, callback, callback;
-        ColorPickerFrame:SetColorRGB(r, g, b, a);
-        ColorPickerFrame.hasOpacity, ColorPickerFrame.opacity = (a ~= nil), a;
-        ColorPickerFrame.previousValues = { r, g, b, a };
-        ShowUIPanel(ColorPickerFrame)
-    end)
-
-    colourSelector:SetSize(150, 20)
-    return colourSelector
-end
-
-local function round(num)
-    if num >= 0 then return math.floor(num + .5)
-    else return math.ceil(num - .5)
-    end
-end
-
-local function CreateSlider(name, parent, min, max, value, callBack)
-    local slider = CreateFrame('Slider', 'DJBagsSettingsColourSelector' .. name .. ADDON.uuid(), parent, 'OptionsSliderTemplate')
-    getglobal(slider:GetName() .. "Text"):SetText(name .. ' - ' .. tostring(value()));
-    getglobal(slider:GetName() .. "High"):SetText(max);
-    getglobal(slider:GetName() .. "Low"):SetText(min);
-    slider:SetMinMaxValues(min, max)
-    slider:SetValue(value())
-    slider:Show()
-
-    slider:SetScript('OnValueChanged', function(self, value)
-        value = round(value)
-        callBack(value)
-        getglobal(self:GetName() .. "Text"):SetText(name .. ' - ' .. tostring(value));
-    end)
-
-    return slider
-end
-
-local function CreateTitle(title, parent)
-    parent.title = parent:CreateFontString('DJBagsSettingsScreenTitle' .. title .. ADDON.uuid(), nil, 'GameFontNormal')
-    parent.title:SetText(title)
-    parent.title:SetPoint('TOPLEFT', 5, -5)
-end
-
-local function CreateCheckBox(name, container, checked, callBack)
-    local check = CreateFrame('CHECKBUTTON', 'DJBagsSettingsCheckButton' .. name .. ADDON.uuid(), container, 'UICheckButtonTemplate')
-    _G[check:GetName() .. "Text"]:SetText(name)
-    check.textW = _G[check:GetName() .. "Text"]:GetStringWidth()
-    check.call = callBack
-    check:SetChecked(checked)
-    check:SetScript('OnClick', function(self)
-        self.call(self:GetChecked())
-    end)
-    return check
-end
-
-function settings:CreateItemSettings()
-    local container = ADDON.container('DJBagsSettingsItemScreen', nil)
-
-    CreateTitle('Item settings', container)
-
-    container.size = CreateSlider('Size', container, 18, 50, function()
-        return ADDON.settings.item.size
-    end, function(value)
-        ADDON.settings.item.size = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end)
-    container.size:SetPoint('TOPLEFT', 10, -35)
-
-    container:SetHeight(65)
-    self:AddSettingsPanel(container)
-end
-
-function settings:CreateContainerSettings()
-    local container = ADDON.container('DJBagsSettingsContainerScreen', nil)
-
-    CreateTitle('Border and Background', container)
-
-    container.borderPicker = CreateColorSelector('Border Colour', container, function()
-        return ADDON.settings.container.borderColor
-    end, function(r, g, b, a)
-        ADDON.settings.container.borderColor = { r, g, b, a }
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE')
-    end)
-    container.borderPicker:SetPoint('TOPLEFT', 5, -25)
-
-    container.backgroundPicker = CreateColorSelector('Background Colour', container, function()
-        return ADDON.settings.container.backgroundColor
-    end, function(r, g, b, a)
-        ADDON.settings.container.backgroundColor = { r, g, b, a }
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE')
-    end)
-    container.backgroundPicker:SetPoint('TOPLEFT', container.borderPicker, 'TOPRIGHT', 15, 0)
-
-    container.borderWidth = CreateSlider('Border Width', container, 1, 4, function()
-        return ADDON.settings.container.borderWidth
-    end, function(value)
-        ADDON.settings.container.borderWidth = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE')
-    end)
-    container.borderWidth:SetPoint('TOPLEFT', container.backgroundPicker, 'TOPRIGHT', 15, 0)
-
-    container:SetHeight(55)
-    self:AddSettingsPanel(container)
-end
-
-function settings:CreateItemContainerSettings()
-    local container = ADDON.container('DJBagsSettingsItemContainerScreen', nil)
-
-    CreateTitle('Category container settings', container)
-
-    container.fontColor = CreateColorSelector('Font Colour', container, function()
-        return ADDON.settings.itemContainer.fontColor
-    end, function(r, g, b, a)
-        ADDON.settings.itemContainer.fontColor = { r, g, b, a }
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE')
-    end)
-    container.fontColor:SetPoint('TOPLEFT', 5, -25)
-
-    container.fontSize = CreateSlider('Font size', container, 8, 18, function()
-        return ADDON.settings.itemContainer.fontSize
-    end, function(value)
-        ADDON.settings.itemContainer.fontSize = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end)
-    container.fontSize:SetPoint('TOPLEFT', container.fontColor, 'TOPRIGHT', 15, 0)
-
-    container.padding = CreateSlider('Padding', container, 1, 10, function()
-        return ADDON.settings.itemContainer.padding
-    end, function(value)
-        ADDON.settings.itemContainer.padding = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end)
-    container.padding:SetPoint('TOPLEFT', container.fontSize, 'TOPRIGHT', 15, 0)
-
-    container.spacing = CreateSlider('Item Spacing', container, 1, 10, function()
-        return ADDON.settings.itemContainer.spacing
-    end, function(value)
-        ADDON.settings.itemContainer.spacing = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end)
-    container.spacing:SetPoint('TOPLEFT', container.fontColor, 'BOTTOMLEFT', 2, -20)
-
-    container.subClassWithClass = CreateCheckBox('Show Class With Subclass', container, ADDON.settings.itemContainer.showClassWithSub, function(value)
-        ADDON.settings.itemContainer.showClassWithSub = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE')
-    end)
-    container.subClassWithClass:SetPoint('LEFT', container.spacing, 'RIGHT', 10, 0)
-
-    container:SetHeight(95)
-    self:AddSettingsPanel(container)
-end
-
-function settings:CreateCategoryContainerSettings()
-    local container = ADDON.container('DJBagsSettingsCategoryContainerScreen', nil)
-
-    CreateTitle('Bag container settings', container)
-
-    container.padding = CreateSlider('Padding', container, 1, 10, function()
-        return ADDON.settings.categoryContainer.padding
-    end, function(value)
-        ADDON.settings.categoryContainer.padding = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end)
-    container.padding:SetPoint('TOPLEFT', 15, -35)
-
-    container.spacing = CreateSlider('Container spacing', container, 1, 10, function()
-        return ADDON.settings.categoryContainer.spacing
-    end, function(value)
-        ADDON.settings.categoryContainer.spacing = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end)
-    container.spacing:SetPoint('TOPLEFT', container.padding, 'TOPRIGHT', 15, 0)
-
-    local closeBtn = CreateCheckBox("Close Button visible", container, ADDON.settings.categoryContainer.closeVisible, function(value)
-        ADDON.settings.categoryContainer.closeVisible = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end)
-    closeBtn:SetPoint('LEFT', container.spacing, 'RIGHT', 15, 0)
-
-    container:SetHeight(65)
-    self:AddSettingsPanel(container)
-end
-
-function settings:CreateMainBarSettings()
-    local container = ADDON.container('DJBagsSettingsMainBarScreen', nil)
-
-    CreateTitle('Main Bar', container)
-
-    container.currencyFontColor = CreateColorSelector('Currency Font Colour', container, function()
-        return ADDON.settings.mainBar.currencyFontColor
-    end, function(r, g, b, a)
-        ADDON.settings.mainBar.currencyFontColor = { r, g, b, a }
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE')
-    end)
-    container.currencyFontColor:SetPoint('TOPLEFT', 5, -25)
-
-    container.slotFontColor = CreateColorSelector('Slot Font Colour', container, function()
-        return ADDON.settings.mainBar.slotsFontColor
-    end, function(r, g, b, a)
-        ADDON.settings.mainBar.slotsFontColor = { r, g, b, a }
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE')
-    end)
-    container.slotFontColor:SetPoint('TOPLEFT', container.currencyFontColor, 'TOPRIGHT', 15, 0)
-
-    container.currencyFontSize = CreateSlider('Currency font size', container, 8, 18, function()
-        return ADDON.settings.mainBar.currencyFontSize
-    end, function(value)
-        ADDON.settings.mainBar.currencyFontSize = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE')
-    end)
-    container.currencyFontSize:SetPoint('TOPLEFT', container.slotFontColor, 'TOPRIGHT', 15, 0)
-
-    container.slotFontSize = CreateSlider('Slots font size', container, 8, 18, function()
-        return ADDON.settings.mainBar.slotsFontSize
-    end, function(value)
-        ADDON.settings.mainBar.slotsFontSize = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE')
-    end)
-    container.slotFontSize:SetPoint('TOPLEFT', container.currencyFontColor, 'BOTTOMLEFT', 2, -20)
-
-    container:SetHeight(95)
-    self:AddSettingsPanel(container)
-end
-
-function settings:CreateCategorySettings()
-    local container = ADDON.container('DJBagsSettingsMainBarScreen', nil)
-
-    CreateTitle('Category Subclassing', container)
-
-    function container:Add(item)
-        self.items = self.items or {}
-        tinsert(self.items, item)
-    end
-
-    container:Add(CreateCheckBox(AUCTION_CATEGORY_ARMOR, container, ADDON.settings.categories.subClass[LE_ITEM_CLASS_ARMOR], function(value)
-        ADDON.settings.categories.subClass[LE_ITEM_CLASS_ARMOR] = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end))
-    container:Add(CreateCheckBox(AUCTION_CATEGORY_CONSUMABLES, container, ADDON.settings.categories.subClass[LE_ITEM_CLASS_CONSUMABLE], function(value)
-        ADDON.settings.categories.subClass[LE_ITEM_CLASS_CONSUMABLE] = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end))
-    container:Add(CreateCheckBox(AUCTION_CATEGORY_GEMS, container, ADDON.settings.categories.subClass[LE_ITEM_CLASS_GEM], function(value)
-        ADDON.settings.categories.subClass[LE_ITEM_CLASS_GEM] = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end))
-    container:Add(CreateCheckBox(AUCTION_CATEGORY_GLYPHS, container, ADDON.settings.categories.subClass[LE_ITEM_CLASS_GLYPH], function(value)
-        ADDON.settings.categories.subClass[LE_ITEM_CLASS_GLYPH] = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end))
-    container:Add(CreateCheckBox(AUCTION_CATEGORY_ITEM_ENHANCEMENT, container, ADDON.settings.categories.subClass[LE_ITEM_CLASS_ITEM_ENHANCEMENT], function(value)
-        ADDON.settings.categories.subClass[LE_ITEM_CLASS_ITEM_ENHANCEMENT] = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end))
-    container:Add(CreateCheckBox(AUCTION_CATEGORY_MISCELLANEOUS, container, ADDON.settings.categories.subClass[LE_ITEM_CLASS_MISCELLANEOUS], function(value)
-        ADDON.settings.categories.subClass[LE_ITEM_CLASS_MISCELLANEOUS] = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end))
-    container:Add(CreateCheckBox(AUCTION_CATEGORY_RECIPES, container, ADDON.settings.categories.subClass[LE_ITEM_CLASS_RECIPE], function(value)
-        ADDON.settings.categories.subClass[LE_ITEM_CLASS_RECIPE] = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end))
-    container:Add(CreateCheckBox(AUCTION_CATEGORY_TRADE_GOODS, container, ADDON.settings.categories.subClass[LE_ITEM_CLASS_TRADEGOODS], function(value)
-        ADDON.settings.categories.subClass[LE_ITEM_CLASS_TRADEGOODS] = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end))
-    container:Add(CreateCheckBox(AUCTION_CATEGORY_WEAPONS, container, ADDON.settings.categories.subClass[LE_ITEM_CLASS_WEAPON], function(value)
-        ADDON.settings.categories.subClass[LE_ITEM_CLASS_WEAPON] = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end))
-
-    local y = -20
-    local x = 5
-    if container.items then
-        for _, item in pairs(container.items) do
-            if x + item.textW > self.scrollFrame:GetWidth() - 10 then
-                x = 5
-                y = y - 30
-            end
-            item:SetPoint('TOPLEFT', x, y)
-            x = x + item.textW + 35
-        end
-    end
-
-    container:SetHeight(35 - y)
-    self:AddSettingsPanel(container)
-end
-
-function settings:CreateAutoSettings()
-    local container = ADDON.container('DJBagsSettingsAutoScreen', nil)
-
-    CreateTitle('Automatic tools', container)
-
-    local autoSellJunk = CreateCheckBox("Auto sell junk", container, ADDON.settings.auto.sellJunk, function(value)
-        ADDON.settings.auto.sellJunk = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end)
-    autoSellJunk:SetPoint('TOPLEFT', 5, -20)
-    local autoDeposit = CreateCheckBox("Auto deposit reagents", container, ADDON.settings.auto.depositReagents, function(value)
-        ADDON.settings.auto.depositReagents = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end)
-    autoDeposit:SetPoint('LEFT', autoSellJunk, 'RIGHT', 75, 0)
-    local autoClearNewItems = CreateCheckBox("Clear New Items on close", container, ADDON.settings.auto.clearNewItems, function(value)
-        ADDON.settings.auto.clearNewItems = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end)
-    autoClearNewItems:SetPoint('LEFT', autoDeposit, 'RIGHT', 115, 0)
-
-    container:SetHeight(55)
-    self:AddSettingsPanel(container)
-end
-
-function settings:CreateFormatterSettings()
-    local container = ADDON.container('DJBagsSettingsFormatter', nil)
-
-    CreateTitle('Format settings', container)
-
-    container.dropDown = CreateFrame("Button", "DJBagsCategoryDialogDropDown", container, "UIDropDownMenuTemplate")
-    container.dropDown:SetPoint('TOPLEFT', container, 5, -20)
-    UIDropDownMenu_SetWidth(container.dropDown, 100);
-    UIDropDownMenu_SetButtonWidth(container.dropDown, 124)
-    UIDropDownMenu_JustifyText(container.dropDown, "LEFT")
-
-    UIDropDownMenu_Initialize(container.dropDown, function(self, level)
-        local info
-        for k, _ in pairs(ADDON.formatters) do
-            info = UIDropDownMenu_CreateInfo()
-            info.text = k
-            info.value = k
-            info.func = function(self)
-                UIDropDownMenu_SetSelectedID(container.dropDown, self:GetID())
-                ADDON.settings.categoryContainer.formatter = tostring(self.value)
-                if self.value == 'vertical' then
-                    container.vertical:Show()
-                    container.horizontal:Hide()
-                else
-                    container.vertical:Hide()
-                    container.horizontal:Show()
-                end
-                ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-            end
-            UIDropDownMenu_AddButton(info, level)
-        end
-    end)
-
-    UIDropDownMenu_SetSelectedValue(container.dropDown, ADDON.settings.categoryContainer.formatter)
-
-    container.vertical = CreateFrame('FRAME', 'DJBagsSettingsFormatterVert', container)
-    container.vertical:SetPoint('TOPLEFT', 0, -50)
-    container.vertical:SetPoint('TOPRIGHT', 0, -50)
-    container.vertical:SetPoint('BOTTOMLEFT')
-    container.vertical:SetPoint('BOTTOMRIGHT')
-
-    container.colsVertical = CreateSlider('Columns', container.vertical, 4, 12, function()
-        return ADDON.settings.formatter.vertical.cols
-    end, function(value)
-        ADDON.settings.formatter.vertical.cols = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end)
-    container.colsVertical:SetPoint('TOPLEFT', 10, -20)
-
-    container.maxHeight = CreateSlider('Max Height', container.vertical, 20, 100, function()
-        return ADDON.settings.formatter.vertical.maxHeight
-    end, function(value)
-        ADDON.settings.formatter.vertical.maxHeight = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end)
-    container.maxHeight:SetPoint('TOPLEFT', container.colsVertical, 'TOPRIGHT', 15, 0)
-
-    container.horizontal = CreateFrame('FRAME', 'DJBagsSettingsFormatterHoz', container)
-    container.horizontal:SetPoint('TOPLEFT', 0, -50)
-    container.horizontal:SetPoint('TOPRIGHT', 0, -50)
-    container.horizontal:SetPoint('BOTTOMLEFT')
-    container.horizontal:SetPoint('BOTTOMRIGHT')
-
-    container.colsHorizontal = CreateSlider('Columns', container.horizontal, 4, 16, function()
-        return ADDON.settings.formatter.horizontal.cols
-    end, function(value)
-        ADDON.settings.formatter.horizontal.cols = value
-        ADDON.eventManager:FireEvent('SETTINGS_UPDATE', true)
-    end)
-    container.colsHorizontal:SetPoint('TOPLEFT', 10, -20)
-
-    if ADDON.settings.categoryContainer.formatter == 'vertical' then
-        container.vertical:Show()
-        container.horizontal:Hide()
-    else
-        container.vertical:Hide()
-        container.horizontal:Show()
-    end
-
-    container:SetHeight(100)
-    self:AddSettingsPanel(container)
-end
\ No newline at end of file
diff --git a/src/lua/settings/settings.lua b/src/lua/settings/settings.lua
deleted file mode 100644
index 385908c..0000000
--- a/src/lua/settings/settings.lua
+++ /dev/null
@@ -1,68 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.settingsController = {}
-local settings = ADDON.settingsController
-settings.__index = settings
-
---region Events
-
-function settings:Init()
-    self:GetCharacterSettings()
-
-    self.screen = ADDON.settingsEditor()
-
-    ADDON.eventManager:AddEvent(self, "SETTINGS_UPDATE")
-end
-
-function settings:ShowSettings()
-    self.screen:Show()
-end
-
-function settings:SETTINGS_UPDATE()
-    local realm = GetRealmName()
-    local player = UnitName("player")
-
-    if not DJBagsConfig then
-        DJBagsConfig = {}
-    end
-    if not DJBagsConfig[realm] then
-        DJBagsConfig[realm] = {}
-    end
-    DJBagsConfig[realm][player] = ADDON.settings
-
-    ADDON.settingsEditor:UpdateSettings()
-end
-
-function settings:GetCharacterSettings()
-    local realm = GetRealmName()
-    local player = UnitName("player")
-
-    ADDON.globalCategories = {}
-    if DJBagsConfig then
-        if DJBagsConfig[realm] and DJBagsConfig[realm][player] then
-            local userSettings = DJBagsConfig[realm][player]
-            self:MigrateSettings(userSettings, ADDON.settings)
-            ADDON.settings = userSettings
-        end
-        ADDON.globalCategories = DJBagsConfig.globalCategories or {}
-    end
-end
-
-function settings:MigrateSettings(table, default)
-    for k, v in pairs(default) do
-        if table[k] ~= nil then
-            if type(v) ~= type(table[k]) then
-                table[k] = v
-            elseif type(v) == 'table' then
-                self:MigrateSettings(table[k], v)
-            end
-        else
-            table[k] = v
-        end
-    end
-    for k, v in pairs(table) do
-        if not default[k] and type(v) == 'table' then
-            table[k] = nil
-        end
-    end
-end
\ No newline at end of file
diff --git a/src/lua/settings/settingsController.lua b/src/lua/settings/settingsController.lua
new file mode 100644
index 0000000..93ffd71
--- /dev/null
+++ b/src/lua/settings/settingsController.lua
@@ -0,0 +1,123 @@
+local NAME, ADDON = ...
+
+function ADDON:PrintTable(tbl, lvl)
+    local prefix = ''
+    lvl = lvl or 0
+    for _ = 1, lvl do
+        prefix = prefix .. '   '
+    end
+    for k, v in pairs(tbl) do
+        print(prefix, k, v)
+        if (type(v) == 'table') then
+            ADDON:PrintTable(v, lvl + 1)
+        end
+    end
+end
+
+ADDON.settings = {}
+local settings = ADDON.settings
+
+function settings:Init()
+    self.realm = GetRealmName()
+    self.player = UnitName("player")
+
+    DJBags_DB = {}
+    DJBags_DB[self.realm] = DJBags_DB[self.realm] or {}
+    DJBags_DB[self.realm][self.player] = DJBags_DB[self.realm][self.player] or {}
+    DJBags_DB[self.realm][self.player].userDefined = DJBags_DB[self.realm][self.player].userDefined or {}
+
+    DJBags_DB.global = DJBags_DB.global or {}
+    DJBags_DB.global.userDefined = DJBags_DB.global.userDefined or {}
+
+    self.default = {
+        [DJBags_TYPE_CONTAINER] = {
+            [DJBags_SETTING_BACKGROUND_COLOR] = {0, 0, 0, 0.6},
+            [DJBags_SETTING_BORDER_COLOR] = {0.3, 0.3, 0.3, 1},
+            [DJBags_SETTING_PADDING] = 5,
+            [DJBags_SETTING_SPACING] = 5,
+            [DJBags_SETTING_SCALE] = 1,
+            [DJBags_SETTING_FORMATTER] = 'massonry',
+            [DJBags_SETTING_FORMATTER_VERT] = false,
+            [DJBags_SETTING_FORMATTER_MAX_ITEMS] = 12,
+            [DJBags_SETTING_FORMATTER_MAX_HEIGHT] = 0.5,
+            [DJBags_SETTING_TRUNCATE_SUB_CLASS] = true,
+        },
+        [DJBags_TYPE_ITEM_CONTAINER] = {
+            [DJBags_SETTING_BACKGROUND_COLOR] = {0, 0, 0, 0.6},
+            [DJBags_SETTING_BORDER_COLOR] = {0.3, 0.3, 0.3, 1},
+            [DJBags_SETTING_TEXT_COLOR] = {1, 1, 1, 1},
+            [DJBags_SETTING_TEXT_SIZE] = 12,
+            [DJBags_SETTING_PADDING] = 3,
+            [DJBags_SETTING_SPACING] = 3,
+        },
+    }
+    self.defaultSubclass = {
+        [LE_ITEM_CLASS_ARMOR] = false,
+        [LE_ITEM_CLASS_CONSUMABLE] = true,
+        [LE_ITEM_CLASS_GEM] = false,
+        [LE_ITEM_CLASS_GLYPH] = false,
+        [LE_ITEM_CLASS_ITEM_ENHANCEMENT] = false,
+        [LE_ITEM_CLASS_MISCELLANEOUS] = true,
+        [LE_ITEM_CLASS_RECIPE] = false,
+        [LE_ITEM_CLASS_TRADEGOODS] = true,
+        [LE_ITEM_CLASS_WEAPON] = false,
+    }
+
+    self:Update()
+end
+
+function settings:Update(force)
+    self:UpdateBag(DJBagsBagContainer, ADDON.cache.bagContainers, force)
+end
+
+function settings:UpdateBag(bag, list, force)
+    bag:UpdateFromSettings()
+    for _, container in pairs(list) do
+        container:UpdateFromSettings()
+    end
+
+    if bag:IsVisible() and force then
+        bag:Arrange(true)
+    end
+end
+
+function settings:GetSettings(type)
+    local settings = DJBags_DB[self.realm][self.player][type] or {}
+    self:MigrateSettings(settings, DJBags_DB.global[type] or {})
+    self:MigrateSettings(settings, self.default[type]or {})
+
+    return settings
+end
+
+function settings:SetSettings(type, setting, out, force)
+    DJBags_DB[self.realm][self.player][type] = DJBags_DB[self.realm][self.player][type] or {}
+    DJBags_DB[self.realm][self.player][type][setting] = out
+
+    self:Update(force)
+end
+
+function settings:GetUserDefinedList()
+    return DJBags_DB[self.realm][self.player].userDefined
+end
+
+function settings:GetGlobalUserDefinedList()
+    return DJBags_DB.global.userDefined
+end
+
+function settings:GetSubClassList()
+    return DJBags_DB[self.realm][self.player].subClass or self.defaultSubclass
+end
+
+function settings:MigrateSettings(table, default)
+    for k, v in pairs(default) do
+        if table[k] ~= nil then
+            if type(v) ~= type(table[k]) then
+                table[k] = v
+            elseif type(v) == 'table' then
+                self:MigrateSettings(table[k], v)
+            end
+        else
+            table[k] = v
+        end
+    end
+end
\ No newline at end of file
diff --git a/src/lua/settings/settingsElements.lua b/src/lua/settings/settingsElements.lua
new file mode 100644
index 0000000..3b3c1b5
--- /dev/null
+++ b/src/lua/settings/settingsElements.lua
@@ -0,0 +1,55 @@
+local NAME, ADDON = ...
+
+local function round(num, idp)
+    local mult = 10^(idp or 0)
+    return math.floor(num * mult + 0.5) / mult
+end
+
+function DJBagsInitSettingsSlider(slider, name, min, max, step, type, setting)
+    local value = ADDON.settings:GetSettings(type)[setting]
+
+    _G[slider:GetName() .. 'Text']:SetText(tostring(name) .. ' - ' .. value)
+    _G[slider:GetName() .. 'Low']:SetText(tostring(min))
+    _G[slider:GetName() .. 'High']:SetText(tostring(max))
+    slider:SetMinMaxValues(min, max)
+    slider.type = type
+    slider.setting = setting
+    slider.name = name
+
+    slider:SetValue(value)
+    slider:SetValueStep(step)
+end
+
+function DJBagsSettingsSlider_OnChange(self, value)
+    _G[self:GetName() .. 'Text']:SetText(tostring(self.name) .. ' - ' .. round(value, 1))
+    ADDON.settings:SetSettings(self.type, self.setting, value, true)
+end
+
+function DJBagsInitSettingsColorPicker(picker, type, setting)
+    picker.type = type
+    picker.setting = setting
+
+    picker:SetBackdropColor(unpack(ADDON.settings:GetSettings(type)[setting]))
+end
+
+function DJBagsSettingsColorPicker_OnClick(self)
+    local r, g, b, a = self:GetBackdropColor()
+
+    local function callback(restore)
+        local newR, newG, newB, newA = r, g, b, a;
+        if not restore then
+            newA, newR, newG, newB = OpacitySliderFrame:GetValue(), ColorPickerFrame:GetColorRGB();
+        end
+
+        local out = { newR, newG, newB, newA }
+        self:SetBackdropColor(unpack(out))
+
+        ADDON.settings:SetSettings(self.type, self.setting, out)
+    end
+
+    ColorPickerFrame.func, ColorPickerFrame.opacityFunc, ColorPickerFrame.cancelFunc = callback, callback, callback;
+    ColorPickerFrame:SetColorRGB(r, g, b, a);
+    ColorPickerFrame.hasOpacity, ColorPickerFrame.opacity = (a ~= nil), a;
+    ColorPickerFrame.previousValues = { r, g, b, a };
+    ShowUIPanel(ColorPickerFrame)
+end
\ No newline at end of file
diff --git a/src/lua/sorters/containers.lua b/src/lua/sorters/containers.lua
deleted file mode 100644
index 621fe89..0000000
--- a/src/lua/sorters/containers.lua
+++ /dev/null
@@ -1,40 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.sorters = ADDON.sorters or {}
-
-ADDON.sorters.containers = {
-    ['defaultVertical'] = function(A, B)
-        if A.name == EMPTY then
-            return true
-        elseif B.name == EMPTY then
-            return false
-        elseif A.name == NEW then
-            return false
-        elseif B.name == NEW then
-            return true
-        elseif A.name == BAG_FILTER_JUNK then
-            return false
-        elseif B.name == BAG_FILTER_JUNK then
-            return true
-        else
-            return A.name > B.name
-        end
-    end,
-    ['defaultHorizontal'] = function(A, B)
-        if A.name == EMPTY then
-            return false
-        elseif B.name == EMPTY then
-            return true
-        elseif A.name == NEW then
-            return true
-        elseif B.name == NEW then
-            return false
-        elseif A.name == BAG_FILTER_JUNK then
-            return true
-        elseif B.name == BAG_FILTER_JUNK then
-            return false
-        else
-            return A.name < B.name
-        end
-    end,
-}
\ No newline at end of file
diff --git a/src/lua/sorters/items.lua b/src/lua/sorters/items.lua
deleted file mode 100644
index be0e56e..0000000
--- a/src/lua/sorters/items.lua
+++ /dev/null
@@ -1,15 +0,0 @@
-local NAME, ADDON = ...
-
-ADDON.sorters = ADDON.sorters or {}
-
-ADDON.sorters.items = {
-    ['default'] = function(A, B)
-        if A.quality == B.quality then
-            if A.ilevel == B.ilevel then
-                return A.name < B.name
-            end
-            return A.ilevel > B.ilevel
-        end
-        return A.quality > B.quality
-    end,
-}
\ No newline at end of file
diff --git a/src/lua/tools/boxFormatter.lua b/src/lua/tools/boxFormatter.lua
new file mode 100644
index 0000000..e69de29
diff --git a/src/lua/tools/itemFormatter.lua b/src/lua/tools/itemFormatter.lua
new file mode 100644
index 0000000..fced31f
--- /dev/null
+++ b/src/lua/tools/itemFormatter.lua
@@ -0,0 +1,53 @@
+local NAME, ADDON = ...
+
+local itemSorter = function (A, B)
+    if A.quality == B.quality then
+        if A.ilevel == B.ilevel then
+            return A.name < B.name
+        end
+        return A.ilevel > B.ilevel
+    end
+    return A.quality > B.quality
+end
+
+local function alreadySorted(frame, max, vert)
+    if frame.arranged and frame.max == max and frame.vert == vert then
+        return true
+    end
+    return false
+end
+
+function ADDON:ArrangeItemContainer(frame, max, vert, maxCnt)
+    if frame:IsEmpty() or alreadySorted(frame, max, vert) then return end
+
+    local itemCount = maxCnt or frame:GetCount()
+    local cnt = 0
+
+    for item in ADDON:PairsByKey(frame.items, itemSorter) do
+        if maxCnt and cnt >= maxCnt then
+            item:Hide()
+        else
+            item:Show()
+            local row = cnt % max
+            local col = math.floor(cnt / max)
+
+            local colPos = (frame.spacing + item:GetWidth()) * col
+            local rowPos = (frame.spacing + item:GetWidth()) * row
+
+            item:SetPoint('TOPLEFT', vert and colPos or rowPos, -(vert and rowPos or colPos))
+
+            cnt = cnt + 1
+            if maxCnt and cnt == maxCnt then
+                item:SetItemCount(frame:GetCount() - cnt + 1)
+            end
+        end
+    end
+
+    local colSize = math.ceil(itemCount / max) * (next(frame.items):GetWidth() + frame.spacing) - frame.spacing
+    local rowSize = max * (frame.spacing + next(frame.items):GetWidth()) - frame.spacing
+
+    frame:SetSize(
+        (vert and colSize or rowSize) + frame.padding * 2,
+        (vert and rowSize or colSize) + frame.padding * 2
+    )
+end
\ No newline at end of file
diff --git a/src/lua/tools/masonryFormatter.lua b/src/lua/tools/masonryFormatter.lua
new file mode 100644
index 0000000..a439620
--- /dev/null
+++ b/src/lua/tools/masonryFormatter.lua
@@ -0,0 +1,71 @@
+local NAME, ADDON = ...
+
+ADDON.format = ADDON.format or {}
+
+local sorter = function(A, B)
+    if A.name.text == EMPTY then
+        return false
+    elseif B.name.text == EMPTY then
+        return true
+    elseif A.name.text == NEW then
+        return true
+    elseif B.name.text == NEW then
+        return false
+    elseif A.name.text == BAG_FILTER_JUNK then
+        return true
+    elseif B.name.text == BAG_FILTER_JUNK then
+        return false
+    else
+        return A.name.text < B.name.text
+    end
+end
+
+ADDON.format['massonry'] = function(frame, maxItems, _, vert, override)
+    local h = 0
+    local x = 0
+    local mH = 0
+    local mW = 0
+    local cnt = 0
+    local lastH = 0
+
+    for v in ADDON:PairsByKey(frame.items, function(A, B)
+        local ans = sorter(A, B)
+        if vert then
+            return not ans
+        end
+        return ans
+    end) do
+        if v:IsEmpty() then
+            v:Hide()
+        else
+            v:Show()
+            local numItems = v.name:GetText() == EMPTY and 1 or v:GetCount()
+
+            if cnt ~= 0 and (cnt + numItems) > maxItems then
+                x = 0
+                h = h + mH + frame.spacing
+                cnt = 0
+                mH = 0
+            end
+
+            if numItems > maxItems then
+                v:Arrange(maxItems, vert, nil, override)
+            else
+                v:Arrange(numItems, vert, (v.name:GetText() == EMPTY and 1), override)
+            end
+
+            v:ClearAllPoints()
+            v:SetPoint(vert and 'BOTTOMRIGHT' or 'TOPLEFT', vert and -h or x, vert and x or -h)
+
+            mH = math.max(mH, vert and v:GetWidth() or v:GetHeight())
+            mW = math.max(mW, x + (vert and v:GetHeight() or v:GetWidth()))
+            x = x + frame.spacing + (vert and v:GetHeight() or v:GetWidth())
+
+            cnt = cnt + numItems
+            lastH = vert and v:GetWidth() or v:GetHeight()
+        end
+    end
+
+    frame:SetSize((vert and (h + lastH) or mW) + frame.padding * 2,
+        (vert and mW or (h + lastH)) + frame.padding * 2)
+end
\ No newline at end of file
diff --git a/src/lua/utils/utils.lua b/src/lua/utils/utils.lua
index b3458d1..7b73d26 100644
--- a/src/lua/utils/utils.lua
+++ b/src/lua/utils/utils.lua
@@ -1,26 +1,38 @@
 local NAME, ADDON = ...

-local random = math.random
-ADDON.uuid = function()
-    local template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
-    return string.gsub(template, '[xy]', function(c)
-        local v = (c == 'x') and random(0, 0xf) or random(8, 0xb)
-        return string.format('%x', v)
-    end)
+function ADDON:IsBankBag(id)
+    if id == BANK_CONTAINER or id == REAGENTBANK_CONTAINER then
+        return true
+    end
+    return false
+end
+
+function ADDON:CreateAddon(obj, tbl, ...)
+    for k, v in pairs(tbl) do
+        obj[k] = v
+    end
+
+    if obj.Init then
+        obj:Init(...)
+    end
 end

-ADDON.utils = {}
-ADDON.utils.__index = ADDON.utils
-ADDON.utils.EMPTY_BAG_NAME = 'SUPER_RANDOM_EMPTY_BAG_NAME_123123'
+function ADDON:Count(table)
+    local cnt = 0;

-local utils = ADDON.utils
+    for _ in pairs(table) do
+        cnt = cnt + 1
+    end
+
+    return cnt
+end

-function utils:PairsByKey(tbl, sortFunction)
+function ADDON:PairsByKey(tbl, sorter)
     local keys = {}
     for k in pairs(tbl) do
         tinsert(keys, k)
     end
-    table.sort(keys, sortFunction)
+    table.sort(keys, sorter)
     local index = 0
     return function()
         index = index + 1
@@ -28,89 +40,32 @@ function utils:PairsByKey(tbl, sortFunction)
     end
 end

-function utils:GetItemContainerName(bag, slot)
-    local id = GetContainerItemID(bag, slot)
-
-    if id then
-        local name, link, quality, iLevel, reqLevel, className, subClassName, maxStack, equipSlot, texture, vendorPrice, cId, sCId = GetItemInfo(id)
-        local isInSet, setName = GetContainerItemEquipmentSetInfo(bag, slot)
-
-        if quality == LE_ITEM_QUALITY_POOR then
-            return BAG_FILTER_JUNK
-        end
-
-        if isInSet then
-            return setName
-        end
-
-        if bag >= 0 and bag <= NUM_BAG_SLOTS and C_NewItems.IsNewItem(bag, slot) then
-            return NEW
-        end
-
-        local userDefinedList = ADDON.settings.categories.userDefined
-        if userDefinedList[id] then
-            return userDefinedList[id] .. '*'
-        end
+function ADDON:UpdateBags(bags)
+    for _, bag in pairs(bags) do
+        local bagSlots = GetContainerNumSlots(bag)

-        local globalDefinedList = ADDON.globalCategories
-        if globalDefinedList[id] then
-            return globalDefinedList[id] .. '**'
-        end
-
-        local subClassSplitList = ADDON.settings.categories.subClass
-        if subClassSplitList[cId] then
-            return className .. (subClassName == BAG_FILTER_JUNK and '' or '_' .. subClassName)
-        end
-
-        return className
-    end
-    return EMPTY
-end
-
-function utils:UpdateItemsForBag(frame, bag, containerFunc)
-    local count = GetContainerNumSlots(bag)
-    if count == 0 and ADDON.cache.items[bag] then
-        for _, item in pairs(ADDON.cache.items[bag]) do
-            if item:GetParent() then
-                local previousContainer = item:GetParent()
-                previousContainer:RemoveItem(item)
-                item:SetParent(nil)
+        if ADDON.cache.items[bag] and bagSlots < ADDON:Count(ADDON.cache.items[bag]) then
+            for index = bagSlots + 1, ADDON:Count(ADDON.cache.items[bag]) do
+                local item = ADDON.cache:GetItem(bag, index)
+                local parent = item:GetParent() and item:GetParent():GetParent()
+                if parent and parent.RemoveItem then
+                    parent:RemoveItem(item)
+                end
                 item:Hide()
             end
         end
-    else
-        for slot = 1, count do
-            local item = ADDON.cache:GetItem(bag, slot)
-            local previousContainer
-            if item:GetParent() and item:GetParent().__class == ADDON.itemContainer.__class then
-                previousContainer = item:GetParent()
-            end

+        for slot = 1, bagSlots do
+            local item = ADDON.cache:GetItem(bag, slot)
             item:Update()

-            local newContainer = containerFunc(ADDON.cache, ADDON.utils:GetItemContainerName(bag, slot))
-            frame:AddContainer(newContainer)
-
-            if previousContainer ~= newContainer then
-                if previousContainer then
-                    previousContainer:RemoveItem(item)
-                end
-                newContainer:AddItem(item)
+            local currentParent = item:GetParent() and item:GetParent():GetParent()
+            if currentParent and currentParent.RemoveItem then
+                currentParent:RemoveItem(item)
             end
-        end
-    end
-end
+            local newParent = ADDON.cache:GetItemContainer(bag, item:GetContainerName())

-function utils:PrintTable(tbl, lvl)
-    local prefix = ''
-    lvl = lvl or 0
-    for _ = 1, lvl do
-        prefix = prefix .. '\t'
-    end
-    for k, v in pairs(tbl) do
-        print(prefix, k, v)
-        if (type(v) == 'table') then
-            printTable(v, lvl + 1)
+            newParent:AddItem(item)
         end
     end
 end
\ No newline at end of file
diff --git a/src/manifest.xml b/src/manifest.xml
index 050d7eb..53747ef 100644
--- a/src/manifest.xml
+++ b/src/manifest.xml
@@ -1,50 +1,42 @@
 <Ui xsi:schemaLocation="http://www.blizzard.com/wow/ui/  http://wowprogramming.com/FrameXML/UI.xsd">
-    <!-- Class -->
-    <Script file="src/lua/base/djclass.lua"/>
+    <!-- Constants -->
+    <Script file="src/lua/constants/contstants.lua" />

     <!-- Utils -->
-    <Script file="src/lua/utils/utils.lua"/>
+    <Script file="src/lua/cache/cache.lua" />
+    <Script file="src/lua/utils/utils.lua" />

-    <!-- Cache -->
-    <Script file="src/lua/cache/cache.lua"/>
+    <!-- Events -->
+    <Script file="src/lua/events/events.lua" />

-    <!-- Settings -->
-    <Script file="src/lua/settings/defaults/item.lua"/>
-    <Script file="src/lua/settings/defaults/container.lua"/>
-    <Script file="src/lua/settings/defaults/itemContainer.lua"/>
-    <Script file="src/lua/settings/defaults/category.lua"/>
-    <Script file="src/lua/settings/defaults/categoryContainer.lua"/>
-    <Script file="src/lua/settings/defaults/mainBar.lua"/>
-    <Script file="src/lua/settings/defaults/bagItem.lua"/>
-    <Script file="src/lua/settings/defaults/auto.lua"/>
-    <Script file="src/lua/settings/defaults/formatter.lua"/>
-    <Script file="src/lua/settings/editor.lua"/>
-    <Script file="src/lua/settings/settings.lua"/>
-
-    <!-- sorters -->
-    <Script file="src/lua/sorters/items.lua"/>
-    <Script file="src/lua/sorters/containers.lua"/>
-
-    <!-- formatters -->
-    <Script file="src/lua/formatters/vertical.lua"/>
-    <Script file="src/lua/formatters/horizontal.lua"/>
-
-    <!-- Tools -->
-    <Script file="src/lua/event/eventManager.lua"/>
-
-    <!-- elements -->
-    <Script file="src/lua/elements/item.lua"/>
-    <Script file="src/lua/elements/container.lua"/>
-    <Script file="src/lua/elements/itemContainer.lua"/>
-    <Script file="src/lua/elements/categoryContainer.lua"/>
-    <Script file="src/lua/elements/mainBar.lua"/>
-    <Script file="src/lua/elements/categoryDialog.lua"/>
-    <Script file="src/lua/elements/bagItem.lua"/>
-    <Script file="src/lua/elements/bagBar.lua"/>
+    <!-- Element XML-->
+    <Include file="src/xml/element/tooltip.xml" />
+    <Include file="src/xml/element/mainBar.xml" />
+    <Include file="src/xml/element/itemContainer.xml" />
+
+    <!-- Element Script -->
+    <Script file="src/lua/element/tooltip.lua" />
+    <Script file="src/lua/element/item.lua" />
+    <Script file="src/lua/element/itemContainer.lua" />
+    <Script file="src/lua/element/bagItem.lua" />
+
+    <!-- Container special load -->
+    <Script file="src/lua/element/container.lua" />
+    <Include file="src/xml/element/container.xml" />
+
+    <!-- Formatters -->
+    <Script file="src/lua/tools/itemFormatter.lua" />
+    <Script file="src/lua/tools/masonryFormatter.lua" />

     <!-- Controller -->
-    <Script file="src/lua/controllers/bag.lua"/>
-    <Script file="src/lua/controllers/bank.lua"/>
+    <Script file="src/lua/controller/bag.lua" />
+
+    <!-- Settings -->
+    <Script file="src/lua/settings/settingsController.lua" />
+    <Script file="src/lua/settings/settingsElements.lua" />
+    <Include file="src/xml/settings/colorPicker.xml" />
+    <Include file="src/xml/settings/slider.xml" />
+    <Include file="src/xml/settings/itemContainerSettings.xml" />

     <!-- Core (Load last) -->
     <Script file="src/lua/core.lua"/>
diff --git a/src/xml/element/bankBar.xml b/src/xml/element/bankBar.xml
new file mode 100644
index 0000000..5031a52
--- /dev/null
+++ b/src/xml/element/bankBar.xml
@@ -0,0 +1,3 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
+
+</Ui>
diff --git a/src/xml/element/container.xml b/src/xml/element/container.xml
new file mode 100644
index 0000000..2f80446
--- /dev/null
+++ b/src/xml/element/container.xml
@@ -0,0 +1,37 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
+    <Frame name="DJBagsContainerTemplate" frameStrata="MEDIUM" toplevel="true" movable="true" enableMouse="true" hidden="true" virtual="true">
+        <Backdrop bgFile="Interface\ChatFrame\ChatFrameBackground" edgeFile="Interface\Buttons\WHITE8x8">
+            <EdgeSize>
+                <AbsValue val="1" />
+            </EdgeSize>
+        </Backdrop>
+        <Frames>
+            <Frame name="$parentContainer" parentKey="container" />
+        </Frames>
+        <Scripts>
+            <OnLoad>
+                DJBagsContainerLoad(self)
+            </OnLoad>
+        </Scripts>
+    </Frame>
+    <Frame name="DJBagsBagContainer" parent="UIParent" inherits="DJBagsContainerTemplate">
+        <Anchors>
+            <Anchor point="BOTTOMRIGHT" x="-150" y="150" />
+        </Anchors>
+        <Frames>
+            <Frame name="$parentMainBar" parentKey="mainBar" inherits="DJBagsMainBarTemplate">
+                <Anchors>
+                    <Anchor point="TOPRIGHT" relativeTo="$parent" relativePoint="BOTTOMRIGHT" x="0" y="-5"/>
+                </Anchors>
+            </Frame>
+        </Frames>
+        <Scripts>
+            <OnShow>
+                DJBagsBagContainer_OnShow(self)
+            </OnShow>
+            <OnHide>
+                DJBagsBagContainer_OnHide(self)
+            </OnHide>
+        </Scripts>
+    </Frame>
+</Ui>
diff --git a/src/xml/element/itemContainer.xml b/src/xml/element/itemContainer.xml
new file mode 100644
index 0000000..5b1529e
--- /dev/null
+++ b/src/xml/element/itemContainer.xml
@@ -0,0 +1,54 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
+    <Frame name="DJBagsItemContainerTemplate" inherits="DJBagsContainerTemplate" virtual="true">
+        <Layers>
+            <Layer level="ARTWORK">
+                <FontString name="$parentName" parentKey="name" inherits="GameFontHighlight">
+                    <Anchors>
+                        <Anchor point="TOPLEFT">
+                            <Offset>
+                                <AbsDimension x="0" y="-5"/>
+                            </Offset>
+                        </Anchor>
+                        <Anchor point="TOPRIGHT">
+                            <Offset>
+                                <AbsDimension x="0" y="-5"/>
+                            </Offset>
+                        </Anchor>
+                    </Anchors>
+                </FontString>
+            </Layer>
+        </Layers>
+        <Frames>
+            <Frame name="$parentTextHover">
+                <Anchors>
+                    <Anchor point="TOPLEFT" relativeTo="$parentName" relativePoint="TOPLEFT" />
+                    <Anchor point="BOTTOMRIGHT" relativeTo="$parentName" relativePoint="BOTTOMRIGHT" />
+                </Anchors>
+                <Scripts>
+                    <OnEnter>
+                        if self:GetParent().name:IsTruncated() or self:GetParent().name:GetText() ~= self:GetParent().name.text then
+                            GameTooltip:SetOwner(self, 'ANCHOR_CURSOR')
+                            GameTooltip:SetText(self:GetParent().name.text)
+                            GameTooltip:Show()
+                        end
+                    </OnEnter>
+                    <OnLeave>
+                        GameTooltip:Hide()
+                    </OnLeave>
+                    <OnMouseUp>
+                        if IsAltKeyDown() and button == 'RightButton' then
+                            DJBagsItemContainerSettings:Open(self:GetParent())
+                        end
+                    </OnMouseUp>
+                </Scripts>
+            </Frame>
+        </Frames>
+        <Scripts>
+            <OnMouseUp>
+                if IsAltKeyDown() and button == 'RightButton' then
+                    DJBagsItemContainerSettings:Open(self)
+                end
+            </OnMouseUp>
+        </Scripts>
+    </Frame>
+</Ui>
diff --git a/src/xml/element/mainBar.xml b/src/xml/element/mainBar.xml
new file mode 100644
index 0000000..555377c
--- /dev/null
+++ b/src/xml/element/mainBar.xml
@@ -0,0 +1,73 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
+    <Frame name="DJBagsMainBarTemplate" virtual="true">
+        <Size x="300" y="25" />
+        <Backdrop bgFile="Interface\ChatFrame\ChatFrameBackground" edgeFile="Interface\Buttons\WHITE8x8">
+            <EdgeSize>
+                <AbsValue val="1" />
+            </EdgeSize>
+        </Backdrop>
+        <Frames>
+            <CheckButton name="$parentBagBtn" inherits="UIRadioButtonTemplate">
+                <Anchors>
+                    <Anchor point="RIGHT" relativePoint="RIGHT" relativeTo="$parent" x="-5"/>
+                </Anchors>
+                <Scripts>
+                    <OnClick>
+                        DJDBagsBagsButton_OnClick(self)
+                    </OnClick>
+                </Scripts>
+            </CheckButton>
+            <Button name="$parentClearButton">
+                <Size x="25" y="25" />
+                <Anchors>
+                    <Anchor point="RIGHT" relativeTo="$parentBagBtn" relativePoint="LEFT" x="-3" />
+                </Anchors>
+                <NormalTexture file="Interface\Buttons\UI-RotationLeft-Button-Up" />
+                <PushedTexture file="Interface\Buttons\UI-RotationLeft-Button-Down" />
+                <HighlightTexture file="Interface\Buttons\ButtonHilight-Square" alphaMode="ADD">
+                    <Size x="22" y="23"/>
+                    <Anchors>
+                        <Anchor point="CENTER" x="0" y="0"/>
+                    </Anchors>
+                </HighlightTexture>
+                <Scripts>
+                    <OnEnter>
+                        GameTooltip:SetOwner(self, 'TOPRIGHT')
+                        GameTooltip:SetText(DJBags_LOCALE_CLEAR_NEW_ITEMS)
+                        GameTooltip:Show()
+                    </OnEnter>
+                    <OnLeave>
+                        GameTooltip:Hide()
+                    </OnLeave>
+                    <OnClick>
+                        C_NewItems:ClearAll()
+                    </OnClick>
+                </Scripts>
+            </Button>
+            <EditBox name="$parentSearchBox" parentKey="search" inherits="BagSearchBoxTemplate" letters="15">
+                <Size x="96" y="18"/>
+                <Anchors>
+                    <Anchor point="RIGHT" relativeTo="$parentClearButton" relativePoint="LEFT" x="-3" />
+                </Anchors>
+            </EditBox>
+            <Frame name="$parentMoney" inherits="SmallMoneyFrameTemplate" hidden="false">
+                <Anchors>
+                    <Anchor point="RIGHT" relativeTo="$parentSearchBox" relativePoint="LEFT"/>
+                </Anchors>
+                <Scripts>
+                    <OnLoad>
+                        SmallMoneyFrame_OnLoad(self);
+                        MoneyFrame_SetType(self, "PLAYER");
+                        MoneyFrame_SetMaxDisplayWidth(self, 168);
+                    </OnLoad>
+                </Scripts>
+            </Frame>
+        </Frames>
+        <Scripts>
+            <OnLoad>
+                self:SetBackdropColor(0, 0, 0, 0.6)
+                self:SetBackdropBorderColor(0.3, 0.3, 0.3, 1)
+            </OnLoad>
+        </Scripts>
+    </Frame>
+</Ui>
diff --git a/src/xml/element/tooltip.xml b/src/xml/element/tooltip.xml
new file mode 100644
index 0000000..1c3c3f7
--- /dev/null
+++ b/src/xml/element/tooltip.xml
@@ -0,0 +1,3 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
+    <GameTooltip name="DJBagsTooltip" inherits="GameTooltipTemplate" />
+</Ui>
diff --git a/src/xml/settings/colorPicker.xml b/src/xml/settings/colorPicker.xml
new file mode 100644
index 0000000..f03a809
--- /dev/null
+++ b/src/xml/settings/colorPicker.xml
@@ -0,0 +1,19 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
+    <Button name="DJBagsColorPickerTemplate" virtual="true">
+        <Size x="150" y="25"/>
+        <Backdrop bgFile="Interface\ChatFrame\ChatFrameBackground" edgeFile="Interface\Buttons\WHITE8x8">
+            <EdgeSize>
+                <AbsValue val="1"/>
+            </EdgeSize>
+        </Backdrop>
+        <NormalFont style="GameFontHighlight"/>
+        <HighlightFont style="GameFontHighlight"/>
+        <DisabledFont style="GameFontDisable"/>
+        <Scripts>
+            <OnClick>
+                DJBagsSettingsColorPicker_OnClick(self)
+            </OnClick>
+        </Scripts>
+    </Button>
+</Ui>
\ No newline at end of file
diff --git a/src/xml/settings/itemContainerSettings.xml b/src/xml/settings/itemContainerSettings.xml
new file mode 100644
index 0000000..eecb878
--- /dev/null
+++ b/src/xml/settings/itemContainerSettings.xml
@@ -0,0 +1,103 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
+    <Frame name="DJBagsItemContainerSettings" parent="UIParent" inherits="DJBagsContainerTemplate">
+        <Size x="500" y="220"/>
+        <Anchors>
+            <Anchor point="CENTER"/>
+        </Anchors>
+        <Layers>
+            <Layer level="ARTWORK">
+                <FontString name="$parentName" inherits="GameFontNormal" text="DJBags_LOCALE_ITEM_CONTAINER_SETTINGS">
+                    <Anchors>
+                        <Anchor point="TOPLEFT" x="15" y="-5"/>
+                    </Anchors>
+                </FontString>
+            </Layer>
+        </Layers>
+        <Frames>
+            <Button name="$parentBackgroundColorSelect" inherits="DJBagsColorPickerTemplate" text="DJBags_LOCALE_BACKGROUND_COLOR">
+                <Anchors>
+                    <Anchor point="TOPLEFT" relativeTo="$parentName" relativePoint="BOTTOMLEFT" x="5" y="-15" />
+                </Anchors>
+                <Scripts>
+                    <OnShow>
+                        DJBagsInitSettingsColorPicker(self, DJBags_TYPE_ITEM_CONTAINER, DJBags_SETTING_BACKGROUND_COLOR)
+                    </OnShow>
+                </Scripts>
+            </Button>
+            <Button name="$parentBorderColorSelect" inherits="DJBagsColorPickerTemplate" text="DJBags_LOCALE_BORDER_COLOR">
+                <Anchors>
+                    <Anchor point="LEFT" relativeTo="$parentBackgroundColorSelect" relativePoint="RIGHT" x="5" y="0" />
+                </Anchors>
+                <Scripts>
+                    <OnShow>
+                        DJBagsInitSettingsColorPicker(self, DJBags_TYPE_ITEM_CONTAINER, DJBags_SETTING_BORDER_COLOR)
+                    </OnShow>
+                </Scripts>
+            </Button>
+            <Button name="$parentTextColorSelect" inherits="DJBagsColorPickerTemplate" text="DJBags_LOCALE_TEXT_COLOR">
+                <Anchors>
+                    <Anchor point="LEFT" relativeTo="$parentBorderColorSelect" relativePoint="RIGHT" x="5" y="0" />
+                </Anchors>
+                <Scripts>
+                    <OnShow>
+                        DJBagsInitSettingsColorPicker(self, DJBags_TYPE_ITEM_CONTAINER, DJBags_SETTING_TEXT_COLOR)
+                    </OnShow>
+                </Scripts>
+            </Button>
+
+            <Slider name="$parentPaddingSlider" inherits="DJBagsSettingsSliderTemplate">
+                <Anchors>
+                    <Anchor point="TOPLEFT" relativeTo="$parentBackgroundColorSelect" relativePoint="BOTTOMLEFT">
+                        <Offset>
+                            <AbsDimension x="0" y="-32"/>
+                        </Offset>
+                    </Anchor>
+                </Anchors>
+                <Scripts>
+                    <OnShow>
+                        DJBagsInitSettingsSlider(self, DJBags_LOCALE_PADDING, 2, 10, 1, DJBags_TYPE_ITEM_CONTAINER, DJBags_SETTING_PADDING)
+                    </OnShow>
+                </Scripts>
+            </Slider>
+            <Slider name="$parentSpacingSlider" inherits="DJBagsSettingsSliderTemplate">
+                <Anchors>
+                    <Anchor point="TOPLEFT" relativeTo="$parentPaddingSlider" relativePoint="BOTTOMLEFT">
+                        <Offset>
+                            <AbsDimension x="0" y="-32"/>
+                        </Offset>
+                    </Anchor>
+                </Anchors>
+                <Scripts>
+                    <OnShow>
+                        DJBagsInitSettingsSlider(self, DJBags_LOCALE_SPACING, 2, 10, 1, DJBags_TYPE_ITEM_CONTAINER, DJBags_SETTING_SPACING)
+                    </OnShow>
+                </Scripts>
+            </Slider>
+            <Slider name="$parentTextSize" inherits="DJBagsSettingsSliderTemplate">
+                <Anchors>
+                    <Anchor point="TOPLEFT" relativeTo="$parentSpacingSlider" relativePoint="BOTTOMLEFT">
+                        <Offset>
+                            <AbsDimension x="0" y="-32"/>
+                        </Offset>
+                    </Anchor>
+                </Anchors>
+                <Scripts>
+                    <OnShow>
+                        DJBagsInitSettingsSlider(self, DJBags_LOCALE_TEXT_SIZE, 8, 16, 1, DJBags_TYPE_ITEM_CONTAINER, DJBags_SETTING_TEXT_SIZE)
+                    </OnShow>
+                </Scripts>
+            </Slider>
+        </Frames>
+        <Scripts>
+            <OnLoad>
+                self:SetBackdropColor(0, 0, 0, 0.6)
+                self:SetBackdropBorderColor(0.3, 0.3, 0.3, 1)
+                function self:Open(element)
+                    self.target = element
+                    self:Show()
+                end
+            </OnLoad>
+        </Scripts>
+    </Frame>
+</Ui>
diff --git a/src/xml/settings/slider.xml b/src/xml/settings/slider.xml
new file mode 100644
index 0000000..42ca122
--- /dev/null
+++ b/src/xml/settings/slider.xml
@@ -0,0 +1,11 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
+    <Slider name="DJBagsSettingsSliderTemplate" inherits="OptionsSliderTemplate" virtual="true">
+        <Size x="460" y="15" />
+        <Scripts>
+            <OnValueChanged>
+                DJBagsSettingsSlider_OnChange(self, value)
+            </OnValueChanged>
+        </Scripts>
+    </Slider>
+</Ui>
\ No newline at end of file