1006 lines
33 KiB
Lua
1006 lines
33 KiB
Lua
|
-- ------------------------------------------------------------------------------ --
|
||
|
-- 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
|