diff --git a/Aux-AddOn.toc b/Aux-AddOn.toc index 350a027..a0c0b28 100644 --- a/Aux-AddOn.toc +++ b/Aux-AddOn.toc @@ -19,6 +19,7 @@ stack.lua post.lua sheet.lua listing.lua +auction_listing.lua listing_util.lua history.lua info.xml diff --git a/auction_listing.lua b/auction_listing.lua new file mode 100644 index 0000000..580e5b4 --- /dev/null +++ b/auction_listing.lua @@ -0,0 +1,794 @@ +local private, public = {} +Aux.auction_listing = public +local RT_COUNT = 1 +local HEAD_HEIGHT = 27 +local HEAD_SPACE = 2 +local AUCTION_PCT_COLORS = { + {color='|cff2992ff', value=50}, -- blue + {color='|cff16ff16', value=80}, -- green + {color='|cffffff00', value=110}, -- yellow + {color='|cffff9218', value=135}, -- orange + {color='|cffff0000', value=Aux.huge}, -- red +} +local TIME_LEFT_STRINGS = { + '|cffff000030m|r', -- Short + '|cffff92182h|r', -- Medium + '|cffffff0012h|r', -- Long + '|cff2992ff48h|r', -- Very Long +} + + +local methods = { + + OnContentSizeChanged = function() + local width = arg1 + local rt = this:GetParent() + for i, cell in ipairs(rt.headCells) do + cell:SetWidth(cell.info.width * width) + end + + for _, row in ipairs(rt.rows) do + for i, cell in ipairs(row.cells) do + cell:SetWidth(rt.headCells[i].info.width * width) + end + end + end, + + OnHeadColumnClick = function() + local button = arg1 + local rt = this.rt + if rt.disabled then return end + + if button == 'RightButton' and rt.headCells[this.columnIndex].info.isPrice then + aux_price_per_unit = not aux_price_per_unit + for i, cell in ipairs(rt.headCells) do + if cell.info.isPrice then + cell:SetText(cell.info.name[aux_price_per_unit and 1 or 2]) + end + end + rt:SetSort() + return + end + + local descending = false + if rt.sortInfo.columnIndex == this.columnIndex then + descending = not rt.sortInfo.descending + end + rt:SetSort((descending and -1 or 1) * this.columnIndex) + end, + +-- OnIconEnter = function() +-- local rt = this:GetParent().row.rt +-- local rowData = this:GetParent().row.data +-- if rowData and rowData.record then +-- GameTooltip:SetOwner(this, "ANCHOR_RIGHT") +-- TSMAPI.Util:SafeTooltipLink(rowData.record.rawItemLink) +-- GameTooltip:Show() +-- rt.isShowingItemTooltip = true +-- end +-- end, +-- +-- OnIconLeave = function() +-- GameTooltip:ClearLines() +-- GameTooltip:Hide() +-- this:GetParent().row.rt.isShowingItemTooltip = nil +-- end, + +-- OnIconClick = function(self, ...) +-- if IsModifiedClick() then +-- HandleModifiedItemClick(self:GetParent().row.data.record.rawItemLink) +-- else +-- self:GetParent():GetScript("OnClick")(self:GetParent(), ...) +-- end +-- end, +-- +-- OnIconDoubleClick = function(self, ...) +-- self:GetParent():GetScript("OnDoubleClick")(self:GetParent(), ...) +-- end, + + OnCellEnter = function() + local rt = this.rt + local row = this.row + if rt.disabled then return end + if this ~= row.cells[1] or not rt.isShowingItemTooltip then + if rt.expanded[row.data.expandKey] then + GameTooltip:SetOwner(this, 'ANCHOR_NONE') + GameTooltip:SetPoint('BOTTOMLEFT', this, 'TOPLEFT') + GameTooltip:AddLine('Double-click to collapse this item and show only the cheapest auction.', 1, 1, 1, true) + GameTooltip:Show() + elseif row.data.expandable then + GameTooltip:SetOwner(this, 'ANCHOR_NONE') + GameTooltip:SetPoint('BOTTOMLEFT', this, 'TOPLEFT') + GameTooltip:AddLine('Double-click to expand this item and show all the auctions.', 1, 1, 1, true) + GameTooltip:Show() + end + end + + -- show highlight for this row + this.row.highlight:Show() + end, + + OnCellLeave = function() + GameTooltip:Hide() + -- hide highlight if it's not selected + if not this.rt.selected or this.rt.selected.search_signature ~= this.row.data.record.search_signature then + this.row.highlight:Hide() + end + end, + + OnCellClick = function() + local button = arg1 + if this.rt.disabled then return end + this.rt:SetSelectedRecord(this.row.data.record) + end, + + OnCellDoubleClick = function() + local rt = this.rt + local rowData = this.row.data + local expand = not rt.expanded[rowData.expandKey] + if rt.disabled or expand and not rowData.expandable then return end + + rt.expanded[rowData.expandKey] = expand + rt:UpdateRowInfo() + rt:UpdateRows() + -- select this row if it's not indented + if not rowData.indented then + rt:SetSelectedRecord(this.row.data.record) + end + end, + + + -- ============================================================================ + -- Internal Results Table Methods + -- ============================================================================ + + -- GetRowPrices = function(record, isPerUnit) return end, -- TODO + GetRowPrices = function(record, per_unit) + if per_unit then + return record.unit_bid_price, record.unit_buyout_price + else + return record.bid_price, record.buyout_price + end + end, + + + GetRecordPercent = function(rt, record) + if not record then return end +-- cache the market value on the record +-- record.market_value = record.market_value or rt.GetMarketValue(record.item_key) or 0 +-- if record.marketValue > 0 then +-- if record.itemBuyout > 0 then +-- return Aux.round(100 * record.itemBuyout / record.marketValue, 1) +-- end +-- return nil, Aux.round(100 * record.itemDisplayedBid / record.marketValue, 1) +-- end + + local market_value = Aux.history.market_value(record.item_key) + if market_value and market_value > 0 then + if record.unit_buyout_price > 0 then + return Aux.round(100 * record.unit_buyout_price / market_value, 1) + end + return nil, Aux.round(100 * record.unit_bid_price / market_value, 1) + end + end, + + UpdateRowInfo = function(rt) + Aux.util.wipe(rt.rowInfo) + rt.rowInfo.numDisplayRows = 0 + rt.sortInfo.isSorted = nil + rt:SetSelectedRecord(nil, true) + + sort(rt.records, function(a,b) return a.search_signature < b.search_signature end) + + local records = rt.records + if getn(records) == 0 then return end + + -- Populate the row info from the database by combining identical auctions and auctions + -- of the same base item. Also, get the number of rows which will be shown. + 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 + rt.rowInfo[getn(rt.rowInfo)].children[getn(rt.rowInfo[getn(rt.rowInfo)].children)].numAuctions = rt.rowInfo[getn(rt.rowInfo)].children[getn(rt.rowInfo[getn(rt.rowInfo)].children)].numAuctions + 1 + elseif 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(rt.rowInfo[getn(rt.rowInfo)].children, {numAuctions=1, record=record}) + if rt.expanded[rt.rowInfo[getn(rt.rowInfo)].expandKey] then + rt.rowInfo.numDisplayRows = rt.rowInfo.numDisplayRows + 1 + end + else + -- it's a different base item from the previous row + tinsert(rt.rowInfo, {item_key=record.item_key, expandKey=record.item_key, children={{numAuctions=1, record=record}}}) + rt.rowInfo.numDisplayRows = rt.rowInfo.numDisplayRows + 1 + end + end + + for _, info in ipairs(rt.rowInfo) do + local totalAuctions, totalPlayerAuctions = 0, 0 + for _, childInfo in ipairs(info.children) do + totalAuctions = totalAuctions + childInfo.numAuctions + if Aux.is_player(childInfo.record.owner) then + totalPlayerAuctions = totalPlayerAuctions + childInfo.numAuctions + end + end + info.totalAuctions = totalAuctions + info.totalPlayerAuctions = totalPlayerAuctions + end + end, + + UpdateRows = function(rt) + -- hide all the rows + for _, row in ipairs(rt.rows) do row:Hide() end + + -- update sorting highlights + for _, cell in ipairs(rt.headCells) do + local tex = cell:GetNormalTexture() + tex:SetTexture([[Interface\AddOns\Aux-AddOn\WorldStateFinalScore-Highlight]]) + tex:SetTexCoord(0.017, 1, 0.083, 0.909) + tex:SetAlpha(0.5) + end + if rt.sortInfo.descending then + rt.headCells[rt.sortInfo.columnIndex]:GetNormalTexture():SetTexture(0.8, 0.6, 1, 0.8) + else + rt.headCells[rt.sortInfo.columnIndex]:GetNormalTexture():SetTexture(0.6, 0.8, 1, 0.8) + end + + -- update the scroll frame + FauxScrollFrame_Update(rt.scrollFrame, rt.rowInfo.numDisplayRows, getn(rt.rows), rt.ROW_HEIGHT) + + -- make sure the offset is not too high + local maxOffset = max(rt.rowInfo.numDisplayRows - getn(rt.rows), 0) + if FauxScrollFrame_GetOffset(rt.scrollFrame) > maxOffset then + FauxScrollFrame_SetOffset(rt.scrollFrame, maxOffset) + end + + if not rt.sortInfo.isSorted then + local function SortHelperFunc(a, b, sortKey) + local hadSortKey = sortKey and true or false + sortKey = sortKey or rt.sortInfo.sortKey + local aVal, bVal + if a.children then + aVal = a.children[1].record + bVal = b.children[1].record + else + aVal = a.record + bVal = b.record + end + if aVal.isFake then + return true + elseif bVal.isFake then + return false + end + if sortKey == "percent" then + aVal = rt:GetRecordPercent(aVal) + bVal = rt:GetRecordPercent(bVal) + elseif sortKey == "numAuctions" then + aVal = a.totalAuctions + bVal = b.totalAuctions + elseif sortKey == "itemDisplayedBid" or sortKey == "displayedBid" then + aVal = rt.GetRowPrices(aVal, sortKey == "itemDisplayedBid") + bVal = rt.GetRowPrices(bVal, sortKey == "itemDisplayedBid") + elseif sortKey == "itemBuyout" or sortKey == "buyout" then + aVal = ({ rt.GetRowPrices(aVal, sortKey == "itemBuyout") })[2] + bVal = ({ rt.GetRowPrices(bVal, sortKey == "itemBuyout") })[2] + else + aVal = aVal[sortKey] + bVal = bVal[sortKey] + end + if sortKey == 'buyout' or sortKey == 'itemBuyout' then + -- for buyout, put bid-only auctions at the bottom + if not aVal or aVal == 0 then + aVal = (rt.sortInfo.descending and -1 or 1) * Aux.huge + end + if not bVal or bVal == 0 then + bVal = (rt.sortInfo.descending and -1 or 1) * Aux.huge + end + elseif sortKey == "percent" then + -- for percent, put bid-only auctions at the bottom + aVal = aVal or ((rt.sortInfo.descending and -1 or 1) * Aux.huge) + bVal = bVal or ((rt.sortInfo.descending and -1 or 1) * Aux.huge) + end + if type(aVal) == "string" or type(bVal) == "string" then + aVal = aVal or "" + bVal = bVal or "" + else + aVal = tonumber(aVal) or 0 + bVal = tonumber(bVal) or 0 + end + if aVal == bVal then + if sortKey == "percent" then + -- sort by buyout + sortKey = aux_price_per_unit and "itemBuyout" or "buyout" + local result = SortHelperFunc(a, b, sortKey) + if result ~= nil then + return result + end + elseif sortKey == "buyout" or sortKey == "itemBuyout" then + -- sort by bid + sortKey = aux_price_per_unit and "itemDisplayedBid" or "displayedBid" + local result = SortHelperFunc(a, b, sortKey) + if result ~= nil then + return result + end + elseif hadSortKey then + -- this was called recursively, so just return nil + return + else + -- sort by percent + return SortHelperFunc(a, b, "percent") + end + -- sort arbitrarily, but make sure the sort is stable + return tostring(a) < tostring(b) + end + if rt.sortInfo.descending then + return aVal > bVal + else + return aVal < bVal + end + end + -- sort the row info + for i, info in ipairs(rt.rowInfo) do + sort(info.children, SortHelperFunc) + end + sort(rt.rowInfo, SortHelperFunc) + rt.sortInfo.isSorted = true + end + + -- update all the rows + local rowIndex = 1 - FauxScrollFrame_GetOffset(rt.scrollFrame) + for i, info in ipairs(rt.rowInfo) do + if rt.expanded[info.expandKey] then + -- show each of the rows for this base item since it's expanded + for j, childInfo in ipairs(info.children) do + rt:SetRowInfo(rowIndex, childInfo.record, childInfo.numAuctions, 0, j > 1, false, info.expandKey, childInfo.numAuctions) + rowIndex = rowIndex + 1 + end + else + -- just show one row for this base item since it's not expanded + rt:SetRowInfo(rowIndex, info.children[1].record, info.totalAuctions, getn(info.children) > 1 and info.totalPlayerAuctions or 0, false, getn(info.children) > 1, info.expandKey, info.children[1].numAuctions) + rowIndex = rowIndex + 1 + end + end + end, + + SetRowInfo = function(rt, rowIndex, record, displayNumAuctions, numPlayerAuctions, indented, expandable, expandKey, numAuctions) + if rowIndex <= 0 or rowIndex > getn(rt.rows) then return end + local row = rt.rows[rowIndex] + -- show this row + row:Show() + if rt.selected and record.search_signature == rt.selected.search_signature then + row.highlight:Show() + else + row.highlight:Hide() + end + row.data = {record=record, expandable=expandable, indented=indented, numAuctions=numAuctions, expandKey=expandKey} + + -- set first cell + row.cells[1].icon:SetTexture(record.texture) + if indented then + row.cells[1].spacer:SetWidth(10) + row.cells[1].icon:SetAlpha(0.5) + row.cells[1]:GetFontString():SetAlpha(0.7) + else + row.cells[1].spacer:SetWidth(1) + row.cells[1].icon:SetAlpha(1) + row.cells[1]:GetFontString():SetAlpha(1) + end + row.cells[1]:SetText(gsub(record.hyperlink, "[%[%]]", "")) + row.cells[2]:SetText(record.level) + if record.isFake then + row.cells[3]:SetText(0) + row.cells[4]:SetText("---") + row.cells[5]:SetText("---") + row.cells[6]:SetText("") + row.cells[7]:SetText("---") + row.cells[8]:SetText("---") + row.cells[9]:SetText("---") + else + local numAuctionsText = expandable and (Aux.gui.inline_color(Aux.gui.config.link_color2)..displayNumAuctions..'|r') or displayNumAuctions + if numPlayerAuctions > 0 then + numAuctionsText = numAuctionsText..(' |cffffff00('..numPlayerAuctions..')|r') + end + row.cells[3]:SetText(numAuctionsText) + row.cells[4]:SetText(record.aux_quantity) + row.cells[5]:SetText(TIME_LEFT_STRINGS[record.duration or 0] or "---") + row.cells[6]:SetText(Aux.is_player(record.owner) and ("|cffffff00"..record.owner.."|r") or record.owner) + local bid, buyout, colorBid, colorBuyout = rt.GetRowPrices(record, aux_price_per_unit) + row.cells[7]:SetText(bid > 0 and Aux.money.to_string(bid, true, false, colorBid) or "---") + row.cells[8]:SetText(buyout > 0 and Aux.money.to_string(buyout, true, false, colorBuyout) or "---") + local pct, bidPct = rt:GetRecordPercent(record) + local pctColor = '|cffffffff' + if pct then + for i=1, getn(AUCTION_PCT_COLORS) do + if pct < AUCTION_PCT_COLORS[i].value then + pctColor = AUCTION_PCT_COLORS[i].color + break + end + end + elseif bidPct then + pctColor = '|cffbbbbbb' + pct = bidPct + end + if pct and pct > 10000 then + pct = '>10000' + end + row.cells[9]:SetText(pct and format('%s%s%%|r', pctColor, pct) or '---') + end + end, + + SetSelectedRecord = function(rt, record, silent) + if rt.disabled then return end + + -- make sure the selected record still exists and get the data for the callback + rt.selected = record + local selectedData = rt:GetSelection() + rt.selected = selectedData and rt.selected or nil + + -- show / hide highlight accordingly + for _, row in ipairs(rt.rows) do + if rt.selected and row.data and row.data.record.search_signature == rt.selected.search_signature then + row.highlight:Show() + else + row.highlight:Hide() + end + end + + if not silent and rt.handlers.OnSelectionChanged and not rt.scrollDisabled then + rt.handlers.OnSelectionChanged(rt, selectedData or nil) + end + end, + + + + -- ============================================================================ + -- General Results Table Methods + -- ============================================================================ + + Clear = function(rt) + Aux.util.wipe(rt.expanded) + Aux.util.wipe(rt.records) + rt:UpdateRowInfo() + rt:UpdateRows() + rt:SetSelectedRecord() + end, + + SetDatabase = function(rt, database, filterFunc, filterHash) + if database and database ~= rt.records then + rt.records = database + end + +-- rt.dbView:SetFilter(filterFunc, filterHash) +-- elseif filterFunc then +-- rt.dbView:SetFilter(filterFunc, filterHash) -- TODO + + -- get index of selected row + local prevSelectedIndex = nil + if rt.selected then + for index, row in ipairs(rt.rows) do + if row:IsVisible() and row.data and row.data.record == rt.selected then + prevSelectedIndex = index + end + end + end + + rt:UpdateRowInfo() + rt:UpdateRows() + + if not rt.selected and prevSelectedIndex then + -- try to select the same row + local row = rt.rows[prevSelectedIndex] + if row and row:IsVisible() and row.data and row.data.record then +-- TSM:LOG_INFO("Selecting row from point 1") + rt:SetSelectedRecord(row.data.record) + end + if not rt.selected then + -- select the first row + row = rt.rows[1] + if row and row:IsVisible() and row.data and row.data.record then +-- TSM:LOG_INFO("Selecting row from point 1") + rt:SetSelectedRecord(row.data.record) + end + end + end + end, + + RemoveSelectedRecord = function(rt, count) +-- TSMAPI:Assert(rt.selected) + count = count or 1 + for i=1, count do + local index = Aux.util.index_of(rt.selected, rt.records) + if index then + tremove(rt.records, index) + end + end + rt:SetDatabase() + end, + + InsertAuctionRecord = function(rt, record, count) + count = count or 1 + for i=1, count do + tinsert(rt.records, record) + end + rt:SetDatabase() + end, + + SetSort = function(rt, sortIndex) + local sortIndexLookup + if aux_price_per_unit then + sortIndexLookup = {"name", "itemLevel", "numAuctions", "stackSize", "timeLeft", "seller", "itemDisplayedBid", "itemBuyout", "percent"} + else + sortIndexLookup = {"name", "itemLevel", "numAuctions", "stackSize", "timeLeft", "seller", "displayedBid", "buyout", "percent"} + end + if sortIndex then + if sortIndex == rt.sortInfo.index then return end + rt.sortInfo.descending = sortIndex < 0 + rt.sortInfo.columnIndex = abs(sortIndex) + end +-- TSMAPI:Assert(rt.sortInfo.columnIndex > 0 and rt.sortInfo.columnIndex <= getn(rt.headCells)) + rt.sortInfo.sortKey = sortIndexLookup[rt.sortInfo.columnIndex] + rt.sortInfo.isSorted = nil + rt.sortInfo.index = sortIndex + rt:UpdateRows() + end, + + SetScrollDisabled = function(rt, disabled) + rt.scrollDisabled = disabled + end, + + SetHandler = function(rt, event, handler) +-- TSMAPI:Assert(event == "OnSelectionChanged") + rt.handlers[event] = handler + end, + + SetDisabled = function(rt, disabled) + rt.disabled = disabled + if not disabled then + -- if there's only one item in the result, expand it + if getn(rt.rowInfo) == 1 and rt.expanded[rt.rowInfo[1].expandKey] == nil then + rt.expanded[rt.rowInfo[1].expandKey] = true + rt.rowInfo.numDisplayRows = getn(rt.rowInfo[1].children) + end + rt:UpdateRows() + -- select the first row + rt:SetSelectedRecord(getn(rt.rowInfo) > 0 and rt.rowInfo[1].children[1].record) + end + end, + + GetSelection = function(rt) + if not rt.selected then return end + local selectedData + for _, info in ipairs(rt.rowInfo) do + for _, childInfo in ipairs(info.children) do + if childInfo.record.search_signature == rt.selected.search_signature then + selectedData = childInfo + break + end + end + end + return selectedData + end, + + GetTotalAuctions = function(rt) + local numResults = 0 + for _, info in ipairs(rt.rowInfo) do + for _, childInfo in ipairs(info.children) do + numResults = numResults + childInfo.numAuctions + end + end + return numResults + end, +} + +function CreateAuctionResultsTable(parent) + local colInfo = { + {name="Item", width=0.35}, + {name="Lvl", width=0.035, align="CENTER"}, + {name="Auctions", width=0.06, align="CENTER"}, + {name="Stack Size", width=0.055, align="CENTER"}, + {name='Time Left', width=0.04, align="CENTER"}, + {name='Seller', width=0.13, align="CENTER"}, + {name={'Auction Bid\n(per item)', 'Auction Bid\n(per stack)'}, width=0.125, align="RIGHT", isPrice=true}, + {name={'Auction Buyout\n(per item)', 'Auction Buyout\n(per stack)'}, width=0.125, align="RIGHT", isPrice=true}, + {name='% Market Value', width=0.08, align="CENTER"}, + } + + local rtName = 'TSMAuctionResultsTable'..RT_COUNT + RT_COUNT = RT_COUNT + 1 + local rt = CreateFrame('Frame', rtName, parent) +-- local numRows = TSM.db.profile.auctionResultRows + local numRows = 16 + rt.ROW_HEIGHT = (parent:GetHeight() - HEAD_HEIGHT-HEAD_SPACE) / numRows + rt.scrollDisabled = nil + rt.expanded = {} + rt.handlers = {} + rt.sortInfo = {} + rt.records = {} + rt.rowInfo = { numDisplayRows=0 } + + for name, func in pairs(methods) do + rt[name] = func + end + + rt:SetScript('OnShow', function() + for i, cell in ipairs(this.headCells) do + if cell.info.isPrice then +-- cell:SetText(cell.info.name[TSM.db.profile.pricePerUnit and 1 or 2]) + cell:SetText(cell.info.name[2]) + end + end + end) + + local contentFrame = CreateFrame('Frame', rtName..'Content', rt) + contentFrame:SetPoint('TOPLEFT', 0, 0) + contentFrame:SetPoint('BOTTOMRIGHT', -15, 0) +-- contentFrame:SetScript('OnSizeChanged', rt.OnContentSizeChanged) + rt.contentFrame = contentFrame + + -- frame to hold the header columns and the rows + local scrollFrame = CreateFrame('ScrollFrame', rtName..'ScrollFrame', rt, 'FauxScrollFrameTemplate') + scrollFrame:SetScript('OnVerticalScroll', function() + if not rt.scrollDisabled then + FauxScrollFrame_OnVerticalScroll(rt.ROW_HEIGHT, function() rt:UpdateRows() end) + end + end) + scrollFrame:SetAllPoints(contentFrame) + rt.scrollFrame = scrollFrame + FauxScrollFrame_Update(rt.scrollFrame, 0, numRows, rt.ROW_HEIGHT) + + -- make the scroll bar consistent with the TSM theme + local scrollBar = getglobal(scrollFrame:GetName()..'ScrollBar') + scrollBar:ClearAllPoints() + scrollBar:SetPoint('BOTTOMRIGHT', rt, -4, 4) + scrollBar:SetPoint('TOPRIGHT', rt, -4, -HEAD_HEIGHT) + scrollBar:SetWidth(10) + local thumbTex = scrollBar:GetThumbTexture() + thumbTex:SetPoint('CENTER', 0, 0) + thumbTex:SetTexture(unpack(Aux.gui.config.content_color)) + thumbTex:SetHeight(150) + thumbTex:SetWidth(scrollBar:GetWidth()) + getglobal(scrollBar:GetName()..'ScrollUpButton'):Hide() + getglobal(scrollBar:GetName()..'ScrollDownButton'):Hide() + + -- create the header cells + rt.headCells = {} + for i, info in ipairs(colInfo) do + local cell = CreateFrame('Button', rtName..'HeadCol'..i, 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 = info + cell.rt = rt + cell.columnIndex = i + cell:RegisterForClicks('LeftButtonUp', 'RightButtonUp') + + cell:SetScript('OnClick', rt.OnHeadColumnClick) + + local text = cell:CreateFontString() + text:SetJustifyH('CENTER') + text:SetJustifyV('CENTER') + text:SetFont(Aux.gui.config.content_font, 12) + text:SetTextColor(unpack(Aux.gui.config.label_color.enabled)) + cell:SetFontString(text) + if not cell.info.isPrice then cell:SetText(info.name or '') end -- TODO + text:SetAllPoints() + + local tex = cell:CreateTexture() + tex:SetAllPoints() + tex:SetTexture([[Interface\AddOns\Aux-AddOn\WorldStateFinalScore-Highlight]]) + tex:SetTexCoord(0.017, 1, 0.083, 0.909) + tex:SetAlpha(0.5) + cell:SetNormalTexture(tex) + + local tex = cell:CreateTexture() + tex:SetAllPoints() + tex:SetTexture([[Interface\Buttons\UI-Listbox-Highlight]]) + tex:SetTexCoord(0.025, 0.957, 0.087, 0.931) + tex:SetAlpha(0.2) + cell:SetHighlightTexture(tex) + + tinsert(rt.headCells, cell) + end + + -- create the rows + rt.rows = {} + for i=1, numRows do + local row = CreateFrame('Frame', rtName..'Row'..i, rt.contentFrame) + row:SetHeight(rt.ROW_HEIGHT) + if i == 1 then + row:SetPoint('TOPLEFT', 0, -(HEAD_HEIGHT + HEAD_SPACE)) + row:SetPoint('TOPRIGHT', 0, -(HEAD_HEIGHT + HEAD_SPACE)) + else + row:SetPoint('TOPLEFT', rt.rows[i-1], 'BOTTOMLEFT') + row:SetPoint('TOPRIGHT', rt.rows[i-1], 'BOTTOMRIGHT') + end + local highlight = row:CreateTexture() + highlight:SetAllPoints() + highlight:SetTexture(1, .9, 0, .5) + highlight:Hide() + row.highlight = highlight + row.rt = rt + + row.cells = {} + for j=1, getn(colInfo) do + local cell = CreateFrame('Button', nil, row) + local text = cell:CreateFontString() + text:SetFont(Aux.gui.config.content_font, min(14, rt.ROW_HEIGHT)) + text:SetJustifyH(colInfo[j].align or 'LEFT') + text:SetJustifyV('MIDDLE') + text:SetPoint('TOPLEFT', 1, -1) + text:SetPoint('BOTTOMRIGHT', -1, 1) + cell:SetFontString(text) + cell:SetHeight(rt.ROW_HEIGHT) + cell:RegisterForClicks('LeftButtonUp', 'RightButtonUp') + cell:SetScript('OnEnter', rt.OnCellEnter) + cell:SetScript('OnLeave', rt.OnCellLeave) + cell:SetScript('OnClick', rt.OnCellClick) + cell:SetScript('OnDoubleClick', rt.OnCellDoubleClick) + 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 + + -- slightly different color for every alternating column + if mod(j,2) == 1 then + local tex = cell:CreateTexture() + tex:SetAllPoints() + tex:SetTexture(0.3, 0.3, 0.3, 0.2) + cell:SetNormalTexture(tex) + end + + -- special first column to hold spacer / item name / item icon + if j == 1 then + 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:SetBackdrop({edgeFile=[[Interface\Buttons\WHITE8X8]], edgeSize=1.5}) + iconBtn:SetBackdropBorderColor(0, 1, 0, 0) + 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) + cell.iconBtn = iconBtn + cell.icon = icon + + text:ClearAllPoints() + text:SetPoint('TOPLEFT', iconBtn, 'TOPRIGHT', 2, 0) + text:SetPoint('BOTTOMRIGHT', 0, 0) + end + tinsert(row.cells, cell) + end + + -- slightly different color for every alternating + if mod(i,2) == 0 then + local tex = row:CreateTexture() + tex:SetAllPoints() + tex:SetTexture(0.3, 0.3, 0.3, 0.3) + end + + tinsert(rt.rows, row) + end + + rt:SetAllPoints() + this = contentFrame -- TODO hack + arg1 = contentFrame:GetWidth() -- TODO hack + rt:OnContentSizeChanged() -- TODO hack + return rt +end \ No newline at end of file diff --git a/core.lua b/core.lua index 6a4bcb3..10ae778 100644 --- a/core.lua +++ b/core.lua @@ -84,9 +84,9 @@ function Aux_OnLoad() end) end - AuxFrameContent:SetBackdrop({bgFile='Interface\\Buttons\\WHITE8X8', edgeFile='Interface\\Buttons\\WHITE8X8', edgeSize=Aux.gui.config.edge_size}) - AuxFrameContent:SetBackdropColor(unpack(Aux.gui.config.content_color)) - AuxFrameContent:SetBackdropBorderColor(unpack(Aux.gui.config.content_border_color)) +-- AuxFrameContent:SetBackdrop({bgFile='Interface\\Buttons\\WHITE8X8', edgeFile='Interface\\Buttons\\WHITE8X8', edgeSize=Aux.gui.config.edge_size}) +-- AuxFrameContent:SetBackdropColor(unpack(Aux.gui.config.content_color)) +-- AuxFrameContent:SetBackdropBorderColor(unpack(Aux.gui.config.content_border_color)) -- Aux.item_search_frame.on_load() Aux.filter_search_frame.on_load() diff --git a/core.xml b/core.xml index 841a70d..00562a8 100644 --- a/core.xml +++ b/core.xml @@ -220,9 +220,10 @@ - + - + + diff --git a/filter_search_frame.lua b/filter_search_frame.lua index 1b8f2e1..33078bd 100644 --- a/filter_search_frame.lua +++ b/filter_search_frame.lua @@ -16,8 +16,29 @@ private.elements = { } function private.update_search_listings() - Aux.sheet.populate(private.listings.favorite_searches, aux_favorite_searches) - Aux.sheet.populate(private.listings.recent_searches, aux_recent_searches) + local favorite_search_rows = {} + for i, favorite_search in ipairs(aux_favorite_searches) do + local name = Aux.test.prettify_search(favorite_search) + tinsert(favorite_search_rows, { + cols = {{value=name}}, + search = favorite_search, + index = i, + name = name, + }) + end + private.favorite_searches_listing:SetData(favorite_search_rows) + + local recent_search_rows = {} + for i, recent_search in ipairs(aux_recent_searches) do + local name = Aux.test.prettify_search(recent_search) + tinsert(recent_search_rows, { + cols = {{value=name}}, + search = recent_search, + index = i, + name = name, + }) + end + private.recent_searches_listing:SetData(recent_search_rows) end function private.update_tab(tab) @@ -92,213 +113,6 @@ function public.on_open() end function public.on_load() - private.recent_searches_config = { - plain = true, - frame = AuxFilterSearchFrameSavedRecentListing, - on_row_click = function (sheet, row_index) - local data_index = row_index + FauxScrollFrame_GetOffset(sheet.scroll_frame) - PlaySound('igMainMenuOptionCheckBoxOn') - if arg1 == 'LeftButton' then - private.search_box:SetText(sheet.data[data_index]) - if not IsShiftKeyDown() then - public.start_search() - end - elseif arg1 == 'RightButton' then - tinsert(aux_favorite_searches, sheet.data[data_index]) - private.update_search_listings() - end - end, - on_row_enter = function(sheet, row_index) - GameTooltip_SetDefaultAnchor(GameTooltip, UIParent) - GameTooltip:AddLine(gsub(sheet.rows[row_index].cells[1].text:GetText(), ';', '\n'), 255/255, 254/255, 250/255) - GameTooltip:Show() - end, - on_row_leave = function(sheet, row_index) - local data_index = row_index + FauxScrollFrame_GetOffset(sheet.scroll_frame) - GameTooltip:ClearLines() - GameTooltip:Hide() - end, - columns = { - { - width = 440, - comparator = function(filter_string1, filter_string2) return Aux.util.compare(filter_string1, filter_string2, Aux.util.GT) end, - cell_initializer = Aux.sheet.default_cell_initializer('LEFT'), - cell_setter = function(cell, filter_string) - cell.text:SetText(Aux.test.prettify_search(filter_string)) - end, - }, - }, - sort_order = {}, - } - private.favorite_searches_config = { - plain = true, - frame = AuxFilterSearchFrameSavedFavoriteListing, - on_row_click = function (sheet, row_index) - local data_index = row_index + FauxScrollFrame_GetOffset(sheet.scroll_frame) - PlaySound('igMainMenuOptionCheckBoxOn') - if arg1 == 'LeftButton' then - private.search_box:SetText(sheet.data[data_index]) - if not IsShiftKeyDown() then - public.start_search() - end - elseif arg1 == 'RightButton' then - tremove(aux_favorite_searches, Aux.util.index_of(sheet.data[data_index], aux_favorite_searches)) - private.update_search_listings() - end - end, - on_row_enter = function(sheet, row_index) - GameTooltip_SetDefaultAnchor(GameTooltip, UIParent) - GameTooltip:AddLine(gsub(sheet.rows[row_index].cells[1].text:GetText(), ';', '\n'), 255/255, 254/255, 250/255) - GameTooltip:Show() - end, - on_row_leave = function(sheet, row_index) - local data_index = row_index + FauxScrollFrame_GetOffset(sheet.scroll_frame) - GameTooltip:ClearLines() - GameTooltip:Hide() - end, - columns = { - { - width = 440, - comparator = function(filter_string1, filter_string2) return Aux.util.compare(filter_string1, filter_string2, Aux.util.GT) end, - cell_initializer = Aux.sheet.default_cell_initializer('LEFT'), - cell_setter = function(cell, filter_string) - cell.text:SetText(Aux.test.prettify_search(filter_string)) - end, - }, - }, - sort_order = {{ column = 1, order = 'ascending' }}, - } - private.results_config = { - frame = AuxFilterSearchFrameResultsListing, - on_row_click = function(sheet, row_index) - local data_index = row_index + FauxScrollFrame_GetOffset(sheet.scroll_frame) - private.on_row_click(sheet.data[data_index], true) - end, - on_row_enter = function(sheet, row_index) - Aux.info.set_tooltip(sheet.rows[row_index].itemstring, sheet.rows[row_index].EnhTooltip_info, this, 'ANCHOR_RIGHT', 0, 0) - end, - on_row_leave = function(sheet, row_index) - AuxTooltip:Hide() - ResetCursor() - end, - on_row_update = function(sheet, row_index) - if IsControlKeyDown() then - ShowInspectCursor() - elseif IsAltKeyDown() then - SetCursor('BUY_CURSOR') - else - ResetCursor() - end - end, - selected = function(datum) - return Aux.util.any(datum, function(entry) return entry == selected_auction end) - end, - row_setter = function(row, group) - row:SetAlpha(Aux.util.all(group, function(auction) return auction.gone end) and 0.3 or 1) - row.itemstring = Aux.info.itemstring(group[1].item_id, group[1].suffix_id, nil, group[1].enchant_id) - row.EnhTooltip_info = group[1].EnhTooltip_info - end, - columns = { - { - title = 'Auction Item', - width = 280, - comparator = function(group1, group2) return Aux.util.compare(group1[1].name, group2[1].name, Aux.util.GT) end, - cell_initializer = function(cell) - local icon = CreateFrame('Button', nil, cell) - icon:EnableMouse(false) - local icon_texture = icon:CreateTexture(nil, 'BORDER') - icon_texture:SetAllPoints(icon) - icon.icon_texture = icon_texture - local normal_texture = icon:CreateTexture(nil) - normal_texture:SetPoint('CENTER', 0, 0) - normal_texture:SetWidth(22) - normal_texture:SetHeight(22) - normal_texture:SetTexture('Interface\\Buttons\\UI-Quickslot2') - icon:SetNormalTexture(normal_texture) - icon:SetPoint('LEFT', cell) - icon:SetWidth(12) - icon:SetHeight(12) - local text = cell:CreateFontString(nil, 'OVERLAY', 'GameFontHighlightSmall') - text:SetPoint('LEFT', icon, 'RIGHT', 1, 0) - text:SetPoint('TOPRIGHT', cell) - text:SetPoint('BOTTOMRIGHT', cell) - text:SetJustifyV('TOP') - text:SetJustifyH('LEFT') - text:SetTextColor(0.8, 0.8, 0.8) - cell.text = text - cell.icon = icon - end, - cell_setter = function(cell, group) - cell.icon.icon_texture:SetTexture(Aux.info.item(group[1].item_id).texture) - if not group[1].usable then - cell.icon.icon_texture:SetVertexColor(1.0, 0.1, 0.1) - else - cell.icon.icon_texture:SetVertexColor(1.0, 1.0, 1.0) - end - cell.text:SetText('['..group[1].tooltip[1][1].text..']') - local color = ITEM_QUALITY_COLORS[group[1].quality] - cell.text:SetTextColor(color.r, color.g, color.b) - end, - }, - { - title = 'Qty', - width = 25, - comparator = function(group1, group2) return Aux.util.compare(group1[1].aux_quantity, group2[1].aux_quantity, Aux.util.LT) end, - cell_initializer = Aux.sheet.default_cell_initializer('RIGHT'), - cell_setter = function(cell, group) - cell.text:SetText(group[1].aux_quantity) - end, - }, - Aux.listing_util.money_column('Bid', function(group) return group[1].bid_price end), - Aux.listing_util.money_column('Buy', function(group) return group[1].buyout_price end), - Aux.listing_util.money_column('Bid/ea', function(group) return group[1].unit_bid_price end), - Aux.listing_util.money_column('Buy/ea', function(group) return group[1].unit_buyout_price end), - { - title = 'Avail', - width = 40, - comparator = function(group1, group2) return Aux.util.compare(getn(Aux.util.filter(group1, function(auction) return not auction.gone end)), getn(Aux.util.filter(group2, function(auction) return not auction.gone end)), Aux.util.LT) end, - cell_initializer = Aux.sheet.default_cell_initializer('RIGHT'), - cell_setter = function(cell, group) - cell.text:SetText(getn(Aux.util.filter(group, function(auction) return not auction.gone end))) - end, - }, - { - title = 'Lvl', - width = 25, - comparator = function(group1, group2) return Aux.util.compare(group1[1].level, group2[1].level, Aux.util.GT) end, - cell_initializer = Aux.sheet.default_cell_initializer('RIGHT'), - cell_setter = function(cell, group) - local level = max(1, group[1].level) - local text - if level > UnitLevel('player') then - text = RED_FONT_COLOR_CODE..level..FONT_COLOR_CODE_CLOSE - else - text = level - end - cell.text:SetText(text) - end, - }, - { - title = 'Status', - width = 70, - comparator = function(group1, group2) return Aux.util.compare(group1[1].status, group2[1].status, Aux.util.GT) end, - cell_initializer = Aux.sheet.default_cell_initializer('CENTER'), - cell_setter = function(cell, group) - cell.text:SetText(group[1].status) - end, - }, - Aux.listing_util.duration_column(function(group) return group[1].duration end), - Aux.listing_util.owner_column(function(group) return group[1].owner end), - Aux.listing_util.percentage_market_column(function(group) return group[1].item_key end, function(group) return group[1].unit_buyout_price end), - }, - sort_order = {{ column = 1, order = 'ascending' }, { column = 4, order = 'ascending' }}, - } - - private.listings = { - favorite_searches = Aux.sheet.create(private.favorite_searches_config), - recent_searches = Aux.sheet.create(private.recent_searches_config), - results = Aux.sheet.create(private.results_config), - } do local panel = Aux.gui.panel(AuxFilterSearchFrame, '$parentFilters') panel:SetWidth(600) @@ -390,18 +204,6 @@ function public.on_load() btn:SetScript('OnClick', function() private.update_tab(FILTER) end) private.new_filter_button = btn end - do - local line = Aux.gui.horizontal_line(AuxFilterSearchFrameSavedRecent, -30) - local label = Aux.gui.label(AuxFilterSearchFrameSavedRecent, 15) - label:SetPoint('BOTTOM', line, 'TOP', 0, 7) - label:SetText('Recent Searches') - end - do - local line = Aux.gui.horizontal_line(AuxFilterSearchFrameSavedFavorite, -30) - local label = Aux.gui.label(AuxFilterSearchFrameSavedFavorite, 15) - label:SetPoint('BOTTOM', line, 'TOP', 0, 7) - label:SetText('Favorite Searches') - end do local btn1 = Aux.gui.button(private.elements[FILTER].filters, 16) btn1:SetPoint('BOTTOMLEFT', 8, 15) @@ -433,8 +235,8 @@ function public.on_load() do local status_bar = Aux.gui.status_bar(AuxFilterSearchFrame) status_bar:SetWidth(265) - status_bar:SetHeight(26) - status_bar:SetPoint('BOTTOMLEFT', AuxFilterSearchFrame, 'BOTTOMLEFT', 6, 6) + status_bar:SetHeight(25) + status_bar:SetPoint('TOPLEFT', AuxFilterSearchFrameResults, 'BOTTOMLEFT', 0, -3) status_bar:update_status(100, 0) status_bar:set_text('') private.status_bar = status_bar @@ -946,30 +748,85 @@ function public.on_load() private.testlisting:SetSort(9) private.testlisting:Clear() private.testlisting:SetHandler('OnSelectionChanged', private.on_selection_changed) + + local handlers = { + OnClick = function(st, data, _, button) + if not data then return end + if button == 'LeftButton' then + if IsShiftKeyDown() then +-- private.popupInfo.export = data.search +-- TSMAPI.Util:ShowStaticPopupDialog('TSM_SHOPPING_SAVED_EXPORT_POPUP') + elseif IsControlKeyDown() then +-- private.popupInfo.renameInfo = data.searchInfo +-- TSMAPI.Util:ShowStaticPopupDialog('TSM_SHOPPING_SAVED_RENAME_POPUP') + else + private.search_box:SetText(data.search) + public.start_search() + end + elseif button == 'RightButton' then + if st == private.recent_searches_listing then + if IsShiftKeyDown() then + tremove(TSM.db.global.savedSearches, data.index) +-- TSM:Printf('Removed '%s' from your recent searches.', data.searchInfo.name) + private.UpdateSTData() + else + tinsert(aux_favorite_searches, data.search) +-- data.searchInfo.isFavorite = true +---- TSM:Printf('Added '%s' to your favorite searches.', data.searchInfo.name) +-- private.UpdateSTData() + end + elseif st == private.favorite_searches_listing then + tremove(aux_favorite_searches, data.index) +-- data.searchInfo.isFavorite = nil +-- TSM:Printf('Removed '%s' from your favorite searches.', data.searchInfo.name) + end + private.update_search_listings() + end + end, + OnEnter = function(st, data, self) + if not data then return end + GameTooltip_SetDefaultAnchor(GameTooltip, UIParent) + GameTooltip:AddLine(gsub(data.name, ';', '\n'), 255/255, 254/255, 250/255) + GameTooltip:Show() +-- GameTooltip:SetOwner(self, 'ANCHOR_RIGHT') +-- GameTooltip:AddLine(data.search, 1, 1, 1, true) +-- GameTooltip:AddLine("") +-- local color = TSMAPI.Design:GetInlineColor("link") +-- if st == private.frame.saved.recentST then +-- GameTooltip:AddLine(color..'Left-Click to run this search.', 1, 1, 1, true) +-- GameTooltip:AddLine(color..'Shift-Left-Click to export this search.', 1, 1, 1, true) +-- GameTooltip:AddLine(color..'Ctrl-Left-Click to rename this search.', 1, 1, 1, true) +-- GameTooltip:AddLine(color..'Right-Click to favorite this recent search.', 1, 1, 1, true) +-- GameTooltip:AddLine(color..'Shift-Right-Click to remove this recent search.', 1, 1, 1, true) +-- elseif st == private.frame.saved.favoriteST then +-- GameTooltip:AddLine(color..'Left-Click to run this search.', 1, 1, 1, true) +-- GameTooltip:AddLine(color..'Shift-Left-Click to export this search.', 1, 1, 1, true) +-- GameTooltip:AddLine(color..'Ctrl-Left-Click to rename this search.', 1, 1, 1, true) +-- GameTooltip:AddLine(color..'Right-Click to remove from favorite searches.', 1, 1, 1, true) +-- end + GameTooltip:Show() + end, + OnLeave = function() + GameTooltip:ClearLines() + GameTooltip:Hide() + end + } + + private.recent_searches_listing = CreateScrollingTable(AuxFilterSearchFrameSavedRecent) + private.recent_searches_listing:SetColInfo({{name='Recent Searches', width=1}}) + private.recent_searches_listing:SetHandler('OnClick', handlers.OnClick) + private.recent_searches_listing:SetHandler('OnEnter', handlers.OnEnter) + + private.favorite_searches_listing = CreateScrollingTable(AuxFilterSearchFrameSavedFavorite) + private.favorite_searches_listing:SetColInfo({{name='Favorite Searches', width=1}}) + private.favorite_searches_listing:SetHandler('OnClick', handlers.OnClick) + private.favorite_searches_listing:SetHandler('OnEnter', handlers.OnEnter) end function public.stop_search() Aux.scan.abort() end -function private.update_listing() - --- if not AuxFilterSearchFrame:IsVisible() then --- return --- end --- --- local buyout_auctions = auctions and Aux.util.filter(auctions, function(auction) return auction.owner ~= UnitName('player') and auction.buyout_price end) or {} --- Aux.sheet.populate(private.listings.results, auctions and Aux.util.group_by(buyout_auctions, function(a1, a2) --- return a1.item_id == a2.item_id --- and a1.suffix_id == a2.suffix_id --- and a1.enchant_id == a2.enchant_id --- and a1.aux_quantity == a2.aux_quantity --- and a1.buyout_price == a2.buyout_price --- and a1.bid_price == a2.bid_price --- and a1.owner == a2.owner --- end) or {}) -end - function public.start_search() Aux.scan.abort(function() diff --git a/filter_search_frame.xml b/filter_search_frame.xml index be3fade..9d0078d 100644 --- a/filter_search_frame.xml +++ b/filter_search_frame.xml @@ -18,7 +18,7 @@ - + @@ -34,27 +34,24 @@ - + + + + - - - - - - - - + + + + + - - - - - - - - + + + + + diff --git a/groups.lua b/groups.lua index 097e66e..fb98066 100644 --- a/groups.lua +++ b/groups.lua @@ -8,7 +8,7 @@ function m.prettify_search(search) if name then search = gsub(search, item_pattern, m.display_name(Aux.static.auctionable_items[strupper(name)])..in_between, 1) else - return search + return Aux.gui.inline_color({216, 225, 211, 1})..search..'|r' end end end diff --git a/listing.lua b/listing.lua index f429009..02ed88c 100644 --- a/listing.lua +++ b/listing.lua @@ -1,794 +1,444 @@ -local private, public = {} +local private, public = {}, {} Aux.listing = public -local RT_COUNT = 1 -local HEAD_HEIGHT = 27 -local HEAD_SPACE = 2 -local AUCTION_PCT_COLORS = { - {color='|cff2992ff', value=50}, -- blue - {color='|cff16ff16', value=80}, -- green - {color='|cffffff00', value=110}, -- yellow - {color='|cffff9218', value=135}, -- orange - {color='|cffff0000', value=Aux.huge}, -- red -} -local TIME_LEFT_STRINGS = { - '|cffff000030m|r', -- Short - '|cffff92182h|r', -- Medium - '|cffffff0012h|r', -- Long - '|cff2992ff48h|r', -- Very Long -} + +local ST_COUNT = 0 + +local ST_ROW_HEIGHT = 15 +local ST_ROW_TEXT_SIZE = 13 +local ST_HEAD_HEIGHT = 27 +local ST_HEAD_SPACE = 4 +local DEFAULT_COL_INFO = {{width=1}} -local methods = { +local function GetTableIndex(tbl, value) + for i, v in pairs(tbl) do + if value == v then + return i + end + end +end - OnContentSizeChanged = function() - local width = arg1 - local rt = this:GetParent() - for i, cell in ipairs(rt.headCells) do - cell:SetWidth(cell.info.width * width) +local function OnColumnClick() + local button = arg1 + if this.st.sortInfo.enabled and button == 'LeftButton' then + if this.st.sortInfo.col == this.colNum then + this.st.sortInfo.ascending = not this.st.sortInfo.ascending + else + this.st.sortInfo.col = this.colNum + this.st.sortInfo.ascending = true + end + this.st.updateSort = true + this.st:RefreshRows() + end + if this.st.handlers.OnColumnClick then + this.st.handlers.OnColumnClick(this, button) + end +end + + +local defaultColScripts = { + OnEnter = function() + if not this.row.data then return end + if not this.st.highlightDisabled then + this.row.highlight:Show() end - for _, row in ipairs(rt.rows) do - for i, cell in ipairs(row.cells) do - cell:SetWidth(rt.headCells[i].info.width * width) - end + local handler = this.st.handlers.OnEnter + if handler then + handler(this.st, this.row.data, this) end end, - OnHeadColumnClick = function() - local button = arg1 - local rt = this.rt - if rt.disabled then return end - - if button == 'RightButton' and rt.headCells[this.columnIndex].info.isPrice then - aux_price_per_unit = not aux_price_per_unit - for i, cell in ipairs(rt.headCells) do - if cell.info.isPrice then - cell:SetText(cell.info.name[aux_price_per_unit and 1 or 2]) - end - end - rt:SetSort() - return - end - - local descending = false - if rt.sortInfo.columnIndex == this.columnIndex then - descending = not rt.sortInfo.descending - end - rt:SetSort((descending and -1 or 1) * this.columnIndex) - end, - --- OnIconEnter = function() --- local rt = this:GetParent().row.rt --- local rowData = this:GetParent().row.data --- if rowData and rowData.record then --- GameTooltip:SetOwner(this, "ANCHOR_RIGHT") --- TSMAPI.Util:SafeTooltipLink(rowData.record.rawItemLink) --- GameTooltip:Show() --- rt.isShowingItemTooltip = true --- end --- end, --- --- OnIconLeave = function() --- GameTooltip:ClearLines() --- GameTooltip:Hide() --- this:GetParent().row.rt.isShowingItemTooltip = nil --- end, - --- OnIconClick = function(self, ...) --- if IsModifiedClick() then --- HandleModifiedItemClick(self:GetParent().row.data.record.rawItemLink) --- else --- self:GetParent():GetScript("OnClick")(self:GetParent(), ...) --- end --- end, --- --- OnIconDoubleClick = function(self, ...) --- self:GetParent():GetScript("OnDoubleClick")(self:GetParent(), ...) --- end, - - OnCellEnter = function() - local rt = this.rt - local row = this.row - if rt.disabled then return end - if this ~= row.cells[1] or not rt.isShowingItemTooltip then - if rt.expanded[row.data.expandKey] then - GameTooltip:SetOwner(this, 'ANCHOR_NONE') - GameTooltip:SetPoint('BOTTOMLEFT', this, 'TOPLEFT') - GameTooltip:AddLine('Double-click to collapse this item and show only the cheapest auction.', 1, 1, 1, true) - GameTooltip:Show() - elseif row.data.expandable then - GameTooltip:SetOwner(this, 'ANCHOR_NONE') - GameTooltip:SetPoint('BOTTOMLEFT', this, 'TOPLEFT') - GameTooltip:AddLine('Double-click to expand this item and show all the auctions.', 1, 1, 1, true) - GameTooltip:Show() - end - end - - -- show highlight for this row - this.row.highlight:Show() - end, - - OnCellLeave = function() - GameTooltip:Hide() - -- hide highlight if it's not selected - if not this.rt.selected or this.rt.selected.search_signature ~= this.row.data.record.search_signature then + OnLeave = function() + if not this.row.data then return end + if this.st.selectionDisabled or not this.st.selected or this.st.selected ~= GetTableIndex(this.st.rowData, this.row.data) then this.row.highlight:Hide() end - end, - OnCellClick = function() - local button = arg1 - if this.rt.disabled then return end - this.rt:SetSelectedRecord(this.row.data.record) - end, - - OnCellDoubleClick = function() - local rt = this.rt - local rowData = this.row.data - local expand = not rt.expanded[rowData.expandKey] - if rt.disabled or expand and not rowData.expandable then return end - - rt.expanded[rowData.expandKey] = expand - rt:UpdateRowInfo() - rt:UpdateRows() - -- select this row if it's not indented - if not rowData.indented then - rt:SetSelectedRecord(this.row.data.record) + local handler = this.st.handlers.OnLeave + if handler then + handler(this.st, this.row.data, this) end end, + OnClick = function() + if not this.row.data then return end + this.st:ClearSelection() + this.st.selected = GetTableIndex(this.st.rowData, this.row.data) + this.row.highlight:Show() - -- ============================================================================ - -- Internal Results Table Methods - -- ============================================================================ - - -- GetRowPrices = function(record, isPerUnit) return end, -- TODO - GetRowPrices = function(record, per_unit) - if per_unit then - return record.unit_bid_price, record.unit_buyout_price - else - return record.bid_price, record.buyout_price + local handler = this.st.handlers.OnClick + if handler then + handler(this.st, this.row.data, this, arg1) end end, - - GetRecordPercent = function(rt, record) - if not record then return end --- cache the market value on the record --- record.market_value = record.market_value or rt.GetMarketValue(record.item_key) or 0 --- if record.marketValue > 0 then --- if record.itemBuyout > 0 then --- return Aux.round(100 * record.itemBuyout / record.marketValue, 1) --- end --- return nil, Aux.round(100 * record.itemDisplayedBid / record.marketValue, 1) --- end - - local market_value = Aux.history.market_value(record.item_key) - if market_value and market_value > 0 then - if record.unit_buyout_price > 0 then - return Aux.round(100 * record.unit_buyout_price / market_value, 1) - end - return nil, Aux.round(100 * record.unit_bid_price / market_value, 1) + OnDoubleClick = function() + if not this.row.data then return end + local handler = this.st.handlers.OnDoubleClick + if handler then + handler(this.st, this.row.data, this, arg1) end end, - - UpdateRowInfo = function(rt) - Aux.util.wipe(rt.rowInfo) - rt.rowInfo.numDisplayRows = 0 - rt.sortInfo.isSorted = nil - rt:SetSelectedRecord(nil, true) - - sort(rt.records, function(a,b) return a.search_signature < b.search_signature end) - - local records = rt.records - if getn(records) == 0 then return end - - -- Populate the row info from the database by combining identical auctions and auctions - -- of the same base item. Also, get the number of rows which will be shown. - 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 - rt.rowInfo[getn(rt.rowInfo)].children[getn(rt.rowInfo[getn(rt.rowInfo)].children)].numAuctions = rt.rowInfo[getn(rt.rowInfo)].children[getn(rt.rowInfo[getn(rt.rowInfo)].children)].numAuctions + 1 - elseif 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(rt.rowInfo[getn(rt.rowInfo)].children, {numAuctions=1, record=record}) - if rt.expanded[rt.rowInfo[getn(rt.rowInfo)].expandKey] then - rt.rowInfo.numDisplayRows = rt.rowInfo.numDisplayRows + 1 - end - else - -- it's a different base item from the previous row - tinsert(rt.rowInfo, {item_key=record.item_key, expandKey=record.item_key, children={{numAuctions=1, record=record}}}) - rt.rowInfo.numDisplayRows = rt.rowInfo.numDisplayRows + 1 - end - end - - for _, info in ipairs(rt.rowInfo) do - local totalAuctions, totalPlayerAuctions = 0, 0 - for _, childInfo in ipairs(info.children) do - totalAuctions = totalAuctions + childInfo.numAuctions - if Aux.is_player(childInfo.record.owner) then - totalPlayerAuctions = totalPlayerAuctions + childInfo.numAuctions - end - end - info.totalAuctions = totalAuctions - info.totalPlayerAuctions = totalPlayerAuctions - end - end, - - UpdateRows = function(rt) - -- hide all the rows - for _, row in ipairs(rt.rows) do row:Hide() end - - -- update sorting highlights - for _, cell in ipairs(rt.headCells) do - local tex = cell:GetNormalTexture() - tex:SetTexture([[Interface\AddOns\Aux-AddOn\WorldStateFinalScore-Highlight]]) - tex:SetTexCoord(0.017, 1, 0.083, 0.909) - tex:SetAlpha(0.5) - end - if rt.sortInfo.descending then - rt.headCells[rt.sortInfo.columnIndex]:GetNormalTexture():SetTexture(0.8, 0.6, 1, 0.8) - else - rt.headCells[rt.sortInfo.columnIndex]:GetNormalTexture():SetTexture(0.6, 0.8, 1, 0.8) - end - - -- update the scroll frame - FauxScrollFrame_Update(rt.scrollFrame, rt.rowInfo.numDisplayRows, getn(rt.rows), rt.ROW_HEIGHT) - - -- make sure the offset is not too high - local maxOffset = max(rt.rowInfo.numDisplayRows - getn(rt.rows), 0) - if FauxScrollFrame_GetOffset(rt.scrollFrame) > maxOffset then - FauxScrollFrame_SetOffset(rt.scrollFrame, maxOffset) - end - - if not rt.sortInfo.isSorted then - local function SortHelperFunc(a, b, sortKey) - local hadSortKey = sortKey and true or false - sortKey = sortKey or rt.sortInfo.sortKey - local aVal, bVal - if a.children then - aVal = a.children[1].record - bVal = b.children[1].record - else - aVal = a.record - bVal = b.record - end - if aVal.isFake then - return true - elseif bVal.isFake then - return false - end - if sortKey == "percent" then - aVal = rt:GetRecordPercent(aVal) - bVal = rt:GetRecordPercent(bVal) - elseif sortKey == "numAuctions" then - aVal = a.totalAuctions - bVal = b.totalAuctions - elseif sortKey == "itemDisplayedBid" or sortKey == "displayedBid" then - aVal = rt.GetRowPrices(aVal, sortKey == "itemDisplayedBid") - bVal = rt.GetRowPrices(bVal, sortKey == "itemDisplayedBid") - elseif sortKey == "itemBuyout" or sortKey == "buyout" then - aVal = ({ rt.GetRowPrices(aVal, sortKey == "itemBuyout") })[2] - bVal = ({ rt.GetRowPrices(bVal, sortKey == "itemBuyout") })[2] - else - aVal = aVal[sortKey] - bVal = bVal[sortKey] - end - if sortKey == 'buyout' or sortKey == 'itemBuyout' then - -- for buyout, put bid-only auctions at the bottom - if not aVal or aVal == 0 then - aVal = (rt.sortInfo.descending and -1 or 1) * Aux.huge - end - if not bVal or bVal == 0 then - bVal = (rt.sortInfo.descending and -1 or 1) * Aux.huge - end - elseif sortKey == "percent" then - -- for percent, put bid-only auctions at the bottom - aVal = aVal or ((rt.sortInfo.descending and -1 or 1) * Aux.huge) - bVal = bVal or ((rt.sortInfo.descending and -1 or 1) * Aux.huge) - end - if type(aVal) == "string" or type(bVal) == "string" then - aVal = aVal or "" - bVal = bVal or "" - else - aVal = tonumber(aVal) or 0 - bVal = tonumber(bVal) or 0 - end - if aVal == bVal then - if sortKey == "percent" then - -- sort by buyout - sortKey = aux_price_per_unit and "itemBuyout" or "buyout" - local result = SortHelperFunc(a, b, sortKey) - if result ~= nil then - return result - end - elseif sortKey == "buyout" or sortKey == "itemBuyout" then - -- sort by bid - sortKey = aux_price_per_unit and "itemDisplayedBid" or "displayedBid" - local result = SortHelperFunc(a, b, sortKey) - if result ~= nil then - return result - end - elseif hadSortKey then - -- this was called recursively, so just return nil - return - else - -- sort by percent - return SortHelperFunc(a, b, "percent") - end - -- sort arbitrarily, but make sure the sort is stable - return tostring(a) < tostring(b) - end - if rt.sortInfo.descending then - return aVal > bVal - else - return aVal < bVal - end - end - -- sort the row info - for i, info in ipairs(rt.rowInfo) do - sort(info.children, SortHelperFunc) - end - sort(rt.rowInfo, SortHelperFunc) - rt.sortInfo.isSorted = true - end - - -- update all the rows - local rowIndex = 1 - FauxScrollFrame_GetOffset(rt.scrollFrame) - for i, info in ipairs(rt.rowInfo) do - if rt.expanded[info.expandKey] then - -- show each of the rows for this base item since it's expanded - for j, childInfo in ipairs(info.children) do - rt:SetRowInfo(rowIndex, childInfo.record, childInfo.numAuctions, 0, j > 1, false, info.expandKey, childInfo.numAuctions) - rowIndex = rowIndex + 1 - end - else - -- just show one row for this base item since it's not expanded - rt:SetRowInfo(rowIndex, info.children[1].record, info.totalAuctions, getn(info.children) > 1 and info.totalPlayerAuctions or 0, false, getn(info.children) > 1, info.expandKey, info.children[1].numAuctions) - rowIndex = rowIndex + 1 - end - end - end, - - SetRowInfo = function(rt, rowIndex, record, displayNumAuctions, numPlayerAuctions, indented, expandable, expandKey, numAuctions) - if rowIndex <= 0 or rowIndex > getn(rt.rows) then return end - local row = rt.rows[rowIndex] - -- show this row - row:Show() - if rt.selected and record.search_signature == rt.selected.search_signature then - row.highlight:Show() - else - row.highlight:Hide() - end - row.data = {record=record, expandable=expandable, indented=indented, numAuctions=numAuctions, expandKey=expandKey} - - -- set first cell - row.cells[1].icon:SetTexture(record.texture) - if indented then - row.cells[1].spacer:SetWidth(10) - row.cells[1].icon:SetAlpha(0.5) - row.cells[1]:GetFontString():SetAlpha(0.7) - else - row.cells[1].spacer:SetWidth(1) - row.cells[1].icon:SetAlpha(1) - row.cells[1]:GetFontString():SetAlpha(1) - end - row.cells[1]:SetText(gsub(record.hyperlink, "[%[%]]", "")) - row.cells[2]:SetText(record.level) - if record.isFake then - row.cells[3]:SetText(0) - row.cells[4]:SetText("---") - row.cells[5]:SetText("---") - row.cells[6]:SetText("") - row.cells[7]:SetText("---") - row.cells[8]:SetText("---") - row.cells[9]:SetText("---") - else - local numAuctionsText = expandable and (Aux.gui.inline_color(Aux.gui.config.link_color2)..displayNumAuctions.."|r") or displayNumAuctions - if numPlayerAuctions > 0 then - numAuctionsText = numAuctionsText..(" |cffffff00("..numPlayerAuctions..")|r") - end - row.cells[3]:SetText(numAuctionsText) - row.cells[4]:SetText(record.aux_quantity) - row.cells[5]:SetText(TIME_LEFT_STRINGS[record.duration or 0] or "---") - row.cells[6]:SetText(Aux.is_player(record.owner) and ("|cffffff00"..record.owner.."|r") or record.owner) - local bid, buyout, colorBid, colorBuyout = rt.GetRowPrices(record, aux_price_per_unit) - row.cells[7]:SetText(bid > 0 and Aux.money.to_string(bid, true, false, colorBid) or "---") - row.cells[8]:SetText(buyout > 0 and Aux.money.to_string(buyout, true, false, colorBuyout) or "---") - local pct, bidPct = rt:GetRecordPercent(record) - local pctColor = "|cffffffff" - if pct then - for i=1, getn(AUCTION_PCT_COLORS) do - if pct < AUCTION_PCT_COLORS[i].value then - pctColor = AUCTION_PCT_COLORS[i].color - break - end - end - elseif bidPct then - pctColor = "|cffbbbbbb" - pct = bidPct - end - if pct and pct > 10000 then - pct = ">10000" - end - row.cells[9]:SetText(pct and format("%s%s%%|r", pctColor, pct) or "---") - end - end, - - SetSelectedRecord = function(rt, record, silent) - if rt.disabled then return end - - -- make sure the selected record still exists and get the data for the callback - rt.selected = record - local selectedData = rt:GetSelection() - rt.selected = selectedData and rt.selected or nil - - -- show / hide highlight accordingly - for _, row in ipairs(rt.rows) do - if rt.selected and row.data and row.data.record.search_signature == rt.selected.search_signature then - row.highlight:Show() - else - row.highlight:Hide() - end - end - - if not silent and rt.handlers.OnSelectionChanged and not rt.scrollDisabled then - rt.handlers.OnSelectionChanged(rt, selectedData or nil) - end - end, - - - - -- ============================================================================ - -- General Results Table Methods - -- ============================================================================ - - Clear = function(rt) - Aux.util.wipe(rt.expanded) - Aux.util.wipe(rt.records) - rt:UpdateRowInfo() - rt:UpdateRows() - rt:SetSelectedRecord() - end, - - SetDatabase = function(rt, database, filterFunc, filterHash) - if database and database ~= rt.records then - rt.records = database - end - --- rt.dbView:SetFilter(filterFunc, filterHash) --- elseif filterFunc then --- rt.dbView:SetFilter(filterFunc, filterHash) -- TODO - - -- get index of selected row - local prevSelectedIndex = nil - if rt.selected then - for index, row in ipairs(rt.rows) do - if row:IsVisible() and row.data and row.data.record == rt.selected then - prevSelectedIndex = index - end - end - end - - rt:UpdateRowInfo() - rt:UpdateRows() - - if not rt.selected and prevSelectedIndex then - -- try to select the same row - local row = rt.rows[prevSelectedIndex] - if row and row:IsVisible() and row.data and row.data.record then --- TSM:LOG_INFO("Selecting row from point 1") - rt:SetSelectedRecord(row.data.record) - end - if not rt.selected then - -- select the first row - row = rt.rows[1] - if row and row:IsVisible() and row.data and row.data.record then --- TSM:LOG_INFO("Selecting row from point 1") - rt:SetSelectedRecord(row.data.record) - end - end - end - end, - - RemoveSelectedRecord = function(rt, count) --- TSMAPI:Assert(rt.selected) - count = count or 1 - for i=1, count do - local index = Aux.util.index_of(rt.selected, rt.records) - if index then - tremove(rt.records, index) - end - end - rt:SetDatabase() - end, - - InsertAuctionRecord = function(rt, record, count) - count = count or 1 - for i=1, count do - tinsert(rt.records, record) - end - rt:SetDatabase() - end, - - SetSort = function(rt, sortIndex) - local sortIndexLookup - if aux_price_per_unit then - sortIndexLookup = {"name", "itemLevel", "numAuctions", "stackSize", "timeLeft", "seller", "itemDisplayedBid", "itemBuyout", "percent"} - else - sortIndexLookup = {"name", "itemLevel", "numAuctions", "stackSize", "timeLeft", "seller", "displayedBid", "buyout", "percent"} - end - if sortIndex then - if sortIndex == rt.sortInfo.index then return end - rt.sortInfo.descending = sortIndex < 0 - rt.sortInfo.columnIndex = abs(sortIndex) - end --- TSMAPI:Assert(rt.sortInfo.columnIndex > 0 and rt.sortInfo.columnIndex <= getn(rt.headCells)) - rt.sortInfo.sortKey = sortIndexLookup[rt.sortInfo.columnIndex] - rt.sortInfo.isSorted = nil - rt.sortInfo.index = sortIndex - rt:UpdateRows() - end, - - SetScrollDisabled = function(rt, disabled) - rt.scrollDisabled = disabled - end, - - SetHandler = function(rt, event, handler) --- TSMAPI:Assert(event == "OnSelectionChanged") - rt.handlers[event] = handler - end, - - SetDisabled = function(rt, disabled) - rt.disabled = disabled - if not disabled then - -- if there's only one item in the result, expand it - if getn(rt.rowInfo) == 1 and rt.expanded[rt.rowInfo[1].expandKey] == nil then - rt.expanded[rt.rowInfo[1].expandKey] = true - rt.rowInfo.numDisplayRows = getn(rt.rowInfo[1].children) - end - rt:UpdateRows() - -- select the first row - rt:SetSelectedRecord(getn(rt.rowInfo) > 0 and rt.rowInfo[1].children[1].record) - end - end, - - GetSelection = function(rt) - if not rt.selected then return end - local selectedData - for _, info in ipairs(rt.rowInfo) do - for _, childInfo in ipairs(info.children) do - if childInfo.record.search_signature == rt.selected.search_signature then - selectedData = childInfo - break - end - end - end - return selectedData - end, - - GetTotalAuctions = function(rt) - local numResults = 0 - for _, info in ipairs(rt.rowInfo) do - for _, childInfo in ipairs(info.children) do - numResults = numResults + childInfo.numAuctions - end - end - return numResults - end, } -function CreateAuctionResultsTable(parent) - local colInfo = { - {name="Item", width=0.35}, - {name="Lvl", width=0.035, align="CENTER"}, - {name="Auctions", width=0.06, align="CENTER"}, - {name="Stack Size", width=0.055, align="CENTER"}, - {name='Time Left', width=0.04, align="CENTER"}, - {name='Seller', width=0.13, align="CENTER"}, - {name={'Auction Bid\n(per item)', 'Auction Bid\n(per stack)'}, width=0.125, align="RIGHT", isPrice=true}, - {name={'Auction Buyout\n(per item)', 'Auction Buyout\n(per stack)'}, width=0.125, align="RIGHT", isPrice=true}, - {name='% Market Value', width=0.08, align="CENTER"}, - } +local methods = { + RefreshRows = function(st) + if not st.rowData then return end + FauxScrollFrame_Update(st.scrollFrame, getn(st.rowData), st.sizes.numRows, ST_ROW_HEIGHT) + local offset = FauxScrollFrame_GetOffset(st.scrollFrame) + st.offset = offset - local rtName = 'TSMAuctionResultsTable'..RT_COUNT - RT_COUNT = RT_COUNT + 1 - local rt = CreateFrame('Frame', rtName, parent) --- local numRows = TSM.db.profile.auctionResultRows - local numRows = 16 - rt.ROW_HEIGHT = (parent:GetHeight() - HEAD_HEIGHT-HEAD_SPACE) / numRows - rt.scrollDisabled = nil - rt.expanded = {} - rt.handlers = {} - rt.sortInfo = {} - rt.records = {} - rt.rowInfo = { numDisplayRows=0 } + -- do sorting if enabled + if st.sortInfo.enabled and st.sortInfo.col and st.updateSort then + local function SortHelper(rowA, rowB) + local sortArgA = rowA.cols[st.sortInfo.col].sortArg + local sortArgB = rowB.cols[st.sortInfo.col].sortArg - for name, func in pairs(methods) do - rt[name] = func - end + if st.sortInfo.ascending then + return sortArgA < sortArgB + else + return sortArgA > sortArgB + end + end + sort(st.rowData, SortHelper) + st.updateSort = nil + end - rt:SetScript('OnShow', function() - for i, cell in ipairs(this.headCells) do - if cell.info.isPrice then --- cell:SetText(cell.info.name[TSM.db.profile.pricePerUnit and 1 or 2]) - cell:SetText(cell.info.name[2]) + -- set row data + for i=1, st.sizes.numRows do + st.rows[i].data = nil + if i > getn(st.rowData) then + st.rows[i]:Hide() + else + st.rows[i]:Show() + local data = st.rowData[i + offset] + if not data then break end + st.rows[i].data = data + + if (st.selected == GetTableIndex(st.rowData, data) and not st.selectionDisabled) or (st.highlighted and st.highlighted == GetTableIndex(st.rowData, data)) then + st.rows[i].highlight:Show() + else + st.rows[i].highlight:Hide() + end + + for colNum, col in ipairs(st.rows[i].cols) do + if st.colInfo[colNum] then + local colData = data.cols[colNum] + if type(colData.value) == 'function' then + col:SetText(colData.value(unpack(colData.args))) + else + col:SetText(colData.value) + end + end + end end end - end) + end, - local contentFrame = CreateFrame('Frame', rtName..'Content', rt) - contentFrame:SetPoint('TOPLEFT', 0, 0) - contentFrame:SetPoint('BOTTOMRIGHT', -15, 0) --- contentFrame:SetScript('OnSizeChanged', rt.OnContentSizeChanged) - rt.contentFrame = contentFrame + SetData = function(st, rowData) + st.rowData = rowData + st.updateSort = true + st:RefreshRows() + end, - -- frame to hold the header columns and the rows - local scrollFrame = CreateFrame('ScrollFrame', rtName..'ScrollFrame', rt, 'FauxScrollFrameTemplate') - scrollFrame:SetScript('OnVerticalScroll', function() - if not rt.scrollDisabled then - FauxScrollFrame_OnVerticalScroll(rt.ROW_HEIGHT, function() rt:UpdateRows() end) + SetSelection = function(st, rowNum) + st.selected = rowNum + st:RefreshRows() + end, + + GetSelection = function(st) + return st.selected + end, + + ClearSelection = function(st) + st.selected = nil + st:RefreshRows() + end, + + DisableSelection = function(st, value) + st.selectionDisabled = value + end, + + EnableSorting = function(st, value, defaultCol) + st.sortInfo.enabled = value + st.sortInfo.col = abs(defaultCol or 1) + st.sortInfo.ascending = not defaultCol or defaultCol > 0 + st.updateSort = true + st:RefreshRows() + end, + + DisableHighlight = function(st, value) + st.highlightDisabled = value + end, + + GetNumRows = function(st) + return st.sizes.numRows + end, + + SetScrollOffset = function(st, offset) + local maxOffset = max(getn(st.rowData) - st.sizes.numRows, 0) + if not offset or offset < 0 or offset > maxOffset then + return -- invalid offset end - end) - scrollFrame:SetAllPoints(contentFrame) - rt.scrollFrame = scrollFrame - FauxScrollFrame_Update(rt.scrollFrame, 0, numRows, rt.ROW_HEIGHT) - -- make the scroll bar consistent with the TSM theme - local scrollBar = getglobal(scrollFrame:GetName()..'ScrollBar') - scrollBar:ClearAllPoints() - scrollBar:SetPoint('BOTTOMRIGHT', rt, -4, 4) - scrollBar:SetPoint('TOPRIGHT', rt, -4, -HEAD_HEIGHT) - scrollBar:SetWidth(10) - local thumbTex = scrollBar:GetThumbTexture() - thumbTex:SetPoint('CENTER', 0, 0) - thumbTex:SetTexture(unpack(Aux.gui.config.content_color)) - thumbTex:SetHeight(150) - thumbTex:SetWidth(scrollBar:GetWidth()) - getglobal(scrollBar:GetName()..'ScrollUpButton'):Hide() - getglobal(scrollBar:GetName()..'ScrollDownButton'):Hide() + local scrollPercent = offset / maxOffset + local maxPixelOffset = st.scrollFrame:GetVerticalScrollRange() + ST_ROW_HEIGHT * 2 + local pixelOffset = scrollPercent * maxPixelOffset + FauxScrollFrame_SetOffset(st.scrollFrame, offset) + st.scrollFrame:SetVerticalScroll(pixelOffset) + end, - -- create the header cells - rt.headCells = {} - for i, info in ipairs(colInfo) do - local cell = CreateFrame('Button', rtName..'HeadCol'..i, rt.contentFrame) - cell:SetHeight(HEAD_HEIGHT) - if i == 1 then - cell:SetPoint('TOPLEFT', 0, 0) + SetHighlighted = function(st, row) + st.highlighted = row + st:RefreshRows() + end, + + Redraw = function(st) + local width = st:GetWidth() - 14 + local height = st:GetHeight() + + if getn(st.colInfo) > 1 or st.colInfo[1].name then + -- there is a header row + st.sizes.headHeight = st.sizes.headFontSize and (st.sizes.headFontSize + 4) or ST_HEAD_HEIGHT else - cell:SetPoint('TOPLEFT', rt.headCells[i-1], 'TOPRIGHT') + -- no header row + st.sizes.headHeight = 0 end - cell.info = info - cell.rt = rt - cell.columnIndex = i - cell:RegisterForClicks('LeftButtonUp', 'RightButtonUp') + st.sizes.numRows = max(floor((st:GetParent():GetHeight() - st.sizes.headHeight - ST_HEAD_SPACE) / ST_ROW_HEIGHT), 0) - cell:SetScript('OnClick', rt.OnHeadColumnClick) + -- update the frame + st.scrollBar:ClearAllPoints() + st.scrollBar:SetPoint('BOTTOMRIGHT', st, -1, 1) + st.scrollBar:SetPoint('TOPRIGHT', st, -1, -st.sizes.headHeight - ST_HEAD_SPACE) - local text = cell:CreateFontString() - text:SetJustifyH('CENTER') + if st.sizes.headHeight > 0 then + st.headLine:Show() + st.headLine:ClearAllPoints() + st.headLine:SetPoint('TOPLEFT', 2, -st.sizes.headHeight) + st.headLine:SetPoint('TOPRIGHT', -2, -st.sizes.headHeight) + else + st.headLine:Hide() + end + + -- update the first row + if st.rows and st.rows[1] then + st.rows[1]:SetPoint('TOPLEFT', 0, -(st.sizes.headHeight + ST_HEAD_SPACE)) + st.rows[1]:SetPoint('TOPRIGHT', 0, -(st.sizes.headHeight + ST_HEAD_SPACE)) + end + + -- add header columns if necessary + while getn(st.headCols) < getn(st.colInfo) do + st:AddColumn() + end + + -- adjust head col widths + for colNum, col in ipairs(st.headCols) do + if st.colInfo[colNum] then + col:Show() + col:SetWidth(st.colInfo[colNum].width*width) + col:SetHeight(st.sizes.headHeight) + col:SetText(st.colInfo[colNum].name or "") + col.text:SetJustifyH(st.colInfo[colNum].headAlign or 'CENTER') + else + col:Hide() + end + end + + -- add more rows if necessary + while getn(st.rows) < st.sizes.numRows do + st:AddRow() + end + + -- adjust rows widths + for rowNum, row in ipairs(st.rows) do + if rowNum > st.sizes.numRows then + row.data = nil + row:Hide() + else + row:Show() + -- add any missing cols + while getn(row.cols) < getn(st.colInfo) do + st:AddRowCol(rowNum) + end + for colNum, col in ipairs(row.cols) do + if st.headCols[colNum] and st.colInfo[colNum] then + col:Show() + col:SetWidth(st.colInfo[colNum].width*width) + col.text:SetJustifyH(st.colInfo[colNum].align or 'LEFT') + else + col:Hide() + end + end + end + end + + st:RefreshRows() + end, + + AddColumn = function(st) + local colNum = getn(st.headCols) + 1 + local col = CreateFrame('Button', st:GetName()..'HeadCol'..colNum, st.contentFrame) + if colNum == 1 then + col:SetPoint('TOPLEFT', 0, 0) + else + col:SetPoint('TOPLEFT', st.headCols[colNum - 1], 'TOPRIGHT') + end + col.st = st + col.colNum = colNum + col:RegisterForClicks('LeftButtonUp', 'RightButtonUp') + col:SetScript('OnClick', OnColumnClick) + + local text = col:CreateFontString() text:SetJustifyV('CENTER') - text:SetFont(Aux.gui.config.content_font, 12) - text:SetTextColor(unpack(Aux.gui.config.label_color.enabled)) - cell:SetFontString(text) - if not cell.info.isPrice then cell:SetText(info.name or '') end -- TODO + text:SetFont(Aux.gui.config.content_font, 15) + text:SetTextColor(unpack(Aux.gui.config.text_color.enabled)) + col.text = text + col:SetFontString(text) text:SetAllPoints() - local tex = cell:CreateTexture() - tex:SetAllPoints() - tex:SetTexture([[Interface\AddOns\Aux-AddOn\WorldStateFinalScore-Highlight]]) - tex:SetTexCoord(0.017, 1, 0.083, 0.909) - tex:SetAlpha(0.5) - cell:SetNormalTexture(tex) - - local tex = cell:CreateTexture() + local tex = col:CreateTexture() tex:SetAllPoints() tex:SetTexture([[Interface\Buttons\UI-Listbox-Highlight]]) tex:SetTexCoord(0.025, 0.957, 0.087, 0.931) tex:SetAlpha(0.2) - cell:SetHighlightTexture(tex) + col:SetHighlightTexture(tex) - tinsert(rt.headCells, cell) - end + tinsert(st.headCols, col) - -- create the rows - rt.rows = {} - for i=1, numRows do - local row = CreateFrame('Frame', rtName..'Row'..i, rt.contentFrame) - row:SetHeight(rt.ROW_HEIGHT) - if i == 1 then - row:SetPoint('TOPLEFT', 0, -(HEAD_HEIGHT + HEAD_SPACE)) - row:SetPoint('TOPRIGHT', 0, -(HEAD_HEIGHT + HEAD_SPACE)) + -- add new cells to the rows + for rowNum, row in ipairs(st.rows) do + while getn(row.cols) < getn(st.headCols) do + st:AddRowCol(rowNum) + end + end + end, + + AddRowCol = function(st, rowNum) + local row = st.rows[rowNum] + local colNum = getn(row.cols) + 1 + local col = CreateFrame('Button', nil, row) + local text = col:CreateFontString() + text:SetFont(Aux.gui.config.content_font, ST_ROW_TEXT_SIZE) + text:SetJustifyV('CENTER') + text:SetPoint('TOPLEFT', 1, -1) + text:SetPoint('BOTTOMRIGHT', -1, 1) + col.text = text + col:SetFontString(text) + col:SetHeight(ST_ROW_HEIGHT) + col:RegisterForClicks('LeftButtonUp', 'RightButtonUp') + for name, func in pairs(defaultColScripts) do + col:SetScript(name, func) + end + col.st = st + col.row = row + + if colNum == 1 then + col:SetPoint('TOPLEFT', 0, 0) else - row:SetPoint('TOPLEFT', rt.rows[i-1], 'BOTTOMLEFT') - row:SetPoint('TOPRIGHT', rt.rows[i-1], 'BOTTOMRIGHT') + col:SetPoint('TOPLEFT', row.cols[colNum - 1], 'TOPRIGHT') + end + tinsert(row.cols, col) + end, + + AddRow = function(st) + local row = CreateFrame('Frame', nil, st.contentFrame) + row:SetHeight(ST_ROW_HEIGHT) + local rowNum = getn(st.rows) + 1 + if rowNum == 1 then + row:SetPoint('TOPLEFT', 0, -(st.sizes.headHeight+ST_HEAD_SPACE)) + row:SetPoint('TOPRIGHT', 0, -(st.sizes.headHeight+ST_HEAD_SPACE)) + else + row:SetPoint('TOPLEFT', st.rows[rowNum-1], 'BOTTOMLEFT') + row:SetPoint('TOPRIGHT', st.rows[rowNum-1], 'BOTTOMRIGHT') end local highlight = row:CreateTexture() highlight:SetAllPoints() - highlight:SetTexture(1, .9, 0, .5) + highlight:SetTexture(1, .9, .9, .1) highlight:Hide() row.highlight = highlight - row.rt = rt + row.st = st - row.cells = {} - for j=1, getn(colInfo) do - local cell = CreateFrame('Button', nil, row) - local text = cell:CreateFontString() - text:SetFont(Aux.gui.config.content_font, min(14, rt.ROW_HEIGHT)) - text:SetJustifyH(colInfo[j].align or 'LEFT') - text:SetJustifyV('MIDDLE') - text:SetPoint('TOPLEFT', 1, -1) - text:SetPoint('BOTTOMRIGHT', -1, 1) - cell:SetFontString(text) - cell:SetHeight(rt.ROW_HEIGHT) - cell:RegisterForClicks('LeftButtonUp', 'RightButtonUp') - cell:SetScript('OnEnter', rt.OnCellEnter) - cell:SetScript('OnLeave', rt.OnCellLeave) - cell:SetScript('OnClick', rt.OnCellClick) - cell:SetScript('OnDoubleClick', rt.OnCellDoubleClick) - cell.rt = rt - cell.row = row + row.cols = {} + st.rows[rowNum] = row + for i=1, getn(st.colInfo) do + st:AddRowCol(rowNum) + end + end, - if j == 1 then - cell:SetPoint('TOPLEFT', 0, 0) + SetHandler = function(st, event, handler) + st.handlers[event] = handler + end, + + SetHeadFontSize = function(st, size) + st.sizes.headFontSize = size + -- update the text size of the head cols + for _, col in ipairs(st.headCols) do + if st.sizes.headFontSize then + col.text:SetFont(Aux.gui.config.content_font, st.sizes.headFontSize) else - cell:SetPoint('TOPLEFT', row.cells[j-1], 'TOPRIGHT') + col.text:SetFont(Aux.gui.config.content_font, 15) end - - -- slightly different color for every alternating column - if mod(j,2) == 1 then - local tex = cell:CreateTexture() - tex:SetAllPoints() - tex:SetTexture(0.3, 0.3, 0.3, 0.2) - cell:SetNormalTexture(tex) - end - - -- special first column to hold spacer / item name / item icon - if j == 1 then - 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:SetBackdrop({edgeFile=[[Interface\Buttons\WHITE8X8]], edgeSize=1.5}) - iconBtn:SetBackdropBorderColor(0, 1, 0, 0) - 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) - cell.iconBtn = iconBtn - cell.icon = icon - - text:ClearAllPoints() - text:SetPoint('TOPLEFT', iconBtn, 'TOPRIGHT', 2, 0) - text:SetPoint('BOTTOMRIGHT', 0, 0) - end - tinsert(row.cells, cell) end + st:Redraw() + end, - -- slightly different color for every alternating - if mod(i,2) == 0 then - local tex = row:CreateTexture() - tex:SetAllPoints() - tex:SetTexture(0.3, 0.3, 0.3, 0.3) - end + SetColInfo = function(st, colInfo) + colInfo = colInfo or DEFAULT_COL_INFO +-- TSMAPI:Assert(type(colInfo) == 'table' and type(colInfo[1]) == 'table', "Invalid colInfo argument.") + st.colInfo = colInfo + st:Redraw() + end, +} - tinsert(rt.rows, row) +function CreateScrollingTable(parent) + -- create the base frame + ST_COUNT = ST_COUNT + 1 + local st = CreateFrame('Frame', 'TSMScrollingTable'..ST_COUNT, parent) + st:SetAllPoints() + st:SetScript('OnSizeChanged', function() st:Redraw() end) + + local contentFrame = CreateFrame('Frame', nil, st) + contentFrame:SetPoint('TOPLEFT', 0, 0) + contentFrame:SetPoint('BOTTOMRIGHT', -15, 0) + st.contentFrame = contentFrame + + -- frame to hold the header columns and the rows + local scrollFrame = CreateFrame('ScrollFrame', st:GetName()..'ScrollFrame', st, 'FauxScrollFrameTemplate') + scrollFrame:SetScript('OnVerticalScroll', function(self, offset) + FauxScrollFrame_OnVerticalScroll(ST_ROW_HEIGHT, function() st:RefreshRows() end) + end) + scrollFrame:SetAllPoints(contentFrame) + st.scrollFrame = scrollFrame + + -- make the scroll bar consistent with the TSM theme + local scrollBar = _G[scrollFrame:GetName()..'ScrollBar'] + scrollBar:SetWidth(12) + st.scrollBar = scrollBar + local thumbTex = scrollBar:GetThumbTexture() + thumbTex:SetPoint('CENTER', 0, 0) + thumbTex:SetTexture(unpack(Aux.gui.config.content_color)) + thumbTex:SetHeight(50) + thumbTex:SetWidth(12) + getglobal(scrollBar:GetName()..'ScrollUpButton'):Hide() + getglobal(scrollBar:GetName()..'ScrollDownButton'):Hide() + + -- create head line at default position + st.headLine = Aux.gui.horizontal_line(st, 0) + + -- add all the methods + for name, func in pairs(methods) do + st[name] = func end - rt:SetAllPoints() - this = contentFrame -- TODO hack - arg1 = contentFrame:GetWidth() -- TODO hack - rt:OnContentSizeChanged() -- TODO hack - return rt + -- setup default values + st.isTSMScrollingTable = true + st.sizes = {} + st.headCols = {} + st.rows = {} + st.handlers = {} + st.sortInfo = {enabled=nil} + st.colInfo = DEFAULT_COL_INFO + + return st end \ No newline at end of file