-- ------------------------------------------------------------------------------ -- -- TradeSkillMaster -- -- https://tradeskillmaster.com -- -- All Rights Reserved - Detailed license information included with addon. -- -- ------------------------------------------------------------------------------ -- --- AuctionScrollingTable UI Element Class. -- An auction scrolling table displays a scrollable list of auctions with a fixed set of columns. It operations on -- auction records returned by the scanning code. It is a subclass of the @{ScrollingTable} class. -- @classmod AuctionScrollingTable local _, TSM = ... local L = TSM.Include("Locale").GetTable() local Math = TSM.Include("Util.Math") local Money = TSM.Include("Util.Money") local String = TSM.Include("Util.String") local TempTable = TSM.Include("Util.TempTable") local Theme = TSM.Include("Util.Theme") local ScriptWrapper = TSM.Include("Util.ScriptWrapper") local ItemInfo = TSM.Include("Service.ItemInfo") local PlayerInfo = TSM.Include("Service.PlayerInfo") local AuctionScrollingTable = TSM.Include("LibTSMClass").DefineClass("AuctionScrollingTable", TSM.UI.ScrollingTable) local UIElements = TSM.Include("UI.UIElements") UIElements.Register(AuctionScrollingTable) TSM.UI.AuctionScrollingTable = AuctionScrollingTable local private = { sortContext = { rowSortValue = {}, baseSortValue = {}, sortValue = {}, self = nil, }, subRowsTemp = {}, } local ICON_SIZE = 12 -- ============================================================================ -- Public Class Methods -- ============================================================================ function AuctionScrollingTable.__init(self) self.__super:__init() self._auctionScan = nil self._marketValueFunc = nil self._sortCol = nil self._sortAscending = nil self._expanded = {} self._firstSubRowByItem = {} self._rowByItem = {} self._browseResultsVisible = false self._firstUnscannedItem = nil self._selectionBaseItemString = nil self._selectionBaseSortValue = nil self._selectionSubRowIndex = nil self._currentSearchItem = nil self._onResultsUpdated = function() self:UpdateData(true) end self._getNextSearchItem = function() if self._selectionBaseItemString and not self._firstSubRowByItem[self._selectionBaseItemString] then -- the selected row has priority return self._selectionBaseItemString end return self._firstUnscannedItem end self._currentSearchChanged = function(_, baseItemString) if not baseItemString then -- the search was paused or unpaused, so just update the current item baseItemString = self._currentSearchItem end self._currentSearchItem = baseItemString -- layout the new row to update it's action icon state for _, row in ipairs(self._rows) do local data = row:GetData() if data and not data:IsSubRow() and data:GetBaseItemString() == baseItemString then row:_LayoutDataRow() end end end end function AuctionScrollingTable.Acquire(self) self.__super:Acquire() -- temporarily set a context table so we can create the table columns (should be overridden later) self:GetScrollingTableInfo() :NewColumn("item") :SetHeaderIndent("8") :SetTitle(L["Item"]) :SetFont("ITEM_BODY3") :SetJustifyH("LEFT") :SetIconSize(ICON_SIZE) :SetTextFunction(private.GetItemCellText) :SetIconFunction(private.GetItemCellIcon) :SetTooltipFunction(private.GetItemCellTooltip) :SetExpanderStateFunction(private.GetExpanderState) :SetBadgeStateFunction(private.GetBadgeState) :SetActionIconInfo(1, 12, private.GetPendingIcon) :SetActionIconClickHandler(private.OnPendingIconClick) :DisableHiding() :Commit() :NewColumn("ilvl") :SetTitle(L["ilvl"]) :SetFont("TABLE_TABLE1") :SetJustifyH("RIGHT") :SetTextFunction(private.GetItemLevelCellText) :Commit() if not TSM.IsWowClassic() then self:GetScrollingTableInfo() :NewColumn("qty") :SetTitle(L["Qty"]) :SetFont("TABLE_TABLE1") :SetJustifyH("RIGHT") :SetTextFunction(private.GetAuctionsQuantityText) :Commit() else self:GetScrollingTableInfo() :NewColumn("posts") :SetTitle(L["Posts"]) :SetFont("TABLE_TABLE1") :SetJustifyH("RIGHT") :SetTextFunction(private.GetAuctionsPostsText) :Commit() :NewColumn("stack") :SetTitle(L["Stack"]) :SetFont("TABLE_TABLE1") :SetJustifyH("RIGHT") :SetTextFunction(private.GetAuctionsStackText) :Commit() end self:GetScrollingTableInfo() :NewColumn("timeLeft") :SetTitleIcon("iconPack.14x14/Clock") :SetFont("TABLE_TABLE1") :SetJustifyH("CENTER") :SetTextFunction(private.GetTimeLeftCellText) :Commit() :NewColumn("seller") :SetTitle(L["Seller"]) :SetFont("ITEM_BODY3") :SetJustifyH("LEFT") :SetTextFunction(private.GetSellerCellText) :Commit() :NewColumn("itemBid") :SetTitle(L["Bid (item)"]) :SetFont("TABLE_TABLE1") :SetJustifyH("RIGHT") :SetTextFunction(private.GetItemBidCellText) :Commit() :NewColumn("bid") :SetTitle(TSM.IsWowClassic() and L["Bid (stack)"] or L["Bid (total)"]) :SetFont("TABLE_TABLE1") :SetJustifyH("RIGHT") :SetTextFunction(private.GetBidCellText) :Commit() :NewColumn("itemBuyout") :SetTitle(L["Buyout (item)"]) :SetFont("TABLE_TABLE1") :SetJustifyH("RIGHT") :SetTextFunction(private.GetItemBuyoutCellText) :Commit() :NewColumn("buyout") :SetTitle(TSM.IsWowClassic() and L["Buyout (stack)"] or L["Buyout (total)"]) :SetFont("TABLE_TABLE1") :SetJustifyH("RIGHT") :SetTextFunction(private.GetBuyoutCellText) :Commit() :NewColumn("bidPct") :SetTitle(BID.." %") :SetFont("TABLE_TABLE1") :SetJustifyH("RIGHT") :SetTextFunction(private.GetBidPercentCellText) :Commit() :NewColumn("pct") :SetTitle("%") :SetFont("TABLE_TABLE1") :SetJustifyH("RIGHT") :SetTextFunction(private.GetPercentCellText) :Commit() :Commit() self._sortCol = "pct" self._sortAscending = true end function AuctionScrollingTable.Release(self) if self._auctionScan then self._auctionScan:RemoveResultsUpdateCallback(self._onResultsUpdated) self._auctionScan:SetNextSearchItemFunction(nil) self._auctionScan:SetScript("OnCurrentSearchChanged", nil) end self._auctionScan = nil self._sortCol = nil self._sortAscending = nil self._marketValueFunc = nil self._browseResultsVisible = false self._firstUnscannedItem = nil wipe(self._expanded) wipe(self._firstSubRowByItem) wipe(self._rowByItem) for _, row in ipairs(self._rows) do ScriptWrapper.Clear(row._frame, "OnDoubleClick") for _, tooltipFrame in pairs(row._buttons) do ScriptWrapper.Clear(tooltipFrame, "OnDoubleClick") end end self._selectionBaseItemString = nil self._selectionBaseSortValue = nil self._selectionSubRowIndex = nil self._currentSearchItem = nil self.__super:Release() end --- Sets the @{DatabaseQuery} source for this table. -- This query is used to populate the entries in the auction scrolling table. -- @tparam AuctionScrollingTable self The auction scrolling table object -- @tparam AuctionScanManager auctionScan The auction scan object -- @tparam[opt=false] bool redraw Whether or not to redraw the scrolling table -- @treturn AuctionScrollingTable The auction scrolling table object function AuctionScrollingTable.SetAuctionScan(self, auctionScan, redraw) if auctionScan == self._auctionScan and not redraw then return self end if self._auctionScan then self._auctionScan:RemoveResultsUpdateCallback(self._onResultsUpdated) self._auctionScan:SetNextSearchItemFunction(nil) self._auctionScan:SetScript("OnCurrentSearchChanged", nil) end self._auctionScan = auctionScan self._auctionScan:AddResultsUpdateCallback(self._onResultsUpdated) self._auctionScan:SetNextSearchItemFunction(self._getNextSearchItem) self._auctionScan:SetScript("OnCurrentSearchChanged", self._currentSearchChanged) wipe(self._expanded) self:UpdateData(redraw) return self end --- Sets whether or not browse results are visible. -- @tparam AuctionScrollingTable self The auction scrolling table object -- @tparam boolean visible Whether or not browse results should be visible -- @treturn AuctionScrollingTable The auction scrolling table object function AuctionScrollingTable.SetBrowseResultsVisible(self, visible) self._browseResultsVisible = visible return self end --- Sets the market value function. -- @tparam AuctionScrollingTable self The auction scrolling table object -- @tparam function func The function to call with the item DB record to get the market value -- @treturn AuctionScrollingTable The auction scrolling table object function AuctionScrollingTable.SetMarketValueFunction(self, func) if self._marketValueFunc ~= func then self._marketValueFunc = func self:UpdateData(false) end return self end --- Gets the selected result row. -- @tparam AuctionScrollingTable self The auction scrolling table object -- @return The selected result row or nil if there's no selection function AuctionScrollingTable.GetSelection(self) local selection = self.__super:GetSelection() if not selection then return nil end local baseItemString = selection:GetBaseItemString() if not selection:IsSubRow() then selection = self._firstSubRowByItem[baseItemString] or selection end return selection end --- Sets the selected result row. -- @tparam AuctionScrollingTable self The auction scrolling table object -- @param selection The selected result row or nil to clear the selection -- @treturn AuctionScrollingTable The auction scrolling table object function AuctionScrollingTable.SetSelection(self, selection) if not selection then self._selectionBaseItemString = nil self._selectionBaseSortValue = nil self._selectionSubRowIndex = nil return self.__super:SetSelection(selection) end local baseItemString = selection:GetBaseItemString() if selection == self._firstSubRowByItem[baseItemString] then selection = self._rowByItem[baseItemString] assert(selection) end self._selectionBaseItemString = baseItemString self._selectionBaseSortValue = self:_GetSortValue(selection, self._sortCol, self._sortAscending) local firstIndex = nil for i, data in ipairs(self._data) do if not firstIndex and data:GetBaseItemString() == baseItemString then firstIndex = i end if data == selection then self._selectionSubRowIndex = i - firstIndex + 1 break end end assert(self._selectionSubRowIndex) return self.__super:SetSelection(selection) end --- Expands a single auction result. -- If there is a single top-level auction result, this will cause it to be expanded. Otherwise, this does nothing. -- @tparam AuctionScrollingTable self The auction scrolling table object -- @treturn AuctionScrollingTable The auction scrolling table object function AuctionScrollingTable.ExpandSingleResult(self) -- if only one result, expand it local singleResult = nil for baseItemString in pairs(self._firstSubRowByItem) do if not singleResult then singleResult = baseItemString elseif singleResult then singleResult = nil break end end if singleResult then self._expanded[singleResult] = true self:UpdateData(true) end end --- Sets the % column header tooltip. -- @tparam AuctionScrollingTable self The auction scrolling table object -- @param tooltip The tooltip -- @treturn AuctionScrollingTable The auction scrolling table object function AuctionScrollingTable.SetPctTooltip(self, tooltip) self._tableInfo:GetColById("pct"):SetHeaderTooltip(tooltip) return self end function AuctionScrollingTable.Draw(self) self.__super:Draw() self._header:SetSort(self._sortCol, self._sortAscending) end -- ============================================================================ -- Private Class Methods -- ============================================================================ function AuctionScrollingTable._UpdateData(self) if not self._auctionScan then return end local sortKey = self._sortCol wipe(self._data) wipe(self._firstSubRowByItem) wipe(self._rowByItem) self._firstUnscannedItem = nil private.sortContext.self = self local rows = TempTable.Acquire() local subRows = TempTable.Acquire() local subRowsStart = TempTable.Acquire() local subRowsEnd = TempTable.Acquire() local sortAscending = self._sortAscending for _, query in self._auctionScan:QueryIterator() do for baseItemString, row in query:BrowseResultsIterator() do if not self._rowByItem[baseItemString] and row:HasItemInfo() then assert(not next(private.subRowsTemp)) local hasSubRows = false for _, subRow in row:SubRowIterator() do hasSubRows = true local sortValue = self:_GetSortValue(subRow, sortKey, sortAscending) private.sortContext.sortValue[subRow] = sortValue tinsert(private.subRowsTemp, subRow) end if hasSubRows then -- sort all the subRows sort(private.subRowsTemp, sortAscending and private.SortSubRowAscendingHelper or private.SortSubRowDescendingHelper) -- grab the first subRow which is shown when this item is collapsed assert(not self._firstSubRowByItem[baseItemString]) local firstSubRow = private.subRowsTemp[1] self._firstSubRowByItem[baseItemString] = firstSubRow private.sortContext.baseSortValue[baseItemString] = private.sortContext.sortValue[firstSubRow] private.sortContext.rowSortValue[row] = private.sortContext.baseSortValue[baseItemString] -- add all the subRows if this item is expanded if self._expanded[baseItemString] and #private.subRowsTemp > 1 then subRowsStart[baseItemString] = #subRows + 1 for i = 2, #private.subRowsTemp do tinsert(subRows, private.subRowsTemp[i]) end subRowsEnd[baseItemString] = #subRows end elseif self._browseResultsVisible then private.sortContext.baseSortValue[baseItemString] = self:_GetSortValue(row, sortKey, sortAscending) private.sortContext.rowSortValue[row] = private.sortContext.baseSortValue[baseItemString] end -- insert this row if hasSubRows or self._browseResultsVisible then self._rowByItem[baseItemString] = row tinsert(rows, row) else self._rowByItem[baseItemString] = private.subRowsTemp[1] end wipe(private.subRowsTemp) end end end -- sort the rows sort(rows, sortAscending and private.SortRowAscendingHelper or private.SortRowDescendingHelper) -- insert all the data local hasPrevSelection, nextIndexSelection = false, nil for _, row in ipairs(rows) do local baseItemString = row:GetBaseItemString() if not self._firstSubRowByItem[baseItemString] and not self._firstUnscannedItem then self._firstUnscannedItem = baseItemString end tinsert(self._data, row) hasPrevSelection = hasPrevSelection or self._selection == row local startIndex = subRowsStart[baseItemString] if startIndex then for i = startIndex, subRowsEnd[baseItemString] do local subRow = subRows[i] tinsert(self._data, subRow) hasPrevSelection = hasPrevSelection or self._selection == subRow end if not hasPrevSelection and not nextIndexSelection then if self._selectionBaseItemString == baseItemString and self._selectionSubRowIndex then -- check if we can find the new selection based on the sub row index (subtract 2 because subRows start from index 2) local index = startIndex + self._selectionSubRowIndex - 2 if index <= subRowsEnd[baseItemString] then nextIndexSelection = subRows[index] end end end end end TempTable.Release(rows) TempTable.Release(subRows) TempTable.Release(subRowsStart) TempTable.Release(subRowsEnd) if self._selection and not hasPrevSelection then -- the previous selection doesn't exist anymore local firstSubRow = self._firstSubRowByItem[self._selectionBaseItemString] if nextIndexSelection then -- we can select the next subRow for the same item self:SetSelection(nextIndexSelection) elseif firstSubRow then -- select the first row of the same item self:SetSelection(firstSubRow) elseif self._selectionBaseSortValue then -- select the next row by sort value (if it exists) local bestSortValue, bestNewSelection = nil, nil for _, row in ipairs(self._data) do local baseItemString = row:GetBaseItemString() local sortValue = private.sortContext.baseSortValue[baseItemString] if sortValue and (row == self._firstSubRowByItem[baseItemString] or row == self._rowByItem[baseItemString]) then local isBetterSortValue = nil if self._sortAscending then isBetterSortValue = (not bestSortValue or sortValue < bestSortValue) and (sortValue > self._selectionBaseSortValue or (sortValue == self._selectionBaseSortValue and baseItemString > self._selectionBaseItemString)) else isBetterSortValue = (not bestSortValue or sortValue > bestSortValue) and (sortValue < self._selectionBaseSortValue or (sortValue == self._selectionBaseSortValue and baseItemString < self._selectionBaseItemString)) end if isBetterSortValue then bestSortValue = sortValue bestNewSelection = row end end end self:SetSelection(bestNewSelection) else self:SetSelection(nil) end elseif self._selection then self._selectionBaseSortValue = private.sortContext.baseSortValue[self._selection:GetBaseItemString()] end wipe(private.sortContext.sortValue) wipe(private.sortContext.rowSortValue) wipe(private.sortContext.baseSortValue) private.sortContext.self = nil end function AuctionScrollingTable._GetSortValue(self, row, id, isAscending) if id == "item" then local baseItemString = row:GetBaseItemString() return ItemInfo.GetName(baseItemString) elseif id == "ilvl" then return ItemInfo.GetItemLevel(row:GetItemString() or row:GetBaseItemString()) elseif id == "posts" then local _, numAuctions = row:GetQuantities() return numAuctions or (isAscending and math.huge or -math.huge) elseif id == "stack" then local quantity = row:GetQuantities() return quantity or (isAscending and math.huge or -math.huge) elseif id == "qty" then local quantity, numAuctions = row:GetQuantities() if not quantity or not numAuctions then return isAscending and math.huge or -math.huge end return quantity * numAuctions elseif id == "timeLeft" then if not row:IsSubRow() then return isAscending and math.huge or -math.huge end local timeLeft = row:GetListingInfo() return timeLeft elseif id == "seller" then if not row:IsSubRow() then return "" end local ownerStr = row:GetOwnerInfo() return ownerStr elseif id == "itemBid" then if not row:IsSubRow() then return isAscending and math.huge or -math.huge end local _, itemDisplayedBid = row:GetDisplayedBids() return itemDisplayedBid elseif id == "bid" then if not row:IsSubRow() then return isAscending and math.huge or -math.huge end local displayedBid = row:GetDisplayedBids() return displayedBid elseif id == "itemBuyout" then local _, itemBuyout, minItemBuyout = row:GetBuyouts() itemBuyout = itemBuyout or minItemBuyout or 0 return itemBuyout == 0 and (isAscending and math.huge or -math.huge) or itemBuyout elseif id == "buyout" then local buyout = row:GetBuyouts() or 0 return buyout == 0 and (isAscending and math.huge or -math.huge) or buyout elseif id == "bidPct" then local _, pct = self:_GetMarketValuePct(row) return pct or (isAscending and math.huge or -math.huge) elseif id == "pct" then local pct = self:_GetMarketValuePct(row) return pct or (isAscending and math.huge or -math.huge) else error("Invalid sort col id: "..tostring(id)) end end function AuctionScrollingTable._GetTableRow(self, isHeader) local row = self.__super:_GetTableRow(isHeader) if not isHeader then for _, tooltipFrame in pairs(row._buttons) do ScriptWrapper.SetPropagate(tooltipFrame, "OnDoubleClick") end ScriptWrapper.Set(row._frame, "OnDoubleClick", private.RowOnDoubleClick, row) end return row end function AuctionScrollingTable._GetMarketValuePct(self, row) if not self._marketValueFunc then -- no market value function was set return nil, nil end local marketValue = self._marketValueFunc(row) or 0 if marketValue == 0 then -- this item doesn't have a market value return nil, nil end local _, itemBuyout, minItemBuyout = row:GetBuyouts() itemBuyout = itemBuyout or minItemBuyout or 0 local bidPct = nil if row:IsSubRow() then local _, itemDisplayedBid = row:GetDisplayedBids() bidPct = itemDisplayedBid / marketValue end return itemBuyout > 0 and itemBuyout / marketValue or nil, bidPct end function AuctionScrollingTable._ToggleSort(self, id) if not self._sortCol or not self._auctionScan then -- sorting disabled so ignore return end local sortCol = nil for _, col in ipairs(self._tableInfo:_GetCols()) do if col:_GetId() == id then sortCol = col:_GetId() end end assert(sortCol) if sortCol == self._sortCol then self._sortAscending = not self._sortAscending else self._sortCol = sortCol self._sortAscending = true end if self._selection then self._selectionBaseSortValue = self:_GetSortValue(self._selection, self._sortCol, self._sortAscending) end self:UpdateData(true) end function AuctionScrollingTable._SetRowData(self, row, data) local ownerStr = private.GetSellerCellText(self, data) local isPlayer = false if ownerStr ~= "" then for owner in String.SplitIterator(ownerStr, ",") do if PlayerInfo.IsPlayer(owner, true, true, true) then isPlayer = true break end end end if isPlayer then row._texts.seller:SetTextColor(0.3, 0.6, 1, 1) else row._texts.seller:SetTextColor(1, 1, 1, 1) end self.__super:_SetRowData(row, data) end -- ============================================================================ -- Local Script Handlers -- ============================================================================ function private.RowOnDoubleClick(row, mouseButton) if mouseButton ~= "LeftButton" then return end local self = row._scrollingTable local subRow = row:GetData() local baseItemString = subRow:GetBaseItemString() self._expanded[baseItemString] = not self._expanded[baseItemString] self:UpdateData(true) end -- ============================================================================ -- Private Helper Functions -- ============================================================================ function private.SortRowAscendingHelper(a, b) local sortContext = private.sortContext local aSortValue = sortContext.rowSortValue[a] local bSortValue = sortContext.rowSortValue[b] if aSortValue == bSortValue then return a:GetBaseItemString() < b:GetBaseItemString() end return aSortValue < bSortValue end function private.SortRowDescendingHelper(a, b) local sortContext = private.sortContext local aSortValue = sortContext.rowSortValue[a] local bSortValue = sortContext.rowSortValue[b] if aSortValue == bSortValue then return a:GetBaseItemString() > b:GetBaseItemString() end return aSortValue > bSortValue end function private.SortSubRowAscendingHelper(a, b) local sortContext = private.sortContext local aBaseItemString = a:GetBaseItemString() local bBaseItemString = b:GetBaseItemString() if aBaseItemString == bBaseItemString then local aSortValue = sortContext.sortValue[a] local bSortValue = sortContext.sortValue[b] if aSortValue == bSortValue then -- always show base records first local self = sortContext.self if self._firstSubRowByItem[aBaseItemString] == a then return true elseif self._firstSubRowByItem[bBaseItemString] == b then return false else -- order by buyout local _, aItemBuyout = a:GetBuyouts() local _, bItemBuyout = b:GetBuyouts() if aItemBuyout ~= bItemBuyout then return aItemBuyout < bItemBuyout end -- show the higher auctionId first local _, aAuctionId, aBrowseId = a:GetListingInfo() local _, bAuctionId, bBrowseId = b:GetListingInfo() if aAuctionId ~= bAuctionId then return aAuctionId > bAuctionId else return aBrowseId > bBrowseId end end end return aSortValue < bSortValue else -- we're sorting different items local aSortValue = sortContext.baseSortValue[aBaseItemString] local bSortValue = sortContext.baseSortValue[bBaseItemString] if aSortValue == bSortValue then return aBaseItemString < bBaseItemString end return aSortValue < bSortValue end end function private.SortSubRowDescendingHelper(a, b) local sortContext = private.sortContext local aBaseItemString = a:GetBaseItemString() local bBaseItemString = b:GetBaseItemString() if aBaseItemString == bBaseItemString then local aSortValue = sortContext.sortValue[a] local bSortValue = sortContext.sortValue[b] if aSortValue == bSortValue then -- always show base records first local self = sortContext.self if self._firstSubRowByItem[aBaseItemString] == a then return true elseif self._firstSubRowByItem[bBaseItemString] == b then return false else -- order by buyout local _, aItemBuyout = a:GetBuyouts() local _, bItemBuyout = b:GetBuyouts() if aItemBuyout ~= bItemBuyout then return aItemBuyout < bItemBuyout end -- show the higher auctionId first local _, aAuctionId, aBrowseId = a:GetListingInfo() local _, bAuctionId, bBrowseId = b:GetListingInfo() if aAuctionId ~= bAuctionId then return aAuctionId > bAuctionId else return aBrowseId > bBrowseId end end end return aSortValue > bSortValue else -- we're sorting different items local aSortValue = sortContext.baseSortValue[aBaseItemString] local bSortValue = sortContext.baseSortValue[bBaseItemString] if aSortValue == bSortValue then return aBaseItemString > bBaseItemString end return aSortValue > bSortValue end end function private.GetItemCellText(self, subRow) local isIndented = subRow:IsSubRow() if not subRow:IsSubRow() then local baseItemString = subRow:GetBaseItemString() local itemString = subRow:GetItemString() subRow = self._firstSubRowByItem[baseItemString] if not subRow then return TSM.UI.GetColoredItemName(itemString or baseItemString, 0) end end local itemLink = subRow:GetLinks() -- TODO: use theme constant for indented tint pct return TSM.UI.GetColoredItemName(itemLink, isIndented and -20 or 0) end function private.GetItemLevelCellText(self, subRow) if not subRow:IsSubRow() then local baseItemString = subRow:GetBaseItemString() local itemString = subRow:GetItemString() subRow = self._firstSubRowByItem[baseItemString] if not subRow then return ItemInfo.GetItemLevel(itemString or baseItemString) end end local itemLink = subRow:GetLinks() return ItemInfo.GetItemLevel(itemLink) end function private.GetAuctionsQuantityText(self, subRow) if not subRow:IsSubRow() then local baseItemString = subRow:GetBaseItemString() subRow = self._firstSubRowByItem[baseItemString] or subRow end local quantity, numAuctions = subRow:GetQuantities() if not quantity or not numAuctions then return "" end return quantity * numAuctions end function private.GetAuctionsPostsText(self, subRow) if not subRow:IsSubRow() then local baseItemString = subRow:GetBaseItemString() subRow = self._firstSubRowByItem[baseItemString] or subRow end local _, numAuctions = subRow:GetQuantities() return numAuctions end function private.GetAuctionsStackText(self, subRow) if not subRow:IsSubRow() then local baseItemString = subRow:GetBaseItemString() subRow = self._firstSubRowByItem[baseItemString] or subRow end local quantity = subRow:GetQuantities() return quantity end function private.GetTimeLeftCellText(self, subRow) if not subRow:IsSubRow() then local baseItemString = subRow:GetBaseItemString() subRow = self._firstSubRowByItem[baseItemString] if not subRow then return "" end end local timeLeft = subRow:GetListingInfo() return TSM.UI.GetTimeLeftString(timeLeft) end function private.GetSellerCellText(self, subRow) if not subRow:IsSubRow() then local baseItemString = subRow:GetBaseItemString() subRow = self._firstSubRowByItem[baseItemString] if not subRow then return "" end end local ownerStr = subRow:GetOwnerInfo() return ownerStr end function private.GetItemBidCellText(self, subRow) if not subRow:IsSubRow() then local baseItemString = subRow:GetBaseItemString() subRow = self._firstSubRowByItem[baseItemString] if not subRow then return "" end end local _, itemDisplayedBid = subRow:GetDisplayedBids() local _, _, _, isHighBidder = subRow:GetBidInfo() return Money.ToString(itemDisplayedBid, isHighBidder and Theme.GetFeedbackColor("GREEN"):GetTextColorPrefix() or nil, "OPT_83_NO_COPPER") end function private.GetBidCellText(self, subRow) if not subRow:IsSubRow() then local baseItemString = subRow:GetBaseItemString() subRow = self._firstSubRowByItem[baseItemString] if not subRow then return "" end end local displayedBid = subRow:GetDisplayedBids() local _, _, _, isHighBidder = subRow:GetBidInfo() return Money.ToString(displayedBid, isHighBidder and Theme.GetFeedbackColor("GREEN"):GetTextColorPrefix() or nil, "OPT_83_NO_COPPER") end function private.GetItemBuyoutCellText(self, subRow) if not subRow:IsSubRow() then local baseItemString = subRow:GetBaseItemString() subRow = self._firstSubRowByItem[baseItemString] or subRow end local _, itemBuyout, minItemBuyout = subRow:GetBuyouts() local value = itemBuyout or minItemBuyout if not value then return "" end return Money.ToString(value, nil, "OPT_83_NO_COPPER") end function private.GetBuyoutCellText(self, subRow) if not subRow:IsSubRow() then local baseItemString = subRow:GetBaseItemString() subRow = self._firstSubRowByItem[baseItemString] or subRow end local buyout = subRow:GetBuyouts() if not buyout then return "" end return Money.ToString(buyout, nil, "OPT_83_NO_COPPER") end function private.GetBidPercentCellText(self, subRow) if not subRow:IsSubRow() then local baseItemString = subRow:GetBaseItemString() subRow = self._firstSubRowByItem[baseItemString] or subRow end local _, pct = self:_GetMarketValuePct(subRow) pct = pct and Math.Round(pct * 100) or nil if not pct then return "---" end local pctColor = Theme.GetAuctionPercentColor(pct) if pct > 999 then pct = ">999" end return pctColor:ColorText(pct.."%") end function private.GetPercentCellText(self, subRow) if not subRow:IsSubRow() then local baseItemString = subRow:GetBaseItemString() subRow = self._firstSubRowByItem[baseItemString] or subRow end local pct, bidPct = self:_GetMarketValuePct(subRow) pct = pct and Math.Round(pct * 100) or nil bidPct = bidPct and Math.Round(bidPct * 100) or nil if pct then local pctColor = Theme.GetAuctionPercentColor(pct) if pct > 999 then pct = ">999" end return pctColor:ColorText(pct.."%") elseif bidPct then local pctColor = Theme.GetAuctionPercentColor("BID") if bidPct > 999 then bidPct = ">999" end return pctColor:ColorText(bidPct.."%") else return "---" end end function private.GetItemCellIcon(self, subRow) if not subRow:IsSubRow() then local baseItemString = subRow:GetBaseItemString() subRow = self._firstSubRowByItem[baseItemString] if not subRow then return ItemInfo.GetTexture(baseItemString) end end local itemLink = subRow:GetLinks() return ItemInfo.GetTexture(itemLink) end function private.GetItemCellTooltip(self, subRow) local baseItemString = subRow:GetBaseItemString() local itemString = subRow:GetItemString() if not subRow:IsSubRow() then subRow = self._firstSubRowByItem[baseItemString] or subRow baseItemString = subRow:GetBaseItemString() itemString = subRow:GetItemString() end if subRow:IsSubRow() then local _, rawLink = subRow:GetLinks() return rawLink or itemString or baseItemString else return itemString or baseItemString end end function private.GetExpanderState(self, subRow) if not subRow:IsSubRow() then local baseItemString = subRow:GetBaseItemString() subRow = self._firstSubRowByItem[baseItemString] if not subRow then return false, false, 0 end end local baseItemString = subRow:GetBaseItemString() local isExpanded = self._expanded[baseItemString] local isIndented = isExpanded and subRow ~= self._firstSubRowByItem[baseItemString] local numSubRows = subRow:GetResultRow():GetNumSubRows() local expanderVisible = not isIndented and numSubRows > 1 return expanderVisible, expanderVisible and isExpanded, isIndented and 1 or 0 end function private.GetBadgeState(self, subRow) if not subRow:IsSubRow() then local baseItemString = subRow:GetBaseItemString() subRow = self._firstSubRowByItem[baseItemString] if not subRow then return false end end local baseItemString = subRow:GetBaseItemString() local numSubRows = subRow:GetResultRow():GetNumSubRows() local isVisible = not self._expanded[baseItemString] and numSubRows > 1 return isVisible, numSubRows > 999 and "(999+)" or ("("..numSubRows..")") end function private.GetPendingIcon(self, subRow, iconIndex) assert(iconIndex == 1) if not subRow:IsSubRow() then local baseItemString = subRow:GetBaseItemString() subRow = self._firstSubRowByItem[baseItemString] if not subRow then local texture, shouldRotate = nil, nil if baseItemString == self._currentSearchItem then local _, isPaused = self._auctionScan:GetProgress() texture = "iconPack.12x12/Running" shouldRotate = not isPaused else texture = TSM.UI.TexturePacks.GetColoredKey("iconPack.12x12/Running", "ACTIVE_BG_ALT") shouldRotate = false end return true, texture, true, nil, shouldRotate end end return false end function private.OnPendingIconClick(self, data) self:SetSelection(data) end