comparison Modules/Summary.lua @ 84:3bec0ea44607

Cleaned the Inventorium folder; moved all classes to classes directory, modules to modules directory and support addons to plugins directory. In addition support addons are now references within XML files rather than inside the TOC. Fixed the default local item count setting, you can now exclude bag and AH data from it. Fixed some mover algorithm bugs. Mover can no longer freeze the game but instead will terminate the process after a 1000 passes. Now reversing the moves table after making it, rather than every single time it is used. Fixed guild bank support. Now displaying the amount of items moved. Scanner now scans all guild bank tabs rather than only the current. Fixed a bug with local item data not being retrieved properly. Disabled ?enterClicksFirstButton? within dialogs as this causes the dialog to consume all keypress. Events are now at the addon object rather than local.
author Zerotorescue
date Thu, 06 Jan 2011 20:05:30 +0100
parents Summary.lua@8d11fc88ecab
children a12d22ef3f39
comparison
equal deleted inserted replaced
83:6b60f7a1410c 84:3bec0ea44607
1 local addon = select(2, ...); -- Get a reference to the main addon object
2 local mod = addon:NewModule("Summary", "AceEvent-3.0", "AceTimer-3.0"); -- register a new module, Summary: resposible for building the summary window
3
4 local unknownItemName = "Unknown (#%d)";
5
6 local CACHE_ITEMS_TOTAL, CACHE_ITEMS_CURRENT, itemsCache = 0, 0, {};
7 local AceGUI, cacheStart;
8
9 local _G = _G; -- prevent looking up of the global table
10 local printf, sgsub, supper, tinsert, pairs, ceil, GetItemInfo = _G.string.format, _G.string.gsub, _G.string.upper, _G.table.insert, _G.pairs, _G.ceil, _G.GetItemInfo; -- prevent looking up of the most used globals all the time
11
12 function mod:OnEnable()
13 -- Register the summary specific widget
14 addon:GetModule("Widgets"):InlineGroupWithButton();
15
16 AceGUI = LibStub("AceGUI-3.0");
17
18 -- Register our own slash commands
19 -- /im summary
20 addon:RegisterSlash(function()
21 mod:BuildMain();
22 mod:Build();
23 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.");
24
25 -- /im reset
26 addon:RegisterSlash(function()
27 if mod.frame then
28 mod.frame:SetWidth(700);
29 mod.frame:SetHeight(600);
30
31 print("Resetting width and height of the summary frame.");
32 end
33 end, { "r", "reset" }, "|Hfunction:InventoriumCommandHandler:reset|h|cff00fff7/im reset|r|h (or /im r) - Reset the size of the summary frame.");
34 end
35
36 local function ShowTooltip(self)
37 -- If this function is called from a widget, self is the widget and self.frame the actual frame
38 local this = self.frame or self;
39
40 GameTooltip:SetOwner(this, "ANCHOR_NONE");
41 GameTooltip:SetPoint("BOTTOM", this, "TOP");
42 GameTooltip:SetText(this.tooltipTitle, 1, .82, 0, 1);
43
44 if type(this.tooltip) == "string" then
45 GameTooltip:AddLine(this.tooltip, 1, 1, 1, 1);
46 end
47
48 GameTooltip:Show();
49 end
50
51 local function HideTooltip()
52 GameTooltip:Hide();
53 end
54
55 function mod:BuildMain()
56 LibStub("AceConfigDialog-3.0"):Close("InventoriumOptions");
57
58 self:CloseFrame();
59
60 -- Main Window
61 mod.frame = AceGUI:Create("Frame");
62 _G["InventoriumSummary"] = mod.frame; -- name the global frame so it can be put in the UISpecialFrames
63 mod.frame:SetTitle("Inventory Summary");
64 mod.frame:SetLayout("Fill");
65 mod.frame:SetCallback("OnClose", function(widget)
66 mod:CancelTimer(self.tmrUpdater, true);
67 mod:CloseFrame();
68 end);
69 mod.frame:SetWidth(addon.db.profile.defaults.summary.width);
70 mod.frame:SetHeight(addon.db.profile.defaults.summary.height);
71 mod.frame.OnWidthSet = function(_, width)
72 addon.db.profile.defaults.summary.width = width;
73 end;
74 mod.frame.OnHeightSet = function(_, height)
75 addon.db.profile.defaults.summary.height = height;
76 end;
77
78 -- Close on escape
79 tinsert(UISpecialFrames, "InventoriumSummary");
80
81 -- ScrollFrame child
82 mod.scrollFrame = AceGUI:Create("ScrollFrame");
83 mod.scrollFrame:SetLayout("Flow");
84
85 mod.frame:AddChild(mod.scrollFrame);
86
87 -- Reset items cache
88 table.wipe(itemsCache);
89 end
90
91 function mod:CloseFrame()
92 if mod.frame then
93 mod.frame:Release();
94 mod.frame = nil;
95
96 -- Stop caching
97
98 -- Stop timer
99 self:CancelTimer(self.tmrUpdater, true);
100
101 -- Reset trackers
102 CACHE_ITEMS_TOTAL = 0;
103 CACHE_ITEMS_CURRENT = 0;
104 end
105 end
106
107 local sortMethod = "item";
108 local sortDirectory = "ASC";
109 local function ReSort(subject)
110 if sortMethod == subject then
111 sortDirectory = (sortDirectory == "ASC" and "DESC") or "ASC";
112 else
113 sortDirectory = "ASC";
114 end
115 sortMethod = subject;
116
117 mod:Build();
118 end
119
120 -- From http://www.wowwiki.com/API_sort
121 local function pairsByKeys (t, f)
122 local a = {}
123 for n in pairs(t) do tinsert(a, n) end
124 table.sort(a, f)
125 local i = 0 -- iterator variable
126 local iter = function () -- iterator function
127 i = i + 1
128 if a[i] == nil then return nil
129 else return a[i], t[a[i]]
130 end
131 end
132 return iter
133 end
134
135 function mod:Build()
136 local buildStartTime, times = GetTime(), {};
137
138 -- 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
139 -- This appears to be required for each container we wish to pause, so also do this for the contents
140 mod.scrollFrame:PauseLayout();
141
142 mod.scrollFrame:ReleaseChildren();
143
144 -- Refresh button
145 local btnRefresh = AceGUI:Create("Button");
146 btnRefresh:SetText("Refresh");
147 btnRefresh:SetRelativeWidth(.2);
148 btnRefresh:SetCallback("OnClick", function()
149 -- Reset items cache
150 table.wipe(itemsCache);
151
152 -- Rebuild itemlist and start caching
153 mod:Build();
154 end);
155 btnRefresh:SetCallback("OnEnter", ShowTooltip);
156 btnRefresh:SetCallback("OnLeave", HideTooltip);
157 btnRefresh.frame.tooltipTitle = "Refresh Cache";
158 btnRefresh.frame.tooltip = "Refresh the list and recache the item counts and auction values.";
159
160 mod.scrollFrame:AddChild(btnRefresh);
161
162 local lblSpacer = AceGUI:Create("Label");
163 lblSpacer:SetRelativeWidth(.03);
164
165 mod.scrollFrame:AddChild(lblSpacer);
166
167 -- Speed slider
168 local sdrSpeed = AceGUI:Create("Slider");
169 sdrSpeed:SetLabel("Processing speed");
170 sdrSpeed:SetSliderValues(0.01, 5, 0.01); -- min, max, interval
171 sdrSpeed:SetIsPercent(true);
172 sdrSpeed:SetRelativeWidth(.3);
173 sdrSpeed:SetCallback("OnMouseUp", function(self, event, value)
174 addon.db.profile.defaults.summary.speed = ceil( ( ( value * 100 ) / 5) - .5 );
175
176 CACHE_ITEMS_PER_UPDATE = addon.db.profile.defaults.summary.speed; -- max = 20, min = 1
177 end);
178 sdrSpeed:SetValue( addon.db.profile.defaults.summary.speed * 5 / 100 );
179 sdrSpeed:SetCallback("OnEnter", ShowTooltip);
180 sdrSpeed:SetCallback("OnLeave", HideTooltip);
181 sdrSpeed.frame.tooltipTitle = "Caching Processing Speed";
182 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.";
183
184 mod.scrollFrame:AddChild(sdrSpeed);
185
186 local lblSpacer = AceGUI:Create("Label");
187 lblSpacer:SetRelativeWidth(.23);
188
189 mod.scrollFrame:AddChild(lblSpacer);
190
191 -- Config button
192 --[[local btnConfig = AceGUI:Create("Button");
193 btnConfig:SetText("Config");
194 btnConfig:SetRelativeWidth(.2);
195 btnConfig:SetCallback("OnClick", function()
196 --TODO: Tidy up
197 SlashCmdList["INVENTORIUM"]("config");
198 end);
199 btnConfig:SetCallback("OnEnter", ShowTooltip);
200 btnConfig:SetCallback("OnLeave", HideTooltip);
201 btnConfig.frame.tooltipTitle = "Config";
202 btnConfig.frame.tooltip = "Click to open the config window. This will close the current window.";
203
204 mod.scrollFrame:AddChild(btnConfig);]]
205
206 local lblSpacer = AceGUI:Create("Label");
207 lblSpacer:SetRelativeWidth(.03);
208
209 mod.scrollFrame:AddChild(lblSpacer);
210
211 -- Queue all button
212 local btnQueueAll = AceGUI:Create("Button");
213 btnQueueAll:SetText("Queue All");
214 btnQueueAll:SetRelativeWidth(.2);
215 btnQueueAll:SetCallback("OnClick", function()
216 self:SendMessage("IM_QUEUE_ALL");
217 end);
218 btnQueueAll:SetCallback("OnEnter", ShowTooltip);
219 btnQueueAll:SetCallback("OnLeave", HideTooltip);
220 btnQueueAll.frame.tooltipTitle = "Queue all";
221 btnQueueAll.frame.tooltip = "Queue everything that requires restocking within every single visible group.";
222
223 mod.scrollFrame:AddChild(btnQueueAll);
224
225 times.init = ceil( ( GetTime() - buildStartTime ) * 1000 );
226 addon:Debug("Time spent legend: (init / sorting / preparing / building / all).");
227
228 local playerName = UnitName("player");
229
230 -- Go through all our stored groups
231 for groupName, values in pairsByKeys(addon.db.profile.groups, function(a, b) return a:lower() < b:lower(); end) do
232 local groupStartTime, groupTimes = GetTime(), {};
233
234 local trackAt = addon:GetOptionByKey(groupName, "trackAtCharacters");
235
236
237 -- Does this group have any items and do we want to track it at this char?
238 if values.items and trackAt[playerName] then
239
240
241 -- Get group settings
242 local minLocalStock = addon:GetOptionByKey(groupName, "minLocalStock");
243 local minGlobalStock = addon:GetOptionByKey(groupName, "minGlobalStock");
244 local showWhenBelow = addon:GetOptionByKey(groupName, "summaryThresholdShow");
245 local priceThreshold = addon:GetOptionByKey(groupName, "priceThreshold");
246 local hideWhenBelowPriceThreshold = addon:GetOptionByKey(groupName, "summaryHidePriceThreshold");
247 local alwaysGetAuctionValue = addon:GetOptionByKey(groupName, "alwaysGetAuctionValue");
248
249 -- Make group container
250 local iGroup = AceGUI:Create("InlineGroupWithButton");
251 iGroup:PauseLayout();
252 iGroup:SetTitle(groupName);
253 iGroup:SetFullWidth(true);
254 iGroup:SetLayout("Flow");
255 iGroup:MakeButton({
256 name = "Queue",
257 desc = "Queue all items in this group.",
258 exec = function()
259 print("Queueing all items within " .. groupName .. " craftable by the currently open profession.");
260 self:SendMessage("IM_QUEUE_GROUP", groupName);
261 end,
262 });
263
264
265
266 -- Headers
267
268 -- Itemlink
269 local lblItem = AceGUI:Create("InteractiveLabel");
270 lblItem:SetText("|cfffed000Item|r");
271 lblItem:SetFontObject(GameFontHighlight);
272 lblItem:SetRelativeWidth(.7);
273 lblItem:SetCallback("OnClick", function() ReSort("item"); end);
274 lblItem:SetCallback("OnEnter", ShowTooltip);
275 lblItem:SetCallback("OnLeave", HideTooltip);
276 lblItem.frame.tooltipTitle = "Item";
277 lblItem.frame.tooltip = "Sort on the item quality, then name.";
278
279 iGroup:AddChild(lblItem);
280
281 -- Local quantity
282 local lblLocal = AceGUI:Create("InteractiveLabel");
283 lblLocal:SetText("|cfffed000Loc.|r");
284 lblLocal:SetFontObject(GameFontHighlight);
285 lblLocal:SetRelativeWidth(.099);
286 lblLocal:SetCallback("OnClick", function() ReSort("local"); end);
287 lblLocal:SetCallback("OnEnter", ShowTooltip);
288 lblLocal:SetCallback("OnLeave", HideTooltip);
289 lblLocal.frame.tooltipTitle = "Local stock";
290 lblLocal.frame.tooltip = "Sort on the amount of items currently in local stock.";
291
292 iGroup:AddChild(lblLocal);
293
294 -- Current quantity
295 local lblQuantity = AceGUI:Create("InteractiveLabel");
296 lblQuantity:SetText("|cfffed000Cur.|r");
297 lblQuantity:SetFontObject(GameFontHighlight);
298 lblQuantity:SetRelativeWidth(.099);
299 lblQuantity:SetCallback("OnClick", function() ReSort("current"); end);
300 lblQuantity:SetCallback("OnEnter", ShowTooltip);
301 lblQuantity:SetCallback("OnLeave", HideTooltip);
302 lblQuantity.frame.tooltipTitle = "Current stock";
303 lblQuantity.frame.tooltip = "Sort on the amount of items currently in stock.";
304
305 iGroup:AddChild(lblQuantity);
306
307 -- Lowest value
308 local lblValue = AceGUI:Create("InteractiveLabel");
309 lblValue:SetText("|cfffed000Value|r");
310 lblValue:SetFontObject(GameFontHighlight);
311 lblValue:SetRelativeWidth(.099);
312 lblValue:SetCallback("OnClick", function() ReSort("value"); end);
313 lblValue:SetCallback("OnEnter", ShowTooltip);
314 lblValue:SetCallback("OnLeave", HideTooltip);
315 lblValue.frame.tooltipTitle = "Value";
316 lblValue.frame.tooltip = "Sort on the item auction value.";
317
318 iGroup:AddChild(lblValue);
319
320
321 -- Retrieve items list
322 if not itemsCache[groupName] then
323 itemsCache[groupName] = {};
324 end
325
326 if #(itemsCache[groupName]) == 0 then
327 -- If the item cache is empty
328 for itemId, _ in pairs(values.items) do
329 local newItemData = addon.ItemData:New(itemId);
330
331 -- if no price threshold is set for this item and you don't want to always get the auction value, then don't look it up either
332 if priceThreshold == 0 and not alwaysGetAuctionValue then
333 newItemData.value = -4;
334 end
335
336 tinsert(itemsCache[groupName], newItemData);
337
338 CACHE_ITEMS_TOTAL = CACHE_ITEMS_TOTAL + 1;
339 end
340 end
341
342 groupTimes.init = ceil( ( GetTime() - groupStartTime ) * 1000 );
343
344
345
346 -- Sort items
347 table.sort(itemsCache[groupName], function(a, b)
348 local aRarity = a.rarity or 1;
349 local bRarity = b.rarity or 1;
350
351 if sortMethod == "item" and aRarity == bRarity then
352 -- Do a name-compare for items of the same rarity
353 -- Otherwise epics first, then junk
354
355 local aName = a.name or printf(unknownItemName, a.id);
356 local bName = b.name or printf(unknownItemName, b.id);
357
358 if sortDirectory == "ASC" then
359 return supper(aName) < supper(bName);
360 else
361 return supper(aName) > supper(bName);
362 end
363 elseif sortMethod == "item" then
364 if sortDirectory == "ASC" then
365 return aRarity > bRarity; -- the comparers were reversed because we want epics first
366 else
367 return aRarity < bRarity; -- the comparers were reversed because we want epics first
368 end
369 elseif sortMethod == "current" then
370 if sortDirectory == "ASC" then
371 return a.globalCount < b.globalCount;
372 else
373 return a.globalCount > b.globalCount;
374 end
375 elseif sortMethod == "local" then
376 if sortDirectory == "ASC" then
377 return a.localCount < b.localCount;
378 else
379 return a.localCount > b.localCount;
380 end
381 elseif sortMethod == "value" then
382 if sortDirectory == "ASC" then
383 return a.value < b.value;
384 else
385 return a.value > b.value;
386 end
387 end
388 end);
389
390 groupTimes.sorting = ceil( ( GetTime() - groupStartTime ) * 1000 );
391
392
393
394
395 -- Show itemslist
396 for i, item in pairs(itemsCache[groupName]) do
397 -- Go through all items for this group
398
399 if (( item.globalCount / minGlobalStock ) < showWhenBelow or ( item.localCount / minLocalStock ) < showWhenBelow) and (not hideWhenBelowPriceThreshold or priceThreshold == 0 or item.value < 0 or item.value >= priceThreshold) then
400 -- 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
401
402 local btnItemLink = AceGUI:Create("ItemLinkButton");
403 btnItemLink:SetUserData("exec", function(_, itemId, _, buttonName)
404 local itemName, itemLink = GetItemInfo(itemId);
405
406 if buttonName == "LeftButton" and IsShiftKeyDown() and itemLink then
407 ChatEdit_InsertLink(itemLink);
408 elseif buttonName == "LeftButton" and IsAltKeyDown() and itemName and AuctionFrame and AuctionFrame:IsShown() and AuctionFrameBrowse then
409 -- Start search at page 0
410 AuctionFrameBrowse.page = 0;
411
412 -- Set the search field (even though we could use "ChatEdit_InsertLink", this ensures the right field is updated)
413 BrowseName:SetText(itemName)
414
415 QueryAuctionItems(itemName, nil, nil, 0, 0, 0, 0, 0, 0);
416 end
417 end);
418 btnItemLink:SetRelativeWidth(.7);
419 btnItemLink:SetItem(item);
420
421 iGroup:AddChild(btnItemLink);
422
423 -- Local quantity
424 local lblLocal = AceGUI:Create("Label");
425 lblLocal:SetText(self:DisplayItemCount(item.localCount, minLocalStock));
426 lblLocal:SetRelativeWidth(.099);
427
428 iGroup:AddChild(lblLocal);
429
430 -- Current quantity
431 local lblQuantity = AceGUI:Create("Label");
432 lblQuantity:SetText(self:DisplayItemCount(item.globalCount, minGlobalStock));
433 lblQuantity:SetRelativeWidth(.099);
434
435 iGroup:AddChild(lblQuantity);
436
437 -- Value
438 local lblValue = AceGUI:Create("Label");
439 lblValue:SetText(self:DisplayMoney(item.value, priceThreshold));
440 lblValue:SetRelativeWidth(.099);
441
442 iGroup:AddChild(lblValue);
443
444 -- Remember references to the value and current fields so we can fill them later
445 item.set.value = lblValue;
446 item.set.globalCount = lblQuantity;
447 item.set.localCount = lblLocal;
448 end
449 end
450
451 groupTimes.preparing = ceil( ( GetTime() - groupStartTime ) * 1000 );
452
453 iGroup:ResumeLayout();
454 mod.scrollFrame:AddChild(iGroup); -- this can take up to .5 seconds, might need to look into again at a later time
455
456 groupTimes.building = ceil( ( GetTime() - groupStartTime ) * 1000 );
457 end
458
459 if groupStartTime and groupTimes then
460 addon:Debug(printf("Building of %s took %d ms (%d / %d / %d / %d / %d).", 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 )));
461 end
462 end
463
464 mod.scrollFrame:ResumeLayout();
465 mod.scrollFrame:DoLayout();
466
467 addon:Debug(printf("Done building summary after %d ms.", ceil( ( GetTime() - buildStartTime ) * 1000 )));
468
469 if CACHE_ITEMS_TOTAL > 0 then
470 cacheStart = GetTime();
471 self:CancelTimer(self.tmrUpdater, true);
472 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)
473 end
474 end
475
476 function mod:UpdateNextItem()
477 local i = 0;
478
479 for groupName, items in pairs(itemsCache) do
480 local minGlobalStock = addon:GetOptionByKey(groupName, "minGlobalStock");
481 local minLocalStock = addon:GetOptionByKey(groupName, "minLocalStock");
482 local priceThreshold = addon:GetOptionByKey(groupName, "priceThreshold");
483
484 for _, item in pairs(items) do
485 if item.globalCount == -3 or item.localCount == -3 or item.value == -3 then
486 if item.globalCount == -3 then
487 -- Only if item count was queued, update it
488 item.globalCount = addon:GetItemCount(item.id, groupName);
489 if item.set.globalCount and item.set.globalCount.SetText then
490 item.set.globalCount:SetText(self:DisplayItemCount(item.globalCount, minGlobalStock));
491 end
492 end
493
494 if item.localCount == -3 then
495 -- Only if item count was queued, update it
496 item.localCount = addon:GetLocalItemCount(item.id, groupName);
497 if item.set.localCount and item.set.localCount.SetText then
498 item.set.localCount:SetText(self:DisplayItemCount(item.localCount, minLocalStock));
499 end
500 end
501
502 if item.value == -3 then
503 -- Only if item value was queued, update it
504
505 -- The itemlink might not have been loaded yet in which case we retry
506 item.link = item.link or select(2, GetItemInfo(item.id));
507
508 if item.link then
509 item.value = addon:GetAuctionValue(item.link, groupName);
510 if item.set.value and item.set.value.SetText then
511 item.set.value:SetText(self:DisplayMoney(item.value, priceThreshold));
512 end
513 end
514 end
515
516 i = i + 1;
517 CACHE_ITEMS_CURRENT = CACHE_ITEMS_CURRENT + 1;
518
519 if mod.frame then
520 mod.frame:SetStatusText(printf("Caching auction values and item-counts... %d%% has already been processed.", floor(CACHE_ITEMS_CURRENT / CACHE_ITEMS_TOTAL * 100)));
521 end
522
523 if i >= addon.db.profile.defaults.summary.speed then
524 return;
525 end
526 end
527 end
528 end
529
530 -- Reset trackers
531 CACHE_ITEMS_TOTAL = 0;
532 CACHE_ITEMS_CURRENT = 0;
533
534 -- Stop timer
535 self:CancelTimer(self.tmrUpdater, true);
536
537 -- Rebuild list so hidden items due to too low prices get added
538 self:Build();
539
540 -- Announce
541 mod.frame:SetStatusText("All required prices and itemcounts have been cached. This process took " .. ceil(GetTime() - cacheStart) .. " seconds.");
542
543 -- Forget time
544 cacheStart = nil;
545 end
546
547 function mod:ColorCode(num, required)
548 local percentage = ( num / required );
549
550 if percentage >= addon.db.profile.defaults.colors.green then
551 return printf("|cff00ff00%d|r", num);
552 elseif percentage >= addon.db.profile.defaults.colors.yellow then
553 return printf("|cffffff00%d|r", num);
554 elseif percentage >= addon.db.profile.defaults.colors.orange then
555 return printf("|cffff9933%d|r", num);
556 elseif percentage >= addon.db.profile.defaults.colors.red then
557 return printf("|cffff0000%d|r", num);
558 else
559 return num;
560 end
561 end
562
563 function mod:DisplayMoney(value, priceThreshold)
564 if value == -1 then
565 return "|cff0000ffNone up|r";
566 elseif value == -2 then
567 return "|cff0000ffNo AH mod|r";
568 elseif value == -3 then
569 return "|cffffff00Unknown|r";
570 elseif value == -4 then
571 return "|cff00ff00-|r";
572 elseif value == -5 then
573 return "|cffff9933Error|r";
574 elseif priceThreshold and value < priceThreshold then
575 return printf("|cffaaaaaa%s|r", sgsub(addon:ReadableMoney(value or 0, true), "|([a-fA-F0-9]+)([gsc]+)|r", "%2"));
576 else
577 return addon:ReadableMoney(value or 0, true);
578 end
579 end
580
581 function mod:DisplayItemCount(value, minimumStock)
582 if value == -1 then
583 return "|cffffff00Unknown|r";
584 elseif value == -3 then
585 return "|cffffff00Unknown|r";
586 else
587 return printf("%s / %d", self:ColorCode(value, minimumStock), minimumStock);
588 end
589 end
590
591 function mod:NumberFormat(num)
592 local formatted = sgsub(num, "(%d)(%d%d%d)$", "%1,%2", 1);
593
594 while true do
595 formatted, matches = sgsub(formatted, "(%d)(%d%d%d),", "%1,%2,", 1);
596
597 if matches == 0 then
598 break;
599 end
600 end
601
602 return formatted;
603 end