-- ------------------------------------------------------------------------------ -- -- TradeSkillMaster_Accounting -- -- http://www.curse.com/addons/wow/tradeskillmaster_accounting -- -- -- -- A TradeSkillMaster Addon (http://tradeskillmaster.com) -- -- All Rights Reserved* - Detailed license information included with addon. -- -- ------------------------------------------------------------------------------ -- -- create a local reference to the TradeSkillMaster_Crafting table and register a new module local TSM = select(2, ...) local GUI = TSM:NewModule("GUI", "AceEvent-3.0", "AceHook-3.0") local AceGUI = LibStub("AceGUI-3.0") local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_Accounting") -- loads the localization table local private = {} TSMAPI:RegisterForTracing(private, "TSM_Accounting.GUI_private") local scrollingTables = {} local ITEM_SELL_BUY_ST_COLS = { {name=L["Item Name"], width=0.34, headAlign="LEFT"}, {name=L["Player"], width=0.1, headAlign="LEFT"}, {name=L["Type"], width=0.06, headAlign="LEFT"}, {name=L["Stack"], width=0.05, headAlign="LEFT"}, {name=L["Aucs"], width=0.05, headAlign="LEFT"}, {name=L["Per Item"], width=0.12, headAlign="LEFT"}, {name=L["Total Price"], width=0.13, headAlign="LEFT"}, {name=L["Time"], width=0.14, headAlign="LEFT"}, defaultSort = -8, } local ITEM_AUCTION_ST_COLS = { {name=L["Item Name"], width=0.5, headAlign="LEFT"}, {name=L["Player"], width=0.15, headAlign="LEFT"}, {name=L["Stack"], width=0.1, headAlign="LEFT"}, {name=L["Aucs"], width=0.1, headAlign="LEFT"}, {name=L["Time"], width=0.15, headAlign="LEFT"}, defaultSort = -5, } local ITEM_MONEY_ST_COLS = { {name=L["Type"], width=0.2, headAlign="LEFT"}, {name=L["Player"], width=0.2, headAlign="LEFT"}, {name=L["Other Player"], width=0.2, headAlign="LEFT"}, {name=L["Amount"], width=0.15, headAlign="LEFT"}, {name=L["Time"], width=0.15, headAlign="LEFT"}, defaultSort = -5, } local ITEM_SUMMARY_ST_COLS_AVG = { {name=L["Item Name"], width=0.38, headAlign="LEFT"}, {name=L["Market Value"], width=0.15, headAlign="LEFT"}, {name=L["Sold"], width=0.06, headAlign="LEFT"}, {name=L["Avg Sell Price"], width=0.15, headAlign="LEFT"}, {name=L["Bought"], width=0.07, headAlign="LEFT"}, {name=L["Avg Buy Price"], width=0.15, headAlign="LEFT"}, defaultSort = 1, } local ITEM_SUMMARY_ST_COLS_TOTAL = { {name=L["Item Name"], width=0.38, headAlign="LEFT"}, {name=L["Market Value"], width=0.15, headAlign="LEFT"}, {name=L["Sold"], width=0.06, headAlign="LEFT"}, {name=L["Total Sale Price"], width=0.15, headAlign="LEFT"}, {name=L["Bought"], width=0.07, headAlign="LEFT"}, {name=L["Total Buy Price"], width=0.15, headAlign="LEFT"}, defaultSort = 1, } local ITEM_RESALE_ST_COLS_AVG = { {name=L["Item Name"], width=0.37, headAlign="LEFT"}, {name=L["Sold"], width=0.06, headAlign="LEFT"}, {name=L["Avg Sell Price"], width=0.14, headAlign="LEFT"}, {name=L["Bought"], width=0.07, headAlign="LEFT"}, {name=L["Avg Buy Price"], width=0.14, headAlign="LEFT"}, {name=L["Avg Resale Profit"], width=0.21, headAlign="LEFT"}, defaultSort = -6, } local ITEM_RESALE_ST_COLS_TOTAL = { {name=L["Item Name"], width=0.37, headAlign="LEFT"}, {name=L["Sold"], width=0.06, headAlign="LEFT"}, {name=L["Total Sale Price"], width=0.14, headAlign="LEFT"}, {name=L["Bought"], width=0.07, headAlign="LEFT"}, {name=L["Total Buy Price"], width=0.14, headAlign="LEFT"}, {name=L["Avg Resale Profit"], width=0.21, headAlign="LEFT"}, defaultSort = -6, } function private:UpdateSTData(st, filters) st:SetData(st.accountingDataFunc(filters or {})) end function private:CreateScrollingTable(container, dataType, dataFunc, stCols, tab, subTab) local stParent = container.children[1].children[#container.children[1].children].frame if not scrollingTables[dataType] then local handlers = { OnClick = function(_, data, self) if not data then return end private:HideScrollingTables() GUI:DrawItemLookup(container, data.itemString, tab, subTab) container.children[1]:DoLayout() end, OnEnter = function(_, data, self) if not data then return end GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT") GameTooltip:SetText(L["Click for a detailed report on this item."], 1, .82, 0, 1) GameTooltip:Show() end, OnLeave = function() GameTooltip:ClearLines() GameTooltip:Hide() end } TSMAPI:CreateTimeDelay(0, function() scrollingTables[dataType] = TSMAPI:CreateScrollingTable(stParent, stCols, tab and handlers or nil) scrollingTables[dataType]:EnableSorting(true, stCols.defaultSort) scrollingTables[dataType]:DisableSelection(true) scrollingTables[dataType]:Show() scrollingTables[dataType]:SetParent(stParent) scrollingTables[dataType]:SetAllPoints() scrollingTables[dataType].accountingDataFunc = dataFunc private:UpdateSTData(scrollingTables[dataType]) end) else scrollingTables[dataType]:Show() scrollingTables[dataType]:SetParent(stParent) scrollingTables[dataType]:SetAllPoints() private:UpdateSTData(scrollingTables[dataType]) end end function private:GetMultiLabelLine(description, data, key, isPerDay, isNumber) local color, color2 = TSMAPI.Design:GetInlineColor("link2"), TSMAPI.Design:GetInlineColor("category2") local total = data[key].total local month = data[key].month local week = data[key].week if isPerDay then total = TSM:Round(total/data.totalTime) month = TSM:Round(month/data.monthTime) week = TSM:Round(week/data.weekTime) end local lines if isNumber then lines = { { text = color2 .. description, relativeWidth = 0.19 }, { text = color .. L["Total:"] .. " |r" .. (total or 0), relativeWidth = 0.22 }, { text = color .. L["Last 30 Days:"] .. " |r" .. (month or 0), relativeWidth = 0.29 }, { text = color .. L["Last 7 Days:"] .. " |r" .. (week or 0), relativeWidth = 0.29 } } else lines = { { text = color2 .. description, relativeWidth = 0.19 }, { text = color .. L["Total:"] .. " |r" .. (TSMAPI:FormatTextMoney(total) or "---"), relativeWidth = 0.22 }, { text = color .. L["Last 30 Days:"] .. " |r" .. (TSMAPI:FormatTextMoney(month) or "---"), relativeWidth = 0.29 }, { text = color .. L["Last 7 Days:"] .. " |r" .. (TSMAPI:FormatTextMoney(week) or "---"), relativeWidth = 0.29 } } end return lines end function private:HideScrollingTables() for _, st in pairs(scrollingTables) do st:Hide() st:SetData({}) end end function GUI:Load(parent) local simpleGroup = AceGUI:Create("SimpleGroup") simpleGroup:SetLayout("Fill") parent:AddChild(simpleGroup) local tabGroup = AceGUI:Create("TSMTabGroup") tabGroup:SetLayout("Fill") tabGroup:SetTabs({ { text = L["Revenue"], value = 1 }, { text = L["Expenses"], value = 2 }, { text = L["Failed Auctions"], value = 3 }, { text = L["Items"], value = 4 }, { text = L["Summary"], value = 5 }, { text = L["Player Gold"], value = 6 }, { text = L["Options"], value = 7 } }) tabGroup:SetCallback("OnGroupSelected", function(self, _, value) tabGroup:ReleaseChildren() private:HideScrollingTables() if GUI.lineGraph then GUI.lineGraph:Hide() end if value == 1 then GUI:DrawRevenueTab(self) elseif value == 2 then GUI:DrawExpenseTab(self) elseif value == 3 then GUI:DrawFailedAucsTab(self) elseif value == 4 then GUI:DrawItemSummary(self) elseif value == 5 then GUI:DrawGoldSummary(self) elseif value == 6 then GUI:DrawGoldGraph(self) elseif value == 7 then GUI:DrawOptions(self) end tabGroup.children[1]:DoLayout() end) simpleGroup:SetWidth(parent.frame:GetWidth() + 32) --fix blank space simpleGroup:AddChild(tabGroup) TSM.Data:PopulateDataCaches() tabGroup:SelectTab(1) GUI:HookScript(simpleGroup.frame, "OnHide", function() GUI:UnhookAll() private:HideScrollingTables() if GUI.lineGraph then GUI.lineGraph:Hide() end end) end function GUI:DrawRevenueTab(container) local simpleGroup = AceGUI:Create("SimpleGroup") simpleGroup:SetLayout("Fill") container:AddChild(simpleGroup) local tabNum = 1 local tabGroup = AceGUI:Create("TSMTabGroup") tabGroup:SetLayout("Fill") tabGroup:SetTabs({ { text = L["Sales"], value = 1 }, { text = L["Other Income"], value = 2 }, { text = L["Resale"], value = 3 } }) tabGroup:SetCallback("OnGroupSelected", function(self, _, value) tabGroup:ReleaseChildren() private:HideScrollingTables() if value == 1 then GUI:CreateFiltersWidgetsItem(self, "sales", {"Auction", "COD", "Trade", "Vendor"}) private:CreateScrollingTable(self, "sales", TSM.Data.GetSaleSTData, ITEM_SELL_BUY_ST_COLS, tabNum, value) elseif value == 2 then GUI:CreateFiltersWidgetsMoney(self, "income", {"Transfer"}) private:CreateScrollingTable(self, "income", TSM.Data.GetIncomeSTData, ITEM_MONEY_ST_COLS) elseif value == 3 then GUI:CreateFiltersWidgetsItem(self, "resale", {"Auction", "COD", "Trade", "Vendor"}) local stCols = TSM.db.realm.priceFormat == "avg" and ITEM_RESALE_ST_COLS_AVG or ITEM_RESALE_ST_COLS_TOTAL private:CreateScrollingTable(self, "resale", TSM.Data.GetResaleSTData, stCols, tabNum, value) end tabGroup.children[1]:DoLayout() end) simpleGroup:AddChild(tabGroup) TSM.Data:PopulateDataCaches() tabGroup:SelectTab(1) end function GUI:DrawExpenseTab(container) local simpleGroup = AceGUI:Create("SimpleGroup") simpleGroup:SetLayout("Fill") container:AddChild(simpleGroup) local tabNum = 2 local tabGroup = AceGUI:Create("TSMTabGroup") tabGroup:SetLayout("Fill") tabGroup:SetTabs({ { text = L["Purchases"], value = 1 }, { text = L["Other"], value = 2 } }) tabGroup:SetCallback("OnGroupSelected", function(self, _, value) tabGroup:ReleaseChildren() private:HideScrollingTables() if value == 1 then GUI:CreateFiltersWidgetsItem(self, "buy", {"Auction", "COD", "Trade", "Vendor"}) private:CreateScrollingTable(self, "buy", TSM.Data.GetBuySTData, ITEM_SELL_BUY_ST_COLS, tabNum, value) elseif value == 2 then GUI:CreateFiltersWidgetsMoney(self, "expense", {"Postage", "Repair", "Transfer"}) private:CreateScrollingTable(self, "expense", TSM.Data.GetExpenseSTData, ITEM_MONEY_ST_COLS) end tabGroup.children[1]:DoLayout() end) simpleGroup:AddChild(tabGroup) TSM.Data:PopulateDataCaches() tabGroup:SelectTab(1) end function GUI:DrawFailedAucsTab(container) local simpleGroup = AceGUI:Create("SimpleGroup") simpleGroup:SetLayout("Fill") container:AddChild(simpleGroup) local tabNum = 3 local tabGroup = AceGUI:Create("TSMTabGroup") tabGroup:SetLayout("Fill") tabGroup:SetTabs({ { text = L["Expired"], value = 1 }, { text = L["Cancelled"], value = 2 } }) tabGroup:SetCallback("OnGroupSelected", function(self, _, value) tabGroup:ReleaseChildren() private:HideScrollingTables() if value == 1 then GUI:CreateFiltersWidgetsItem(self, "expired", {}) private:CreateScrollingTable(self, "expired", TSM.Data.GetExpireSTData, ITEM_AUCTION_ST_COLS, tabNum, value) elseif value == 2 then GUI:CreateFiltersWidgetsItem(self, "cancelled", {}) private:CreateScrollingTable(self, "cancelled", TSM.Data.GetCancelSTData, ITEM_AUCTION_ST_COLS, tabNum, value) end tabGroup.children[1]:DoLayout() end) simpleGroup:AddChild(tabGroup) TSM.Data:PopulateDataCaches() tabGroup:SelectTab(1) end function GUI:DrawItemSummary(container) GUI:CreateFiltersWidgetsItem(container, "itemSummary", {"Auction", "COD", "Trade", "Vendor"}) local stCols = TSM.db.realm.priceFormat == "avg" and ITEM_SUMMARY_ST_COLS_AVG or ITEM_SUMMARY_ST_COLS_TOTAL private:CreateScrollingTable(container, "itemSummary", TSM.Data.GetItemSummarySTData, stCols, 4) end function GUI:DrawItemLookup(container, itemString, returnTab, returnSubTab) container:ReleaseChildren() local itemID = TSMAPI:GetItemID(itemString) local itemData = TSM.Data.GetItemDetailData(itemString) local color, color2 = TSMAPI.Design:GetInlineColor("link2"), TSMAPI.Design:GetInlineColor("category2") local buyers, sellers = {}, {} for name, quantity in pairs(itemData.sales.players) do tinsert(buyers, { name = name, quantity = quantity }) end for name, quantity in pairs(itemData.buys.players) do tinsert(sellers, { name = name, quantity = quantity }) end sort(buyers, function(a, b) return a.quantity > b.quantity end) sort(sellers, function(a, b) return a.quantity > b.quantity end) local buyersText, sellersText = "", "" for i = 1, min(#buyers, 5) do buyersText = buyersText .. "|cffffffff" .. buyers[i].name .. "|r" .. color .. "(" .. buyers[i].quantity .. ")|r, " end for i = 1, min(#sellers, 5) do sellersText = sellersText .. "|cffffffff" .. sellers[i].name .. "|r" .. color .. "(" .. sellers[i].quantity .. ")|r, " end local page = { { type = "SimpleGroup", layout = "Flow", children = { { type = "SimpleGroup", layout = "Flow", children = { { type = "Label", relativeWidth = 0.1, }, { type = "InteractiveLabel", text = select(2, TSMAPI:GetSafeItemInfo(itemString)) or TSM.items[itemString].name, fontObject = GameFontNormalLarge, relativeWidth = 0.4, callback = function() SetItemRef("item:" .. itemID, itemID) end, tooltip = itemID, }, { type = "Label", relativeWidth = 0.1, }, { type = "Button", text = L["Back to Previous Page"], relativeWidth = 0.29, callback = function() if returnSubTab then local topTabGroup = container.parent.parent -- not sure why, but sometimes the details get displayed within the top tabgroup, rather than the sub-tabgroup if topTabGroup.type == "TSMMainFrame" then topTabGroup = container end if topTabGroup.localstatus.selected ~= returnTab then topTabGroup:SelectTab(returnTab) end TSMAPI:CreateTimeDelay("accountingReturnDelay", 0, function() container:SelectTab(returnSubTab) end) else container:SelectTab(returnTab) end end, }, }, }, { type = "HeadingLine", }, { type = "InlineGroup", title = L["Sale Data"], layout = "Flow", backdrop = true, children = {}, }, { type = "InlineGroup", title = L["Purchase Data"], layout = "Flow", backdrop = true, children = {}, }, { type = "Spacer", quantity = 2, }, { type = "ScrollFrame", layout = "Flow", fullHeight = true, }, }, }, } local sellWidgets, buyWidgets if itemData.sales.hasData then sellWidgets = { { type = "MultiLabel", labelInfo = private:GetMultiLabelLine(L["Average Prices:"], itemData.sales, "avg"), relativeWidth = 1, }, { type = "MultiLabel", labelInfo = private:GetMultiLabelLine(L["Quantity Sold:"], itemData.sales, "num", nil, true), relativeWidth = 1, }, { type = "MultiLabel", labelInfo = private:GetMultiLabelLine(L["Gold Earned:"], itemData.sales, "price"), relativeWidth = 1, }, { type = "Label", relativeWidth = 1, text = color2 .. L["Top Buyers:"] .. " |r" .. buyersText, }, } else sellWidgets = { { type = "Label", relativeWidth = 1, text = "|cffffffff" .. L["There is no sale data for this item."] .. "|r", }, } end if itemData.buys.hasData then buyWidgets = { { type = "MultiLabel", labelInfo = private:GetMultiLabelLine(L["Average Prices:"], itemData.buys, "avg"), relativeWidth = 1, }, { type = "MultiLabel", labelInfo = private:GetMultiLabelLine(L["Quantity Bought:"], itemData.buys, "num", nil, true), relativeWidth = 1, }, { type = "MultiLabel", labelInfo = private:GetMultiLabelLine(L["Total Spent:"], itemData.buys, "price"), relativeWidth = 1, }, { type = "Label", relativeWidth = 1, text = color2 .. L["Top Sellers:"] .. " |r" .. sellersText, }, } else buyWidgets = { { type = "Label", relativeWidth = 1, text = "|cffffffff" .. L["There is no purchase data for this item."] .. "|r", }, } end local index for i = 2, #page[1].children do if page[1].children[i].type == "InlineGroup" then index = i break end end for i = 1, #sellWidgets do tinsert(page[1].children[index].children, sellWidgets[i]) end for i = 1, #buyWidgets do tinsert(page[1].children[index + 1].children, buyWidgets[i]) end TSMAPI:BuildPage(container, page) local stParent = container.children[1].children[#container.children[1].children].frame if not scrollingTables.itemDetail then local stCols = { { name = L["Activity Type"], width = 0.15, align = "LEFT", headAlign = "LEFT", }, { name = L["Source"], width = 0.14, align = "LEFT", headAlign = "LEFT", }, { name = L["Buyer/Seller"], width = 0.15, align = "LEFT", headAlign = "LEFT", }, { name = L["Quantity"], width = 0.1, align = "LEFT", headAlign = "LEFT", }, { name = L["Per Item"], width = 0.15, align = "LEFT", headAlign = "LEFT", }, { name = L["Total Price"], width = 0.15, align = "LEFT", headAlign = "LEFT", }, { name = L["Time"], width = 0.15, align = "LEFT", headAlign = "LEFT", }, } local handlers = { OnClick = function(_, data, self, button) if not data then return end if button == "RightButton" and IsShiftKeyDown() then if data.recordType == "Sale" then for i, v in ipairs(TSM.items[itemString].sales) do if v == data.record then tremove(TSM.items[itemString].sales, i) break end end elseif data.recordType == "Purchase" then for i, v in ipairs(TSM.items[itemString].buys) do if v == data.record then tremove(TSM.items[itemString].buys, i) break end end end for i, v in ipairs(itemData.stData) do if v == data then tremove(itemData.stData, i) break end end scrollingTables.itemDetail:SetData(itemData.stData) TSM:Print(L["Removed record."]) end end, OnEnter = function(_, data, self) if not data then return end GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT") GameTooltip:SetText(L["Shift-Right-Click to delete this record."], 1, .82, 0, 1) GameTooltip:Show() end, OnLeave = function() GameTooltip:ClearLines() GameTooltip:Hide() end } TSMAPI:CreateTimeDelay(0, function() scrollingTables.itemDetail = TSMAPI:CreateScrollingTable(stParent, stCols, handlers) scrollingTables.itemDetail:EnableSorting(true, -7) scrollingTables.itemDetail:DisableSelection(true) scrollingTables.itemDetail:Show() scrollingTables.itemDetail:SetParent(stParent) scrollingTables.itemDetail:SetAllPoints() scrollingTables.itemDetail:SetData(itemData.stData) end) else scrollingTables.itemDetail:Show() scrollingTables.itemDetail:SetParent(stParent) scrollingTables.itemDetail:SetAllPoints() scrollingTables.itemDetail:SetData(itemData.stData) end end local goldSummaryFilters = {} function GUI:DrawGoldSummary(container) if goldSummaryFilters.isReloading then goldSummaryFilters.isReloading = nil else goldSummaryFilters = {} -- reset options on fresh update end local data = TSM.Data.GetSummaryData(goldSummaryFilters) local color, color2 = TSMAPI.Design:GetInlineColor("link2"), TSMAPI.Design:GetInlineColor("category2") local playerList = CopyTable(TSM.Data.playerListCache) playerList["all"] = L["All"] local page = { { type = "ScrollFrame", layout = "Flow", children = { { type = "SimpleGroup", layout = "Flow", children = { { type = "GroupBox", label = L["Group"], relativeWidth = 0.5, value = TSMAPI:FormatGroupPath(goldSummaryFilters.group), callback = function(_, _, value) goldSummaryFilters.group = value goldSummaryFilters.isReloading = true container:ReloadTab() end, }, { type = "Dropdown", label = L["Player"], relativeWidth = 0.49, list = playerList, value = goldSummaryFilters.player, callback = function(_, _, value) if value == "all" then goldSummaryFilters.player = nil else goldSummaryFilters.player = value end goldSummaryFilters.isReloading = true container:ReloadTab() end, }, }, }, -- { -- type = "HeadingLine", -- }, { type = "InlineGroup", layout = "Flow", title = L["Sales"], backdrop = true, children = { { type = "MultiLabel", labelInfo = private:GetMultiLabelLine(L["Gold Earned:"], data, "sales"), relativeWidth = 1, }, { type = "MultiLabel", labelInfo = private:GetMultiLabelLine(L["Earned Per Day:"], data, "sales", true), relativeWidth = 1, }, { type = "Label", relativeWidth = 0.28, text = color2 .. L["Top Item by Gold / Quantity:"] .. "|r", }, { type = "InteractiveLabel", text = data.sales.topGold.link .. " (" .. (TSMAPI:FormatTextMoney(data.sales.topGold.copper) or "---") .. ")", relativeWidth = 0.36, callback = function() SetItemRef("item:" .. data.sales.topGold.itemID, data.sales.topGold.itemID) end, tooltip = data.sales.topGold.itemID, }, { type = "InteractiveLabel", text = data.sales.topQuantity.link .. " (" .. (data.sales.topQuantity.num or "---") .. ")", relativeWidth = 0.36, callback = function() SetItemRef("item:" .. data.sales.topQuantity.itemID, data.sales.topQuantity.itemID) end, tooltip = data.sales.topQuantity.itemID, }, }, }, { type = "InlineGroup", layout = "Flow", title = L["Other Income"], backdrop = true, children = { { type = "MultiLabel", labelInfo = private:GetMultiLabelLine(L["Gold Earned:"], data, "income"), relativeWidth = 1, }, { type = "MultiLabel", labelInfo = private:GetMultiLabelLine(L["Earned Per Day:"], data, "income", true), relativeWidth = 1, }, { type = "Label", relativeWidth = 0.28, text = color2 .. L["Top Income by Gold / Quantity:"] .. "|r", }, { type = "Label", text = (data.income.topGold.key or L["none"]) .. " (" .. (TSMAPI:FormatTextMoney(data.income.topGold.copper) or "---") .. ")", relativeWidth = 0.36, }, { type = "Label", text = (data.income.topQuantity.key or L["none"]) .. " (" .. (data.income.topQuantity.num or "---") .. ")", relativeWidth = 0.36, }, }, }, { type = "InlineGroup", layout = "Flow", title = L["Purchases"], backdrop = true, children = { { type = "MultiLabel", labelInfo = private:GetMultiLabelLine(L["Gold Spent:"], data, "buys"), relativeWidth = 1, }, { type = "MultiLabel", labelInfo = private:GetMultiLabelLine(L["Spent Per Day:"], data, "buys", true), relativeWidth = 1, }, { type = "Label", relativeWidth = 0.28, text = color2 .. L["Top Item by Gold / Quantity:"] .. "|r", }, { type = "InteractiveLabel", text = data.buys.topGold.link .. " (" .. (TSMAPI:FormatTextMoney(data.buys.topGold.copper) or "---") .. ")", relativeWidth = 0.36, callback = function() SetItemRef("item:" .. data.buys.topGold.itemID, data.buys.topGold.itemID) end, tooltip = data.buys.topGold.itemID, }, { type = "InteractiveLabel", text = data.buys.topQuantity.link .. " (" .. (data.buys.topQuantity.num or "---") .. ")", relativeWidth = 0.36, callback = function() SetItemRef("item:" .. data.buys.topQuantity.itemID, data.buys.topQuantity.itemID) end, tooltip = data.buys.topQuantity.itemID, }, }, }, { type = "InlineGroup", layout = "Flow", title = L["Expenses"], backdrop = true, children = { { type = "MultiLabel", labelInfo = private:GetMultiLabelLine(L["Gold Spent:"], data, "expense"), relativeWidth = 1, }, { type = "MultiLabel", labelInfo = private:GetMultiLabelLine(L["Spent Per Day:"], data, "expense", true), relativeWidth = 1, }, { type = "Label", relativeWidth = 0.28, text = color2 .. L["Top Expense by Gold / Quantity:"] .. "|r", }, { type = "Label", text = (data.expense.topGold.key or L["none"]) .. " (" .. (TSMAPI:FormatTextMoney(data.expense.topGold.copper) or "---") .. ")", relativeWidth = 0.36, }, { type = "Label", text = (data.expense.topQuantity.key or L["none"]) .. " (" .. (data.expense.topQuantity.num or "---") .. ")", relativeWidth = 0.36, }, }, }, { type = "InlineGroup", layout = "Flow", title = L["Balance"], backdrop = true, children = { { type = "MultiLabel", labelInfo = private:GetMultiLabelLine(L["Profit:"], data, "profit"), relativeWidth = 1, }, { type = "MultiLabel", labelInfo = private:GetMultiLabelLine(L["Profit Per Day:"], data, "profit", true), relativeWidth = 1, }, }, }, }, }, } TSMAPI:BuildPage(container, page) end function private:GetGoldGraphPoints(goldLog) if not goldLog or #goldLog < 3 then return end local minY, maxY = math.huge, 0 local minX, maxX = math.huge, 0 local data = {} for _, info in ipairs(goldLog) do local x1, x2 = info.startMinute, info.endMinute local y = info.copper / COPPER_PER_GOLD minX = min(minX, x1) maxX = max(maxX, x2) minY = min(minY, floor(y)) maxY = max(maxY, ceil(y)) tinsert(data, {x1, y}) tinsert(data, {x2, y}) end return data, minX, maxX, minY, maxY end function private:GetGoldGraphSumData() local currentMinute = floor(time() / 60) local players = {} local starts = {} for _, playerData in pairs(TSM.db.realm.goldLog) do if #playerData > 2 then local data = CopyTable(playerData) for i=1, #data do if i > 1 then data[i].startMinute = data[i-1].endMinute+1 end data[i].copper = TSM:Round(data[i].copper, COPPER_PER_GOLD) end tinsert(players, data) tinsert(starts, data[1].startMinute) end end if #players == 0 then return end local indicies = {} local absStartMinute = min(unpack(starts)) for i=1, #players do indicies[i] = 1 end local temp = {} local staticCopper = 0 for t=absStartMinute, currentMinute do local copper = staticCopper for i=#players, 1, -1 do if starts[i] <= t then local playerData = players[i] local index = indicies[i] while true do if index >= #playerData then index = #playerData tremove(players, i) staticCopper = staticCopper + playerData[index].copper copper = copper + playerData[index].copper break end if t > playerData[index].endMinute then -- move to the next datapoint for this player index = index + 1 else -- we are in the range copper = copper + playerData[index].copper break end end indicies[i] = index end end local j = #temp+1 if j > 1 and temp[j-1].copper == copper then temp[j-1].endMinute = t else tinsert(temp, {startMinute=t, endMinute=t, copper=copper}) end end if #temp == 0 then return end return private:GetGoldGraphPoints(temp) end function GUI:DrawGoldGraph(container) TSM.db.realm.goldGraphCharacter = TSM.db.realm.goldGraphCharacter or UnitName("player") local player = TSM.db.realm.goldGraphCharacter local data, minX, maxX, minY, maxY if player == "" then data, minX, maxX, minY, maxY = private:GetGoldGraphSumData() else data, minX, maxX, minY, maxY = private:GetGoldGraphPoints(TSM.db.realm.goldLog[player]) end local dropdownList = {[""]="Sum of All Characters"} for player in pairs(TSM.db.realm.goldLog) do dropdownList[player] = player end if not data then local page = { { type = "SimpleGroup", layout = "Flow", children = { { type = "Label", text = L["Accounting has not yet collected enough information for this tab. This is likely due to not having recorded enough data points or not seeing any significant fluctuations in your gold on hand."], relativeWidth = 1, }, { type = "Spacer", }, { type = "Dropdown", label = "Character to Graph", settingInfo = {TSM.db.realm, "goldGraphCharacter"}, relativeWidth = 0.5, list = dropdownList, callback = function() container:ReloadTab() end, tooltip = "", }, }, }, } TSMAPI:BuildPage(container, page) return end local startDate, endDate if TSM.db.realm.timeFormat == "eudate" then startDate = date("%d/%m/%y %H:%M", minX * 60) endDate = date("%d/%m/%y %H:%M", maxX * 60) elseif TSM.db.realm.timeFormat == "aidate" then startDate = date("%y/%m/%d %H:%M", minX * 60) endDate = date("%y/%m/%d %H:%M", maxX * 60) else startDate = date("%m/%d/%y %H:%M", minX * 60) endDate = date("%m/%d/%y %H:%M", maxX * 60) end local page = { { type = "SimpleGroup", layout = "Flow", children = { { type = "Label", text = format(L["Below is a graph of the your character's gold on hand over time.\n\nThe x-axis is time and goes from %s to %s\nThe y-axis is gold."], startDate, endDate), relativeWidth = 1, }, -- { -- type = "Spacer", -- }, { type = "Dropdown", label = L["Character to Graph"], settingInfo = {TSM.db.realm, "goldGraphCharacter"}, relativeWidth = 0.5, list = dropdownList, callback = function() container:ReloadTab() end, }, -- { -- type = "HeadingLine" -- }, { type = "Spacer", }, { type = "ScrollFrame", fullHeight = false, --true layout = "flow" }, }, }, } TSMAPI:BuildPage(container, page) local parent = container.children[1].children[#container.children[1].children].frame parent:SetWidth(container.frame:GetWidth() - 80) parent:SetHeight(container.frame:GetHeight() - 140) --if not GUI.lineGraph then local graph = LibStub("LibGraph-2.0"):CreateGraphLine(nil, parent, "CENTER", nil, nil, nil, parent:GetWidth(), parent:GetHeight()) graph:SetGridColor({ 0.8, 0.8, 0.8, 0.6 }) graph:SetYLabels(true) GUI.lineGraph = graph --end GUI.lineGraph:Show() GUI.lineGraph:SetParent(parent) GUI.lineGraph:ClearAllPoints() GUI.lineGraph:SetAllPoints(parent) GUI.lineGraph:ResetData() local ySpacing = max(ceil((maxY - minY) / 20), 0.5) GUI.lineGraph:SetGridSpacing(nil, ySpacing) local xBuffer = (maxX-minX)*0.05 local yBuffer = (maxY-minY)*0.03 GUI.lineGraph:SetXAxis(minX-xBuffer, maxX) GUI.lineGraph:SetYAxis(minY-yBuffer, maxY+yBuffer) GUI.lineGraph:AddDataSeries(data, {1, 0.83, 0, 1}) GUI.lineGraph:RefreshGraph() end function GUI:DrawOptions(container) local mvSources = TSMAPI:GetPriceSources() local daysOld = 45 local page = { { type = "ScrollFrame", layout = "List", children = { { type = "InlineGroup", title = L["General Options"], layout = "Flow", children = { { type = "Dropdown", label = L["Time Format"], settingInfo = {TSM.db.realm, "timeFormat"}, relativeWidth = 0.5, list = { ["ago"] = L["_ Hr _ Min ago"], ["usdate"] = L["MM/DD/YY HH:MM"], ["aidate"] = L["YY/MM/DD HH:MM"], ["eudate"] = L["DD/MM/YY HH:MM"] }, tooltip = L["Select what format Accounting should use to display times in applicable screens."], }, { type = "Dropdown", label = L["Market Value Source"], settingInfo = {TSM.db.realm, "mvSource"}, relativeWidth = 0.49, list = mvSources, tooltip = L["Select where you want Accounting to get market value info from to show in applicable screens."], }, { type = "Dropdown", label = "Items/Resale Price Format", settingInfo = {TSM.db.realm, "priceFormat"}, relativeWidth = 0.49, list = { ["avg"] = L["Per Item"], ["total"] = L["Total Value"] }, tooltip = L["Select how you would like prices to be shown in the \"Items\" and \"Resale\" tabs; either average price per item or total value."], }, { type = "Label", relativeWidth = .49 }, { type = "CheckBox", label = L["Track sales/purchases via trade"], settingInfo = { TSM.db.realm, "trackTrades" }, callback = function() container:ReloadTab() end, tooltip = L["If checked, whenever you buy or sell any quantity of a single item via trade, Accounting will display a popup asking if you want it to record that transaction."], }, { type = "CheckBox", label = L["Don't prompt to record trades"], settingInfo = { TSM.db.realm, "autoTrackTrades" }, disabled = not TSM.db.realm.trackTrades, tooltip = L["If checked, you won't get a popup confirmation about whether or not to track trades."], }, { type = "CheckBox", label = L["Display Grey Items in Sales"], settingInfo = { TSM.db.realm, "displayGreys" }, tooltip = L["If checked, poor quality items will be shown in sales data. They will still be included in gold earned totals on the summary tab regardless of this setting"], }, { type = "CheckBox", label = L["Display Money Transfers in Income/Expense/Summary"], settingInfo = { TSM.db.realm, "displayTransfers" }, tooltip = L["If checked, Money Transfers will be included in income / expense and summary. Accounting will still track these if disabled but will not show them."], }, { type = "CheckBox", label = L["Use smart average for purchase price"], settingInfo = { TSM.db.realm, "smartBuyPrice" }, tooltip = L["If checked, the average purchase price that shows in the tooltip will be the average price for the most recent X you have purchased, where X is the number you have in your bags / bank / gbank using data from the ItemTracker module. Otherwise, a simple average of all purchases will be used."], }, }, }, { type = "InlineGroup", title = L["Clear Old Data"], layout = "Flow", children = { { type = "Label", text = L["You can use the options below to clear old data. It is recommened to occasionally clear your old data to keep Accounting running smoothly. Select the minimum number of days old to be removed in the dropdown, then click the button.\n\nNOTE: There is no confirmation."], relativeWidth = 1, }, { type = "HeadingLine", }, { type = "Dropdown", label = L["Days:"], relativeWidth = 0.4, list = { "30", "45", "60", "75", "90" }, value = 2, callback = function(_, _, value) daysOld = (tonumber(value) + 1) * 15 end, tooltip = L["Data older than this many days will be deleted when you click on the button to the right."], }, { type = "Button", text = L["Remove Old Data (No Confirmation)"], relativeWidth = 0.59, callback = function() TSM.Data:RemoveOldData(daysOld) end, tooltip = L["Click this button to permanently remove data older than the number of days selected in the dropdown."], }, }, }, }, }, } TSMAPI:BuildPage(container, page) end function GUI:LoadTooltipOptions(container) local page = { { type = "SimpleGroup", layout = "Flow", fullHeight = true, children = { { type = "CheckBox", label = L["Show sale info in item tooltips"], settingInfo = { TSM.db.realm.tooltip, "sale" }, tooltip = L["If checked, the number you have sold and the average sale price will show up in an item's tooltip."], }, { type = "CheckBox", label = L["Show Expired Auctions as Failed Auctions since Last Sale in item tooltips"], settingInfo = { TSM.db.realm, "expiredAuctions" }, relativeWidth = 1, tooltip = L["If checked, the number of expired auctions since the last sale will show as up as failed auctions in an item's tooltip. if no sales then the total number of expired auctions will be shown."], }, { type = "CheckBox", label = L["Show Cancelled Auctions as Failed Auctions since Last Sale in item tooltips"], settingInfo = { TSM.db.realm, "cancelledAuctions" }, relativeWidth = 1, tooltip = L["If checked, the number of cancelled auctions since the last sale will show as up as failed auctions in an item's tooltip. if no sales then the total number of cancelled auctions will be shown."], }, { type = "CheckBox", label = L["Show Sale Rate in item tooltips"], settingInfo = { TSM.db.realm, "saleRate" }, relativeWidth = 1, tooltip = L["If checked, the sale rate will be shown in item tooltips. sale rate is calculated as total sold / (total sold + total expired + total cancelled)."], }, { type = "CheckBox", label = L["Show purchase info in item tooltips"], settingInfo = { TSM.db.realm.tooltip, "purchase" }, tooltip = L["If checked, the number you have purchased and the average purchase price will show up in an item's tooltip."], }, }, }, } TSMAPI:BuildPage(container, page) end function GUI:CreateFiltersWidgetsItem(container, dataType, types) local rarityList = {[0]=L["None"]} for i = 1, 4 do rarityList[i] = _G[format("ITEM_QUALITY%d_DESC", i)] end local timeList = { [99] = L["All"], [0] = L["Today"], [1] = L["Yesterday"], [7] = L["Last 7 Days"], [14] = L["Last 14 Days"], [30] = L["Last 30 Days"], [60] = L["Last 60 Days"] } local playerList = CopyTable(TSM.Data.playerListCache) playerList["all"] = L["All"] local typeList = {["all"] = L["All"]} for _, dataType in ipairs(types) do typeList[dataType] = dataType end local filters = {} local page = { { type = "SimpleGroup", layout = "Flow", children = { { type = "EditBox", label = L["Search"], relativeWidth = 0.18, onTextChanged = true, callback = function(_, _, value) value = value:trim() if value == "" then filters.name = nil else filters.name = TSMAPI:StrEscape(value) end private:UpdateSTData(scrollingTables[dataType], filters) end, }, { type = "GroupBox", label = L["Group"], relativeWidth = 0.19, callback = function(_, _, value) filters.group = value private:UpdateSTData(scrollingTables[dataType], filters) end, }, { type = "Dropdown", label = L["Type"], relativeWidth = 0.13, list = typeList, value = "all", callback = function(_, _, key) if key == "all" then filters.key = nil else filters.key = key end private:UpdateSTData(scrollingTables[dataType], filters) end, }, { type = "Dropdown", label = L["Rarity"], relativeWidth = 0.16, list = rarityList, value = 0, callback = function(_, _, key) if key > 0 then filters.rarity = key else filters.rarity = nil end private:UpdateSTData(scrollingTables[dataType], filters) end, }, { type = "Dropdown", label = L["Player"], relativeWidth = 0.15, list = playerList, value = "all", callback = function(_, _, value) if value == "all" then filters.player = nil else filters.player = value end private:UpdateSTData(scrollingTables[dataType], filters) end, }, { type = "Dropdown", label = L["Timeframe Filter"], relativeWidth = 0.18, list = timeList, value = 99, callback = function(_, _, value) if value == 99 then filters.time = nil else filters.time = value end private:UpdateSTData(scrollingTables[dataType], filters) end, }, { type = "ScrollFrame", fullHeight = true, layout = "flow" }, }, }, } TSMAPI:BuildPage(container, page) end function GUI:CreateFiltersWidgetsMoney(container, dataType, types) local timeList = {[99]=L["All"], [0]=L["Today"], [1]=L["Yesterday"], [7]=L["Last 7 Days"], [14]=L["Last 14 Days"], [30]=L["Last 30 Days"], [60]=L["Last 60 Days"]} local playerList = CopyTable(TSM.Data.playerListCache) playerList["all"] = L["All"] local typeList = {["all"] = L["All"]} for _, dataType in ipairs(types) do typeList[dataType] = dataType end local filters = {} local page = { { type = "SimpleGroup", layout = "Flow", children = { { type = "Dropdown", label = L["Type"], relativeWidth = 0.13, list = typeList, value = "all", callback = function(_, _, key) if key == "all" then filters.key = nil else filters.key = key end private:UpdateSTData(scrollingTables[dataType], filters) end, }, { type = "Dropdown", label = L["Player"], relativeWidth = 0.15, list = playerList, value = "all", callback = function(_, _, value) if value == "all" then filters.player = nil else filters.player = value end private:UpdateSTData(scrollingTables[dataType], filters) end, }, { type = "Dropdown", label = L["Timeframe Filter"], relativeWidth = 0.18, list = timeList, value = 99, callback = function(_, _, value) if value == 99 then filters.time = nil else filters.time = value end private:UpdateSTData(scrollingTables[dataType], filters) end, }, { type = "ScrollFrame", fullHeight = true, layout = "flow" }, }, }, } TSMAPI:BuildPage(container, page) end