local _, addon = ... local API = addon.API; local L = addon.L; local TooltipFrame = addon.SharedTooltip; local ENABLE_THIS_MODULE = true; --DB.BackpackItemTracker local HIDE_ZERO_COUNT_ITEM = true; --DB.HideZeroCountItem Dock items inside a flyout menu local USE_CONSISE_TOOLTIP = true; --DB.ConciseTokenTooltip local TRACK_UPGRADE_CURRENCY = true; --DB.TrackItemUpgradeCurrency local TRACK_HOLIDAY_ITEM = true; --DB.TrackHolidayItem local INSIDE_SEPARATE_BAG = false; local MAX_CUSTOM_ITEMS = 6; local BORDER_SHRINK = 2; local TRAY_FRAME_HEIGHT_BASE = 16; --Single Row local TRAY_FRAME_MIN_WIDTH = 32; local TRAY_FRAME_MAX_WDITH = 384; local TRAY_FRAME_WIDTH_THRESHOLD = 240; local RECEPTOR_MIN_WIDTH = 128; local TRAY_BUTTON_GAP = 8; local TRAY_BUTTON_HEIGHT = 20; local TRAY_FRAME_SIDE_PADDING = 8; local BAG_FUNC_HOOKED = false; local FORMAT_ITEM_UNIQUE_MULTIPLE = ITEM_UNIQUE_MULTIPLE or "Unique (%d)"; local PATTERN_UNIQUE_COUNT = string.gsub(FORMAT_ITEM_UNIQUE_MULTIPLE, "[()]", "%%%1"); PATTERN_UNIQUE_COUNT = string.gsub(PATTERN_UNIQUE_COUNT, "%%d", "(%%d+)"); local GetColorizedItemName = API.GetColorizedItemName; local CursorHasItem = CursorHasItem; local ClearCursor = ClearCursor; local GetCursorInfo = GetCursorInfo; local GetItemCount = C_Item.GetItemCount; --local GetItemUniquenessByID = C_Item.GetItemUniquenessByID; --Only returns True for equipment, not items with Unique (10) local GetItemIconByID = C_Item.GetItemIconByID; local GetItemMaxStackSizeByID = C_Item.GetItemMaxStackSizeByID; local GetCurrencyInfo = C_CurrencyInfo.GetCurrencyInfo; local GetItemTooltipInfo = C_TooltipInfo.GetItemByID; local type = type; local tonumber = tonumber; local ExcludeFromSave = {}; local CurrentPinnedItems = {}; local HolidayItems = { --Holidays: lunarfestival = 21100, --Coin of Ancestry loveintheair = 49927, --Love Token noblegarden = 44791, --Noblegarden Chocolate --childrensweek midsummer = 23247, --Burning Blossom brewfest = 37829, --Brewfest Prize Token hallowsendend = 33226, --Tricky Treat --winterveil }; local UpgradeCurrencies = addon.UpgradeCurrencies; --Defined in SharedTooltip.lua local EL = CreateFrame("Frame"); EL:RegisterEvent("PLAYER_ENTERING_WORLD"); local UseSpecialTooltip = {}; --item/currency that use a custom tooltip local InitializeModule; --will be defined later local CrestUtil = {}; CrestUtil.watchedCurrrencies = {}; function CrestUtil:GetBestCrestName(colorized) local numTiers = #UpgradeCurrencies; local info, currencyID; local name; for tier = 1, numTiers do currencyID = UpgradeCurrencies[tier]; info = GetCurrencyInfo(currencyID); if info and info.discovered then name = info.name; if colorized then name = API.ColorizeTextByQuality(name, info.quality); end return name end end name = NONE or "None"; if colorized then name = "|cffffffff"..name.."|r" end return name end function CrestUtil:GetBestCrestForPlayer() --return the highest tier if not TRACK_UPGRADE_CURRENCY then EL:UnregisterEvent("CURRENCY_DISPLAY_UPDATE"); return end local numTiers = #UpgradeCurrencies; local bestTier = 0; local info, currencyID, bestCurrencyID; for tier = 1, numTiers do currencyID = UpgradeCurrencies[tier]; info = GetCurrencyInfo(currencyID); if info and info.discovered then bestTier = numTiers - tier + 1; bestCurrencyID = currencyID; break end end self.watchedCurrrencies = {}; if bestTier < numTiers then --if there is an undiscovered tier above the player's best tier, listen to Events for update local temp = ""; for tier = bestTier + 1, numTiers do currencyID = UpgradeCurrencies[tier]; temp = temp .. " "..currencyID; self.watchedCurrrencies[currencyID] = true; end EL:RegisterEvent("CURRENCY_DISPLAY_UPDATE"); else EL:UnregisterEvent("CURRENCY_DISPLAY_UPDATE"); end return bestCurrencyID end do for _, id in pairs(HolidayItems) do ExcludeFromSave[id] = true; end for _, id in pairs(UpgradeCurrencies) do ExcludeFromSave[ tostring(id) ] = true; UseSpecialTooltip[id] = true; end end local TrackerFrame = CreateFrame("Frame", nil, UIParent); TrackerFrame.list = {}; TrackerFrame.numCustomItems = 0; TrackerFrame.isBlizzardBag = true; TrackerFrame:EnableMouse(true); TrackerFrame:SetFrameStrata("HIGH"); TrackerFrame:SetFixedFrameStrata(true); TrackerFrame:Hide(); local SettingsFrame = {}; --frame created on-use local ItemDataProvider = {}; ItemDataProvider.counts = {}; ItemDataProvider.maxQuantities = {}; ItemDataProvider.bondingTexts = {}; ItemDataProvider.expirationTexts = {}; function ItemDataProvider:GetItemCount(itemID, overwrite) if (not self.counts[itemID]) or overwrite then self.counts[itemID] = GetItemCount(itemID, true); --includeBank end return self.counts[itemID] end function ItemDataProvider:HasZeroCountItem() return self.hasZero end function ItemDataProvider:GetZeroCountItem() return self.zeroCountItems end function ItemDataProvider:GetOwnedItem() return self.ownedItems end function ItemDataProvider:UpdateItemCount() local count; self.zeroCountItems = {}; self.ownedItems = {}; local totalZero = 0; local totalOwned = 0; for _, itemID in ipairs(TrackerFrame.list) do count = self:GetItemCount(itemID, true); if count == 0 and not ExcludeFromSave[itemID] then totalZero = totalZero + 1; self.zeroCountItems[totalZero] = itemID; else totalOwned = totalOwned + 1; self.ownedItems[totalOwned] = itemID; end end self.hasZero = totalZero > 0; end function ItemDataProvider:CacheItemInfo(id) if self.maxQuantities[id] then return end; if type(id) == "number" then local data = GetItemTooltipInfo(id); local maxQuantity; if data and data.lines then for i, line in ipairs(data.lines) do if line.bonding then --Bonding: 5(BLZ), 6(on-pick-up) if line.bonding == 6 then self.bondingTexts[id] = ITEM_SOULBOUND or "Soulbound"; else if line.bonding == 5 then self.bondingTexts[id] = "|cff82c5ff".. (ITEM_BNETACCOUNTBOUND or "Blizzard Account Bound") .."|r"; --BATTLENET_FONT_COLOR else self.bondingTexts[id] = line.leftText; end end elseif not maxQuantity then maxQuantity = string.match(line.leftText, PATTERN_UNIQUE_COUNT); if maxQuantity then self.maxQuantities[id] = tonumber(maxQuantity); end end end if not maxQuantity then self.maxQuantities[id] = 0; end end else local currencyID = tonumber(id); end end function ItemDataProvider:RequestAllItemData() local list = TrackerFrame:CopyUserTrackList(); for i, id in ipairs(list) do if type(id) == "number" then GetItemTooltipInfo(id); end end end function ItemDataProvider:CacheAllItems() for i, id in ipairs(TrackerFrame.list) do self:CacheItemInfo(id); end end function ItemDataProvider:GetMaxQuantity(itemID) self:CacheItemInfo(itemID); return self.maxQuantities[itemID] or 0 end function ItemDataProvider:GetBondingText(itemID) self:CacheItemInfo(itemID); return self.bondingTexts[itemID] end function ItemDataProvider:GetExpirationText(itemID) if self.expirationTexts[itemID] then local info = self.expirationTexts[itemID]; if type(info == "function") then return info(info) else return info end end end function ItemDataProvider:SetExpirationText(itemID, stringOrFunc) self.expirationTexts[itemID] = stringOrFunc; end local function ShowButtonTooltip(owner, itemID, currencyID) GameTooltip:Hide(); if currencyID then local tooltip = TooltipFrame; if UseSpecialTooltip[currencyID] then tooltip:SetOwner(owner, "ANCHOR_RIGHT"); TooltipFrame:DisplayUpgradeCurrencies(); else tooltip:SetOwner(owner, "ANCHOR_RIGHT"); tooltip:SetCurrencyByID(currencyID); tooltip:Show(); end return end if USE_CONSISE_TOOLTIP then local tooltip = TooltipFrame; tooltip:SetOwner(owner, "ANCHOR_RIGHT"); local itemName = GetColorizedItemName(itemID); if itemName then tooltip:AddLeftLine(itemName, 1, 1, 1, true, nil, 1); local bonding = ItemDataProvider:GetBondingText(itemID); if bonding then tooltip:AddLeftLine(bonding, 1, 1, 1, true); end local maxQuantity = ItemDataProvider:GetMaxQuantity(itemID); if maxQuantity > 0 then tooltip:AddLeftLine(string.format(FORMAT_ITEM_UNIQUE_MULTIPLE, maxQuantity), 1, 1, 1, true); end local expirationText = ItemDataProvider:GetExpirationText(itemID); if expirationText then tooltip:AddLeftLine(expirationText, 1, 0.5, 0.25, true); end local numInBags = GetItemCount(itemID); local numTotal = GetItemCount(itemID, true); if numInBags ~= numTotal then local numInBanks = numTotal - numInBags; tooltip:AddLeftLine(BANK, 1, 0.82, 0); tooltip:AddRightLine(numInBanks, 1, 1, 1); end tooltip:Show(); else tooltip:Hide(); end return else local tooltip = GameTooltip; tooltip:SetOwner(owner, "ANCHOR_RIGHT"); tooltip:SetItemByID(itemID); tooltip:Show(); return end end local DragUtil = CreateFrame("Frame"); DragUtil.GetCursorPositon = GetCursorPosition; --[[ function DragUtil.OnUpdate_WatchDragging(self, elapsed) --Watch X Offset self.t = self.t + elapsed; if self.t > 0.016 then self.t = 0; self.x, self.y = self.GetCursorPositon(); self.deltaX = self.x - self.fromX; if self.deltaX > 4 or self.deltaX < -4 then self:SetScript("OnUpdate", nil); self:StartDragging(); end end end --]] function DragUtil.OnUpdate_WatchDragging(self, elapsed) --Watch Y Offset self.t = self.t + elapsed; if self.t > 0.016 then self.t = 0; self.x, self.y = self.GetCursorPositon(); self.deltaY = self.y - self.fromY; if self.deltaY > 4 or self.deltaY < -4 then self:SetScript("OnUpdate", nil); self:StartDragging(); end end end function DragUtil:StartMouseDown(tokenButton) self.object = tokenButton; self.t = 0; self.fromX, self.fromY = self.GetCursorPositon(); self:SetScript("OnUpdate", self.OnUpdate_WatchDragging); end function DragUtil.OnUpdate_OnDragging(self, elapsed) self.t = self.t + elapsed; if self.t > 0.1 then self.t = 0; self.x, self.y = self.GetCursorPositon(); self.x = self.x * self.scaleReciprocal; self.y = self.y * self.scaleReciprocal; local newIndex; --move to the left of button #index for i = 1, self.numPos do if self.y > self.positions[i] then newIndex = i; break end end if not newIndex then newIndex = self.numPos + 1; --to the bottom end SettingsFrame:SetButtonNewPosition(newIndex); end end --[[ function DragUtil:StartDragging() --Horizontal TrackerFrame:StartArranging(self.object); --Get position table self.positions = {}; self.numPos = #TrackerFrame.list; self.scaleReciprocal = 1 / UIParent:GetEffectiveScale(); self.fromX, self.fromY = self.GetCursorPositon(); self.fromX = self.fromX*self.scaleReciprocal; self.fromY = self.fromY*self.scaleReciprocal; local bagScale = TrackerFrame:GetEffectiveScale(); local x; for i = 1, self.numPos do x = TrackerFrame.TrayButtons[i]:GetCenter(); self.positions[i] = x * self.scaleReciprocal * bagScale; --When UI Scale is too large, the game may reduce the ContainerFrame's scale, so we need to compensate that end self.t = 0; self:SetScript("OnUpdate", self.OnUpdate_OnDragging); end --]] function DragUtil:StartDragging() SettingsFrame:StartArranging(self.object); --Get position table self.positions = {}; self.numPos = #SettingsFrame.customList; self.scaleReciprocal = 1 / UIParent:GetEffectiveScale(); self.fromX, self.fromY = self.GetCursorPositon(); self.fromX = self.fromX*self.scaleReciprocal; self.fromY = self.fromY*self.scaleReciprocal; local bagScale = TrackerFrame:GetEffectiveScale(); local x, y; for i = 1, self.numPos do x, y = SettingsFrame.ListButtons[i]:GetCenter(); self.positions[i] = y * self.scaleReciprocal * bagScale; end self.t = 0; self:SetScript("OnUpdate", self.OnUpdate_OnDragging); end function DragUtil:Stop() self:SetScript("OnUpdate", nil); end function DragUtil:StopArranging() self:SetScript("OnUpdate", nil); --TrackerFrame:StopArranging(); SettingsFrame:StopArranging(); end local function UpdateFrameSize_Modified(self, extraHeight) local height = self:CalculateHeight(); self:SetHeight(height + extraHeight); end local function UpdateFrameSize_Callback(self) if not TrackerFrame:IsPlacedInsideBag() then return end local extraHeight = TrackerFrame:CalculateHeight(); UpdateFrameSize_Modified(self, extraHeight); end local function UpdateCurrencyFrames_Modified(self, extraHeight) local tokenFrame = BackpackTokenFrame; if tokenFrame and tokenFrame:IsShown() then tokenFrame:ClearAllPoints(); tokenFrame:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", 8, 8 + extraHeight); tokenFrame:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -8, 8 + extraHeight); else self.MoneyFrame:ClearAllPoints(); self.MoneyFrame:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", 8, 8 + extraHeight); self.MoneyFrame:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -8, 8 + extraHeight); end end local function UpdateCurrencyFrames_Callback(self) if not TrackerFrame:IsPlacedInsideBag() then return end local extraHeight = TrackerFrame:CalculateHeight(); UpdateCurrencyFrames_Modified(self, extraHeight); end local function UpdateContainerLayout() UpdateFrameSize_Callback(ContainerFrame1); UpdateCurrencyFrames_Callback(ContainerFrame1); UpdateContainerFrameAnchors() end function SettingsFrame.OnChanged(manual) local db = PlumberDB; if not db then return end; HIDE_ZERO_COUNT_ITEM = db.HideZeroCountItem; USE_CONSISE_TOOLTIP = db.ConciseTokenTooltip; TRACK_UPGRADE_CURRENCY = db.TrackItemUpgradeCurrency; TRACK_HOLIDAY_ITEM = db.TrackHolidayItem; local insideSeparateBag = db.TrackerBarInsideSeparateBag; if insideSeparateBag then if not BAG_FUNC_HOOKED then local f = ContainerFrame1; if f.UpdateFrameSize then hooksecurefunc(f, "UpdateFrameSize", UpdateFrameSize_Callback); end if f.UpdateCurrencyFrames then hooksecurefunc(f, "UpdateCurrencyFrames", UpdateCurrencyFrames_Callback); end end elseif INSIDE_SEPARATE_BAG then UpdateFrameSize_Modified(ContainerFrame1, 0); UpdateCurrencyFrames_Modified(ContainerFrame1, 0); UpdateContainerFrameAnchors() end INSIDE_SEPARATE_BAG = insideSeparateBag; TrackerFrame:RequestUpdate(manual); end local function OptionButton_TrackItemUpgradeCurrency_OnClick() local db = PlumberDB; if not db then return end; TRACK_UPGRADE_CURRENCY = db.TrackItemUpgradeCurrency; InitializeModule(); end local function OptionButton_TrackItemUpgradeCurrency_OnEnter(self) local tooltip = GameTooltip; tooltip:Hide(); tooltip:SetOwner(self, "ANCHOR_RIGHT"); tooltip:SetText(L["Track Upgrade Currency"], 1, 1, 1, true); tooltip:AddLine(L["Track Upgrade Currency Tooltip"], 1, 0.82, 0, true); local currencyName = CrestUtil:GetBestCrestName(true); tooltip:AddLine(" "); tooltip:AddLine(L["Currently Pinned Colon"].."\n"..currencyName, 1, 0.82, 0, true); tooltip:Show(); end local function OptionButton_TrackHolidayItem_OnClick() local db = PlumberDB; if not db then return end; TRACK_HOLIDAY_ITEM = db.TrackHolidayItem; InitializeModule(); end local function OptionButton_InsideBag_OnClick() end function SettingsFrame:Init() if self.frame then return end; local showCloseButton = true; local f = addon.CreateHeaderFrame(UIParent, showCloseButton); self.frame = f; f:SetPoint("CENTER", UIParent, "CENTER", 0, 0); f:SetSize(225, 300); f:SetTitle(L["ModuleName BackpackItemTracker"]); f:Hide(); f:SetScript("OnHide", function() f:Hide(); DragUtil:Stop(); self:StopArranging(); end); function SettingsFrame:CloseUI() f:Hide(); PlaySound(SOUNDKIT.IG_MAINMENU_QUIT); end f.CloseUI = SettingsFrame.CloseUI; local PADDING = 12; local HEADER_HEIGHT = 18; local FRAME_MIN_WIDTH = 208; local baseFrameLevel = f:GetFrameLevel(); --Checkboxs local options = { {dbKey = "HideZeroCountItem", label = L["Hide Not Owned Items"], tooltip = L["Hide Not Owned Items Tooltip"], onClickFunc = SettingsFrame.OnChanged}, {dbKey = "ConciseTokenTooltip", label = L["Concise Tooltip"], tooltip = L["Concise Tooltip Tooltip"], onClickFunc = SettingsFrame.OnChanged}, {dbKey = "TrackItemUpgradeCurrency", label = L["Track Upgrade Currency"], onClickFunc = OptionButton_TrackItemUpgradeCurrency_OnClick, onEnterFunc = OptionButton_TrackItemUpgradeCurrency_OnEnter}, {dbKey = "TrackHolidayItem", label = L["Track Holiday Item"], onClickFunc = OptionButton_TrackHolidayItem_OnClick}, }; if TrackerFrame.isBlizzardBag and (not C_CVar.GetCVarBool("combinedBags")) then table.insert(options, { dbKey = "TrackerBarInsideSeparateBag", label = L["Bar Inside The Bag"], tooltip = L["Bar Inside The Bag Tooltip"], onClickFunc = SettingsFrame.OnChanged, }); end local BUTTON_HEIGHT = 24; local OPTION_GAP_Y = 8; local checkbox, checkboxWidth; local fullHeight = HEADER_HEIGHT + PADDING; local maxButtonWidth = 0; for i, data in ipairs(options) do checkbox = addon.CreateCheckbox(f); checkbox:SetPoint("TOPLEFT", f, "TOPLEFT", PADDING, -fullHeight); fullHeight = fullHeight + OPTION_GAP_Y + BUTTON_HEIGHT; checkboxWidth = checkbox:SetData(data); if checkboxWidth > maxButtonWidth then maxButtonWidth = checkboxWidth; end if data.dbKey and PlumberDB[data.dbKey] then checkbox:SetChecked(PlumberDB[data.dbKey]); end end local contentSpan = math.floor( math.max(checkboxWidth, FRAME_MIN_WIDTH - 2*PADDING) + 0.5); local frameWidth = contentSpan + 2*PADDING; --List of tracked items local ICON_SIZE = 12; local LIST_BUTTON_HEIGHT = 20; local listHeight = LIST_BUTTON_HEIGHT * MAX_CUSTOM_ITEMS; self.ListButtons = {}; local AlertText = f:CreateFontString(nil, "OVERLAY", "GameTooltipTextSmall"); self.AlertText = AlertText; AlertText:Hide(); AlertText:SetWidth(contentSpan); AlertText:SetPoint("CENTER", f, "TOP", 0, -fullHeight -0.5*listHeight); AlertText:SetText(L["Tracking List Empty"]); AlertText:SetTextColor(0.5, 0.5, 0.5); AlertText:SetShadowOffset(1, -1); AlertText:SetJustifyH("CENTER"); AlertText:SetJustifyV("MIDDLE"); local SelectionTexture = f:CreateTexture(nil, "OVERLAY"); SelectionTexture:SetSize(frameWidth - 4, LIST_BUTTON_HEIGHT); SelectionTexture:SetColorTexture(0.16, 0.16, 0.16); SelectionTexture:Hide(); local function SelectionTexture_SetColorMode(mode) if mode == 1 then --Normal Highlight SelectionTexture:SetColorTexture(0.16, 0.16, 0.16); elseif mode == 2 then --OnDrag Highlight SelectionTexture:SetColorTexture(0.25, 0.25, 0.25); elseif mode == 3 then --To-be-Deleted SelectionTexture:SetColorTexture(0.27, 0.1, 0.1); end end local ActionBlocker = CreateFrame("Frame", nil, f); ActionBlocker:SetFrameLevel(baseFrameLevel + 30); ActionBlocker:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -HEADER_HEIGHT); ActionBlocker:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0); ActionBlocker:EnableMouse(true); ActionBlocker:Hide(); local function ShowActionBlocker() ActionBlocker:Show(); C_Timer.After(0.5, function() ActionBlocker:Hide(); end); end local DeleteButton = CreateFrame("Button", nil, f); DeleteButton:Hide(); DeleteButton:SetSize(24, LIST_BUTTON_HEIGHT); DeleteButton:SetFrameLevel(baseFrameLevel + 20); DeleteButton.RedCross = DeleteButton:CreateTexture(nil, "OVERLAY"); DeleteButton.RedCross:SetSize(16, 16); DeleteButton.RedCross:SetPoint("CENTER", DeleteButton, "RIGHT", -10, 0); DeleteButton.RedCross:SetTexture("Interface/AddOns/Plumber/Art/BackpackItemTracker/RedCross"); local function DeleteButton_SetOwner(listButton) DeleteButton:ClearAllPoints(); DeleteButton:SetPoint("RIGHT", listButton, "RIGHT", 0, 0); DeleteButton:Show(); DeleteButton.owner = listButton; end function SettingsFrame:HighlightListButton(b) if b then SelectionTexture:ClearAllPoints(); SelectionTexture:SetPoint("CENTER", b, "CENTER", 0, 0); SelectionTexture:Show(); else SelectionTexture:Hide(); end for i, button in ipairs(self.ListButtons) do if button == b then button:SetAlpha(1); else button:SetAlpha(0.8); end end end local function TokenListButton_OnEnter(b) if not self.isArranging then SelectionTexture_SetColorMode(1); self:HighlightListButton(b); DeleteButton_SetOwner(b); end end local function TokenListButton_OnLeave(b) if not self.isArranging then self:HighlightListButton(); if not b:IsMouseOver() then DeleteButton:Hide(); end end end local function TokenListButton_OnMouseDown(b, button) if button == "LeftButton" then DragUtil:StartMouseDown(b); end end local function TokenListButton_OnMouseUp(b, button) if button == "LeftButton" then DragUtil:StopArranging(); end end local function DeleteButton_OnEnter(b) DeleteButton.RedCross:SetVertexColor(1, 1, 1); if b.owner then TokenListButton_OnEnter(b.owner); SelectionTexture_SetColorMode(3); end end local function DeleteButton_OnLeave(b) DeleteButton.RedCross:SetVertexColor(0.5, 0.5, 0.5); if b.owner then TokenListButton_OnLeave(b.owner); end end local function DeleteButton_OnClick(b) if b.owner then self:DeleteItemByIndex(b.owner.index); b:Hide(); ShowActionBlocker(); PlaySound(SOUNDKIT.IG_MAINMENU_QUIT); end end DeleteButton:SetScript("OnEnter", DeleteButton_OnEnter); DeleteButton:SetScript("OnLeave", DeleteButton_OnLeave); DeleteButton:SetScript("OnClick", DeleteButton_OnClick); DeleteButton_OnLeave(DeleteButton); local function CreateTokenListButton() local b = CreateFrame("Frame", nil, f); b:SetSize(contentSpan, LIST_BUTTON_HEIGHT); b.Icon = b:CreateTexture(nil, "ARTWORK"); b.Icon:SetSize(ICON_SIZE, ICON_SIZE); b.Icon:SetPoint("LEFT", b, "LEFT", 0, 0); b.Icon:SetTexCoord(0.0625, 0.9375, 0.0625, 0.9375); b.Name = b:CreateFontString(nil, "ARTWORK", "GameTooltipTextSmall"); b.Name:SetJustifyH("LEFT"); b.Name:SetSize(128, 12); b.Name:SetPoint("LEFT", b, "LEFT", ICON_SIZE + 4, 0); b.Name:SetMaxLines(1); b.Name:SetShadowOffset(1, -1); b:SetScript("OnEnter", TokenListButton_OnEnter); b:SetScript("OnLeave", TokenListButton_OnLeave); b:SetScript("OnMouseDown", TokenListButton_OnMouseDown); b:SetScript("OnMouseUp", TokenListButton_OnMouseUp); b:SetAlpha(0.8); return b end for i = 1, MAX_CUSTOM_ITEMS do self.ListButtons[i] = CreateTokenListButton(); self.ListButtons[i]:SetPoint("TOPLEFT", f, "TOPLEFT", PADDING, -fullHeight); self.ListButtons[i].index = i; fullHeight = fullHeight + LIST_BUTTON_HEIGHT; end f:SetSize(frameWidth, fullHeight + PADDING); f:ClearAllPoints(); f:SetParent(TrackerFrame); f:SetPoint("BOTTOMLEFT", TrackerFrame, "TOPLEFT", 0, 4); f:SetClampedToScreen(true); f:SetFrameStrata("DIALOG"); f:SetFixedFrameStrata(true); function SettingsFrame:StartArranging(listButton) self.isArranging = true; self.newPositionIndex = nil; self.movedButtonIndex = listButton.index; self:ShowDragLine(true, listButton); self:HighlightListButton(listButton); SelectionTexture_SetColorMode(2); DeleteButton:Hide(); end function SettingsFrame:ShowDragLine(state, button, alignToBottom) if state then if not self.DragLine then self.DragLine = addon.CreateThreeSliceFrame(f); self.DragLine.pieces[1]:SetSize(8, 8); self.DragLine.pieces[3]:SetSize(8, 8); self.DragLine:SetTexture("Interface/AddOns/Plumber/Art/BackpackItemTracker/DragLine_Horizontal"); self.DragLine:SetSize(contentSpan + 8, 8); self.DragLine:Hide(); end self.DragLine:ClearAllPoints(); if alignToBottom then self.DragLine:SetPoint("CENTER", button, "BOTTOM", 0, 0); else self.DragLine:SetPoint("CENTER", button, "TOP", 0, 0); end self.DragLine:Show(); else self:StopArranging(); end end function SettingsFrame:StopArranging() self.isArranging = nil; if self.DragLine then self.DragLine:Hide(); end self:HighlightListButton(); if f:IsShown() then self:ConfirmNewArrangement(); for _, b in pairs(self.ListButtons) do if b:IsMouseOver() and b:IsShown() then TokenListButton_OnEnter(b); break end end end self.newPositionIndex = nil; end function SettingsFrame:SetButtonNewPosition(buttonIndex) if buttonIndex ~= self.newPositionIndex then self.newPositionIndex = buttonIndex; if self.ListButtons[buttonIndex] then self:ShowDragLine(true, self.ListButtons[buttonIndex]); else self:ShowDragLine(true, self.ListButtons[ self.numActiveButton ], true); end end end function SettingsFrame:ConfirmNewArrangement() local targetIndex = self.newPositionIndex; local fromIndex = self.movedButtonIndex; if (targetIndex and fromIndex) and (targetIndex ~= fromIndex) and (targetIndex ~= fromIndex + 1) then local list = self.customList; local itemID = table.remove(list, fromIndex); if targetIndex > fromIndex then table.insert(list, targetIndex - 1, itemID); else table.insert(list, targetIndex, itemID); end TrackerFrame.list = self.customList; TrackerFrame:SaveUserTrackList(); TrackerFrame:BuildTrackList(); TrackerFrame:UpdateTray(true); self:UpdateListFrame(); end end function SettingsFrame:DeleteItemByIndex(listButtonIndex) local list = self.customList; local itemID = table.remove(list, listButtonIndex); TrackerFrame.list = self.customList; TrackerFrame:SaveUserTrackList(); TrackerFrame:BuildTrackList(); TrackerFrame:UpdateTray(true); self:UpdateListFrame(); end end function SettingsFrame:UpdateListFrame() if not self.ListButtons then return end; --Doesn't include items tracked by default self.customList = TrackerFrame:CopyUserTrackList(); local itemID; local numActiveButton = 0; for i = 1, MAX_CUSTOM_ITEMS do itemID = self.customList[i]; if itemID then numActiveButton = numActiveButton + 1; if itemID ~= self.ListButtons[i].itemID then self.ListButtons[i].Icon:SetTexture(GetItemIconByID(itemID)); self.ListButtons[i].Name:SetText(GetColorizedItemName(itemID)); self.ListButtons[i]:Show(); end else self.ListButtons[i]:Hide(); end self.ListButtons[i].itemID = itemID; end self.numActiveButton = numActiveButton; self.AlertText:SetShown(numActiveButton == 0); end function SettingsFrame:ShowUI() self:Init(); if not self.frame:IsShown() then self.frame:Show(); self:UpdateListFrame(); PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON); end end function SettingsFrame:ToggleUI() if (not self.frame) or (not self.frame:IsShown()) then self:ShowUI(); else self:CloseUI(); end end do --Tray Button: [itemCount][itemIcon] TrackerFrame.TrayButtons = {}; local ICON_SIZE = 12; local TEXT_ICON_GAP = 2; local TrayButtonMixin = {}; function TrayButtonMixin:OnLoad() self.Icon = self:CreateTexture(nil, "ARTWORK"); self.Icon:SetSize(ICON_SIZE, ICON_SIZE); self.Icon:SetPoint("RIGHT", self, "RIGHT", 0, 0); self.Icon:SetTexCoord(0.0625, 0.9375, 0.0625, 0.9375); self.Count = self:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall"); self.Count:SetJustifyH("RIGHT"); self.Count:SetPoint("RIGHT", self.Icon, "LEFT", -TEXT_ICON_GAP, 0); self:SetScript("OnEnter", self.OnEnter); self:SetScript("OnLeave", self.OnLeave); self:SetScript("OnClick", self.OnClick); self:SetScript("OnDragStart", self.OnDragStart); self:RegisterForClicks("LeftButtonUp", "RightButtonUp"); self:RegisterForDrag("LeftButton"); self:SetSize(TRAY_BUTTON_HEIGHT, TRAY_BUTTON_HEIGHT); end function TrayButtonMixin:OnEnter() if TrackerFrame.isArranging then return end; ShowButtonTooltip(self, self.itemID, self.currencyID); --TrackerFrame:HighlightTrayButton(self); end function TrayButtonMixin:OnLeave() GameTooltip:Hide(); TooltipFrame:Hide(); if TrackerFrame.isArranging then return end; --TrackerFrame:HighlightTrayButton(); end function TrayButtonMixin:OnClick(button) if button == "LeftButton" then if IsShiftKeyDown() then TrackerFrame:SearchItemByID(self.itemID); else end elseif button == "RightButton" then SettingsFrame:ToggleUI(); GameTooltip:Hide(); end end function TrayButtonMixin:OnDragStart(button) SettingsFrame:ShowUI(); end function TrayButtonMixin:UpdateAndRetureWidth() local width = math.floor(self.Count:GetWrappedWidth() + TEXT_ICON_GAP + ICON_SIZE + 0.5); self:SetWidth(width); self.width = width; return width end function TrayButtonMixin:SetItem(itemID) local anyChange; if itemID ~= self.itemID then anyChange = true; self.itemID = itemID; self.Icon:SetTexture( GetItemIconByID(itemID) ); end self.currencyID = nil; local count = ItemDataProvider:GetItemCount(itemID); if count ~= self.lastCount then self.lastCount = count; anyChange = true; self.Count:SetText(count); if count > 0 then local maxQuantity = ItemDataProvider:GetMaxQuantity(itemID); if maxQuantity > 0 and count >= maxQuantity then self.Count:SetTextColor(1.000, 0.282, 0.000); --WARNING_FONT_COLOR else self.Count:SetTextColor(1, 1, 1); end else self.Count:SetTextColor(0.5, 0.5, 0.5); end end if anyChange then return self:UpdateAndRetureWidth(); else return self.width end end function TrayButtonMixin:SetCurrency(currencyID) local anyChange; if currencyID ~= self.currencyID then anyChange = true; self.currencyID = currencyID; end self.itemID = nil; local info = currencyID and GetCurrencyInfo(currencyID); if not info then self.Count:SetText("??"); self.Icon:SetTexture(134400); return self:UpdateAndRetureWidth(); end local count = info.quantity or 0; self.Icon:SetTexture(info.iconFileID); if count ~= self.lastCount then self.lastCount = count; anyChange = true; self.Count:SetText(count); if count > 0 then local maxQuantity = info.maxQuantity; if maxQuantity > 0 and count >= maxQuantity then self.Count:SetTextColor(0.251, 0.753, 0.251); --DIM_GREEN_FONT_COLOR else self.Count:SetTextColor(1, 1, 1); end else self.Count:SetTextColor(0.5, 0.5, 0.5); end end if anyChange then return self:UpdateAndRetureWidth(); else return self.width end end function TrayButtonMixin:SetToken(id) if type(id) == "number" then return self:SetItem(id); else return self:SetCurrency( tonumber(id) ); end end function TrackerFrame:AcquireTrayButton(i) if not self.TrayButtons[i] then local b = CreateFrame("Button", nil, self); b.index = i; API.Mixin(b, TrayButtonMixin); b:SetFrameLevel(self:GetFrameLevel() + 1); b:Hide(); b:OnLoad(); b:ClearAllPoints(); if i == 1 then b:SetPoint("LEFT", self, "LEFT", TRAY_FRAME_SIDE_PADDING, 0); else b:SetPoint("LEFT", self.TrayButtons[i - 1], "RIGHT", TRAY_BUTTON_GAP, 0); end self.TrayButtons[i] = b; end return self.TrayButtons[i]; end function TrackerFrame:HighlightTrayButton(button) if button then if not self.ButtonHighlight then self.ButtonHighlight = self:CreateTexture(nil, "OVERLAY", nil, -1); self.ButtonHighlight:SetColorTexture(0.35, 0.35, 0.35); end self.ButtonHighlight:ClearAllPoints(); self.ButtonHighlight:SetPoint("TOPLEFT", button, "TOPLEFT", -4, -3); self.ButtonHighlight:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", 4, 3); self.ButtonHighlight:Show(); elseif self.ButtonHighlight then self.ButtonHighlight:Hide(); end end function TrackerFrame:ShowDragLine(state, button, alignToRight) if state then if not self.DragLine then self.DragLine = self:CreateTexture(nil, "OVERLAY", nil, 5); self.DragLine:SetSize(8, 32); self.DragLine:SetTexture("Interface/AddOns/Plumber/Art/BackpackItemTracker/DragLine_Vertical"); API.DisableSharpening(self.DragLine); end self.DragLine:ClearAllPoints(); if alignToRight then self.DragLine:SetPoint("CENTER", button, "RIGHT", 4, 0); else self.DragLine:SetPoint("CENTER", button, "LEFT", -4, 0); end self.DragLine:Show(); else self:StopArranging(); end end function TrackerFrame:StartArranging(button) self.isArranging = true; self.newPositionIndex = nil; self.movedButtonIndex = button.index; self:ShowDragLine(true, button); self:HighlightTrayButton(button); end function TrackerFrame:StopArranging() self.isArranging = nil; self:HighlightTrayButton(); if self.DragLine then self.DragLine:Hide(); end self:ConfirmNewArrangement(); self.newPositionIndex = nil; if self:IsShown() then for _, b in pairs(self.TrayButtons) do if b:IsMouseOver() and b:IsShown() then b:OnEnter(); break end end end end function TrackerFrame:SetButtonNewPosition(buttonIndex) if buttonIndex ~= self.newPositionIndex then self.newPositionIndex = buttonIndex; if buttonIndex == -1 then self.DragLine:Hide(); else if self.TrayButtons[buttonIndex] then self:ShowDragLine(true, self.TrayButtons[buttonIndex]); else self:ShowDragLine(true, self.TrayButtons[ #self.TrayButtons ], true); end end end end function TrackerFrame:ConfirmNewArrangement() local targetIndex = self.newPositionIndex; local fromIndex = self.movedButtonIndex; if (targetIndex and fromIndex) and (targetIndex ~= fromIndex) and (targetIndex ~= fromIndex + 1) then local itemID = table.remove(self.list, fromIndex); if targetIndex == -1 then --remove item else if self.list[targetIndex] then table.insert(self.list, targetIndex, itemID); else table.insert(self.list, itemID); end end self:SaveUserTrackList(); self:BuildTrackList(); self:UpdateTray(true); end end end do --Create main UI objects --local parent = ContainerFrameCombinedBags.MoneyFrame; --ContainerFrameCombinedBags.MoneyFrame; local parent = UIParent; local f = TrackerFrame; f:SetParent(parent); f:Hide(); f:SetSize(TRAY_FRAME_MIN_WIDTH, TRAY_FRAME_HEIGHT_BASE); --f:SetPoint("LEFT", parent, "LEFT", 0, 0); f:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", 0, -64); --child of UIParent local bg = addon.CreateNineSliceFrame(f, "NineSlice_GenericBox"); --addon.CreateThreeSliceFrame(f, "GenericBox"); bg:SetCornerSize(8); f.Background = bg; bg:SetFrameLevel(f:GetFrameLevel() - 1); bg:SetPoint("TOPLEFT", f, "TOPLEFT", BORDER_SHRINK, -BORDER_SHRINK); bg:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -BORDER_SHRINK, BORDER_SHRINK); local border = addon.CreateNineSliceFrame(f, "NineSlice_GenericBox_Border"); --addon.CreateThreeSliceFrame(f, "WhiteBorderBlackBackdrop"); border:SetCornerSize(8); f.Border = border; local r, g, b = API.GetColorByName("SmoothGreen"); border:SetColor(r, g, b); border:SetFrameLevel(f:GetFrameLevel() + 10); border:Hide(); border:SetSize(16, 16 - 2*BORDER_SHRINK); border:SetPoint("CENTER", f, "CENTER", 0, 0); border.Instruction = border:CreateFontString(nil, "OVERLAY", "GameTooltipTextSmall"); border.Instruction:SetJustifyH("CENTER"); border.Instruction:SetPoint("CENTER", border, "CENTER", 0, 0); border.Instruction:SetTextColor(1, 1, 1); border.PlusSign = border:CreateTexture(nil, "OVERLAY"); border.PlusSign:SetSize(16, 16); border.PlusSign:SetPoint("CENTER", border, "CENTER", 0, 0); border.PlusSign:Hide(); border.PlusSign:SetTexture("Interface/AddOns/Plumber/Art/BackpackItemTracker/PlusSign"); local glow = f:CreateTexture(nil, "BORDER", nil, -1); border.Glow = glow; glow:Hide(); glow:SetSize(160, 64); glow:SetPoint("CENTER", border, "CENTER", 0, 0); glow:SetTexture("Interface/AddOns/Plumber/Art/Frame/ThreeSliceFrameGlowDispersive"); glow:SetVertexColor(9/255, 89/255, 57/255); glow:SetBlendMode("ADD"); glow:SetAlpha(0); --ThreeDotButton (items with 0 count dock here) local tdb = CreateFrame("Frame", nil, f); tdb:Hide(); f.ThreeDotButton = tdb; tdb:SetSize(24, 20); tdb:SetPoint("RIGHT", f, "RIGHT", 0, 0); tdb.Icon = tdb:CreateTexture(nil, "OVERLAY"); tdb.Icon:SetSize(16, 16); tdb.Icon:SetPoint("CENTER", tdb, "CENTER", 0, 0); tdb.Icon:SetTexture("Interface/AddOns/Plumber/Art/BackpackItemTracker/ThreeDot"); API.DisableSharpening(tdb.Icon); --show a list of zero item on drop-up menu local function ThreeDotButton_OnEnter(self) GameTooltip:Hide(); TooltipFrame:Hide(); tdb.Icon:SetVertexColor(0.8, 0.8, 0.8); TooltipFrame:SetOwner(tdb, "ANCHOR_RIGHT"); TooltipFrame:AddCenterLine(L["Not Found"], 1, 0.82, 0); local text, icon; for i, itemID in ipairs(ItemDataProvider:GetZeroCountItem()) do text = GetColorizedItemName(itemID); if text then icon = GetItemIconByID(itemID); if icon then text = string.format("|T%s:0:0:0:-1:64:64:4:60:4:60|t %s", icon, text); end TooltipFrame:AddLeftLine(text, 1, 1, 1); end end TooltipFrame:Show(); end local function ThreeDotButton_OnLeave(self) tdb.Icon:SetVertexColor(0.5, 0.5, 0.5); TooltipFrame:Hide(); end local function ThreeDotButton_OnMouseUp(self) SettingsFrame:ToggleUI(); TooltipFrame:Hide(); end ThreeDotButton_OnLeave(tdb); tdb:SetScript("OnEnter", ThreeDotButton_OnEnter); tdb:SetScript("OnLeave", ThreeDotButton_OnLeave); tdb:SetScript("OnMouseUp", ThreeDotButton_OnMouseUp); end function TrackerFrame:UpdateAnchor(forceUpdate) --When using CombinedBags, default to MoneyFrame, until it becomes to wide and we will put it under the ContainerUI local useCombinedBags = C_CVar.GetCVarBool("combinedBags"); local anchorMode; local parent; if useCombinedBags then if self:GetWidth() < TRAY_FRAME_WIDTH_THRESHOLD then anchorMode = 1; else anchorMode = 2; end else anchorMode = 3; end if (anchorMode == self.anchorMode) and (not forceUpdate) then return end; self.anchorMode = anchorMode; self:ClearAllPoints(); self.Border:ClearAllPoints(); if anchorMode == 3 then --Anchor to Backpack self.Background:Show(); parent = ContainerFrame1; self:SetParent(parent); if self:IsPlacedInsideBag() then self:SetPoint("BOTTOMLEFT", parent, "BOTTOMLEFT", 8, 8); self:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", -8, 8); self.Border:SetPoint("TOPLEFT", self.Background, "TOPLEFT", 0, 0); self.Border:SetPoint("BOTTOMRIGHT", self.Background, "BOTTOMRIGHT", 0, 0); else self:SetPoint("TOPRIGHT", parent, "BOTTOMLEFT", -12, -4); self.Border:SetPoint("RIGHT", self, "RIGHT", -BORDER_SHRINK, 0); end else parent = ContainerFrameCombinedBags; self:SetParent(parent) self.Border:SetPoint("LEFT", self, "LEFT", BORDER_SHRINK, 0); if anchorMode == 1 then --Anchor to MonenyFrame self.Background:Hide(); self:SetPoint("LEFT", parent.MoneyFrame, "LEFT", 0, 0); elseif anchorMode == 2 then --Anchor to CombinedBag BottomLeft self.Background:Show(); self:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", 8, -4); end end end function TrackerFrame:GetSaveTable() local db = PlumberDB; if db then if not db.BackpackTrackedItems then db.BackpackTrackedItems = {}; end for k, v in pairs(db.BackpackTrackedItems) do if type(v) ~= "number" then db.BackpackTrackedItems = {}; break end end return db.BackpackTrackedItems else return {} end end function TrackerFrame:CopyUserTrackList() local tbl = {}; for i, v in ipairs( self:GetSaveTable() ) do tbl[i] = v; end return tbl end function TrackerFrame:SaveUserTrackList() local tbl = {}; local n = 0; for i, id in ipairs(self.list) do if not ExcludeFromSave[id] then n = n + 1; tbl[n] = id; end end if PlumberDB then PlumberDB.BackpackTrackedItems = tbl; end end function TrackerFrame:IsTrackingAnyItems() return self.anyTracking == true end function TrackerFrame:UpdateState() self.anyTracking = #self.list > 0; local n = 0; for i, id in ipairs(self.list) do if not ExcludeFromSave[id] then n = n + 1; end end self.numCustomItems = n; end function TrackerFrame:CanTrackMoreItems() return self.numCustomItems < MAX_CUSTOM_ITEMS end function TrackerFrame:IsTrackedItem(itemID) for _, id in ipairs(self.list) do if itemID == id then return true end end return false end function TrackerFrame:AddTrackItem(itemID, toTop) if (not self:IsTrackedItem(itemID)) and self:CanTrackMoreItems() then if toTop then table.insert(self.list, 1, itemID); else table.insert(self.list, itemID); end return true end end function TrackerFrame:IsReceptorFocused() return self.Receptor:IsMouseOver() end function TrackerFrame:ShowBorder(colorName) local r, g, b = API.GetColorByName(colorName); self.Border:SetColor(r, g, b); self.Border:Show(); end function TrackerFrame:HideBorderAndGlow() self.Border:Hide(); self.Border.Glow:Hide(); self.Border.Glow:SetAlpha(0); end local function Glow_Show_OnUpdate(self, elapsed) self.alpha = self.alpha + 2*elapsed; if self.alpha > 1 then self.alpha = 1; self:SetScript("OnUpdate", nil); end self.Glow:SetAlpha(self.alpha); end local function Glow_Hide_OnUpdate(self, elapsed) self.alpha = self.alpha - 5*elapsed; if self.alpha < 0 then self.alpha = 0; self:SetScript("OnUpdate", nil); self.Glow:Hide(); end self.Glow:SetAlpha(self.alpha); end function TrackerFrame:ShowGlow() self.Border.alpha = self.Border.Glow:GetAlpha(); self.Border:SetScript("OnUpdate", Glow_Show_OnUpdate); self.Border.Glow:Show(); end function TrackerFrame:HideGlow() if self.Border.Glow:IsShown() then self.Border.alpha = self.Border.Glow:GetAlpha(); self.Border:SetScript("OnUpdate", Glow_Hide_OnUpdate); end end function TrackerFrame:ShowGreenLight() self:ShowBorder("SmoothGreen"); self:ShowGlow(); self.Border.Instruction:SetText(""); self.Border.PlusSign:Show(); end function TrackerFrame:HighlightSelection() self:ShowBorder("SelectionBlue"); self:HideGlow(); self.Border.Instruction:SetText(L["Instruction Track Item"]); self.Border.PlusSign:Hide(); end local function GetCursorItemID() local infoType, id = GetCursorInfo(); if infoType == "item" then return id end end local function CanItemBeTracked(itemID) local stackSize = itemID and GetItemMaxStackSizeByID(itemID) return stackSize and stackSize > 1 end do -- Receptor process the cursor item local f = CreateFrame("Frame", nil, TrackerFrame); f:Hide(); TrackerFrame.Receptor = f; f:SetPoint("TOPLEFT", TrackerFrame.Border, "TOPLEFT", 0, 4); --Slightly increase its hitrect so users don't drop the item into the gap between BagUI and or frame and show Destroy Item dialogue f:SetPoint("BOTTOMRIGHT", TrackerFrame.Border, "BOTTOMRIGHT", 0, -4); local function TokenTray_Receptor_OnEnter(self) if CursorHasItem() then TrackerFrame:ShowGreenLight(); end end local function TokenTray_Receptor_OnLeave(self) if CursorHasItem() then TrackerFrame:HighlightSelection(); end end local function TokenTray_Receptor_ReceiveCursorItem(self) if CursorHasItem() then local itemID = GetCursorItemID(); ClearCursor(); local success = TrackerFrame:AddTrackItem(itemID); if success then TrackerFrame:UpdateState(); TrackerFrame:UpdateTray(); TrackerFrame:SaveUserTrackList(); SettingsFrame:UpdateListFrame(); end end end local function TokenTray_Receptor_ShowWarning(self) GameTooltip:Hide(); GameTooltip:SetOwner(self, "ANCHOR_CURSOR"); GameTooltip:AddLine(string.format(L["Item Track Too Many"], MAX_CUSTOM_ITEMS), 1.000, 0.282, 0.000, true); GameTooltip:Show(); end local function TokenTray_Receptor_HideWarning(self) GameTooltip:Hide(); end function TrackerFrame:SetToReceptorMode() self:Show(); f:Show(); f:SetFrameLevel(self:GetFrameLevel() + 20); f:SetScript("OnEnter", TokenTray_Receptor_OnEnter); f:SetScript("OnLeave", TokenTray_Receptor_OnLeave); f:SetScript("OnMouseDown", TokenTray_Receptor_ReceiveCursorItem); f:SetScript("OnReceiveDrag", TokenTray_Receptor_ReceiveCursorItem); end function TrackerFrame:SetToWarningMode() self:Show(); f:Show(); f:SetFrameLevel(self:GetFrameLevel() + 20); f:SetScript("OnEnter", TokenTray_Receptor_ShowWarning); f:SetScript("OnLeave", TokenTray_Receptor_HideWarning); f:SetScript("OnMouseDown", nil); f:SetScript("OnReceiveDrag", nil); end end function TrackerFrame:SetToDisplayMode() self.Receptor:Hide(); self:HideBorderAndGlow(); end local function TrackerFrame_OnUpdate_Request(self, elapsed) self.delay = self.delay + elapsed; if self.delay > 0 then self:SetScript("OnUpdate", nil); TrackerFrame:UpdateTray(self.manualRequset); self.manualRequset = nil; end end function TrackerFrame:RequestUpdate(manual) self.delay = -0.1; self.manualRequset = manual; self:SetScript("OnUpdate", TrackerFrame_OnUpdate_Request); end local function TokenTray_OnShow(self) self:SetToDisplayMode(); self:RegisterEvent("CURSOR_CHANGED"); self:RegisterEvent("BAG_UPDATE"); end local function TokenTray_OnHide(self) self:UnregisterEvent("CURSOR_CHANGED"); self:UnregisterEvent("BAG_UPDATE"); end local function TokenTray_OnEvent(self, event, ...) if event == "CURSOR_CHANGED" then if CursorHasItem() and CanItemBeTracked( GetCursorItemID() ) then if TrackerFrame:CanTrackMoreItems() then TrackerFrame:SetToReceptorMode(); if TrackerFrame:IsReceptorFocused() then TrackerFrame:ShowGreenLight(); else TrackerFrame:HighlightSelection(); end else TrackerFrame:SetToWarningMode(); end else TrackerFrame:SetToDisplayMode(); end elseif event == "BAG_UPDATE" then TrackerFrame:RequestUpdate(); end end local function TrackerFrame_OnMouseUp(self, button) if button == "RightButton" and self:IsVisible() and self:IsMouseOver() then SettingsFrame:ToggleUI(); end end TrackerFrame:SetScript("OnShow", TokenTray_OnShow); TrackerFrame:SetScript("OnHide", TokenTray_OnHide); TrackerFrame:SetScript("OnEvent", TokenTray_OnEvent); TrackerFrame:SetScript("OnMouseUp", TrackerFrame_OnMouseUp); function TrackerFrame:GetTrackList() if HIDE_ZERO_COUNT_ITEM then return ItemDataProvider:GetOwnedItem(); else return self.list end end function TrackerFrame:IsPlacedInsideBag() local f = ContainerFrame1; return f and f:IsShown() and INSIDE_SEPARATE_BAG and self.isBlizzardBag == true end function TrackerFrame:UpdateTray(manual) ItemDataProvider:UpdateItemCount(); local list = self:GetTrackList(); local numItems = #list; local fullWidth = 0; local button, width; local itemID, wasTracked; if manual then --Fade in new items wasTracked = {}; for k, button in ipairs(self.TrayButtons) do itemID = button.itemID or button.currencyID; if itemID then wasTracked[itemID] = true; end end end --Layout if self:IsPlacedInsideBag() then self.placedInsideBag = true; local paddingX = 6; local paddingY = 2; local buttonHeight = 16; local maxRowWidth = ContainerFrame1:GetWidth() - 2*8 - 1*paddingX; local rowWidth = 0; local numRows = 1; local offsetX = paddingX; local offsetY = paddingY; local buttonGapY = 0; for i = 1, numItems do button = self:AcquireTrayButton(i); button:Show(); button:SetHeight(buttonHeight); itemID = list[i]; width = button:SetToken(itemID); rowWidth = rowWidth + width + TRAY_BUTTON_GAP; if rowWidth > maxRowWidth then numRows = numRows + 1; offsetX = paddingX; offsetY = offsetY + buttonGapY + buttonHeight; rowWidth = offsetX + width + TRAY_BUTTON_GAP; end itemID = tonumber(itemID); if manual and not wasTracked[itemID] then API.UIFrameFadeIn(button, 0.5); end button:ClearAllPoints(); button:SetPoint("TOPLEFT", self, "TOPLEFT", offsetX, -offsetY); offsetX = offsetX + width + TRAY_BUTTON_GAP; end --UpdateHeight if HIDE_ZERO_COUNT_ITEM and ItemDataProvider:HasZeroCountItem() then self.ThreeDotButton:Show(); if rowWidth + TRAY_BUTTON_GAP + 20 > maxRowWidth then numRows = numRows + 1; offsetX = TRAY_FRAME_SIDE_PADDING; offsetY = offsetY + buttonGapY + buttonHeight; end self.ThreeDotButton:ClearAllPoints(); self.ThreeDotButton:SetPoint("TOPLEFT", self, "TOPLEFT", offsetX, -offsetY); self.ThreeDotButton:SetHeight(16); else self.ThreeDotButton:Hide(); end local height; if numRows == 1 then height = TRAY_FRAME_HEIGHT_BASE; else height = numRows * (buttonGapY + buttonHeight) - buttonGapY + 2*paddingY; end self:SetHeight(height); if height ~= self.effectiveHeight then self.effectiveHeight = height; C_Timer.After(0.0, function() UpdateContainerLayout(); --Safe? self:UpdateAnchor(true); end); end else local resetPoint = false; if self.placedInsideBag then self.placedInsideBag = nil; self.effectiveHeight = 0; resetPoint = true; end for i = 1, numItems do button = self:AcquireTrayButton(i); button:Show(); itemID = list[i]; width = button:SetToken(itemID); fullWidth = fullWidth + width; itemID = tonumber(itemID); if manual and not wasTracked[itemID] then API.UIFrameFadeIn(button, 0.5); end if resetPoint then button:SetHeight(TRAY_BUTTON_HEIGHT); button:ClearAllPoints(); if i == 1 then button:SetPoint("LEFT", self, "LEFT", TRAY_FRAME_SIDE_PADDING, 0); else button:SetPoint("LEFT", self.TrayButtons[i - 1], "RIGHT", TRAY_BUTTON_GAP, 0); end end end if resetPoint then self.ThreeDotButton:ClearAllPoints(); self.ThreeDotButton:SetPoint("RIGHT", self, "RIGHT", 0, 0); self.ThreeDotButton:SetHeight(TRAY_BUTTON_HEIGHT); self:SetHeight(TRAY_FRAME_HEIGHT_BASE); C_Timer.After(0.01, function() self:UpdateAnchor(true); end); end --UpdateWidth fullWidth = fullWidth + 2*TRAY_FRAME_SIDE_PADDING + (numItems - 1)*TRAY_BUTTON_GAP; if HIDE_ZERO_COUNT_ITEM and ItemDataProvider:HasZeroCountItem() then self.ThreeDotButton:Show(); fullWidth = fullWidth + 16; else self.ThreeDotButton:Hide(); end if fullWidth < TRAY_FRAME_MIN_WIDTH then fullWidth = TRAY_FRAME_MIN_WIDTH; elseif fullWidth > TRAY_FRAME_MAX_WDITH then fullWidth = TRAY_FRAME_MAX_WDITH; end self:SetWidth(fullWidth); self.Border:SetWidth(math.max(fullWidth, RECEPTOR_MIN_WIDTH)); end self:UpdateAnchor(); for i = numItems + 1, #self.TrayButtons do self.TrayButtons[i]:Hide(); self.TrayButtons[i].itemID = nil; self.TrayButtons[i].currencyID = nil; end end function TrackerFrame:CalculateHeight() if self.effectiveHeight then return self.effectiveHeight + 3; else return TRAY_FRAME_HEIGHT_BASE end end local function GetSearchBox() return _G["BagItemSearchBox"] end function TrackerFrame:SearchItemByID(itemID) if itemID then local box = GetSearchBox(); if box and box:IsVisible() then local currentText = box:GetText(); local itemName = C_Item.GetItemNameByID(itemID) or ""; if currentText ~= "" and string.find(string.lower(itemName), string.lower(currentText)) then box:SetText(""); else box:SetText(itemName); end end end end function TrackerFrame:OnBagOpen() if (not ENABLE_THIS_MODULE) or self.isOpen then return end; self.isOpen = true; if self:IsTrackingAnyItems() then self:UpdateTray(); end end function TrackerFrame:OnBagClose() if self.isOpen then self.isOpen = false; else return end end function TrackerFrame:BuildTrackList() --Pin top the top: Holiday Token self.list = TrackerFrame:CopyUserTrackList(); for _, itemID in ipairs(CurrentPinnedItems) do table.insert(self.list, 1, itemID); end TrackerFrame:UpdateState(); end local function TrackerFrame_Update_OnShow(self) --for bag addons that don't trigger EventRegistry, the TrackerFrame with be parented to the bag addon itself and update OnShow TokenTray_OnShow(self); if self:IsTrackingAnyItems() then self:UpdateTray(); end end local RepositionUtil = {}; RepositionUtil.minYSize = TRAY_FRAME_HEIGHT_BASE + 4; function RepositionUtil:Start() if not self.f then self.f = CreateFrame("Frame", nil, TrackerFrame); self.f:Hide(); self.f:SetScript("OnHide", function(f) f:Hide(); end); local function OnUpdate(f, elapsed) f.t = f.t + elapsed; if f.t > 0.1 then f.t = 0; self:UpdateAnchor(); end end self.f:SetScript("OnUpdate", OnUpdate); end self.f.t = 0; self.f:Show(); end function RepositionUtil:UpdateAnchor() self.x = self.parent:GetLeft(); self.y = self.parent:GetBottom(); local anchorMode; if (not self.x) or (not self.y) or (self.y > self.minYSize) then anchorMode = 1; else if self.x > TRAY_FRAME_MAX_WDITH then anchorMode = 2; else anchorMode = 3; end end if anchorMode ~= self.anchorMode then self:SetAnchorMode(anchorMode); end end function RepositionUtil:Stop() if self.f then self.f:Hide(); end end function RepositionUtil:SetAnchorMode(id) self.anchorMode = id; local f = TrackerFrame; f:ClearAllPoints(); f.Border:ClearAllPoints(); if id == 1 then --Bellow bag, align to Left f:SetPoint("TOPLEFT", self.parent, "BOTTOMLEFT", 1, -2); f.Border:SetPoint("LEFT", f, "LEFT", BORDER_SHRINK, 0); elseif id == 2 then --Left of bottom-left, align to Right f:SetPoint("BOTTOMRIGHT", self.parent, "BOTTOMLEFT", -2, 2); f.Border:SetPoint("RIGHT", f, "RIGHT", -BORDER_SHRINK, 0); elseif id == 3 then --Right of bottom-right, align to Left f:SetPoint("BOTTOMLEFT", self.parent, "BOTTOMRIGHT", 2, 2); f.Border:SetPoint("LEFT", f, "LEFT", BORDER_SHRINK, 0); end end function TrackerFrame:ParentTo_Bagnon() --Changes to Bagnon 10.2.15: Frame Struture Changed, Bottom Left of the Bag becomes DataBroker local parent = BagnonInventory1; if not parent then local frameInQuestion = BagnonContainerItem1 and BagnonContainerItem1:GetParent() and BagnonContainerItem1:GetParent():GetParent() and BagnonContainerItem1:GetParent():GetParent():GetParent(); if frameInQuestion and frameInQuestion.Title then parent = frameInQuestion; end end if not parent then return end; self.isBlizzardBag = false; self.Background:Show(); self:SetParent(parent); self:SetScript("OnShow", TrackerFrame_Update_OnShow); self:Show(); self:SetClampedToScreen(true); RepositionUtil.parent = parent; RepositionUtil:UpdateAnchor(); local header = parent.Title; if header then if header:GetScript("OnMouseDown") then header:HookScript("OnMouseDown", function() RepositionUtil:Start(); end); end if header:GetScript("OnMouseUp") then header:HookScript("OnMouseUp", function() RepositionUtil:Stop(); end); end end end function TrackerFrame:ParentTo_AdiBags() local parent = AdiBagsContainer1; if not parent then return end; self.isBlizzardBag = false; self.Background:Show(); self:SetParent(parent); self:SetScript("OnShow", TrackerFrame_Update_OnShow); self:Show(); self:SetClampedToScreen(true); RepositionUtil.parent = parent; C_Timer.After(0.5, function() --anchor not available on-created RepositionUtil:UpdateAnchor(); local header = AdiBagsBagAnchor1; if header then if header:GetScript("OnMouseDown") then header:HookScript("OnMouseDown", function() RepositionUtil:Start(); end); end if header:GetScript("OnMouseUp") then header:HookScript("OnMouseUp", function() RepositionUtil:Stop(); end); end end end); end function TrackerFrame:ParentTo_ArkInventory() local parent = ARKINV_Frame1; if not parent then return end; self.isBlizzardBag = false; self.Background:Show(); self:SetParent(parent); self:SetScript("OnShow", TrackerFrame_Update_OnShow); self:Show(); self:SetClampedToScreen(true); RepositionUtil.parent = parent; RepositionUtil:UpdateAnchor(); if parent.StartMoving then hooksecurefunc(parent, "StartMoving", function(_) RepositionUtil:Start(); end); end if parent.StopMovingOrSizing then hooksecurefunc(parent, "StopMovingOrSizing", function(_) RepositionUtil:Stop(); end); end end function TrackerFrame:ParentTo_ElvUI() local parent = ElvUI_ContainerFrame; if not parent then return end; self.isBlizzardBag = false; self.Background:Show(); self:SetParent(parent); self:SetScript("OnShow", TrackerFrame_Update_OnShow); self:Show(); self:SetClampedToScreen(true); RepositionUtil.parent = parent; RepositionUtil:UpdateAnchor(); if parent.StartMoving then hooksecurefunc(parent, "StartMoving", function(_) RepositionUtil:Start(); end); end if parent.StopMovingOrSizing then hooksecurefunc(parent, "StopMovingOrSizing", function(_) RepositionUtil:Stop(); end); end end function TrackerFrame:ParentTo_NDui() local parent = NDui_BackpackBag; if not parent then return end; self.isBlizzardBag = false; self.Background:Show(); self:SetParent(parent); self:SetScript("OnShow", TrackerFrame_Update_OnShow); self:Show(); self:SetClampedToScreen(true); RepositionUtil.parent = parent; RepositionUtil:UpdateAnchor(); if parent.StartMoving then hooksecurefunc(parent, "StartMoving", function(_) RepositionUtil:Start(); end); end if parent.StopMovingOrSizing then hooksecurefunc(parent, "StopMovingOrSizing", function(_) RepositionUtil:Stop(); end); end end function TrackerFrame:ParentTo_LiteBag() local parent = LiteBagBackpack; if not parent then return end; self.isBlizzardBag = false; self.Background:Show(); self:SetParent(parent); self:SetScript("OnShow", TrackerFrame_Update_OnShow); self:Show(); self:SetClampedToScreen(true); RepositionUtil.parent = parent; RepositionUtil:UpdateAnchor(); if parent.StartMoving then hooksecurefunc(parent, "StartMoving", function(_) RepositionUtil:Start(); end); end if parent.StopMovingOrSizing then hooksecurefunc(parent, "StopMovingOrSizing", function(_) RepositionUtil:Stop(); end); end end function TrackerFrame:ParentTo_Baganator() local backpackView1 = Baganator_SingleViewBackpackViewFrame; local backpackView2 = Baganator_CategoryViewBackpackViewFrame; local parent = backpackView1; if not parent then return end; self.isBlizzardBag = false; self.Background:Show(); self:SetParent(parent); self:SetScript("OnShow", TrackerFrame_Update_OnShow); self:Show(); self:SetClampedToScreen(false); self:ClearAllPoints(); local isSingleView = true; local anchorTo = backpackView1; local function Callback_AllocateBags() if isSingleView and anchorTo.lastBagDetails then local numButtons = anchorTo.lastBagDetails.special and #anchorTo.lastBagDetails.special or 0; local fromOffset = 0; local iconButtonWidth = 32; local buttonSpacing = 5; local offset = (numButtons) * (iconButtonWidth + buttonSpacing) + fromOffset; if anchorTo.BagLive then self:ClearAllPoints(); self:SetPoint("LEFT", anchorTo.BagLive, "LEFT", offset, 0); self:SetPoint("BOTTOM", anchorTo, "BOTTOM", 0, 9); end end end --Supporting Category Group View if backpackView1 and backpackView1:GetScript("OnShow") ~= nil then backpackView1:HookScript("OnShow", function() if not isSingleView then isSingleView = true; self:ClearAllPoints(); self.Border:ClearAllPoints(); self:SetParent(backpackView1); Callback_AllocateBags(); end end); end if backpackView2 and backpackView2:GetScript("OnShow") ~= nil then backpackView2:HookScript("OnShow", function() if isSingleView then isSingleView = false; self:ClearAllPoints(); self.Border:ClearAllPoints(); self:SetParent(backpackView2); self:SetPoint("LEFT", backpackView2, "BOTTOMLEFT", 17, 17); self.Border:SetPoint("LEFT", self, "LEFT", BORDER_SHRINK, 0); end end); end if anchorTo then if anchorTo.AllocateBags then hooksecurefunc(backpackView1, "AllocateBags", Callback_AllocateBags) end self:SetPoint("LEFT", anchorTo, "BOTTOMLEFT", 54, 17); self.Border:SetPoint("LEFT", self, "LEFT", BORDER_SHRINK, 0); else self:Hide(); end end function TrackerFrame:ParentTo_BetterBags() local parent = BetterBagsBagBackpack; if not parent then return end; self.isBlizzardBag = false; self.Background:Show(); self:SetParent(parent); self:SetScript("OnShow", TrackerFrame_Update_OnShow); self:Show(); self:SetClampedToScreen(false); RepositionUtil.parent = parent; self:ClearAllPoints(); self.Border:ClearAllPoints(); self.Border:SetPoint("LEFT", self, "LEFT", BORDER_SHRINK, 0); local anchorOutside = true; if anchorOutside then self:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", 0, -2); else self:SetPoint("BOTTOMLEFT", parent, "BOTTOMLEFT", 4, 5); end end local GetAddOnSearchBox = { Bagnon = function() if not (BagnonInventory1 and BagnonInventory1.SearchFrame and BagnonInventory1.searchToggle) then return end; local toggle = BagnonInventory1.searchToggle; if not toggle:GetChecked() then toggle:Click(); end return BagnonInventory1.SearchFrame end, AdiBags = function() return _G["AdiBagsContainer1SearchBox"] end, ArkInventory = function() return _G["ARKINV_Frame1SearchFilter"] end, ElvUI = function() return _G["ElvUI_ContainerFrameEditBox"] end, NDui = function() local box = NDui_BackpackBag.Search; if box then box:Show(); end return box end, Baganator = function() local bagFarme = Baganator_SingleViewBackpackViewFrame; return bagFarme and bagFarme.SearchBox end, }; local function DoesNothing() end local function AnchorToCompatibleAddOn() local IsAddOnLoaded = (C_AddOns and C_AddOns.IsAddOnLoaded) or IsAddOnLoaded; if IsAddOnLoaded("Bagnon") then if Bagnon and Bagnon.Frames and Bagnon.Frames.Toggle then local bagHook = false; hooksecurefunc(Bagnon.Frames, "Toggle", function(_, label) if label == "inventory" then if not bagHook then bagHook = true; TrackerFrame.UpdateAnchor = DoesNothing; TrackerFrame:ParentTo_Bagnon(); GetSearchBox = GetAddOnSearchBox.Bagnon; end end end); end elseif IsAddOnLoaded("AdiBags") then local AdiBags = LibStub('AceAddon-3.0'):GetAddon("AdiBags"); if AdiBags and AdiBags.CreateContainerFrame then local bagHook = false; hooksecurefunc(AdiBags, "CreateContainerFrame", function(_, bagName, isBank) if not bagHook then if bagName == "Backpack" then bagHook = true; TrackerFrame.UpdateAnchor = DoesNothing; TrackerFrame:ParentTo_AdiBags(); GetSearchBox = GetAddOnSearchBox.AdiBags; end end end); end elseif IsAddOnLoaded("ArkInventory") then local bagFrame = ARKINV_Frame1; if bagFrame then TrackerFrame.UpdateAnchor = DoesNothing; TrackerFrame:ParentTo_ArkInventory(); TrackerFrame:SetScale(1.2); GetSearchBox = GetAddOnSearchBox.ArkInventory; end elseif IsAddOnLoaded("LiteBag") then local bagFrame = LiteBagBackpack; if bagFrame then TrackerFrame.UpdateAnchor = DoesNothing; TrackerFrame:ParentTo_LiteBag(); --This addon is using stock searchbox end elseif IsAddOnLoaded("Baganator") then --Baganator is being actively developed --Available space (width) is affected by Bag Columns, we ignore it for now local bagFrame = Baganator_SingleViewBackpackViewFrame; if bagFrame then TrackerFrame.UpdateAnchor = DoesNothing; TrackerFrame:ParentTo_Baganator(); GetSearchBox = GetAddOnSearchBox.Baganator; end elseif IsAddOnLoaded("BetterBags") then --New Adibags(Still WIP) local bagFrame = BetterBagsBagBackpack; --WTF is this name if bagFrame then TrackerFrame.UpdateAnchor = DoesNothing; TrackerFrame:ParentTo_BetterBags(); --GetSearchBox = GetAddOnSearchBox.BetterBags; --No Search Bar yet end elseif IsAddOnLoaded("ElvUI") then local bagFrame = ElvUI_ContainerFrame; if bagFrame then TrackerFrame.UpdateAnchor = DoesNothing; TrackerFrame:ParentTo_ElvUI(); GetSearchBox = GetAddOnSearchBox.ElvUI; end elseif IsAddOnLoaded("NDui") then local bagFrame = NDui_BackpackBag; if bagFrame then TrackerFrame.UpdateAnchor = DoesNothing; TrackerFrame:ParentTo_NDui(); GetSearchBox = GetAddOnSearchBox.NDui; end end AnchorToCompatibleAddOn = nil; end local function RegisterBag() EventRegistry:RegisterCallback("ContainerFrame.OpenAllBags", TrackerFrame.OnBagOpen, TrackerFrame); EventRegistry:RegisterCallback("ContainerFrame.CloseAllBags", TrackerFrame.OnBagClose, TrackerFrame); RegisterBag = nil; end local function OnModuleEnabled() ENABLE_THIS_MODULE = true; TrackerFrame:BuildTrackList(); TrackerFrame:Show(); if RegisterBag then RegisterBag(); end SettingsFrame.OnChanged(); EL:RegisterEvent("USE_COMBINED_BAGS_CHANGED"); EL:RegisterEvent("CURRENCY_DISPLAY_UPDATE"); if AnchorToCompatibleAddOn then AnchorToCompatibleAddOn(); end end local function OnModuleDisabled() ENABLE_THIS_MODULE = false; TrackerFrame:Hide(); EL:UnregisterEvent("USE_COMBINED_BAGS_CHANGED"); EL:UnregisterEvent("CURRENCY_DISPLAY_UPDATE"); end function InitializeModule() CurrentPinnedItems = {}; local bestCurrencyID = CrestUtil:GetBestCrestForPlayer(); --Returns nil if player opts out if bestCurrencyID then table.insert(CurrentPinnedItems, 1, tostring(bestCurrencyID)); end local HolidayInfo = TRACK_HOLIDAY_ITEM and API.GetActiveMajorHolidayInfo(); if HolidayInfo then for _, info in ipairs(HolidayInfo) do local key = info:GetKey(); local itemID = HolidayItems[key]; if itemID then table.insert(CurrentPinnedItems, 1, itemID); --[[ local expirationText = info:GetEndTimeString(); if expirationText then expirationText = string.format(L["Holiday Ends Format"], expirationText); end --]] local function GetExpirationTextFunc() local expirationText = info:GetRemainingTimeString(); local ENDS_IN_FORMAT = BRAWL_TOOLTIP_ENDS or "Ends in %s"; return string.format(ENDS_IN_FORMAT, expirationText); end ItemDataProvider:SetExpirationText(itemID, GetExpirationTextFunc); end end end if ENABLE_THIS_MODULE then ItemDataProvider:CacheAllItems(); OnModuleEnabled(); end end function CrestUtil:ProcessCurrencyUpdate(currencyID) if currencyID and self.watchedCurrrencies[currencyID] then InitializeModule(); end end local function EL_OnUpdate_OneShot(self, elapsed) self.t = self.t + elapsed; if self.t > 0 then self:SetScript("OnUpdate", nil); if self.callback then self.callback(self); end end end EL:SetScript("OnEvent", function(self, event, ...) if event == "PLAYER_ENTERING_WORLD" then self:UnregisterEvent(event); local currentCalendarTime = C_DateAndTime.GetCurrentCalendarTime(); C_Calendar.SetAbsMonth(currentCalendarTime.month, currentCalendarTime.year); C_Calendar.OpenCalendar(); ItemDataProvider:RequestAllItemData(); self.t = -2; self.callback = InitializeModule; self:SetScript("OnUpdate", EL_OnUpdate_OneShot); elseif event == "USE_COMBINED_BAGS_CHANGED" then self.delay = -0.1; self:SetScript("OnUpdate", TrackerFrame_OnUpdate_Request); elseif event == "CURRENCY_DISPLAY_UPDATE" then local currencyID = ... CrestUtil:ProcessCurrencyUpdate(currencyID); end end); local function EnableModule(state) if state then OnModuleEnabled(); else OnModuleDisabled(); end end do local moduleData = { name = L["ModuleName BackpackItemTracker"], dbKey = "BackpackItemTracker", description = L["ModuleDescription BackpackItemTracker"], toggleFunc = EnableModule, categoryID = 1, uiOrder = 1, }; addon.ControlCenter:AddModule(moduleData); end