Files
aux-addon-ClassicAPI/aux-addon/gui/auction_listing.lua
T
geojak 02cfc420dd aux auto bid and price heuristics
this commit does two things
1. it implements auto bid just like auto buy
2. it has some minimum pricing heuristics when posting items. this behavoiur actiaves when the post bid price is set to 0, the buyout price behaves like a minimum
2022-02-20 23:51:19 +01:00

1046 lines
37 KiB
Lua

module 'aux.gui.auction_listing'
local T = require 'T'
local aux = require 'aux'
local info = require 'aux.util.info'
local sort_util = require 'aux.util.sort'
local money = require 'aux.util.money'
local history = require 'aux.core.history'
local gui = require 'aux.gui'
local tooltip = require 'aux.core.tooltip'
local price_per_unit = false
local HEAD_HEIGHT = 27
local HEAD_SPACE = 2
local TIME_LEFT_STRINGS = {
aux.color.red'30m', -- Short
aux.color.orange'2h', -- Medium
aux.color.yellow'8h', -- Long
aux.color.blue'24h', -- Very Long
}
function item_column_init(rt, cell)
local spacer = CreateFrame('Frame', nil, cell)
spacer:SetPoint('TOPLEFT', 0, 0)
spacer:SetHeight(rt.ROW_HEIGHT)
spacer:SetWidth(1)
cell.spacer = spacer
local iconBtn = CreateFrame('Button', nil, cell)
iconBtn:SetPoint('TOPLEFT', spacer, 'TOPRIGHT')
iconBtn:SetHeight(rt.ROW_HEIGHT)
iconBtn:SetWidth(rt.ROW_HEIGHT)
iconBtn:SetScript('OnEnter', rt.OnIconEnter)
iconBtn:SetScript('OnLeave', rt.OnIconLeave)
iconBtn:SetScript('OnClick', rt.OnIconClick)
iconBtn:SetScript('OnDoubleClick', rt.OnIconDoubleClick)
local icon = iconBtn:CreateTexture(nil, 'ARTWORK')
icon:SetPoint('TOPLEFT', 2, -2)
icon:SetPoint('BOTTOMRIGHT', -2, 2)
icon:SetTexCoord(.08, .92, .08, .92)
cell.iconBtn = iconBtn
cell.icon = icon
cell.text:ClearAllPoints()
cell.text:SetPoint('TOPLEFT', iconBtn, 'TOPRIGHT', 2, 0)
cell.text:SetPoint('BOTTOMRIGHT', 0, 0)
end
function item_column_fill(cell, record, _, _, _, indented)
cell.icon:SetTexture(record.texture)
if indented then
cell.spacer:SetWidth(10)
cell.icon:SetAlpha(.5)
cell.text:SetAlpha(.7)
else
cell.spacer:SetWidth(1)
cell.icon:SetAlpha(1)
cell.text:SetAlpha(1)
end
cell.text:SetText(gsub(record.link, '[%[%]]', ''))
end
M.search_columns = {
{
title = 'Item',
width = .35,
init = item_column_init,
fill = item_column_fill,
cmp = function(record_a, record_b, desc)
return sort_util.compare(record_a.name, record_b.name, desc)
end,
},
{
title = 'Lvl',
width = .035,
align = 'CENTER',
fill = function(cell, record)
local display_level = max(record.level, 1)
display_level = UnitLevel'player' < record.level and aux.color.red(display_level) or display_level
cell.text:SetText(display_level)
end,
cmp = function(record_a, record_b, desc)
return sort_util.compare(record_a.level, record_b.level, desc)
end,
},
{
title = 'Auctions',
width = .06,
align = 'CENTER',
fill = function(cell, record, count, own, expandable)
local numAuctionsText = expandable and aux.color.link(count) or count
if own > 0 then
numAuctionsText = numAuctionsText .. (' ' .. aux.color.yellow('(' .. own .. ')'))
end
cell.text:SetText(numAuctionsText)
end,
cmp = function(record_a, record_b, desc)
return sort_util.EQ
-- if sortKey == 'numAuctions' then
-- if a.children then
-- aVal = a.totalAuctions
-- bVal = b.totalAuctions
-- else
-- aVal = a.numAuctions
-- bVal = b.numAuctions
-- end
-- end
end,
},
{
title = 'Stack\nSize',
width = .055,
align = 'CENTER',
fill = function(cell, record)
cell.text:SetText(record.aux_quantity)
end,
cmp = function(record_a, record_b, desc)
return sort_util.compare(record_a.aux_quantity, record_b.aux_quantity, desc)
end,
},
{
title = 'Time\nLeft',
width = .04,
align = 'CENTER',
fill = function(cell, record)
cell.text:SetText(TIME_LEFT_STRINGS[record.duration or 0] or '?')
end,
cmp = function(record_a, record_b, desc)
return sort_util.compare(record_a.duration, record_b.duration, desc)
end,
},
{
title = 'Seller',
width = .13,
align = 'CENTER',
fill = function(cell, record)
cell.text:SetText(info.is_player(record.owner) and (aux.color.yellow(record.owner)) or (record.owner or '?'))
end,
cmp = function(record_a, record_b, desc)
if not record_a.owner and not record_b.owner then
return sort_util.EQ
elseif not record_a.owner then
return sort_util.GT
elseif not record_b.owner then
return sort_util.LT
else
return sort_util.compare(record_a.owner, record_b.owner, desc)
end
end,
},
{
title = {'Auction Bid\n(per item)', 'Auction Bid\n(per stack)'},
width = .125,
align = 'RIGHT',
isPrice = true,
fill = function(cell, record)
local price_color
if record.high_bidder then
price_color = aux.color.green
elseif record.high_bid ~= 0 then
price_color = aux.color.orange
end
local price
if record.high_bidder then
price = price_per_unit and ceil(record.high_bid / record.aux_quantity) or record.high_bid
else
price = price_per_unit and ceil(record.unit_bid_price) or record.bid_price
end
cell.text:SetText(money.to_string(price, true, false, price_color))
end,
cmp = function(record_a, record_b, desc)
local price_a
if record_a.high_bidder then
price_a = price_per_unit and record_a.high_bid / record_a.aux_quantity or record_a.high_bid
else
price_a = price_per_unit and record_a.unit_bid_price or record_a.bid_price
end
local price_b
if record_b.high_bidder then
price_b = price_per_unit and record_b.high_bid / record_b.aux_quantity or record_b.high_bid
else
price_b = price_per_unit and record_b.unit_bid_price or record_b.bid_price
end
if record_a.high_bidder and not record_b.high_bidder then
return sort_util.GT
elseif record_b.high_bidder and not record_a.high_bidder then
return sort_util.LT
end
if price_a == price_b then
if record_a.high_bid == 0 and record_b.high_bid ~= 0 then
return sort_util.GT
elseif record_b.high_bid == 0 and record_a.high_bid ~= 0 then
return sort_util.LT
end
end
return sort_util.compare(price_a, price_b, desc)
end,
},
{
title = {'Auction Buyout\n(per item)', 'Auction Buyout\n(per stack)'},
width = .125,
align = 'RIGHT',
isPrice = true,
fill = function(cell, record)
local price = price_per_unit and ceil(record.unit_buyout_price) or record.buyout_price
cell.text:SetText(price > 0 and money.to_string(price, true) or '---')
end,
cmp = function(record_a, record_b, desc)
local price_a = price_per_unit and record_a.unit_buyout_price or record_a.buyout_price
local price_b = price_per_unit and record_b.unit_buyout_price or record_b.buyout_price
price_a = price_a > 0 and price_a or (desc and -aux.huge or aux.huge)
price_b = price_b > 0 and price_b or (desc and -aux.huge or aux.huge)
return sort_util.compare(price_a, price_b, desc)
end,
},
{
title = '% Hist.\nValue',
width = .08,
align = 'CENTER',
fill = function(cell, record)
local pct, bidPct = record_percentage(record)
cell.text:SetText((pct or bidPct) and gui.percentage_historical(pct or bidPct, not pct) or '?')
end,
cmp = function(record_a, record_b, desc)
local pct_a = record_percentage(record_a) or (desc and -aux.huge or aux.huge)
local pct_b = record_percentage(record_b) or (desc and -aux.huge or aux.huge)
return sort_util.compare(pct_a, pct_b, desc)
end,
},
}
M.auctions_columns = {
{
title = 'Item',
width = .35,
init = item_column_init,
fill = item_column_fill,
cmp = function(record_a, record_b, desc)
return sort_util.compare(record_a.name, record_b.name, desc)
end,
},
{
title = 'Lvl',
width = .035,
align = 'CENTER',
fill = function(cell, record)
local display_level = max(record.level, 1)
display_level = UnitLevel('player') < record.level and aux.color.red(display_level) or display_level
cell.text:SetText(display_level)
end,
cmp = function(record_a, record_b, desc)
return sort_util.compare(record_a.level, record_b.level, desc)
end,
},
{
title = 'Auctions',
width = .06,
align = 'CENTER',
fill = function(cell, record, count, own, expandable)
local numAuctionsText = expandable and aux.color.link(count) or count
cell.text:SetText(numAuctionsText)
end,
cmp = function(record_a, record_b, desc)
return sort_util.EQ
-- if sortKey == 'numAuctions' then
-- if a.children then
-- aVal = a.totalAuctions
-- bVal = b.totalAuctions
-- else
-- aVal = a.numAuctions
-- bVal = b.numAuctions
-- end
-- end
end,
},
{
title = 'Stack\nSize',
width = .055,
align = 'CENTER',
fill = function(cell, record)
cell.text:SetText(record.aux_quantity)
end,
cmp = function(record_a, record_b, desc)
return sort_util.compare(record_a.aux_quantity, record_b.aux_quantity, desc)
end,
},
{
title = 'Time\nLeft',
width = .04,
align = 'CENTER',
fill = function(cell, record)
cell.text:SetText(TIME_LEFT_STRINGS[record.duration or 0] or '?')
end,
cmp = function(record_a, record_b, desc)
return sort_util.compare(record_a.duration, record_b.duration, desc)
end,
},
{
title = {'Auction Bid\n(per item)', 'Auction Bid\n(per stack)'},
width = .125,
align = 'RIGHT',
isPrice = true,
fill = function(cell, record)
local price
if record.high_bidder then
price = price_per_unit and ceil(record.high_bid / record.aux_quantity) or record.high_bid
else
price = price_per_unit and ceil(record.start_price / record.aux_quantity) or record.start_price
end
cell.text:SetText(money.to_string(price, true))
end,
cmp = function(record_a, record_b, desc)
local price_a
if record_a.high_bidder then
price_a = price_per_unit and record_a.high_bid / record_a.aux_quantity or record_a.high_bid
else
price_a = price_per_unit and record_a.start_price / record_b.aux_quantity or record_a.start_price
end
local price_b
if record_b.high_bidder then
price_b = price_per_unit and record_b.high_bid / record_b.aux_quantity or record_b.high_bid
else
price_b = price_per_unit and record_b.start_price / record_b.aux_quantity or record_b.start_price
end
return sort_util.compare(price_a, price_b, desc)
end,
},
{
title = {'Auction Buyout\n(per item)', 'Auction Buyout\n(per stack)'},
width = .125,
align = 'RIGHT',
isPrice = true,
fill = function(cell, record)
local price = price_per_unit and ceil(record.unit_buyout_price) or record.buyout_price
cell.text:SetText(price > 0 and money.to_string(price, true) or '---')
end,
cmp = function(record_a, record_b, desc)
local price_a = price_per_unit and record_a.unit_buyout_price or record_a.buyout_price
local price_b = price_per_unit and record_b.unit_buyout_price or record_b.buyout_price
price_a = price_a > 0 and price_a or (desc and -aux.huge or aux.huge)
price_b = price_b > 0 and price_b or (desc and -aux.huge or aux.huge)
return sort_util.compare(price_a, price_b, desc)
end,
},
{
title = 'High Bidder',
width = .21,
align = 'CENTER',
fill = function(cell, record)
cell.text:SetText(record.high_bidder or aux.color.red 'No Bids')
end,
cmp = function(record_a, record_b, desc)
if not record_a.high_bidder and not record_b.high_bidder then
return sort_util.EQ
elseif not record_a.high_bidder then
return sort_util.GT
elseif not record_b.high_bidder then
return sort_util.LT
else
return sort_util.compare(record_a.high_bidder, record_b.high_bidder, desc)
end
end,
},
}
M.bids_columns = {
{
title = 'Item',
width = .35,
init = item_column_init,
fill = item_column_fill,
cmp = function(record_a, record_b, desc)
return sort_util.compare(record_a.name, record_b.name, desc)
end,
},
{
title = 'Auctions',
width = .06,
align = 'CENTER',
fill = function(cell, record, count, own, expandable)
local numAuctionsText = expandable and aux.color.link(count) or count
cell.text:SetText(numAuctionsText)
end,
cmp = function(record_a, record_b, desc)
return sort_util.EQ
-- if sortKey == 'numAuctions' then
-- if a.children then
-- aVal = a.totalAuctions
-- bVal = b.totalAuctions
-- else
-- aVal = a.numAuctions
-- bVal = b.numAuctions
-- end
-- end
end,
},
{
title = 'Stack\nSize',
width = .055,
align = 'CENTER',
fill = function(cell, record)
cell.text:SetText(record.aux_quantity)
end,
cmp = function(record_a, record_b, desc)
return sort_util.compare(record_a.aux_quantity, record_b.aux_quantity, desc)
end,
},
{
title = 'Time\nLeft',
width = .04,
align = 'CENTER',
fill = function(cell, record)
cell.text:SetText(TIME_LEFT_STRINGS[record.duration or 0] or '?')
end,
cmp = function(record_a, record_b, desc)
return sort_util.compare(record_a.duration, record_b.duration, desc)
end,
},
{
title = 'Seller',
width = .13,
align = 'CENTER',
fill = function(cell, record)
cell.text:SetText(info.is_player(record.owner) and (aux.color.yellow(record.owner)) or (record.owner or '?'))
end,
cmp = function(record_a, record_b, desc)
if not record_a.owner and not record_b.owner then
return sort_util.EQ
elseif not record_a.owner then
return sort_util.GT
elseif not record_b.owner then
return sort_util.LT
else
return sort_util.compare(record_a.owner, record_b.owner, desc)
end
end,
},
{
title = {'Auction Bid\n(per item)', 'Auction Bid\n(per stack)'},
width = .125,
align = 'RIGHT',
isPrice = true,
fill = function(cell, record)
local price
if record.high_bidder then
price = price_per_unit and ceil(record.high_bid / record.aux_quantity) or record.high_bid
else
price = price_per_unit and ceil(record.unit_bid_price) or record.bid_price
end
cell.text:SetText(money.to_string(price))
end,
cmp = function(record_a, record_b, desc)
local price_a
if record_a.high_bidder then
price_a = price_per_unit and record_a.high_bid / record_a.aux_quantity or record_a.high_bid
else
price_a = price_per_unit and record_a.unit_bid_price or record_a.bid_price
end
local price_b
if record_b.high_bidder then
price_b = price_per_unit and record_b.high_bid / record_b.aux_quantity or record_b.high_bid
else
price_b = price_per_unit and record_b.unit_bid_price or record_b.bid_price
end
return sort_util.compare(price_a, price_b, desc)
end,
},
{
title = {'Auction Buyout\n(per item)', 'Auction Buyout\n(per stack)'},
width = .125,
align = 'RIGHT',
isPrice = true,
fill = function(cell, record)
local price = price_per_unit and ceil(record.unit_buyout_price) or record.buyout_price
cell.text:SetText(price > 0 and money.to_string(price, true) or '---')
end,
cmp = function(record_a, record_b, desc)
local price_a = price_per_unit and record_a.unit_buyout_price or record_a.buyout_price
local price_b = price_per_unit and record_b.unit_buyout_price or record_b.buyout_price
price_a = price_a > 0 and price_a or (desc and -aux.huge or aux.huge)
price_b = price_b > 0 and price_b or (desc and -aux.huge or aux.huge)
return sort_util.compare(price_a, price_b, desc)
end,
},
{
title = 'Status',
width = .115,
align = 'CENTER',
fill = function(cell, record)
local status
if record.high_bidder then
status = aux.color.yellow'High Bidder'
else
status = aux.color.red'Outbid'
end
cell.text:SetText(status)
end,
cmp = function(record_a, record_b, desc)
return sort_util.compare(record_a.high_bidder and 1 or 0, record_b.high_bidder and 1 or 0, desc)
end,
},
}
function record_percentage(record)
if not record then return end
local historical_value = history.value(record.item_key) or 0
if historical_value > 0 then
if record.unit_buyout_price > 0 then
return aux.round(100 * record.unit_buyout_price / historical_value)
end
return nil, aux.round(100 * record.unit_bid_price / historical_value)
end
end
function M.time_left(code)
return TIME_LEFT_STRINGS[code]
end
local methods = {
ResizeColumns = function(self)
local weight = 0
for _, cell in self.headCells do
weight = weight + cell.info.width
end
weight = (self.contentFrame:GetRight() - self.contentFrame:GetLeft()) / weight
for i, cell in self.headCells do
local width = cell.info.width * weight
cell:SetWidth(width)
for _, row in self.rows do
row.cells[i]:SetWidth(width)
end
end
end,
OnHeadColumnClick = function()
local button = arg1
local rt = this.rt
if button == 'RightButton' and rt.headCells[this.columnIndex].info.isPrice then
price_per_unit = not price_per_unit
for _, cell in rt.headCells do
if cell.info.isPrice then
cell:SetText(cell.info.title[price_per_unit and 1 or 2])
end
end
rt:SetSort()
return
end
local descending = false
if getn(rt.sorts) > 0 and rt.sorts[1].index == this.columnIndex then
descending = not rt.sorts[1].descending
end
rt:SetSort((descending and -1 or 1) * this.columnIndex)
end,
OnIconEnter = function()
local rt = this:GetParent().row.rt
local row = this:GetParent().row
if row.record then
GameTooltip:SetOwner(this, 'ANCHOR_RIGHT')
info.load_tooltip(GameTooltip, row.record.tooltip)
tooltip.extend_tooltip(GameTooltip, row.record.link, row.record.aux_quantity)
info.set_shopping_tooltip(row.record.slot)
end
end,
OnIconLeave = function()
GameTooltip:Hide()
end,
OnEnter = function()
local rt = this.rt
if rt.expanded[this.expandKey] then
GameTooltip_SetDefaultAnchor(GameTooltip, UIParent)
GameTooltip:AddLine('Double-click to collapse this item and show only the cheapest auction.', 1, 1, 1, true)
GameTooltip:Show()
elseif this.expandable then
GameTooltip_SetDefaultAnchor(GameTooltip, UIParent)
GameTooltip:AddLine('Double-click to expand this item and show all the auctions.', 1, 1, 1, true)
GameTooltip:Show()
end
this.highlight:Show()
end,
OnLeave = function()
GameTooltip:Hide()
if not this.rt.selected or this.rt.selected.search_signature ~= this.record.search_signature then
this.highlight:Hide()
end
end,
OnClick = function()
local button = arg1
if IsControlKeyDown() then
DressUpItemLink(this.record.link)
elseif IsShiftKeyDown() and ChatFrameEditBox:IsVisible() then
ChatFrameEditBox:Insert(this.record.link)
else
local selection = this.rt:GetSelection()
if not selection or selection.record ~= this.record then
this.rt:SetSelectedRecord(this.record)
end
do (this.rt.handlers.OnClick or pass)(this, button) end
end
end,
OnDoubleClick = function()
local rt = this.rt
local expand = not rt.expanded[this.expandKey]
rt.expanded[this.expandKey] = expand
rt:UpdateRowInfo()
rt:UpdateRows()
if not this.indented then
rt:SetSelectedRecord(this.record)
end
end,
UpdateRowInfo = function(self)
for _, v in ipairs(self.rowInfo) do
if type(v) == 'table' then
for _, child in v.children do
T.release(child)
end
T.release(v.children)
T.release(v)
end
end
T.wipe(self.rowInfo)
self.rowInfo.numDisplayRows = 0
self.isSorted = nil
self:SetSelectedRecord(nil, true)
local records = self.records
local single_item = aux.all(records, function(record) return record.item_key == records[1].item_key end)
sort(records, function(a, b) return a.search_signature < b.search_signature or a.search_signature == b.search_signature and tostring(a) < tostring(b) end)
for i = 1, getn(records) do
local record = records[i]
local prevRecord = records[i - 1]
if prevRecord and record.search_signature == prevRecord.search_signature then
-- it's an identical auction to the previous row so increment the number of auctions
self.rowInfo[getn(self.rowInfo)].children[getn(self.rowInfo[getn(self.rowInfo)].children)].count = self.rowInfo[getn(self.rowInfo)].children[getn(self.rowInfo[getn(self.rowInfo)].children)].count + 1
elseif not single_item and prevRecord and record.item_key == prevRecord.item_key then
-- it's the same base item as the previous row so insert a new auction
tinsert(self.rowInfo[getn(self.rowInfo)].children, T.map('count', 1, 'record', record))
if self.expanded[self.rowInfo[getn(self.rowInfo)].expandKey] then
self.rowInfo.numDisplayRows = self.rowInfo.numDisplayRows + 1
end
else
-- it's a different base item from the previous row
tinsert(self.rowInfo, T.map('item_key', record.item_key, 'expandKey', record.item_key, 'children', T.list(T.map('count', 1, 'record', record))))
self.rowInfo.numDisplayRows = self.rowInfo.numDisplayRows + 1
end
end
for _, v in ipairs(self.rowInfo) do
local totalAuctions, totalPlayerAuctions = 0, 0
for _, childInfo in v.children do
totalAuctions = totalAuctions + childInfo.count
if info.is_player(childInfo.record.owner) then
totalPlayerAuctions = totalPlayerAuctions + childInfo.count
end
end
v.totalAuctions = totalAuctions
v.totalPlayerAuctions = totalPlayerAuctions
end
end,
UpdateRows = function(self)
if self.rowInfo.numDisplayRows > getn(self.rows) then
self.contentFrame:SetPoint('BOTTOMRIGHT', -15, 0)
else
self.contentFrame:SetPoint('BOTTOMRIGHT', 0, 0)
end
self:ResizeColumns()
FauxScrollFrame_Update(self.scrollFrame, self.rowInfo.numDisplayRows, getn(self.rows), self.ROW_HEIGHT)
local maxOffset = max(self.rowInfo.numDisplayRows - getn(self.rows), 0)
if FauxScrollFrame_GetOffset(self.scrollFrame) > maxOffset then
FauxScrollFrame_SetOffset(self.scrollFrame, maxOffset)
end
for _, cell in self.headCells do
local tex = cell:GetNormalTexture()
tex:SetTexture[[Interface\AddOns\aux-AddOn\WorldStateFinalScore-Highlight]]
tex:SetTexCoord(.017, 1, .083, .909)
tex:SetAlpha(.5)
end
if getn(self.sorts) > 0 then
local last_sort = self.sorts[1]
if last_sort.descending then
self.headCells[last_sort.index]:GetNormalTexture():SetTexture(.8, .6, 1, .8)
else
self.headCells[last_sort.index]:GetNormalTexture():SetTexture(.6, .8, 1, .8)
end
end
if not self.isSorted then
local function sort_helper(a, b)
local record_a, record_b
if a.children then
record_a = a.children[1].record
record_b = b.children[1].record
else
record_a = a.record
record_b = b.record
end
for _, sort in self.sorts do
local ordering = self.columns[sort.index].cmp and self.columns[sort.index].cmp(record_a, record_b, sort.descending) or sort_util.EQ
if ordering == sort_util.LT then
return true
elseif ordering == sort_util.GT then
return false
end
end
return tostring(a) < tostring(b)
end
for _, v in ipairs(self.rowInfo) do
sort(v.children, sort_helper)
end
sort(self.rowInfo, sort_helper)
self.isSorted = true
end
for _, row in self.rows do
row:Hide()
end
local rowIndex = 1 - FauxScrollFrame_GetOffset(self.scrollFrame)
for _, v in ipairs(self.rowInfo) do
if self.expanded[v.expandKey] then
for j, childInfo in ipairs(v.children) do
self:SetRowInfo(rowIndex, childInfo.record, childInfo.count, 0, j > 1, false, v.expandKey)
rowIndex = rowIndex + 1
end
else
self:SetRowInfo(rowIndex, v.children[1].record, v.totalAuctions, getn(v.children) > 1 and v.totalPlayerAuctions or 0, false, getn(v.children) > 1, v.expandKey)
rowIndex = rowIndex + 1
end
end
end,
SetRowInfo = function(self, rowIndex, record, totalAuctions, totalPlayerAuctions, indented, expandable, expandKey)
if rowIndex <= 0 or rowIndex > getn(self.rows) then return end
local row = self.rows[rowIndex]
row:Show()
if self.selected and record.search_signature == self.selected.search_signature then
row.highlight:Show()
else
row.highlight:Hide()
end
row.record = record
row.expandable = expandable
row.indented = indented
row.expandKey = expandKey
for i, column in self.columns do
column.fill(row.cells[i], record, totalAuctions, totalPlayerAuctions, expandable, indented)
end
end,
SetSelectedRecord = function(self, record, silent)
self.selected = record
local selectedData = self:GetSelection()
self.selected = selectedData and self.selected or nil
for _, row in self.rows do
if self.selected and row.record and row.record.search_signature == self.selected.search_signature then
row.highlight:Show()
else
row.highlight:Hide()
end
end
if not silent and self.handlers.OnSelectionChanged then
self.handlers.OnSelectionChanged(self, selectedData or nil)
end
end,
Reset = function(self)
T.wipe(self.expanded)
self:UpdateRowInfo()
self:UpdateRows()
self:SetSelectedRecord()
end,
SetDatabase = function(self, database)
if database and database ~= self.records then
self.records = database
end
local prevSelectedIndex
if self.selected then
for i, row in self.rows do
if row:IsVisible() and row.record == self.selected then
prevSelectedIndex = i
end
end
end
self:UpdateRowInfo()
self:UpdateRows()
if not self.selected and prevSelectedIndex then
-- try to select the same row
local row = self.rows[prevSelectedIndex]
if row and row:IsVisible() and row.record then
self:SetSelectedRecord(row.record)
end
if not self.selected then
-- select the first row
row = self.rows[1]
if row and row:IsVisible() and row.record then
self:SetSelectedRecord(row.record)
end
end
end
end,
RemoveAuctionRecord = function(self, record)
local index = aux.key(self.records, record)
if index then
tremove(self.records, index)
end
self:SetDatabase()
end,
ContainsRecord = function(self, record)
if aux.key(self.records, record) then
return true
end
end,
SetSort = T.vararg-function(arg)
local self = tremove(arg, 1)
for _, v in ipairs(arg) do
for i, sort in self.sorts do
if sort.index == abs(v) then
tremove(self.sorts, i)
break
end
end
tinsert(self.sorts, 1, {index=abs(v), descending=v < 0})
end
self.isSorted = nil
self:UpdateRows()
end,
SetHandler = function(self, event, handler)
self.handlers[event] = handler
end,
GetSelection = function(self)
if not self.selected then return end
local selectedData
for _, v in ipairs(self.rowInfo) do
for _, childInfo in v.children do
if childInfo.record.search_signature == self.selected.search_signature then
selectedData = childInfo
break
end
end
end
return selectedData
end,
}
function M.new(parent, rows, columns)
local rt = CreateFrame('Frame', nil, parent)
rt.columns = columns
rt.ROW_HEIGHT = (parent:GetHeight() - HEAD_HEIGHT - HEAD_SPACE) / rows
rt.expanded = {}
rt.handlers = {}
rt.sorts = {}
rt.records = {}
rt.rowInfo = {numDisplayRows=0}
for name, func in methods do
rt[name] = func
end
rt:SetScript('OnShow', function()
for _, cell in this.headCells do
if cell.info.isPrice then
cell:SetText(cell.info.title[price_per_unit and 1 or 2])
end
end
end)
local contentFrame = CreateFrame('Frame', nil, rt)
contentFrame:SetPoint('TOPLEFT', 0, 0)
contentFrame:SetPoint('BOTTOMRIGHT', 0, 0)
rt.contentFrame = contentFrame
local scrollFrame = CreateFrame('ScrollFrame', gui.unique_name(), rt, 'FauxScrollFrameTemplate')
scrollFrame:SetScript('OnVerticalScroll', function()
FauxScrollFrame_OnVerticalScroll(rt.ROW_HEIGHT, function() rt:UpdateRows() end)
end)
scrollFrame:SetAllPoints(contentFrame)
rt.scrollFrame = scrollFrame
FauxScrollFrame_Update(rt.scrollFrame, 0, rows, rt.ROW_HEIGHT)
local scrollBar = _G[scrollFrame:GetName() .. 'ScrollBar']
scrollBar:ClearAllPoints()
scrollBar:SetPoint('TOPRIGHT', rt, -4, -HEAD_HEIGHT)
scrollBar:SetPoint('BOTTOMRIGHT', rt, -4, 4)
scrollBar:SetWidth(10)
local thumbTex = scrollBar:GetThumbTexture()
thumbTex:SetPoint('CENTER', 0, 0)
thumbTex:SetTexture(aux.color.content.background())
thumbTex:SetHeight(150)
thumbTex:SetWidth(scrollBar:GetWidth())
_G[scrollBar:GetName() .. 'ScrollUpButton']:Hide()
_G[scrollBar:GetName() .. 'ScrollDownButton']:Hide()
rt.headCells = {}
for i, column in ipairs(rt.columns) do
local cell = CreateFrame('Button', nil, rt.contentFrame)
cell:SetHeight(HEAD_HEIGHT)
if i == 1 then
cell:SetPoint('TOPLEFT', 0, 0)
else
cell:SetPoint('TOPLEFT', rt.headCells[i - 1], 'TOPRIGHT')
end
cell.info = column
cell.rt = rt
cell.columnIndex = i
cell:RegisterForClicks('LeftButtonUp', 'RightButtonUp')
cell:SetScript('OnClick', rt.OnHeadColumnClick)
local text = cell:CreateFontString()
text:SetJustifyH('CENTER')
text:SetFont(gui.font, 12)
text:SetTextColor(aux.color.label.enabled())
cell:SetFontString(text)
if not column.isPrice then cell:SetText(column.title or '') end -- TODO
text:SetAllPoints()
local tex = cell:CreateTexture()
tex:SetAllPoints()
tex:SetTexture([[Interface\AddOns\aux-AddOn\WorldStateFinalScore-Highlight]])
tex:SetTexCoord(.017, 1, .083, .909)
tex:SetAlpha(.5)
cell:SetNormalTexture(tex)
local tex = cell:CreateTexture()
tex:SetAllPoints()
tex:SetTexture([[Interface\Buttons\UI-Listbox-Highlight]])
tex:SetTexCoord(.025, .957, .087, .931)
tex:SetAlpha(.2)
cell:SetHighlightTexture(tex)
tinsert(rt.headCells, cell)
end
rt.rows = {}
for i = 1, rows do
local row = CreateFrame('Button', nil, rt.contentFrame)
row.rt = rt
row:SetHeight(rt.ROW_HEIGHT)
row:RegisterForClicks('LeftButtonUp', 'RightButtonUp')
row:SetScript('OnEnter', rt.OnEnter)
row:SetScript('OnLeave', rt.OnLeave)
row:SetScript('OnClick', rt.OnClick)
row:SetScript('OnDoubleClick', rt.OnDoubleClick)
if i == 1 then
row:SetPoint('TOPLEFT', 0, -(HEAD_HEIGHT + HEAD_SPACE))
row:SetPoint('TOPRIGHT', 0, -(HEAD_HEIGHT + HEAD_SPACE))
else
row:SetPoint('TOPLEFT', 0, -(HEAD_HEIGHT + HEAD_SPACE + (i - 1) * rt.ROW_HEIGHT))
row:SetPoint('TOPRIGHT', 0, -(HEAD_HEIGHT + HEAD_SPACE + (i - 1) * rt.ROW_HEIGHT))
end
local highlight = row:CreateTexture()
highlight:SetAllPoints()
highlight:SetTexture(1, .9, 0, .5)
highlight:Hide()
row.highlight = highlight
row.cells = {}
for j, column in ipairs(rt.columns) do
local cell = CreateFrame('Frame', nil, row)
local text = cell:CreateFontString()
cell.text = text
text:SetFont(gui.font, min(14, rt.ROW_HEIGHT))
text:SetJustifyH(column.align or 'LEFT')
text:SetJustifyV('CENTER')
text:SetPoint('TOPLEFT', 1, -1)
text:SetPoint('BOTTOMRIGHT', -1, 1)
cell:SetHeight(rt.ROW_HEIGHT)
cell.rt = rt
cell.row = row
if j == 1 then
cell:SetPoint('TOPLEFT', 0, 0)
else
cell:SetPoint('TOPLEFT', row.cells[j - 1], 'TOPRIGHT')
end
if mod(j, 2) == 1 then
local tex = cell:CreateTexture()
tex:SetAllPoints()
tex:SetTexture(.3, .3, .3, .2)
end
if column.init then
column.init(rt, cell)
end
tinsert(row.cells, cell)
end
if mod(i, 2) == 0 then
local tex = row:CreateTexture()
tex:SetAllPoints()
tex:SetTexture(.3, .3, .3, .3)
end
tinsert(rt.rows, row)
end
rt:SetAllPoints()
rt:ResizeColumns()
return rt
end