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 -- Initialize from account data when available aux.handle.LOAD = function() if aux.account_data and aux.account_data.price_per_unit ~= nil then price_per_unit = aux.account_data.price_per_unit end end 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'72h', -- 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 aux.account_data.price_per_unit = 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', gui.is_blizzard() and -30 or -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() if not gui.is_blizzard() then tex:SetTexture[[Interface\AddOns\aux-AddOn\WorldStateFinalScore-Highlight]] tex:SetTexCoord(.017, 1, .083, .909) tex:SetAlpha(.5) else tex:SetTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]]) tex:SetTexCoord(0.1, 0.8, 0, 1) tex:SetVertexColor(1, 1, 1) end end if getn(self.sorts) > 0 then local last_sort = self.sorts[1] local tex = self.headCells[last_sort.index]:GetNormalTexture() if last_sort.descending then if not gui.is_blizzard() then tex:SetTexture(.8, .6, 1, .8) else tex:SetVertexColor(0.75, .5, 1) end else if not gui.is_blizzard() then tex:SetTexture(.6, .8, 1, .8) else tex:SetVertexColor(.5, .75, 1) end 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) local rowLimit = getn(self.rows) for _, v in ipairs(self.rowInfo) do if rowIndex > rowLimit then break end if self.expanded[v.expandKey] then for j, childInfo in ipairs(v.children) do if rowIndex > rowLimit then break end 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 for _, v in ipairs(self.rowInfo) do for _, childInfo in v.children do if childInfo.record.search_signature == self.selected.search_signature then return childInfo end end end end, } function M.new(parent, rows, columns) local rt = CreateFrame('Frame', nil, parent) rt.columns = columns rt.ROW_HEIGHT = ((parent:GetHeight() / parent:GetEffectiveScale()) - 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) gui.set_scrollbar_style(scrollFrame, not gui.is_blizzard() and { {'TOPRIGHT', parent, -4, -HEAD_HEIGHT}, {'BOTTOMRIGHT', parent, -4, 4} -- Default } or { {'TOPRIGHT', parent, -7, -20}, {'BOTTOMRIGHT', parent, -7, 18} -- Blizzard }) 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() local highlight = cell:CreateTexture() tex:SetAllPoints() highlight:SetAllPoints() if not gui.is_blizzard() then tex:SetTexture([[Interface\AddOns\aux-AddOn\WorldStateFinalScore-Highlight]]) tex:SetTexCoord(.017, 1, .083, .909) tex:SetAlpha(.5) highlight:SetTexture([[Interface\Buttons\UI-Listbox-Highlight]]) highlight:SetTexCoord(.025, .957, .087, .931) else tex:SetTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]]) tex:SetTexCoord(0.1, 0.8, 0, 1) highlight:SetTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]]) highlight:SetTexCoord(0.1, 0.8, 0, 1) end highlight:SetAlpha(.2) cell:SetNormalTexture(tex) cell:SetHighlightTexture(highlight) 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() if not gui.is_blizzard() then highlight:SetTexture(1, .9, 0, .5) else highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") end 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 gui.is_blizzard() or mod(j, 2) == 1 then local tex = cell:CreateTexture() tex:SetAllPoints() if not gui.is_blizzard() then tex:SetTexture(.3, .3, .3, .2) else tex:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") tex:SetTexCoord(0.1, 0.8, 0, 1) tex:SetAlpha(0.3) end 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