Mercurial > wow > inventory
view Summary.lua @ 13:5006cb0e97c6
Removed sound media registrations since we don?t use them.
Added an option to include tadeskill items above a certain item level threshold in the add items config tab.
Renamed the variable for toggling hiding from summary when below price threshold-option. You will have to re-set it.
Summary size and processing speed will now be remembered.
Processing speed slider can now go up to 500% (up from 100%).
Silver will be hidden from money when it includes more than 10 gold (down from 100g) and copper will be hidden if it includes more than 1 gold (down from 10g).
Auction addons, crafting addons and itemcount addons can now register themselves through a few global functions. The most used addons have been included in the addon folder.
You can now select the prefered default pricing, item count and crafting addons.
Temporarily removed the ?dialogControl = ?DropDown?? from the track at select boxes. This functionality is broken within the Ace3 library and until it is fixed I wish to keep these options somewhat functional.
The item list will now be truncated before rebuilding. Previously items disappearing from your inventory would still appear in this list.
Mass add is now functional.
All buttons and sliders that were meant to receive a tooltip (including the sort-headers), now have one.
Added spacers between all buttons and sliders of the summary window.
Added a ?queue all? button to the summary window. This button is not yet functional.
If the value of an item is not retrieved from the auction prices database, it will appear as a dash (-) rather than ?0c?.
If no item count is enabled, item counts will appear as ?Unknown? instead of breaking (or defaulting to 0).
author | Zerotorescue |
---|---|
date | Mon, 18 Oct 2010 15:26:42 +0200 |
parents | 417c3cfb9623 |
children | 0fc8a54516d7 |
line wrap: on
line source
local addon = LibStub("AceAddon-3.0"):GetAddon("Inventorium"); local mod = addon:NewModule("Summary", "AceEvent-3.0", "AceTimer-3.0"); local AceGUI = LibStub("AceGUI-3.0"); function mod:OnEnable() self:RegisterWidgets(); -- Register our own slash commands addon:RegisterSlash(function() mod:BuildMain(); mod:Build(); end, "s", "sum", "summary"); end local function ShowTooltip(self) -- If this function is called from a widget, self is the widget and self.frame the actual frame local this = self.frame or self; GameTooltip:SetOwner(this, "ANCHOR_NONE"); GameTooltip:SetPoint("BOTTOM", this, "TOP"); GameTooltip:SetText(this.tooltipTitle, 1, .82, 0, 1); if type(this.tooltip) == "string" then GameTooltip:AddLine(this.tooltip, 1, 1, 1, 1); end GameTooltip:Show(); end local function HideTooltip() GameTooltip:Hide(); end function mod:RegisterWidgets() -- Register InlineGroupWithButton-widget -- This widget adds a button next to the header of an inline group -- SetPoint doesn't seem usable within AceGUI. local widgetType = "InlineGroupWithButton"; local widgetVersion = 1; local function Constructor() local widget = AceGUI:Create("InlineGroup"); widget.type = widgetType; widget.MakeButton = function(self, buttonSettings) if type(buttonSettings) == "table" then local button = CreateFrame("Button", nil, self.frame, "UIPanelButtonTemplate"); button:SetText(buttonSettings.name); button:SetHeight(22); button:SetWidth(120); button:SetPoint("TOPRIGHT", self.frame, "TOPRIGHT", -10, 5); button:SetScript("OnClick", buttonSettings.exec); button.tooltipTitle = buttonSettings.name; button.tooltip = buttonSettings.desc or ""; button:SetScript("OnEnter", ShowTooltip); button:SetScript("OnLeave", HideTooltip); else error("settings must be a table - usage: MakeButton(table);"); end end return widget; end AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion); end local itemsCache = {}; local CACHE_ITEMS_TOTAL, CACHE_ITEMS_CURRENT = 0, 0; local cacheStart; function mod:BuildMain() LibStub("AceConfigDialog-3.0"):Close("InventoriumOptions"); self:CloseFrame(); -- Main Window mod.frame = AceGUI:Create("Frame"); mod.frame:SetTitle("Summary"); mod.frame:SetLayout("Fill"); mod.frame:SetCallback("OnClose", function(widget) mod:CancelTimer(self.tmrUpdater, true); mod:CloseFrame(); end); mod.frame:SetWidth(addon.db.global.defaults.summary.width); mod.frame:SetHeight(addon.db.global.defaults.summary.height); mod.frame.OnWidthSet = function(_, width) addon.db.global.defaults.summary.width = width; end; mod.frame.OnHeightSet = function(_, height) addon.db.global.defaults.summary.height = height; end; -- ScrollFrame child mod.scrollFrame = AceGUI:Create("ScrollFrame"); mod.scrollFrame:SetLayout("Flow"); mod.frame:AddChild(mod.scrollFrame); -- Reset items cache table.wipe(itemsCache); end function mod:CloseFrame() if mod.frame then mod.frame:Release(); mod.frame = nil; -- Stop caching -- Stop timer self:CancelTimer(self.tmrUpdater, true); -- Reset trackers CACHE_ITEMS_TOTAL = 0; CACHE_ITEMS_CURRENT = 0; end end local sortMethod = "item"; local sortDirectory = "ASC"; local function ReSort(subject) if sortMethod == subject then sortDirectory = (sortDirectory == "ASC" and "DESC") or "ASC"; else sortDirectory = "ASC"; end sortMethod = subject; mod:Build(); end -- From http://www.wowwiki.com/API_sort local function pairsByKeys (t, f) local a = {} for n in pairs(t) do table.insert(a, n) end table.sort(a, f) local i = 0 -- iterator variable local iter = function () -- iterator function i = i + 1 if a[i] == nil then return nil else return a[i], t[a[i]] end end return iter end function mod:Build() local buildStartTime, times = GetTime(), {}; -- 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 -- This appears to be required for each container we wish to pause, so also do this for the contents mod.scrollFrame:PauseLayout(); mod.scrollFrame:ReleaseChildren(); -- Refresh button local btnRefresh = AceGUI:Create("Button"); btnRefresh:SetText("Refresh"); btnRefresh:SetRelativeWidth(.2); btnRefresh:SetCallback("OnClick", function() -- Reset items cache table.wipe(itemsCache); -- Rebuild itemlist and start caching mod:Build(); end); btnRefresh:SetCallback("OnEnter", ShowTooltip); btnRefresh:SetCallback("OnLeave", HideTooltip); btnRefresh.frame.tooltipTitle = "Refresh Cache"; btnRefresh.frame.tooltip = "Refresh the list and recache the item counts and auction values."; mod.scrollFrame:AddChild(btnRefresh); local lblSpacer = AceGUI:Create("Label"); lblSpacer:SetRelativeWidth(.03); mod.scrollFrame:AddChild(lblSpacer); -- Speed slider local sdrSpeed = AceGUI:Create("Slider"); sdrSpeed:SetLabel("Processing speed"); sdrSpeed:SetSliderValues(0.01, 5, 0.01); sdrSpeed:SetIsPercent(true); sdrSpeed:SetRelativeWidth(.3); sdrSpeed:SetCallback("OnMouseUp", function(self, event, value) addon.db.global.defaults.summary.speed = ceil( value * 100 / 5 ); CACHE_ITEMS_PER_UPDATE = addon.db.global.defaults.summary.speed; -- max = 20, min = 1 end); sdrSpeed:SetValue( addon.db.global.defaults.summary.speed * 5 / 100 ); sdrSpeed:SetCallback("OnEnter", ShowTooltip); sdrSpeed:SetCallback("OnLeave", HideTooltip); sdrSpeed.frame.tooltipTitle = "Caching Processing Speed"; 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."; mod.scrollFrame:AddChild(sdrSpeed); local lblSpacer = AceGUI:Create("Label"); lblSpacer:SetRelativeWidth(.23); mod.scrollFrame:AddChild(lblSpacer); -- Config button --[[local btnConfig = AceGUI:Create("Button"); btnConfig:SetText("Config"); btnConfig:SetRelativeWidth(.2); btnConfig:SetCallback("OnClick", function() --TODO: Tidy up SlashCmdList["INVENTORIUM"]("config"); end); btnConfig:SetCallback("OnEnter", ShowTooltip); btnConfig:SetCallback("OnLeave", HideTooltip); btnConfig.frame.tooltipTitle = "Config"; btnConfig.frame.tooltip = "Click to open the config window. This will close the current window."; mod.scrollFrame:AddChild(btnConfig);]] local lblSpacer = AceGUI:Create("Label"); lblSpacer:SetRelativeWidth(.03); mod.scrollFrame:AddChild(lblSpacer); -- Queue all button local btnQueueAll = AceGUI:Create("Button"); btnQueueAll:SetText("Queue All"); btnQueueAll:SetRelativeWidth(.2); btnQueueAll:SetCallback("OnClick", function() end); btnQueueAll:SetCallback("OnEnter", ShowTooltip); btnQueueAll:SetCallback("OnLeave", HideTooltip); btnQueueAll.frame.tooltipTitle = "Queue all"; btnQueueAll.frame.tooltip = "Queue everything that requires restocking within every single visible group."; mod.scrollFrame:AddChild(btnQueueAll); times.init = ceil( ( GetTime() - buildStartTime ) * 1000 ); addon:Debug("Time spent legend: (init / sorting / preparing / building / all)."); local playerName = UnitName("player"); -- Go through all our stored groups for groupName, values in pairsByKeys(addon.db.global.groups, function(a, b) return a:lower() < b:lower(); end) do local groupStartTime, groupTimes = GetTime(), {}; local trackAt = (values.trackAtCharacters or (values.trackAtCharacters == nil and addon.db.global.defaults.trackAtCharacters)); -- Does this group have any items and do we want to track it at this char? if values.items and trackAt[playerName] then -- Get group settings local minimumStock = (values.minimumStock or (values.minimumStock == nil and addon.db.global.defaults.minimumStock)); local showWhenBelow = (values.summaryThresholdShow or (values.summaryThresholdShow == nil and addon.db.global.defaults.summaryThresholdShow)); local priceThreshold = (values.priceThreshold or (values.priceThreshold == nil and addon.db.global.defaults.priceThreshold)); local hideWhenBelowPriceThreshold = (values.hideFromSummaryWhenBelowPriceThreshold or (values.hideFromSummaryWhenBelowPriceThreshold == nil and addon.db.global.defaults.hideFromSummaryWhenBelowPriceThreshold)); -- Make group container local iGroup = AceGUI:Create("InlineGroupWithButton"); iGroup:PauseLayout(); iGroup:SetTitle(groupName); iGroup:SetFullWidth(true); iGroup:SetLayout("Flow"); iGroup:MakeButton({ name = "Queue", desc = "Queue all items in this group.", exec = function() print(groupName); end, }); -- Headers -- Itemlink local lblItem = AceGUI:Create("InteractiveLabel"); lblItem:SetText("|cfffed000Item|r"); lblItem:SetFontObject(GameFontHighlight); lblItem:SetRelativeWidth(.7); lblItem:SetCallback("OnClick", function() ReSort("item"); end); lblItem:SetCallback("OnEnter", ShowTooltip); lblItem:SetCallback("OnLeave", HideTooltip); lblItem.frame.tooltipTitle = "Item"; lblItem.frame.tooltip = "Sort on the item quality, then name."; iGroup:AddChild(lblItem); -- Current quantity local lblQuantity = AceGUI:Create("InteractiveLabel"); lblQuantity:SetText("|cfffed000Cur.|r"); lblQuantity:SetFontObject(GameFontHighlight); lblQuantity:SetRelativeWidth(.099); lblQuantity:SetCallback("OnClick", function() ReSort("current"); end); lblQuantity:SetCallback("OnEnter", ShowTooltip); lblQuantity:SetCallback("OnLeave", HideTooltip); lblQuantity.frame.tooltipTitle = "Current stock"; lblQuantity.frame.tooltip = "Sort on the amount of items currently in stock."; iGroup:AddChild(lblQuantity); -- Required stock local lblMinimumStock = AceGUI:Create("InteractiveLabel"); lblMinimumStock:SetText("|cfffed000Min.|r"); lblMinimumStock:SetFontObject(GameFontHighlight); lblMinimumStock:SetRelativeWidth(.099); lblMinimumStock:SetCallback("OnClick", function() ReSort("percentage"); end); lblMinimumStock:SetCallback("OnEnter", ShowTooltip); lblMinimumStock:SetCallback("OnLeave", HideTooltip); lblMinimumStock.frame.tooltipTitle = "Minimum stock"; lblMinimumStock.frame.tooltip = "Sort on the minimum amount of items you wish to keep in stock."; iGroup:AddChild(lblMinimumStock); -- Lowest value local lblValue = AceGUI:Create("InteractiveLabel"); lblValue:SetText("|cfffed000Value|r"); lblValue:SetFontObject(GameFontHighlight); lblValue:SetRelativeWidth(.099); lblValue:SetCallback("OnClick", function() ReSort("value"); end); lblValue:SetCallback("OnEnter", ShowTooltip); lblValue:SetCallback("OnLeave", HideTooltip); lblValue.frame.tooltipTitle = "Value"; lblValue.frame.tooltip = "Sort on the item auction value."; iGroup:AddChild(lblValue); -- Retrieve items list if not itemsCache[groupName] then itemsCache[groupName] = {}; local unknownItemName = "Unknown (#%d)"; -- Sort item list for itemId, _ in pairs(values.items) do local itemName, itemLink, itemRarity = GetItemInfo(itemId); table.insert(itemsCache[groupName], { id = itemId, name = itemName or unknownItemName:format(itemId), link = itemLink or unknownItemName:format(itemId), value = ((priceThreshold == 0) and -4) or -3,-- if no price threshold is set for this item, then don't look it up either --addon:GetAuctionValue(itemLink), rarity = itemRarity or 1, count = -3,--addon:GetItemCount(itemId), set = {}, }); CACHE_ITEMS_TOTAL = CACHE_ITEMS_TOTAL + 1; end end groupTimes.init = ceil( ( GetTime() - groupStartTime ) * 1000 ); -- Sort items table.sort(itemsCache[groupName], function(a, b) if sortMethod == "item" and a.rarity == b.rarity then -- Do a name-compare for items of the same rarity -- Otherwise epics first, then junk if sortDirectory == "ASC" then return a.name:upper() < b.name:upper(); else return a.name:upper() > b.name:upper(); end elseif sortMethod == "item" then if sortDirectory == "ASC" then return a.rarity > b.rarity; -- the comparers were reversed because we want epics first else return a.rarity < b.rarity; -- the comparers were reversed because we want epics first end elseif sortMethod == "current" then if sortDirectory == "ASC" then return a.count < b.count; else return a.count > b.count; end elseif sortMethod == "percentage" then if sortDirectory == "ASC" then return ( a.count / minimumStock ) < ( b.count / minimumStock ); else return ( a.count / minimumStock ) > ( b.count / minimumStock ); end elseif sortMethod == "value" then if sortDirectory == "ASC" then return a.value < b.value; else return a.value > b.value; end end end); groupTimes.sorting = ceil( ( GetTime() - groupStartTime ) * 1000 ); -- Show itemslist for i, item in pairs(itemsCache[groupName]) do if ( item.count / minimumStock ) < showWhenBelow and not (hideWhenBelowPriceThreshold and item.value < priceThreshold) then local btnItemLink = AceGUI:Create("ItemLinkButton"); --btnItemLink:SetUserData("exec", function() -- print("Nothing happening yet."); --end); btnItemLink:SetRelativeWidth(.7); btnItemLink:SetItemId(item.id); iGroup:AddChild(btnItemLink); -- Current quantity local lblQuantity = AceGUI:Create("Label"); lblQuantity:SetText(self:DisplayItemCount(item.count, minimumStock)); lblQuantity:SetRelativeWidth(.099); iGroup:AddChild(lblQuantity); -- Required stock local lblMinimumStock = AceGUI:Create("Label"); lblMinimumStock:SetText(minimumStock); lblMinimumStock:SetRelativeWidth(.099); iGroup:AddChild(lblMinimumStock); -- Value local lblValue = AceGUI:Create("Label"); lblValue:SetText(self:DisplayMoney(item.value, priceThreshold)); lblValue:SetRelativeWidth(.099); iGroup:AddChild(lblValue); -- Remember references to the value and current fields so we can fill them later if item.set then -- -3 means the price is unknown, queue look up if item.value == -3 then item.set.value = lblValue; end if item.count == -3 then item.set.current = lblQuantity; end -- Don't queue if we already know everything we want to know if item.value ~= -3 and item.count ~= -3 then item.set = nil; end end end end groupTimes.preparing = ceil( ( GetTime() - groupStartTime ) * 1000 ); iGroup:ResumeLayout(); mod.scrollFrame:AddChild(iGroup); -- this can take up to .5 seconds, might need to look into again at a later time groupTimes.building = ceil( ( GetTime() - groupStartTime ) * 1000 ); end if groupStartTime and groupTimes then 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 ))); end end mod.scrollFrame:ResumeLayout(); mod.scrollFrame:DoLayout(); addon:Debug(("Done building summary after %d ms."):format(ceil( ( GetTime() - buildStartTime ) * 1000 ))); if CACHE_ITEMS_TOTAL > 0 then cacheStart = GetTime(); self:CancelTimer(self.tmrUpdater, true); 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) end end function mod:UpdateNextItem() local i = 0; for groupName, items in pairs(itemsCache) do local minimumStock = addon:GetOptionByKey(groupName, "minimumStock"); local priceThreshold = addon:GetOptionByKey(groupName, "priceThreshold"); for _, item in pairs(items) do if item.set then if item.count == -3 then -- Only if item count was queued, update it item.count = addon:GetItemCount(item.id); if item.set.current and item.set.current.SetText then item.set.current:SetText(self:DisplayItemCount(item.count, minimumStock)); end end if item.value == -3 then -- Only if item value was queued, update it item.value = addon:GetAuctionValue(item.link); if item.set.value and item.set.value.SetText then item.set.value:SetText(self:DisplayMoney(item.value, priceThreshold)); end end item.set = nil; i = i + 1; CACHE_ITEMS_CURRENT = CACHE_ITEMS_CURRENT + 1; if mod.frame then mod.frame:SetStatusText(("Caching auction values and item-counts... %d%% has already been processed."):format(floor(CACHE_ITEMS_CURRENT / CACHE_ITEMS_TOTAL * 100))); end if i >= addon.db.global.defaults.summary.speed then return; end end end end -- Reset trackers CACHE_ITEMS_TOTAL = 0; CACHE_ITEMS_CURRENT = 0; -- Stop timer self:CancelTimer(self.tmrUpdater, true); -- Rebuild list so hidden items due to too low prices get added self:Build(); -- Announce mod.frame:SetStatusText("All required prices and itemcounts have been cached. This process took " .. ceil(GetTime() - cacheStart) .. " seconds."); -- Forget time cacheStart = nil; end function mod:ColorCode(num, required) local percentage = ( num / required ); if percentage >= addon.db.global.defaults.colors.green then return ("|cff00ff00%d|r"):format(num); elseif percentage >= addon.db.global.defaults.colors.yellow then return ("|cffffff00%d|r"):format(num); elseif percentage >= addon.db.global.defaults.colors.orange then return ("|cffff9933%d|r"):format(num); elseif percentage >= addon.db.global.defaults.colors.red then return ("|cffff0000%d|r"):format(num); end end function mod:DisplayMoney(value, priceThreshold) if value == -1 then return "|cff0000ffNone up|r"; elseif value == -2 then return "|cff0000ffNo AH mod|r"; elseif value == -3 then return "|cffffff00Unknown|r"; elseif value == -4 then return "|cff00ff00-|r"; elseif value < priceThreshold then return ("|cffff0000%s|r"):format(addon:ReadableMoney(value or 0, true)); else return addon:ReadableMoney(value or 0, true); end end function mod:DisplayItemCount(value, minimumStock) if value == -1 then return "|cffffff00Unknown|r"; elseif value == -3 then return "|cffffff00Unknown|r"; else return self:ColorCode(value, minimumStock); end end function mod:NumberFormat(num) local formatted = string.gsub(num, "(%d)(%d%d%d)$", "%1,%2", 1); while true do formatted, matches = string.gsub(formatted, "(%d)(%d%d%d),", "%1,%2,", 1); if matches == 0 then break; end end return formatted; end