annotate Summary.lua @ 1:9fff13c08f99

Initial release, config and summary windows mostly working. Base functionality available.
author Zerotorescue
date Fri, 08 Oct 2010 16:11:59 +0200
parents c6ff7ba0e8f6
children 1a815139e4c3
rev   line source
Zerotorescue@0 1 local addon = LibStub("AceAddon-3.0"):GetAddon("Inventory");
Zerotorescue@1 2 local mod = addon:NewModule("Summary", "AceEvent-3.0", "AceTimer-3.0");
Zerotorescue@0 3
Zerotorescue@0 4 local AceGUI = LibStub("AceGUI-3.0");
Zerotorescue@0 5
Zerotorescue@0 6 function mod:OnEnable()
Zerotorescue@0 7 self:RegisterWidgets();
Zerotorescue@0 8
Zerotorescue@1 9 -- Register our own slash commands
Zerotorescue@1 10 addon:RegisterSlash(function()
Zerotorescue@1 11 mod:BuildMain();
Zerotorescue@1 12 mod:Build();
Zerotorescue@1 13 end, "s", "sum", "summary");
Zerotorescue@0 14 end
Zerotorescue@0 15
Zerotorescue@0 16 function mod:RegisterWidgets()
Zerotorescue@0 17 -- Register InlineGroupWithButton-widget
Zerotorescue@0 18 -- This widget adds a button next to the header of an inline group
Zerotorescue@0 19 -- SetPoint doesn't seem usable within AceGUI.
Zerotorescue@0 20
Zerotorescue@0 21 local widgetType = "InlineGroupWithButton";
Zerotorescue@0 22 local widgetVersion = 1;
Zerotorescue@0 23
Zerotorescue@0 24 local function Constructor()
Zerotorescue@0 25 local widget = AceGUI:Create("InlineGroup");
Zerotorescue@0 26 widget.type = widgetType;
Zerotorescue@0 27
Zerotorescue@0 28 widget.MakeButton = function(self, buttonSettings)
Zerotorescue@0 29 if type(buttonSettings) == "table" then
Zerotorescue@0 30 local button = CreateFrame("Button", nil, self.frame, "UIPanelButtonTemplate");
Zerotorescue@0 31 button:SetText(buttonSettings.name);
Zerotorescue@0 32 button:SetHeight(22);
Zerotorescue@0 33 button:SetWidth(120);
Zerotorescue@0 34 button:SetPoint("TOPRIGHT", self.frame, "TOPRIGHT", -10, 5);
Zerotorescue@0 35 button:SetScript("OnClick", buttonSettings.exec);
Zerotorescue@0 36 button.tooltipTitle = buttonSettings.name;
Zerotorescue@0 37 button.tooltip = buttonSettings.desc or "";
Zerotorescue@0 38 button:SetScript("OnEnter", function(self)
Zerotorescue@0 39 GameTooltip:SetOwner(self, "ANCHOR_NONE")
Zerotorescue@0 40 GameTooltip:SetPoint("BOTTOM", self, "TOP")
Zerotorescue@0 41 GameTooltip:SetText(self.tooltipTitle, 1, .82, 0, 1)
Zerotorescue@0 42
Zerotorescue@0 43 if type(self.tooltip) == "string" then
Zerotorescue@0 44 GameTooltip:AddLine(self.tooltip, 1, 1, 1, 1);
Zerotorescue@0 45 end
Zerotorescue@0 46
Zerotorescue@0 47 GameTooltip:Show();
Zerotorescue@0 48 end);
Zerotorescue@0 49 button:SetScript("OnLeave", function(self)
Zerotorescue@0 50 GameTooltip:Hide();
Zerotorescue@0 51 end);
Zerotorescue@0 52 else
Zerotorescue@0 53 error("settings must be a table - usage: MakeButton(table);");
Zerotorescue@0 54 end
Zerotorescue@0 55 end
Zerotorescue@0 56
Zerotorescue@0 57 return widget;
Zerotorescue@0 58 end
Zerotorescue@0 59
Zerotorescue@0 60 AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion);
Zerotorescue@0 61 end
Zerotorescue@0 62
Zerotorescue@1 63 local itemsCache = {};
Zerotorescue@1 64 local CACHE_ITEMS_TOTAL, CACHE_ITEMS_CURRENT, CACHE_ITEMS_PER_UPDATE = 0, 0, 5;
Zerotorescue@1 65 local cacheStart;
Zerotorescue@1 66
Zerotorescue@0 67 function mod:BuildMain()
Zerotorescue@1 68 LibStub("AceConfigDialog-3.0"):Close("InventoryOptions");
Zerotorescue@0 69
Zerotorescue@1 70 -- Main Window
Zerotorescue@1 71 mod.frame = AceGUI:Create("Frame");
Zerotorescue@1 72 mod.frame:SetTitle("Inventory Summary");
Zerotorescue@1 73 mod.frame:SetLayout("Fill");
Zerotorescue@1 74 mod.frame:SetCallback("OnClose", function(widget)
Zerotorescue@1 75 AceGUI:Release(widget);
Zerotorescue@1 76 end);
Zerotorescue@0 77
Zerotorescue@1 78 -- ScrollFrame child
Zerotorescue@1 79 mod.scrollFrame = AceGUI:Create("ScrollFrame");
Zerotorescue@1 80 mod.scrollFrame:SetLayout("Flow");
Zerotorescue@0 81
Zerotorescue@1 82 mod.frame:AddChild(mod.scrollFrame);
Zerotorescue@1 83
Zerotorescue@1 84 -- Reset items cache
Zerotorescue@1 85 table.wipe(itemsCache);
Zerotorescue@0 86 end
Zerotorescue@0 87
Zerotorescue@0 88 local sortMethod = "item";
Zerotorescue@0 89 local sortDirectory = "ASC";
Zerotorescue@0 90 local function ReSort(subject)
Zerotorescue@0 91 if sortMethod == subject then
Zerotorescue@0 92 sortDirectory = (sortDirectory == "ASC" and "DESC") or "ASC";
Zerotorescue@0 93 else
Zerotorescue@0 94 sortDirectory = "ASC";
Zerotorescue@0 95 end
Zerotorescue@0 96 sortMethod = subject;
Zerotorescue@0 97
Zerotorescue@0 98 mod:Build();
Zerotorescue@0 99 end
Zerotorescue@0 100
Zerotorescue@0 101 function mod:Build()
Zerotorescue@1 102 local start = GetTime();
Zerotorescue@1 103
Zerotorescue@0 104 mod.scrollFrame:ReleaseChildren();
Zerotorescue@0 105
Zerotorescue@1 106 -- 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 107 -- This appears to be required for each container we wish to pause, so also do this for the contents
Zerotorescue@1 108 mod.scrollFrame:PauseLayout();
Zerotorescue@1 109
Zerotorescue@1 110 local playerName = UnitName("player");
Zerotorescue@1 111
Zerotorescue@1 112 -- Go through all our stored groups
Zerotorescue@0 113 for groupName, values in pairs(addon.db.global.groups) do
Zerotorescue@1 114 local trackAt = (values.trackAtCharacters or (values.trackAtCharacters == nil and addon.db.global.defaults.trackAtCharacters));
Zerotorescue@1 115
Zerotorescue@1 116 -- Does this group have any items and do we want to track it at this char?
Zerotorescue@1 117 if values.items and trackAt[playerName] then
Zerotorescue@0 118 -- Get group settings
Zerotorescue@1 119 local stockRequired = (values.minimumStock or (values.minimumStock == nil and addon.db.global.defaults.minimumStock));
Zerotorescue@1 120 local showWhenBelow = (values.summaryThresholdShow or (values.summaryThresholdShow == nil and addon.db.global.defaults.summaryThresholdShow));
Zerotorescue@1 121 local priceThreshold = (values.priceThreshold or (values.priceThreshold == nil and addon.db.global.defaults.priceThreshold));
Zerotorescue@1 122 local hideWhenBelowPriceThreshold = (values.hideFromSummaryWhenBelowPriceThreshold or (values.hideFromSummaryWhenBelowPriceThreshold == nil and addon.db.global.defaults.hideFromSummaryWhenBelowPriceThreshold));
Zerotorescue@0 123
Zerotorescue@0 124 -- Make group container
Zerotorescue@0 125 local iGroup = AceGUI:Create("InlineGroupWithButton");
Zerotorescue@1 126 iGroup:PauseLayout();
Zerotorescue@0 127 iGroup:SetTitle(groupName);
Zerotorescue@0 128 iGroup:SetFullWidth(true);
Zerotorescue@0 129 iGroup:SetLayout("Flow");
Zerotorescue@0 130 iGroup:MakeButton({
Zerotorescue@0 131 name = "Queue",
Zerotorescue@0 132 desc = "Queue all items in this group.",
Zerotorescue@0 133 exec = function()
Zerotorescue@0 134 print(groupName);
Zerotorescue@0 135 end,
Zerotorescue@0 136 });
Zerotorescue@0 137
Zerotorescue@0 138 -- Headers
Zerotorescue@1 139
Zerotorescue@0 140 -- Itemlink
Zerotorescue@0 141 local lblItem = AceGUI:Create("InteractiveLabel");
Zerotorescue@0 142 lblItem:SetText("|cfffed000Item|r");
Zerotorescue@0 143 lblItem:SetFontObject(GameFontHighlight);
Zerotorescue@0 144 lblItem:SetRelativeWidth(0.7);
Zerotorescue@0 145 lblItem:SetCallback("OnClick", function() ReSort("item"); end);
Zerotorescue@0 146
Zerotorescue@0 147 iGroup:AddChild(lblItem);
Zerotorescue@0 148
Zerotorescue@0 149 -- Current quantity
Zerotorescue@0 150 local lblQuantity = AceGUI:Create("InteractiveLabel");
Zerotorescue@0 151 lblQuantity:SetText("|cfffed000Cur.|r");
Zerotorescue@0 152 lblQuantity:SetFontObject(GameFontHighlight);
Zerotorescue@1 153 lblQuantity:SetRelativeWidth(0.099);
Zerotorescue@0 154 lblQuantity:SetCallback("OnClick", function() ReSort("current"); end);
Zerotorescue@0 155
Zerotorescue@0 156 iGroup:AddChild(lblQuantity);
Zerotorescue@0 157
Zerotorescue@0 158 -- Required stock
Zerotorescue@0 159 local lblStockRequired = AceGUI:Create("InteractiveLabel");
Zerotorescue@0 160 lblStockRequired:SetText("|cfffed000Req.|r");
Zerotorescue@0 161 lblStockRequired:SetFontObject(GameFontHighlight);
Zerotorescue@1 162 lblStockRequired:SetRelativeWidth(0.099);
Zerotorescue@0 163 lblStockRequired:SetCallback("OnClick", function() ReSort("percentage"); end);
Zerotorescue@0 164
Zerotorescue@0 165 iGroup:AddChild(lblStockRequired);
Zerotorescue@0 166
Zerotorescue@1 167 -- Lowest value
Zerotorescue@1 168 local lblValue = AceGUI:Create("InteractiveLabel");
Zerotorescue@1 169 lblValue:SetText("|cfffed000Value|r");
Zerotorescue@1 170 lblValue:SetFontObject(GameFontHighlight);
Zerotorescue@1 171 lblValue:SetRelativeWidth(0.099);
Zerotorescue@1 172 lblValue:SetCallback("OnClick", function() ReSort("value"); end);
Zerotorescue@1 173
Zerotorescue@1 174 iGroup:AddChild(lblValue);
Zerotorescue@1 175
Zerotorescue@1 176 if not itemsCache[groupName] then
Zerotorescue@1 177 itemsCache[groupName] = {};
Zerotorescue@0 178
Zerotorescue@1 179 -- Sort item list
Zerotorescue@1 180 for itemId in pairs(values.items) do
Zerotorescue@1 181 local itemName, itemLink, itemRarity = GetItemInfo(itemId);
Zerotorescue@1 182
Zerotorescue@1 183 table.insert(itemsCache[groupName], {
Zerotorescue@1 184 id = itemId,
Zerotorescue@1 185 name = itemName,
Zerotorescue@1 186 link = itemLink,
Zerotorescue@1 187 value = 0,--addon:GetAuctionValue(itemLink),
Zerotorescue@1 188 rarity = itemRarity,
Zerotorescue@1 189 count = 0,--addon:GetItemCount(itemId),
Zerotorescue@1 190 set = {},
Zerotorescue@1 191 });
Zerotorescue@1 192 CACHE_ITEMS_TOTAL = CACHE_ITEMS_TOTAL + 1;
Zerotorescue@1 193 end
Zerotorescue@0 194 end
Zerotorescue@0 195
Zerotorescue@1 196 table.sort(itemsCache[groupName], function(a, b)
Zerotorescue@1 197 if sortMethod == "item" and a.rarity == b.rarity then
Zerotorescue@1 198 -- Do a name-compare for items of the same rarity
Zerotorescue@1 199 -- Otherwise epics first, then junk
Zerotorescue@0 200 if sortDirectory == "ASC" then
Zerotorescue@1 201 return a.name:upper() < b.name:upper();
Zerotorescue@0 202 else
Zerotorescue@1 203 return a.name:upper() > b.name:upper();
Zerotorescue@1 204 end
Zerotorescue@1 205 elseif sortMethod == "item" then
Zerotorescue@1 206 if sortDirectory == "ASC" then
Zerotorescue@1 207 return a.rarity > b.rarity; -- the comparers were reversed because we want epics first
Zerotorescue@1 208 else
Zerotorescue@1 209 return a.rarity < b.rarity; -- the comparers were reversed because we want epics first
Zerotorescue@0 210 end
Zerotorescue@0 211 elseif sortMethod == "current" then
Zerotorescue@0 212 if sortDirectory == "ASC" then
Zerotorescue@0 213 return a.count < b.count;
Zerotorescue@0 214 else
Zerotorescue@0 215 return a.count > b.count;
Zerotorescue@0 216 end
Zerotorescue@0 217 elseif sortMethod == "percentage" then
Zerotorescue@0 218 if sortDirectory == "ASC" then
Zerotorescue@0 219 return ( a.count / stockRequired ) < ( b.count / stockRequired );
Zerotorescue@0 220 else
Zerotorescue@0 221 return ( a.count / stockRequired ) > ( b.count / stockRequired );
Zerotorescue@0 222 end
Zerotorescue@1 223 elseif sortMethod == "value" then
Zerotorescue@1 224 if sortDirectory == "ASC" then
Zerotorescue@1 225 return a.value < b.value;
Zerotorescue@1 226 else
Zerotorescue@1 227 return a.value > b.value;
Zerotorescue@1 228 end
Zerotorescue@0 229 end
Zerotorescue@0 230 end);
Zerotorescue@0 231
Zerotorescue@0 232 -- Show stuff
Zerotorescue@1 233 for i, item in pairs(itemsCache[groupName]) do
Zerotorescue@1 234 if ( item.count / stockRequired ) < showWhenBelow and not (hideWhenBelowPriceThreshold and item.value < priceThreshold) then
Zerotorescue@0 235 local btnItemLink = AceGUI:Create("ItemLinkButton");
Zerotorescue@1 236 btnItemLink:SetUserData("exec", function()
Zerotorescue@1 237 print("Win.");
Zerotorescue@1 238 end);
Zerotorescue@0 239 btnItemLink:SetRelativeWidth(0.7);
Zerotorescue@1 240 btnItemLink:SetItemId(item.id);
Zerotorescue@0 241
Zerotorescue@0 242 iGroup:AddChild(btnItemLink);
Zerotorescue@0 243
Zerotorescue@0 244 -- Current quantity
Zerotorescue@0 245 local lblQuantity = AceGUI:Create("Label");
Zerotorescue@0 246 lblQuantity:SetText(self:ColorCode(item.count, stockRequired));
Zerotorescue@1 247 lblQuantity:SetRelativeWidth(0.099);
Zerotorescue@0 248
Zerotorescue@0 249 iGroup:AddChild(lblQuantity);
Zerotorescue@0 250
Zerotorescue@0 251 -- Required stock
Zerotorescue@0 252 local lblStockRequired = AceGUI:Create("Label");
Zerotorescue@0 253 lblStockRequired:SetText(stockRequired);
Zerotorescue@1 254 lblStockRequired:SetRelativeWidth(0.099);
Zerotorescue@0 255
Zerotorescue@0 256 iGroup:AddChild(lblStockRequired);
Zerotorescue@1 257
Zerotorescue@1 258 -- Value
Zerotorescue@1 259 local lblValue = AceGUI:Create("Label");
Zerotorescue@1 260 lblValue:SetText(self:DisplayMoney(item.value, priceThreshold));
Zerotorescue@1 261 lblValue:SetRelativeWidth(0.099);
Zerotorescue@1 262
Zerotorescue@1 263 iGroup:AddChild(lblValue);
Zerotorescue@1 264
Zerotorescue@1 265 -- Remember references to the value and current fields so we can fill them later
Zerotorescue@1 266 if item.set then
Zerotorescue@1 267 item.set.value = lblValue;
Zerotorescue@1 268 item.set.current = lblQuantity;
Zerotorescue@1 269 end
Zerotorescue@0 270 end
Zerotorescue@0 271 end
Zerotorescue@0 272
Zerotorescue@1 273 iGroup:ResumeLayout();
Zerotorescue@1 274 mod.scrollFrame:AddChild(iGroup); -- this can take up to .5 seconds, might need to look into again at a later time
Zerotorescue@0 275 end
Zerotorescue@0 276 end
Zerotorescue@1 277
Zerotorescue@1 278 mod.scrollFrame:ResumeLayout();
Zerotorescue@1 279 mod.scrollFrame:DoLayout();
Zerotorescue@1 280
Zerotorescue@1 281 if CACHE_ITEMS_TOTAL > 0 then
Zerotorescue@1 282 cacheStart = GetTime();
Zerotorescue@1 283 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 284 end
Zerotorescue@1 285 end
Zerotorescue@1 286
Zerotorescue@1 287 function mod:UpdateNextItem()
Zerotorescue@1 288 local i = 0;
Zerotorescue@1 289
Zerotorescue@1 290 for groupName, items in pairs(itemsCache) do
Zerotorescue@1 291 local minimumStock = addon:GetOptionByKey(groupName, "minimumStock");
Zerotorescue@1 292 local priceThreshold = addon:GetOptionByKey(groupName, "priceThreshold");
Zerotorescue@1 293
Zerotorescue@1 294 for _, item in pairs(items) do
Zerotorescue@1 295 if item.set then
Zerotorescue@1 296 item.count = addon:GetItemCount(item.id);
Zerotorescue@1 297 if item.set.current then
Zerotorescue@1 298 item.set.current:SetText(self:ColorCode(item.count, minimumStock));
Zerotorescue@1 299 end
Zerotorescue@1 300
Zerotorescue@1 301 item.value = addon:GetAuctionValue(item.link);
Zerotorescue@1 302 if item.set.value then
Zerotorescue@1 303 item.set.value:SetText(self:DisplayMoney(item.value, priceThreshold));
Zerotorescue@1 304 end
Zerotorescue@1 305
Zerotorescue@1 306 item.set = nil;
Zerotorescue@1 307
Zerotorescue@1 308 i = i + 1;
Zerotorescue@1 309 CACHE_ITEMS_CURRENT = CACHE_ITEMS_CURRENT + 1;
Zerotorescue@1 310
Zerotorescue@1 311 mod.frame:SetStatusText("Caching auction values and item-counts... " .. floor(CACHE_ITEMS_CURRENT / CACHE_ITEMS_TOTAL * 100) .. "% has already been processed.");
Zerotorescue@1 312
Zerotorescue@1 313 if i >= CACHE_ITEMS_PER_UPDATE then
Zerotorescue@1 314 return;
Zerotorescue@1 315 end
Zerotorescue@1 316 end
Zerotorescue@1 317 end
Zerotorescue@1 318 end
Zerotorescue@1 319
Zerotorescue@1 320 -- Reset trackers
Zerotorescue@1 321 CACHE_ITEMS_TOTAL = 0;
Zerotorescue@1 322 CACHE_ITEMS_CURRENT = 0;
Zerotorescue@1 323
Zerotorescue@1 324 -- Rebuild list so hidden items due to too low prices get added
Zerotorescue@1 325 self:Build();
Zerotorescue@1 326
Zerotorescue@1 327 -- Stop timer
Zerotorescue@1 328 self:CancelTimer(self.tmrUpdater, true);
Zerotorescue@1 329
Zerotorescue@1 330 -- Announce
Zerotorescue@1 331 mod.frame:SetStatusText("All prices and itemcounts have been cached. This process took " .. ceil(GetTime() - cacheStart) .. " seconds.");
Zerotorescue@1 332
Zerotorescue@1 333 -- Forget time
Zerotorescue@1 334 cacheStart = nil;
Zerotorescue@0 335 end
Zerotorescue@0 336
Zerotorescue@0 337 function mod:ColorCode(num, required)
Zerotorescue@0 338 local percentage = ( num / required );
Zerotorescue@0 339
Zerotorescue@0 340 if percentage >= addon.db.global.defaults.colors.green then
Zerotorescue@0 341 return ("|cff00ff00%d|r"):format(num);
Zerotorescue@0 342 elseif percentage >= addon.db.global.defaults.colors.yellow then
Zerotorescue@0 343 return ("|cffffff00%d|r"):format(num);
Zerotorescue@0 344 elseif percentage >= addon.db.global.defaults.colors.orange then
Zerotorescue@0 345 return ("|cffff9933%d|r"):format(num);
Zerotorescue@0 346 elseif percentage >= addon.db.global.defaults.colors.red then
Zerotorescue@0 347 return ("|cffff0000%d|r"):format(num);
Zerotorescue@0 348 end
Zerotorescue@0 349 end
Zerotorescue@0 350
Zerotorescue@1 351 function mod:DisplayMoney(value, priceThreshold)
Zerotorescue@1 352 if value < priceThreshold then
Zerotorescue@1 353 return ("|cffff0000%s|r"):format(addon:ReadableMoney(value or 0, true));
Zerotorescue@1 354 else
Zerotorescue@1 355 return addon:ReadableMoney(value or 0, true);
Zerotorescue@1 356 end
Zerotorescue@1 357 end
Zerotorescue@1 358
Zerotorescue@0 359 function mod:NumberFormat(num)
Zerotorescue@0 360 local formatted = string.gsub(num, "(%d)(%d%d%d)$", "%1,%2", 1);
Zerotorescue@0 361
Zerotorescue@0 362 while true do
Zerotorescue@0 363 formatted, matches = string.gsub(formatted, "(%d)(%d%d%d),", "%1,%2,", 1);
Zerotorescue@0 364
Zerotorescue@0 365 if matches == 0 then
Zerotorescue@0 366 break;
Zerotorescue@0 367 end
Zerotorescue@0 368 end
Zerotorescue@0 369
Zerotorescue@0 370 return formatted;
Zerotorescue@1 371 end
Zerotorescue@1 372
Zerotorescue@1 373 --[[
Zerotorescue@1 374 No longer used, we're now caching complete item data instead of just AH values.
Zerotorescue@1 375 local AuctionValueCache = {};
Zerotorescue@1 376 function mod:GetAuctionValue(link)
Zerotorescue@1 377 local itemId = addon:GetItemId(link);
Zerotorescue@1 378
Zerotorescue@1 379 if AuctionValueCache[itemId] then
Zerotorescue@1 380 return AuctionValueCache[itemId];
Zerotorescue@1 381 else
Zerotorescue@1 382 local value = addon:GetAuctionValue(link);
Zerotorescue@1 383
Zerotorescue@1 384 AuctionValueCache[itemId] = value;
Zerotorescue@1 385
Zerotorescue@1 386 -- Reset the cache 1 minute after last updating it
Zerotorescue@1 387 self:CancelTimer(self.tmrResetCache, true);
Zerotorescue@1 388 self.tmrResetCache = self:ScheduleTimer(function()
Zerotorescue@1 389 table.wipe(AuctionValueCache);
Zerotorescue@1 390
Zerotorescue@1 391 mod.frame:SetStatusText("The auction item value cache has been reset.");
Zerotorescue@1 392 end, 60);
Zerotorescue@1 393 mod.frame:SetStatusText("");
Zerotorescue@1 394
Zerotorescue@1 395 return value;
Zerotorescue@1 396 end
Zerotorescue@1 397 end
Zerotorescue@1 398 ]]