Zerotorescue@17: local addon = select(2, ...); Zerotorescue@1: local mod = addon:NewModule("Summary", "AceEvent-3.0", "AceTimer-3.0"); Zerotorescue@0: Zerotorescue@0: local AceGUI = LibStub("AceGUI-3.0"); Zerotorescue@0: Zerotorescue@23: local unknownItemName = "Unknown (#%d)"; Zerotorescue@23: Zerotorescue@23: local itemsCache = {}; Zerotorescue@23: Zerotorescue@23: local CACHE_ITEMS_TOTAL, CACHE_ITEMS_CURRENT = 0, 0; Zerotorescue@23: local cacheStart; Zerotorescue@23: Zerotorescue@0: function mod:OnEnable() Zerotorescue@0: self:RegisterWidgets(); Zerotorescue@0: Zerotorescue@1: -- Register our own slash commands Zerotorescue@1: addon:RegisterSlash(function() Zerotorescue@1: mod:BuildMain(); Zerotorescue@1: mod:Build(); Zerotorescue@36: end, { "s", "sum", "summary" }, "|Hfunction:InventoriumCommandHandler:summary|h|cff00fff7/im summary|r|h (or /im s) - Show the summary window containing an overview of all items within the groups tracked at this current character."); Zerotorescue@23: addon:RegisterSlash(function() Zerotorescue@23: if mod.frame then Zerotorescue@23: mod.frame:SetWidth(650); Zerotorescue@23: mod.frame:SetHeight(600); Zerotorescue@23: Zerotorescue@23: print("Resetting width and height of the summary frame."); Zerotorescue@23: end Zerotorescue@36: end, { "r", "reset" }, "|Hfunction:InventoriumCommandHandler:reset|h|cff00fff7/im reset|r|h (or /im r) - Reset the size of the summary frame."); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@13: local function ShowTooltip(self) Zerotorescue@13: -- If this function is called from a widget, self is the widget and self.frame the actual frame Zerotorescue@13: local this = self.frame or self; Zerotorescue@13: Zerotorescue@13: GameTooltip:SetOwner(this, "ANCHOR_NONE"); Zerotorescue@13: GameTooltip:SetPoint("BOTTOM", this, "TOP"); Zerotorescue@13: GameTooltip:SetText(this.tooltipTitle, 1, .82, 0, 1); Zerotorescue@13: Zerotorescue@13: if type(this.tooltip) == "string" then Zerotorescue@13: GameTooltip:AddLine(this.tooltip, 1, 1, 1, 1); Zerotorescue@13: end Zerotorescue@13: Zerotorescue@13: GameTooltip:Show(); Zerotorescue@13: end Zerotorescue@13: Zerotorescue@13: local function HideTooltip() Zerotorescue@13: GameTooltip:Hide(); Zerotorescue@13: end Zerotorescue@13: Zerotorescue@0: function mod:RegisterWidgets() Zerotorescue@0: -- Register InlineGroupWithButton-widget Zerotorescue@0: -- This widget adds a button next to the header of an inline group Zerotorescue@0: -- SetPoint doesn't seem usable within AceGUI. Zerotorescue@0: Zerotorescue@0: local widgetType = "InlineGroupWithButton"; Zerotorescue@0: local widgetVersion = 1; Zerotorescue@0: Zerotorescue@0: local function Constructor() Zerotorescue@0: local widget = AceGUI:Create("InlineGroup"); Zerotorescue@0: widget.type = widgetType; Zerotorescue@0: Zerotorescue@0: widget.MakeButton = function(self, buttonSettings) Zerotorescue@0: if type(buttonSettings) == "table" then Zerotorescue@14: if not self.btnQueue then Zerotorescue@14: -- Because widgets are re-used, we don't want to recreate this button Zerotorescue@14: self.btnQueue = CreateFrame("Button", nil, self.frame, "UIPanelButtonTemplate"); Zerotorescue@14: self.btnQueue:SetHeight(22); Zerotorescue@14: self.btnQueue:SetWidth(120); Zerotorescue@14: end Zerotorescue@14: self.btnQueue:SetText(buttonSettings.name); Zerotorescue@14: self.btnQueue:SetPoint("TOPRIGHT", self.frame, "TOPRIGHT", -10, 5); Zerotorescue@14: Zerotorescue@14: -- Triggers Zerotorescue@14: self.btnQueue:SetScript("OnClick", buttonSettings.exec); Zerotorescue@14: Zerotorescue@14: -- Tooltip Zerotorescue@14: self.btnQueue.tooltipTitle = buttonSettings.name; Zerotorescue@14: self.btnQueue.tooltip = buttonSettings.desc or ""; Zerotorescue@14: self.btnQueue:SetScript("OnEnter", ShowTooltip); Zerotorescue@14: self.btnQueue:SetScript("OnLeave", HideTooltip); Zerotorescue@0: else Zerotorescue@0: error("settings must be a table - usage: MakeButton(table);"); Zerotorescue@0: end Zerotorescue@14: end; Zerotorescue@0: Zerotorescue@0: return widget; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function mod:BuildMain() Zerotorescue@11: LibStub("AceConfigDialog-3.0"):Close("InventoriumOptions"); Zerotorescue@0: Zerotorescue@10: self:CloseFrame(); Zerotorescue@10: Zerotorescue@1: -- Main Window Zerotorescue@1: mod.frame = AceGUI:Create("Frame"); Zerotorescue@23: _G["InventoriumSummary"] = mod.frame; -- name the global frame so it can be put in the UISpecialFrames Zerotorescue@13: mod.frame:SetTitle("Summary"); Zerotorescue@1: mod.frame:SetLayout("Fill"); Zerotorescue@1: mod.frame:SetCallback("OnClose", function(widget) Zerotorescue@7: mod:CancelTimer(self.tmrUpdater, true); Zerotorescue@9: mod:CloseFrame(); Zerotorescue@1: end); Zerotorescue@13: mod.frame:SetWidth(addon.db.global.defaults.summary.width); Zerotorescue@13: mod.frame:SetHeight(addon.db.global.defaults.summary.height); Zerotorescue@13: mod.frame.OnWidthSet = function(_, width) Zerotorescue@13: addon.db.global.defaults.summary.width = width; Zerotorescue@13: end; Zerotorescue@13: mod.frame.OnHeightSet = function(_, height) Zerotorescue@13: addon.db.global.defaults.summary.height = height; Zerotorescue@13: end; Zerotorescue@0: Zerotorescue@23: -- Close on escape Zerotorescue@23: tinsert(UISpecialFrames, "InventoriumSummary"); Zerotorescue@23: Zerotorescue@1: -- ScrollFrame child Zerotorescue@1: mod.scrollFrame = AceGUI:Create("ScrollFrame"); Zerotorescue@1: mod.scrollFrame:SetLayout("Flow"); Zerotorescue@0: Zerotorescue@1: mod.frame:AddChild(mod.scrollFrame); Zerotorescue@1: Zerotorescue@1: -- Reset items cache Zerotorescue@1: table.wipe(itemsCache); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@9: function mod:CloseFrame() Zerotorescue@9: if mod.frame then Zerotorescue@9: mod.frame:Release(); Zerotorescue@9: mod.frame = nil; Zerotorescue@10: Zerotorescue@10: -- Stop caching Zerotorescue@10: Zerotorescue@10: -- Stop timer Zerotorescue@10: self:CancelTimer(self.tmrUpdater, true); Zerotorescue@10: Zerotorescue@10: -- Reset trackers Zerotorescue@10: CACHE_ITEMS_TOTAL = 0; Zerotorescue@10: CACHE_ITEMS_CURRENT = 0; Zerotorescue@9: end Zerotorescue@9: end Zerotorescue@9: Zerotorescue@0: local sortMethod = "item"; Zerotorescue@0: local sortDirectory = "ASC"; Zerotorescue@0: local function ReSort(subject) Zerotorescue@0: if sortMethod == subject then Zerotorescue@0: sortDirectory = (sortDirectory == "ASC" and "DESC") or "ASC"; Zerotorescue@0: else Zerotorescue@0: sortDirectory = "ASC"; Zerotorescue@0: end Zerotorescue@0: sortMethod = subject; Zerotorescue@0: Zerotorescue@0: mod:Build(); Zerotorescue@0: end Zerotorescue@10: Zerotorescue@10: -- From http://www.wowwiki.com/API_sort Zerotorescue@10: local function pairsByKeys (t, f) Zerotorescue@10: local a = {} Zerotorescue@10: for n in pairs(t) do table.insert(a, n) end Zerotorescue@10: table.sort(a, f) Zerotorescue@10: local i = 0 -- iterator variable Zerotorescue@10: local iter = function () -- iterator function Zerotorescue@10: i = i + 1 Zerotorescue@10: if a[i] == nil then return nil Zerotorescue@10: else return a[i], t[a[i]] Zerotorescue@10: end Zerotorescue@10: end Zerotorescue@10: return iter Zerotorescue@10: end Zerotorescue@0: Zerotorescue@0: function mod:Build() Zerotorescue@10: local buildStartTime, times = GetTime(), {}; Zerotorescue@0: Zerotorescue@1: -- We are going to add hunderds of widgets to this container, but don't want it to also cause hunderds of reflows, thus pause reflowing and just do it once when everything is prepared Zerotorescue@1: -- This appears to be required for each container we wish to pause, so also do this for the contents Zerotorescue@1: mod.scrollFrame:PauseLayout(); Zerotorescue@1: Zerotorescue@10: mod.scrollFrame:ReleaseChildren(); Zerotorescue@10: Zerotorescue@10: -- Refresh button Zerotorescue@10: local btnRefresh = AceGUI:Create("Button"); Zerotorescue@10: btnRefresh:SetText("Refresh"); Zerotorescue@10: btnRefresh:SetRelativeWidth(.2); Zerotorescue@10: btnRefresh:SetCallback("OnClick", function() Zerotorescue@10: -- Reset items cache Zerotorescue@10: table.wipe(itemsCache); Zerotorescue@10: Zerotorescue@10: -- Rebuild itemlist and start caching Zerotorescue@10: mod:Build(); Zerotorescue@10: end); Zerotorescue@13: btnRefresh:SetCallback("OnEnter", ShowTooltip); Zerotorescue@13: btnRefresh:SetCallback("OnLeave", HideTooltip); Zerotorescue@13: btnRefresh.frame.tooltipTitle = "Refresh Cache"; Zerotorescue@13: btnRefresh.frame.tooltip = "Refresh the list and recache the item counts and auction values."; Zerotorescue@10: Zerotorescue@10: mod.scrollFrame:AddChild(btnRefresh); Zerotorescue@10: Zerotorescue@13: local lblSpacer = AceGUI:Create("Label"); Zerotorescue@13: lblSpacer:SetRelativeWidth(.03); Zerotorescue@13: Zerotorescue@13: mod.scrollFrame:AddChild(lblSpacer); Zerotorescue@13: Zerotorescue@10: -- Speed slider Zerotorescue@13: local sdrSpeed = AceGUI:Create("Slider"); Zerotorescue@13: sdrSpeed:SetLabel("Processing speed"); Zerotorescue@14: sdrSpeed:SetSliderValues(0.01, 5, 0.05); Zerotorescue@13: sdrSpeed:SetIsPercent(true); Zerotorescue@13: sdrSpeed:SetRelativeWidth(.3); Zerotorescue@13: sdrSpeed:SetCallback("OnMouseUp", function(self, event, value) Zerotorescue@13: addon.db.global.defaults.summary.speed = ceil( value * 100 / 5 ); Zerotorescue@13: Zerotorescue@13: CACHE_ITEMS_PER_UPDATE = addon.db.global.defaults.summary.speed; -- max = 20, min = 1 Zerotorescue@10: end); Zerotorescue@13: sdrSpeed:SetValue( addon.db.global.defaults.summary.speed * 5 / 100 ); Zerotorescue@13: sdrSpeed:SetCallback("OnEnter", ShowTooltip); Zerotorescue@13: sdrSpeed:SetCallback("OnLeave", HideTooltip); Zerotorescue@13: sdrSpeed.frame.tooltipTitle = "Caching Processing Speed"; Zerotorescue@13: sdrSpeed.frame.tooltip = "Change the speed at which item counts and auction values are being cached. Higher is faster but may drastically reduce your FPS while caching.\n\nAnything above 100% will probably become uncomfortable."; Zerotorescue@10: Zerotorescue@13: mod.scrollFrame:AddChild(sdrSpeed); Zerotorescue@13: Zerotorescue@13: local lblSpacer = AceGUI:Create("Label"); Zerotorescue@13: lblSpacer:SetRelativeWidth(.23); Zerotorescue@13: Zerotorescue@13: mod.scrollFrame:AddChild(lblSpacer); Zerotorescue@13: Zerotorescue@13: -- Config button Zerotorescue@13: --[[local btnConfig = AceGUI:Create("Button"); Zerotorescue@13: btnConfig:SetText("Config"); Zerotorescue@13: btnConfig:SetRelativeWidth(.2); Zerotorescue@13: btnConfig:SetCallback("OnClick", function() Zerotorescue@13: --TODO: Tidy up Zerotorescue@13: SlashCmdList["INVENTORIUM"]("config"); Zerotorescue@13: end); Zerotorescue@13: btnConfig:SetCallback("OnEnter", ShowTooltip); Zerotorescue@13: btnConfig:SetCallback("OnLeave", HideTooltip); Zerotorescue@13: btnConfig.frame.tooltipTitle = "Config"; Zerotorescue@13: btnConfig.frame.tooltip = "Click to open the config window. This will close the current window."; Zerotorescue@13: Zerotorescue@13: mod.scrollFrame:AddChild(btnConfig);]] Zerotorescue@13: Zerotorescue@13: local lblSpacer = AceGUI:Create("Label"); Zerotorescue@13: lblSpacer:SetRelativeWidth(.03); Zerotorescue@13: Zerotorescue@13: mod.scrollFrame:AddChild(lblSpacer); Zerotorescue@13: Zerotorescue@13: -- Queue all button Zerotorescue@13: local btnQueueAll = AceGUI:Create("Button"); Zerotorescue@13: btnQueueAll:SetText("Queue All"); Zerotorescue@13: btnQueueAll:SetRelativeWidth(.2); Zerotorescue@13: btnQueueAll:SetCallback("OnClick", function() Zerotorescue@14: self:SendMessage("IM_QUEUE_ALL"); Zerotorescue@13: end); Zerotorescue@13: btnQueueAll:SetCallback("OnEnter", ShowTooltip); Zerotorescue@13: btnQueueAll:SetCallback("OnLeave", HideTooltip); Zerotorescue@13: btnQueueAll.frame.tooltipTitle = "Queue all"; Zerotorescue@13: btnQueueAll.frame.tooltip = "Queue everything that requires restocking within every single visible group."; Zerotorescue@13: Zerotorescue@13: mod.scrollFrame:AddChild(btnQueueAll); Zerotorescue@10: Zerotorescue@10: times.init = ceil( ( GetTime() - buildStartTime ) * 1000 ); Zerotorescue@10: addon:Debug("Time spent legend: (init / sorting / preparing / building / all)."); Zerotorescue@10: Zerotorescue@1: local playerName = UnitName("player"); Zerotorescue@1: Zerotorescue@1: -- Go through all our stored groups Zerotorescue@10: for groupName, values in pairsByKeys(addon.db.global.groups, function(a, b) return a:lower() < b:lower(); end) do Zerotorescue@10: local groupStartTime, groupTimes = GetTime(), {}; Zerotorescue@10: Zerotorescue@50: local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters"); Zerotorescue@50: Zerotorescue@1: Zerotorescue@1: -- Does this group have any items and do we want to track it at this char? Zerotorescue@1: if values.items and trackAt[playerName] then Zerotorescue@10: Zerotorescue@10: Zerotorescue@0: -- Get group settings Zerotorescue@50: local minimumStock = addon:GetOptionByKey(groupName, "minimumStock"); Zerotorescue@50: local showWhenBelow = addon:GetOptionByKey(groupName, "summaryThresholdShow"); Zerotorescue@50: local priceThreshold = addon:GetOptionByKey(groupName, "priceThreshold"); Zerotorescue@50: local hideWhenBelowPriceThreshold = addon:GetOptionByKey(groupName, "summaryHidePriceThreshold"); Zerotorescue@50: local alwaysGetAuctionValue = addon:GetOptionByKey(groupName, "alwaysGetAuctionValue"); Zerotorescue@10: Zerotorescue@0: -- Make group container Zerotorescue@0: local iGroup = AceGUI:Create("InlineGroupWithButton"); Zerotorescue@1: iGroup:PauseLayout(); Zerotorescue@0: iGroup:SetTitle(groupName); Zerotorescue@0: iGroup:SetFullWidth(true); Zerotorescue@0: iGroup:SetLayout("Flow"); Zerotorescue@0: iGroup:MakeButton({ Zerotorescue@0: name = "Queue", Zerotorescue@0: desc = "Queue all items in this group.", Zerotorescue@0: exec = function() Zerotorescue@14: print("Queueing all items within " .. groupName .. " craftable by the currently open profession."); Zerotorescue@14: self:SendMessage("IM_QUEUE_GROUP", groupName); Zerotorescue@0: end, Zerotorescue@0: }); Zerotorescue@0: Zerotorescue@10: Zerotorescue@10: Zerotorescue@0: -- Headers Zerotorescue@1: Zerotorescue@0: -- Itemlink Zerotorescue@0: local lblItem = AceGUI:Create("InteractiveLabel"); Zerotorescue@0: lblItem:SetText("|cfffed000Item|r"); Zerotorescue@0: lblItem:SetFontObject(GameFontHighlight); Zerotorescue@50: lblItem:SetRelativeWidth(.6); Zerotorescue@0: lblItem:SetCallback("OnClick", function() ReSort("item"); end); Zerotorescue@13: lblItem:SetCallback("OnEnter", ShowTooltip); Zerotorescue@13: lblItem:SetCallback("OnLeave", HideTooltip); Zerotorescue@13: lblItem.frame.tooltipTitle = "Item"; Zerotorescue@13: lblItem.frame.tooltip = "Sort on the item quality, then name."; Zerotorescue@0: Zerotorescue@0: iGroup:AddChild(lblItem); Zerotorescue@0: Zerotorescue@50: -- Local quantity Zerotorescue@50: local lblLocal = AceGUI:Create("InteractiveLabel"); Zerotorescue@50: lblLocal:SetText("|cfffed000Loc.|r"); Zerotorescue@50: lblLocal:SetFontObject(GameFontHighlight); Zerotorescue@50: lblLocal:SetRelativeWidth(.099); Zerotorescue@50: lblLocal:SetCallback("OnClick", function() ReSort("local"); end); Zerotorescue@50: lblLocal:SetCallback("OnEnter", ShowTooltip); Zerotorescue@50: lblLocal:SetCallback("OnLeave", HideTooltip); Zerotorescue@50: lblLocal.frame.tooltipTitle = "Local stock"; Zerotorescue@50: lblLocal.frame.tooltip = "Sort on the amount of items currently in local stock."; Zerotorescue@50: Zerotorescue@50: iGroup:AddChild(lblLocal); Zerotorescue@50: Zerotorescue@0: -- Current quantity Zerotorescue@0: local lblQuantity = AceGUI:Create("InteractiveLabel"); Zerotorescue@0: lblQuantity:SetText("|cfffed000Cur.|r"); Zerotorescue@0: lblQuantity:SetFontObject(GameFontHighlight); Zerotorescue@10: lblQuantity:SetRelativeWidth(.099); Zerotorescue@0: lblQuantity:SetCallback("OnClick", function() ReSort("current"); end); Zerotorescue@13: lblQuantity:SetCallback("OnEnter", ShowTooltip); Zerotorescue@13: lblQuantity:SetCallback("OnLeave", HideTooltip); Zerotorescue@13: lblQuantity.frame.tooltipTitle = "Current stock"; Zerotorescue@13: lblQuantity.frame.tooltip = "Sort on the amount of items currently in stock."; Zerotorescue@0: Zerotorescue@0: iGroup:AddChild(lblQuantity); Zerotorescue@0: Zerotorescue@0: -- Required stock Zerotorescue@9: local lblMinimumStock = AceGUI:Create("InteractiveLabel"); Zerotorescue@13: lblMinimumStock:SetText("|cfffed000Min.|r"); Zerotorescue@9: lblMinimumStock:SetFontObject(GameFontHighlight); Zerotorescue@10: lblMinimumStock:SetRelativeWidth(.099); Zerotorescue@9: lblMinimumStock:SetCallback("OnClick", function() ReSort("percentage"); end); Zerotorescue@13: lblMinimumStock:SetCallback("OnEnter", ShowTooltip); Zerotorescue@13: lblMinimumStock:SetCallback("OnLeave", HideTooltip); Zerotorescue@13: lblMinimumStock.frame.tooltipTitle = "Minimum stock"; Zerotorescue@13: lblMinimumStock.frame.tooltip = "Sort on the minimum amount of items you wish to keep in stock."; Zerotorescue@0: Zerotorescue@9: iGroup:AddChild(lblMinimumStock); Zerotorescue@0: Zerotorescue@1: -- Lowest value Zerotorescue@1: local lblValue = AceGUI:Create("InteractiveLabel"); Zerotorescue@1: lblValue:SetText("|cfffed000Value|r"); Zerotorescue@1: lblValue:SetFontObject(GameFontHighlight); Zerotorescue@10: lblValue:SetRelativeWidth(.099); Zerotorescue@1: lblValue:SetCallback("OnClick", function() ReSort("value"); end); Zerotorescue@13: lblValue:SetCallback("OnEnter", ShowTooltip); Zerotorescue@13: lblValue:SetCallback("OnLeave", HideTooltip); Zerotorescue@13: lblValue.frame.tooltipTitle = "Value"; Zerotorescue@13: lblValue.frame.tooltip = "Sort on the item auction value."; Zerotorescue@1: Zerotorescue@1: iGroup:AddChild(lblValue); Zerotorescue@1: Zerotorescue@10: Zerotorescue@10: -- Retrieve items list Zerotorescue@1: if not itemsCache[groupName] then Zerotorescue@1: itemsCache[groupName] = {}; Zerotorescue@0: Zerotorescue@1: -- Sort item list Zerotorescue@12: for itemId, _ in pairs(values.items) do Zerotorescue@1: local itemName, itemLink, itemRarity = GetItemInfo(itemId); Zerotorescue@1: Zerotorescue@1: table.insert(itemsCache[groupName], { Zerotorescue@1: id = itemId, Zerotorescue@12: name = itemName or unknownItemName:format(itemId), Zerotorescue@23: link = itemLink, Zerotorescue@23: value = ((priceThreshold == 0 and not alwaysGetAuctionValue) and -4) or -3,-- if (no price threshold is set for this item and you don't want to always get auction value), then don't look it up either --addon:GetAuctionValue(itemLink), Zerotorescue@12: rarity = itemRarity or 1, Zerotorescue@23: count = -3,--addon:GetItemCount(itemId, groupName), Zerotorescue@50: localCount = -3, Zerotorescue@1: set = {}, Zerotorescue@1: }); Zerotorescue@1: CACHE_ITEMS_TOTAL = CACHE_ITEMS_TOTAL + 1; Zerotorescue@1: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@10: groupTimes.init = ceil( ( GetTime() - groupStartTime ) * 1000 ); Zerotorescue@10: Zerotorescue@10: Zerotorescue@10: Zerotorescue@10: -- Sort items Zerotorescue@1: table.sort(itemsCache[groupName], function(a, b) Zerotorescue@1: if sortMethod == "item" and a.rarity == b.rarity then Zerotorescue@1: -- Do a name-compare for items of the same rarity Zerotorescue@1: -- Otherwise epics first, then junk Zerotorescue@0: if sortDirectory == "ASC" then Zerotorescue@1: return a.name:upper() < b.name:upper(); Zerotorescue@0: else Zerotorescue@1: return a.name:upper() > b.name:upper(); Zerotorescue@1: end Zerotorescue@1: elseif sortMethod == "item" then Zerotorescue@1: if sortDirectory == "ASC" then Zerotorescue@1: return a.rarity > b.rarity; -- the comparers were reversed because we want epics first Zerotorescue@1: else Zerotorescue@1: return a.rarity < b.rarity; -- the comparers were reversed because we want epics first Zerotorescue@0: end Zerotorescue@0: elseif sortMethod == "current" then Zerotorescue@0: if sortDirectory == "ASC" then Zerotorescue@0: return a.count < b.count; Zerotorescue@0: else Zerotorescue@0: return a.count > b.count; Zerotorescue@0: end Zerotorescue@50: elseif sortMethod == "local" then Zerotorescue@50: if sortDirectory == "ASC" then Zerotorescue@50: return a.localCount < b.localCount; Zerotorescue@50: else Zerotorescue@50: return a.localCount > b.localCount; Zerotorescue@50: end Zerotorescue@0: elseif sortMethod == "percentage" then Zerotorescue@0: if sortDirectory == "ASC" then Zerotorescue@10: return ( a.count / minimumStock ) < ( b.count / minimumStock ); Zerotorescue@0: else Zerotorescue@10: return ( a.count / minimumStock ) > ( b.count / minimumStock ); Zerotorescue@0: end Zerotorescue@1: elseif sortMethod == "value" then Zerotorescue@1: if sortDirectory == "ASC" then Zerotorescue@1: return a.value < b.value; Zerotorescue@1: else Zerotorescue@1: return a.value > b.value; Zerotorescue@1: end Zerotorescue@0: end Zerotorescue@0: end); Zerotorescue@0: Zerotorescue@10: groupTimes.sorting = ceil( ( GetTime() - groupStartTime ) * 1000 ); Zerotorescue@10: Zerotorescue@10: Zerotorescue@10: Zerotorescue@10: Zerotorescue@10: -- Show itemslist Zerotorescue@1: for i, item in pairs(itemsCache[groupName]) do Zerotorescue@31: -- Go through all items for this group Zerotorescue@31: Zerotorescue@50: if (( item.count / minimumStock ) < showWhenBelow or ( item.localCount / minimumStock ) < showWhenBelow) and (not hideWhenBelowPriceThreshold or priceThreshold == 0 or item.value < 0 or item.value >= priceThreshold) then Zerotorescue@31: -- if the option "hide when below threshold" is disabled or no price threshold is set or the value is above the price threshold or the value could not be determined, proceed Zerotorescue@50: Zerotorescue@0: local btnItemLink = AceGUI:Create("ItemLinkButton"); Zerotorescue@23: btnItemLink:SetUserData("exec", function(_, itemId, _, buttonName) Zerotorescue@23: local itemName, itemLink = GetItemInfo(itemId); Zerotorescue@23: Zerotorescue@23: if buttonName == "LeftButton" and IsShiftKeyDown() and itemLink then Zerotorescue@23: ChatEdit_InsertLink(itemLink); Zerotorescue@23: elseif buttonName == "LeftButton" and IsAltKeyDown() and itemName and AuctionFrame and AuctionFrame:IsShown() and AuctionFrameBrowse then Zerotorescue@23: -- Start search at page 0 Zerotorescue@23: AuctionFrameBrowse.page = 0; Zerotorescue@23: Zerotorescue@23: -- Set the search field (even though we could use "ChatEdit_InsertLink", this ensures the right field is updated) Zerotorescue@23: BrowseName:SetText(itemName) Zerotorescue@23: Zerotorescue@23: QueryAuctionItems(itemName, nil, nil, 0, 0, 0, 0, 0, 0); Zerotorescue@23: end Zerotorescue@23: end); Zerotorescue@50: btnItemLink:SetRelativeWidth(.6); Zerotorescue@1: btnItemLink:SetItemId(item.id); Zerotorescue@0: Zerotorescue@0: iGroup:AddChild(btnItemLink); Zerotorescue@0: Zerotorescue@50: -- Local quantity Zerotorescue@50: local lblLocal = AceGUI:Create("Label"); Zerotorescue@50: lblLocal:SetText(self:DisplayItemCount(item.localCount, minimumStock)); Zerotorescue@50: lblLocal:SetRelativeWidth(.099); Zerotorescue@50: Zerotorescue@50: iGroup:AddChild(lblLocal); Zerotorescue@50: Zerotorescue@0: -- Current quantity Zerotorescue@0: local lblQuantity = AceGUI:Create("Label"); Zerotorescue@9: lblQuantity:SetText(self:DisplayItemCount(item.count, minimumStock)); Zerotorescue@10: lblQuantity:SetRelativeWidth(.099); Zerotorescue@0: Zerotorescue@0: iGroup:AddChild(lblQuantity); Zerotorescue@0: Zerotorescue@0: -- Required stock Zerotorescue@9: local lblMinimumStock = AceGUI:Create("Label"); Zerotorescue@9: lblMinimumStock:SetText(minimumStock); Zerotorescue@10: lblMinimumStock:SetRelativeWidth(.099); Zerotorescue@0: Zerotorescue@9: iGroup:AddChild(lblMinimumStock); Zerotorescue@1: Zerotorescue@1: -- Value Zerotorescue@1: local lblValue = AceGUI:Create("Label"); Zerotorescue@1: lblValue:SetText(self:DisplayMoney(item.value, priceThreshold)); Zerotorescue@10: lblValue:SetRelativeWidth(.099); Zerotorescue@1: Zerotorescue@1: iGroup:AddChild(lblValue); Zerotorescue@1: Zerotorescue@1: -- Remember references to the value and current fields so we can fill them later Zerotorescue@1: if item.set then Zerotorescue@10: -- -3 means the price is unknown, queue look up Zerotorescue@10: if item.value == -3 then Zerotorescue@10: item.set.value = lblValue; Zerotorescue@10: end Zerotorescue@10: if item.count == -3 then Zerotorescue@10: item.set.current = lblQuantity; Zerotorescue@10: end Zerotorescue@50: if item.localCount == -3 then Zerotorescue@50: item.set.localCount = lblLocal; Zerotorescue@50: end Zerotorescue@10: Zerotorescue@10: -- Don't queue if we already know everything we want to know Zerotorescue@50: if item.value ~= -3 and item.count ~= -3 and item.localCount ~= -3 then Zerotorescue@10: item.set = nil; Zerotorescue@10: end Zerotorescue@1: end Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@10: groupTimes.preparing = ceil( ( GetTime() - groupStartTime ) * 1000 ); Zerotorescue@10: Zerotorescue@1: iGroup:ResumeLayout(); Zerotorescue@1: mod.scrollFrame:AddChild(iGroup); -- this can take up to .5 seconds, might need to look into again at a later time Zerotorescue@10: Zerotorescue@10: groupTimes.building = ceil( ( GetTime() - groupStartTime ) * 1000 ); Zerotorescue@0: end Zerotorescue@10: Zerotorescue@13: if groupStartTime and groupTimes then Zerotorescue@13: addon:Debug(("Building of %s took %d ms (%d / %d / %d / %d / %d)."):format(groupName, ceil( ( GetTime() - groupStartTime ) * 1000 ), groupTimes.init or 0, groupTimes.sorting or 0, groupTimes.preparing or 0, groupTimes.building or 0, ceil( ( GetTime() - buildStartTime ) * 1000 ))); Zerotorescue@13: end Zerotorescue@0: end Zerotorescue@1: Zerotorescue@1: mod.scrollFrame:ResumeLayout(); Zerotorescue@1: mod.scrollFrame:DoLayout(); Zerotorescue@1: Zerotorescue@10: addon:Debug(("Done building summary after %d ms."):format(ceil( ( GetTime() - buildStartTime ) * 1000 ))); Zerotorescue@10: Zerotorescue@1: if CACHE_ITEMS_TOTAL > 0 then Zerotorescue@1: cacheStart = GetTime(); Zerotorescue@7: self:CancelTimer(self.tmrUpdater, true); Zerotorescue@1: self.tmrUpdater = self:ScheduleRepeatingTimer("UpdateNextItem", .01); -- Once every 100 frames (or once every x frames if you have less than 100 FPS, basically, once every frame) Zerotorescue@1: end Zerotorescue@1: end Zerotorescue@1: Zerotorescue@1: function mod:UpdateNextItem() Zerotorescue@1: local i = 0; Zerotorescue@1: Zerotorescue@1: for groupName, items in pairs(itemsCache) do Zerotorescue@1: local minimumStock = addon:GetOptionByKey(groupName, "minimumStock"); Zerotorescue@1: local priceThreshold = addon:GetOptionByKey(groupName, "priceThreshold"); Zerotorescue@1: Zerotorescue@1: for _, item in pairs(items) do Zerotorescue@1: if item.set then Zerotorescue@10: if item.count == -3 then Zerotorescue@10: -- Only if item count was queued, update it Zerotorescue@23: item.count = addon:GetItemCount(item.id, groupName); Zerotorescue@10: if item.set.current and item.set.current.SetText then Zerotorescue@10: item.set.current:SetText(self:DisplayItemCount(item.count, minimumStock)); Zerotorescue@10: end Zerotorescue@1: end Zerotorescue@1: Zerotorescue@50: if item.localCount == -3 then Zerotorescue@50: -- Only if item count was queued, update it Zerotorescue@54: item.localCount = addon:GetLocalItemCount(item.id, groupName); Zerotorescue@50: if item.set.localCount and item.set.localCount.SetText then Zerotorescue@50: item.set.localCount:SetText(self:DisplayItemCount(item.localCount, minimumStock)); Zerotorescue@50: end Zerotorescue@50: end Zerotorescue@50: Zerotorescue@10: if item.value == -3 then Zerotorescue@10: -- Only if item value was queued, update it Zerotorescue@23: Zerotorescue@23: -- The itemlink might not have been loaded yet in which case we retry Zerotorescue@23: item.link = item.link or select(2, GetItemInfo(item.id)); Zerotorescue@23: Zerotorescue@23: if item.link then Zerotorescue@23: item.value = addon:GetAuctionValue(item.link, groupName); Zerotorescue@23: if item.set.value and item.set.value.SetText then Zerotorescue@23: item.set.value:SetText(self:DisplayMoney(item.value, priceThreshold)); Zerotorescue@23: end Zerotorescue@10: end Zerotorescue@1: end Zerotorescue@1: Zerotorescue@1: item.set = nil; Zerotorescue@1: Zerotorescue@1: i = i + 1; Zerotorescue@1: CACHE_ITEMS_CURRENT = CACHE_ITEMS_CURRENT + 1; Zerotorescue@1: Zerotorescue@9: if mod.frame then Zerotorescue@9: mod.frame:SetStatusText(("Caching auction values and item-counts... %d%% has already been processed."):format(floor(CACHE_ITEMS_CURRENT / CACHE_ITEMS_TOTAL * 100))); Zerotorescue@9: end Zerotorescue@1: Zerotorescue@13: if i >= addon.db.global.defaults.summary.speed then Zerotorescue@1: return; Zerotorescue@1: end Zerotorescue@1: end Zerotorescue@1: end Zerotorescue@1: end Zerotorescue@1: Zerotorescue@1: -- Reset trackers Zerotorescue@1: CACHE_ITEMS_TOTAL = 0; Zerotorescue@1: CACHE_ITEMS_CURRENT = 0; Zerotorescue@1: Zerotorescue@1: -- Stop timer Zerotorescue@1: self:CancelTimer(self.tmrUpdater, true); Zerotorescue@10: Zerotorescue@10: -- Rebuild list so hidden items due to too low prices get added Zerotorescue@10: self:Build(); Zerotorescue@1: Zerotorescue@1: -- Announce Zerotorescue@10: mod.frame:SetStatusText("All required prices and itemcounts have been cached. This process took " .. ceil(GetTime() - cacheStart) .. " seconds."); Zerotorescue@1: Zerotorescue@1: -- Forget time Zerotorescue@1: cacheStart = nil; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function mod:ColorCode(num, required) Zerotorescue@0: local percentage = ( num / required ); Zerotorescue@0: Zerotorescue@0: if percentage >= addon.db.global.defaults.colors.green then Zerotorescue@0: return ("|cff00ff00%d|r"):format(num); Zerotorescue@0: elseif percentage >= addon.db.global.defaults.colors.yellow then Zerotorescue@0: return ("|cffffff00%d|r"):format(num); Zerotorescue@0: elseif percentage >= addon.db.global.defaults.colors.orange then Zerotorescue@0: return ("|cffff9933%d|r"):format(num); Zerotorescue@0: elseif percentage >= addon.db.global.defaults.colors.red then Zerotorescue@0: return ("|cffff0000%d|r"):format(num); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@1: function mod:DisplayMoney(value, priceThreshold) Zerotorescue@7: if value == -1 then Zerotorescue@7: return "|cff0000ffNone up|r"; Zerotorescue@7: elseif value == -2 then Zerotorescue@7: return "|cff0000ffNo AH mod|r"; Zerotorescue@9: elseif value == -3 then Zerotorescue@9: return "|cffffff00Unknown|r"; Zerotorescue@13: elseif value == -4 then Zerotorescue@13: return "|cff00ff00-|r"; Zerotorescue@23: elseif value == -5 then Zerotorescue@23: return "|cffff9933Error|r"; Zerotorescue@23: elseif priceThreshold and value < priceThreshold then Zerotorescue@17: return ("|cffaaaaaa%s|r"):format(addon:ReadableMoney(value or 0, true):gsub("|([a-fA-F0-9]+)([gsc]+)|r", "%2")); Zerotorescue@1: else Zerotorescue@1: return addon:ReadableMoney(value or 0, true); Zerotorescue@1: end Zerotorescue@1: end Zerotorescue@1: Zerotorescue@9: function mod:DisplayItemCount(value, minimumStock) Zerotorescue@13: if value == -1 then Zerotorescue@13: return "|cffffff00Unknown|r"; Zerotorescue@13: elseif value == -3 then Zerotorescue@9: return "|cffffff00Unknown|r"; Zerotorescue@9: else Zerotorescue@9: return self:ColorCode(value, minimumStock); Zerotorescue@9: end Zerotorescue@9: end Zerotorescue@9: Zerotorescue@0: function mod:NumberFormat(num) Zerotorescue@0: local formatted = string.gsub(num, "(%d)(%d%d%d)$", "%1,%2", 1); Zerotorescue@0: Zerotorescue@0: while true do Zerotorescue@0: formatted, matches = string.gsub(formatted, "(%d)(%d%d%d),", "%1,%2,", 1); Zerotorescue@0: Zerotorescue@0: if matches == 0 then Zerotorescue@0: break; Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: return formatted; Zerotorescue@1: end