aux auto bid and price heuristics
this commit does two things 1. it implements auto bid just like auto buy 2. it has some minimum pricing heuristics when posting items. this behavoiur actiaves when the post bid price is set to 0, the buyout price behaves like a minimum
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
module 'aux.tabs.auctions'
|
||||
|
||||
local T = require 'T'
|
||||
local aux = require 'aux'
|
||||
local scan_util = require 'aux.util.scan'
|
||||
local scan = require 'aux.core.scan'
|
||||
|
||||
local tab = aux.tab 'Auctions'
|
||||
|
||||
auction_records = T.acquire()
|
||||
|
||||
function tab.OPEN()
|
||||
frame:Show()
|
||||
scan_auctions()
|
||||
end
|
||||
|
||||
function tab.CLOSE()
|
||||
frame:Hide()
|
||||
end
|
||||
|
||||
function update_listing()
|
||||
listing:SetDatabase(auction_records)
|
||||
end
|
||||
|
||||
function M.scan_auctions()
|
||||
|
||||
status_bar:update_status(0, 0)
|
||||
status_bar:set_text('Scanning auctions...')
|
||||
|
||||
T.wipe(auction_records)
|
||||
update_listing()
|
||||
scan.start{
|
||||
type = 'owner',
|
||||
queries = {{blizzard_query = T.acquire()}},
|
||||
on_page_loaded = function(page, total_pages)
|
||||
status_bar:update_status(page / total_pages, 0)
|
||||
status_bar:set_text(format('Scanning (Page %d / %d)', page, total_pages))
|
||||
end,
|
||||
on_auction = function(auction_record)
|
||||
tinsert(auction_records, auction_record)
|
||||
end,
|
||||
on_complete = function()
|
||||
status_bar:update_status(1, 1)
|
||||
status_bar:set_text('Scan complete')
|
||||
update_listing()
|
||||
end,
|
||||
on_abort = function()
|
||||
status_bar:update_status(1, 1)
|
||||
status_bar:set_text('Scan aborted')
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
do
|
||||
local scan_id = 0
|
||||
local IDLE, SEARCHING, FOUND = aux.enum(3)
|
||||
local state = IDLE
|
||||
local found_index
|
||||
|
||||
function find_auction(record)
|
||||
if not listing:ContainsRecord(record) then return end
|
||||
|
||||
scan.abort(scan_id)
|
||||
state = SEARCHING
|
||||
scan_id = scan_util.find(
|
||||
record,
|
||||
status_bar,
|
||||
function() state = IDLE end,
|
||||
function() state = IDLE; listing:RemoveAuctionRecord(record) end,
|
||||
function(index)
|
||||
state = FOUND
|
||||
found_index = index
|
||||
|
||||
cancel_button:SetScript('OnClick', function()
|
||||
if scan_util.test(record, index) and listing:ContainsRecord(record) then
|
||||
aux.cancel_auction(index, function() listing:RemoveAuctionRecord(record) end)
|
||||
end
|
||||
end)
|
||||
cancel_button:Enable()
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
function on_update()
|
||||
if state == IDLE or state == SEARCHING then
|
||||
cancel_button:Disable()
|
||||
end
|
||||
|
||||
if state == SEARCHING then return end
|
||||
|
||||
local selection = listing:GetSelection()
|
||||
if not selection then
|
||||
state = IDLE
|
||||
elseif selection and state == IDLE then
|
||||
find_auction(selection.record)
|
||||
elseif state == FOUND and not scan_util.test(selection.record, found_index) then
|
||||
cancel_button:Disable()
|
||||
if not aux.cancel_in_progress() then state = IDLE end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,62 @@
|
||||
module 'aux.tabs.auctions'
|
||||
|
||||
local aux = require 'aux'
|
||||
local info = require 'aux.util.info'
|
||||
local gui = require 'aux.gui'
|
||||
local auction_listing = require 'aux.gui.auction_listing'
|
||||
local search_tab = require 'aux.tabs.search'
|
||||
|
||||
frame = CreateFrame('Frame', nil, aux.frame)
|
||||
frame:SetAllPoints()
|
||||
frame:SetScript('OnUpdate', on_update)
|
||||
frame:Hide()
|
||||
|
||||
frame.listing = gui.panel(frame)
|
||||
frame.listing:SetPoint('TOP', frame, 'TOP', 0, -8)
|
||||
frame.listing:SetPoint('BOTTOMLEFT', aux.frame.content, 'BOTTOMLEFT', 0, 0)
|
||||
frame.listing:SetPoint('BOTTOMRIGHT', aux.frame.content, 'BOTTOMRIGHT', 0, 0)
|
||||
|
||||
listing = auction_listing.new(frame.listing, 20, auction_listing.auctions_columns)
|
||||
listing:SetSort(1, 2, 3, 4, 5, 6, 7, 8)
|
||||
listing:Reset()
|
||||
listing:SetHandler('OnClick', function(row, button)
|
||||
if IsAltKeyDown() then
|
||||
if listing:GetSelection().record == row.record then
|
||||
if IsAltKeyDown() and listing:GetSelection().record == row.record then
|
||||
cancel_button:Click()
|
||||
end
|
||||
end
|
||||
elseif button == 'RightButton' then
|
||||
aux.set_tab(1)
|
||||
search_tab.set_filter(strlower(info.item(this.record.item_id).name) .. '/exact')
|
||||
search_tab.execute(nil, false)
|
||||
end
|
||||
end)
|
||||
listing:SetHandler('OnSelectionChanged', function(rt, datum)
|
||||
if not datum then return end
|
||||
find_auction(datum.record)
|
||||
end)
|
||||
|
||||
do
|
||||
status_bar = gui.status_bar(frame)
|
||||
status_bar:SetWidth(265)
|
||||
status_bar:SetHeight(25)
|
||||
status_bar:SetPoint('TOPLEFT', aux.frame.content, 'BOTTOMLEFT', 0, -6)
|
||||
status_bar:update_status(1, 1)
|
||||
status_bar:set_text('')
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame)
|
||||
btn:SetPoint('TOPLEFT', status_bar, 'TOPRIGHT', 5, 0)
|
||||
btn:SetText('Cancel')
|
||||
btn:Disable()
|
||||
cancel_button = btn
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame)
|
||||
btn:SetPoint('TOPLEFT', cancel_button, 'TOPRIGHT', 5, 0)
|
||||
btn:SetText('Refresh')
|
||||
btn:SetScript('OnClick', function()
|
||||
scan_auctions()
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,125 @@
|
||||
module 'aux.tabs.bids'
|
||||
|
||||
local T = require 'T'
|
||||
local aux = require 'aux'
|
||||
local info = require 'aux.util.info'
|
||||
local scan_util = require 'aux.util.scan'
|
||||
local scan = require 'aux.core.scan'
|
||||
|
||||
local tab = aux.tab 'Bids'
|
||||
|
||||
auction_records = {}
|
||||
|
||||
function tab.OPEN()
|
||||
frame:Show()
|
||||
scan_bids()
|
||||
end
|
||||
|
||||
function tab.CLOSE()
|
||||
frame:Hide()
|
||||
end
|
||||
|
||||
function update_listing()
|
||||
listing:SetDatabase(auction_records)
|
||||
end
|
||||
|
||||
function M.scan_bids()
|
||||
|
||||
status_bar:update_status(0, 0)
|
||||
status_bar:set_text('Scanning auctions...')
|
||||
|
||||
T.wipe(auction_records)
|
||||
update_listing()
|
||||
scan.start{
|
||||
type = 'bidder',
|
||||
queries = T.list(T.map('blizzard_query', T.acquire())),
|
||||
on_page_loaded = function(page, total_pages)
|
||||
status_bar:update_status(page / total_pages, 0)
|
||||
status_bar:set_text(format('Scanning (Page %d / %d)', page, total_pages))
|
||||
end,
|
||||
on_auction = function(auction_record)
|
||||
tinsert(auction_records, auction_record)
|
||||
end,
|
||||
on_complete = function()
|
||||
status_bar:update_status(1, 1)
|
||||
status_bar:set_text('Scan complete')
|
||||
update_listing()
|
||||
end,
|
||||
on_abort = function()
|
||||
status_bar:update_status(1, 1)
|
||||
status_bar:set_text('Scan aborted')
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
do
|
||||
local scan_id = 0
|
||||
local IDLE, SEARCHING, FOUND = aux.enum(3)
|
||||
local state = IDLE
|
||||
local found_index
|
||||
|
||||
function find_auction(record)
|
||||
if not listing:ContainsRecord(record) then return end
|
||||
|
||||
scan.abort(scan_id)
|
||||
state = SEARCHING
|
||||
scan_id = scan_util.find(
|
||||
record,
|
||||
status_bar,
|
||||
function() state = IDLE end,
|
||||
function()
|
||||
state = IDLE
|
||||
listing:RemoveAuctionRecord(record)
|
||||
end,
|
||||
function(index)
|
||||
state = FOUND
|
||||
found_index = index
|
||||
|
||||
if not record.high_bidder then
|
||||
bid_button:SetScript('OnClick', function()
|
||||
if scan_util.test(record, index) and listing:ContainsRecord(record) then
|
||||
aux.place_bid('bidder', index, record.bid_price, record.bid_price < record.buyout_price and function()
|
||||
info.bid_update(record)
|
||||
listing:SetDatabase()
|
||||
end or function() listing:RemoveAuctionRecord(record) end)
|
||||
end
|
||||
end)
|
||||
bid_button:Enable()
|
||||
else
|
||||
bid_button:Disable()
|
||||
end
|
||||
|
||||
if record.buyout_price > 0 then
|
||||
buyout_button:SetScript('OnClick', function()
|
||||
if scan_util.test(record, index) and listing:ContainsRecord(record) then
|
||||
aux.place_bid('bidder', index, record.buyout_price, function() listing:RemoveAuctionRecord(record) end)
|
||||
end
|
||||
end)
|
||||
buyout_button:Enable()
|
||||
else
|
||||
buyout_button:Disable()
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
function on_update()
|
||||
if state == IDLE or state == SEARCHING then
|
||||
buyout_button:Disable()
|
||||
bid_button:Disable()
|
||||
end
|
||||
|
||||
if state == SEARCHING then return end
|
||||
|
||||
local selection = listing:GetSelection()
|
||||
if not selection then
|
||||
state = IDLE
|
||||
elseif selection and state == IDLE then
|
||||
find_auction(selection.record)
|
||||
elseif state == FOUND and not scan_util.test(selection.record, found_index) then
|
||||
buyout_button:Disable()
|
||||
bid_button:Disable()
|
||||
if not aux.bid_in_progress() then state = IDLE end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,71 @@
|
||||
module 'aux.tabs.bids'
|
||||
|
||||
local aux = require 'aux'
|
||||
local info = require 'aux.util.info'
|
||||
local gui = require 'aux.gui'
|
||||
local auction_listing = require 'aux.gui.auction_listing'
|
||||
local search_tab = require 'aux.tabs.search'
|
||||
|
||||
frame = CreateFrame('Frame', nil, aux.frame)
|
||||
frame:SetAllPoints()
|
||||
frame:SetScript('OnUpdate', on_update)
|
||||
frame:Hide()
|
||||
|
||||
frame.listing = gui.panel(frame)
|
||||
frame.listing:SetPoint('TOP', frame, 'TOP', 0, -8)
|
||||
frame.listing:SetPoint('BOTTOMLEFT', aux.frame.content, 'BOTTOMLEFT', 0, 0)
|
||||
frame.listing:SetPoint('BOTTOMRIGHT', aux.frame.content, 'BOTTOMRIGHT', 0, 0)
|
||||
|
||||
listing = auction_listing.new(frame.listing, 20, auction_listing.bids_columns)
|
||||
listing:SetSort(1, 2, 3, 4, 5, 6, 7, 8)
|
||||
listing:Reset()
|
||||
listing:SetHandler('OnClick', function(row, button)
|
||||
if IsAltKeyDown() then
|
||||
if listing:GetSelection().record == row.record then
|
||||
if button == 'LeftButton' then
|
||||
buyout_button:Click()
|
||||
elseif button == 'RightButton' then
|
||||
bid_button:Click()
|
||||
end
|
||||
end
|
||||
elseif button == 'RightButton' then
|
||||
aux.set_tab(1)
|
||||
search_tab.set_filter(strlower(info.item(this.record.item_id).name) .. '/exact')
|
||||
search_tab.execute(nil, false)
|
||||
end
|
||||
end)
|
||||
listing:SetHandler('OnSelectionChanged', function(rt, datum)
|
||||
if not datum then return end
|
||||
find_auction(datum.record)
|
||||
end)
|
||||
|
||||
do
|
||||
status_bar = gui.status_bar(frame)
|
||||
status_bar:SetWidth(265)
|
||||
status_bar:SetHeight(25)
|
||||
status_bar:SetPoint('TOPLEFT', aux.frame.content, 'BOTTOMLEFT', 0, -6)
|
||||
status_bar:update_status(1, 0)
|
||||
status_bar:set_text('')
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame)
|
||||
btn:SetPoint('TOPLEFT', status_bar, 'TOPRIGHT', 5, 0)
|
||||
btn:SetText('Bid')
|
||||
btn:Disable()
|
||||
bid_button = btn
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame)
|
||||
btn:SetPoint('TOPLEFT', bid_button, 'TOPRIGHT', 5, 0)
|
||||
btn:SetText('Buyout')
|
||||
btn:Disable()
|
||||
buyout_button = btn
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame)
|
||||
btn:SetPoint('TOPLEFT', buyout_button, 'TOPRIGHT', 5, 0)
|
||||
btn:SetText('Refresh')
|
||||
btn:SetScript('OnClick', function()
|
||||
scan_bids()
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,560 @@
|
||||
module 'aux.tabs.post'
|
||||
|
||||
local T = require 'T'
|
||||
local aux = require 'aux'
|
||||
local info = require 'aux.util.info'
|
||||
local sort_util = require 'aux.util.sort'
|
||||
local persistence = require 'aux.util.persistence'
|
||||
local money = require 'aux.util.money'
|
||||
local scan_util = require 'aux.util.scan'
|
||||
local post = require 'aux.core.post'
|
||||
local scan = require 'aux.core.scan'
|
||||
local history = require 'aux.core.history'
|
||||
local item_listing = require 'aux.gui.item_listing'
|
||||
local al = require 'aux.gui.auction_listing'
|
||||
local gui = require 'aux.gui'
|
||||
|
||||
local tab = aux.tab 'Post'
|
||||
|
||||
local settings_schema = {'tuple', '#', {duration='number'}, {start_price='number'}, {buyout_price='number'}, {hidden='boolean'}}
|
||||
|
||||
local scan_id, inventory_records, bid_records, buyout_records = 0, {}, {}, {}
|
||||
|
||||
M.DURATION_2, M.DURATION_8, M.DURATION_24 = 120, 480, 1440
|
||||
|
||||
refresh = true
|
||||
|
||||
selected_item = nil
|
||||
|
||||
function get_default_settings()
|
||||
return T.map('duration', aux.account_data.post_duration, 'start_price', 0, 'buyout_price', 0, 'hidden', false)
|
||||
end
|
||||
|
||||
function aux.handle.LOAD2()
|
||||
data = aux.faction_data.post
|
||||
end
|
||||
|
||||
function read_settings(item_key)
|
||||
item_key = item_key or selected_item.key
|
||||
return data[item_key] and persistence.read(settings_schema, data[item_key]) or get_default_settings()
|
||||
end
|
||||
function write_settings(settings, item_key)
|
||||
item_key = item_key or selected_item.key
|
||||
data[item_key] = persistence.write(settings_schema, settings)
|
||||
end
|
||||
|
||||
do
|
||||
local bid_selections, buyout_selections = {}, {}
|
||||
function get_bid_selection()
|
||||
return bid_selections[selected_item.key]
|
||||
end
|
||||
function set_bid_selection(record)
|
||||
bid_selections[selected_item.key] = record
|
||||
end
|
||||
function get_buyout_selection()
|
||||
return buyout_selections[selected_item.key]
|
||||
end
|
||||
function set_buyout_selection(record)
|
||||
buyout_selections[selected_item.key] = record
|
||||
end
|
||||
end
|
||||
|
||||
function refresh_button_click()
|
||||
scan.abort(scan_id)
|
||||
refresh_entries()
|
||||
refresh = true
|
||||
end
|
||||
|
||||
function tab.OPEN()
|
||||
frame:Show()
|
||||
update_inventory_records()
|
||||
refresh = true
|
||||
end
|
||||
|
||||
function tab.CLOSE()
|
||||
selected_item = nil
|
||||
frame:Hide()
|
||||
end
|
||||
|
||||
function tab.USE_ITEM(item_info)
|
||||
select_item(item_info.item_key)
|
||||
end
|
||||
|
||||
function get_unit_start_price()
|
||||
return selected_item and read_settings().start_price or 0
|
||||
end
|
||||
|
||||
function set_unit_start_price(amount)
|
||||
local settings = read_settings()
|
||||
settings.start_price = amount
|
||||
write_settings(settings)
|
||||
end
|
||||
|
||||
function get_unit_buyout_price()
|
||||
return selected_item and read_settings().buyout_price or 0
|
||||
end
|
||||
|
||||
function set_unit_buyout_price(amount)
|
||||
local settings = read_settings()
|
||||
settings.buyout_price = amount
|
||||
write_settings(settings)
|
||||
end
|
||||
|
||||
function update_inventory_listing()
|
||||
local records = aux.values(aux.filter(aux.copy(inventory_records), function(record)
|
||||
local settings = read_settings(record.key)
|
||||
return record.aux_quantity > 0 and (not settings.hidden or show_hidden_checkbox:GetChecked())
|
||||
end))
|
||||
sort(records, function(a, b) return a.name < b.name end)
|
||||
item_listing.populate(inventory_listing, records)
|
||||
end
|
||||
|
||||
function update_auction_listing(listing, records, reference)
|
||||
local rows = T.acquire()
|
||||
if selected_item then
|
||||
local historical_value = history.value(selected_item.key)
|
||||
local stack_size = stack_size_slider:GetValue()
|
||||
for _, record in records[selected_item.key] or T.empty do
|
||||
local price_color = undercut(record, stack_size_slider:GetValue(), listing == 'bid') < reference and aux.color.red
|
||||
local price = record.unit_price * (listing == 'bid' and record.stack_size / stack_size_slider:GetValue() or 1)
|
||||
tinsert(rows, T.map(
|
||||
'cols', T.list(
|
||||
T.map('value', record.own and aux.color.green(record.count) or record.count),
|
||||
T.map('value', al.time_left(record.duration)),
|
||||
T.map('value', record.stack_size == stack_size and aux.color.green(record.stack_size) or record.stack_size),
|
||||
T.map('value', money.to_string(price, true, nil, price_color)),
|
||||
T.map('value', historical_value and gui.percentage_historical(aux.round(price / historical_value * 100)) or '---')
|
||||
),
|
||||
'record', record
|
||||
))
|
||||
end
|
||||
if historical_value then
|
||||
tinsert(rows, T.map(
|
||||
'cols', T.list(
|
||||
T.map('value', '---'),
|
||||
T.map('value', '---'),
|
||||
T.map('value', '---'),
|
||||
T.map('value', money.to_string(historical_value, true, nil, aux.color.green)),
|
||||
T.map('value', historical_value and gui.percentage_historical(100) or '---')
|
||||
),
|
||||
'record', T.map('historical_value', true, 'stack_size', stack_size, 'unit_price', historical_value, 'own', true)
|
||||
))
|
||||
end
|
||||
sort(rows, function(a, b)
|
||||
return sort_util.multi_lt(
|
||||
a.record.unit_price * (listing == 'bid' and a.record.stack_size or 1),
|
||||
b.record.unit_price * (listing == 'bid' and b.record.stack_size or 1),
|
||||
|
||||
a.record.historical_value and 1 or 0,
|
||||
b.record.historical_value and 1 or 0,
|
||||
|
||||
b.record.own and 0 or 1,
|
||||
a.record.own and 0 or 1,
|
||||
|
||||
a.record.stack_size,
|
||||
b.record.stack_size,
|
||||
|
||||
a.record.duration,
|
||||
b.record.duration
|
||||
)
|
||||
end)
|
||||
end
|
||||
if listing == 'bid' then
|
||||
bid_listing:SetData(rows)
|
||||
elseif listing == 'buyout' then
|
||||
buyout_listing:SetData(rows)
|
||||
end
|
||||
end
|
||||
|
||||
function update_auction_listings()
|
||||
update_auction_listing('bid', bid_records, get_unit_start_price())
|
||||
update_auction_listing('buyout', buyout_records, get_unit_buyout_price())
|
||||
end
|
||||
|
||||
function M.select_item(item_key)
|
||||
for _, inventory_record in aux.filter(aux.copy(inventory_records), function(record) return record.aux_quantity > 0 end) do
|
||||
if inventory_record.key == item_key then
|
||||
update_item(inventory_record)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function price_update()
|
||||
if selected_item then
|
||||
local historical_value = history.value(selected_item.key)
|
||||
if get_bid_selection() or get_buyout_selection() then
|
||||
set_unit_start_price(undercut(get_bid_selection() or get_buyout_selection(), stack_size_slider:GetValue(), get_bid_selection()))
|
||||
unit_start_price_input:SetText(money.to_string(get_unit_start_price(), true, nil, nil, true))
|
||||
end
|
||||
if get_buyout_selection() then
|
||||
set_unit_buyout_price(undercut(get_buyout_selection(), stack_size_slider:GetValue()))
|
||||
unit_buyout_price_input:SetText(money.to_string(get_unit_buyout_price(), true, nil, nil, true))
|
||||
end
|
||||
start_price_percentage:SetText(historical_value and gui.percentage_historical(aux.round(get_unit_start_price() / historical_value * 100)) or '---')
|
||||
buyout_price_percentage:SetText(historical_value and gui.percentage_historical(aux.round(get_unit_buyout_price() / historical_value * 100)) or '---')
|
||||
end
|
||||
end
|
||||
|
||||
function post_auctions()
|
||||
if selected_item then
|
||||
local unit_start_price = get_unit_start_price()
|
||||
local unit_buyout_price = get_unit_buyout_price()
|
||||
local stack_size = stack_size_slider:GetValue()
|
||||
local stack_count
|
||||
stack_count = stack_count_slider:GetValue()
|
||||
local duration = UIDropDownMenu_GetSelectedValue(duration_dropdown)
|
||||
local key = selected_item.key
|
||||
|
||||
local duration_code
|
||||
if duration == DURATION_2 then
|
||||
duration_code = 2
|
||||
elseif duration == DURATION_8 then
|
||||
duration_code = 3
|
||||
elseif duration == DURATION_24 then
|
||||
duration_code = 4
|
||||
end
|
||||
|
||||
post.start(
|
||||
key,
|
||||
stack_size,
|
||||
duration,
|
||||
unit_start_price,
|
||||
unit_buyout_price,
|
||||
stack_count,
|
||||
function(posted)
|
||||
if not frame:IsShown() then
|
||||
return
|
||||
end
|
||||
for i = 1, posted do
|
||||
record_auction(key, stack_size, unit_start_price * stack_size, unit_buyout_price, duration_code, UnitName'player')
|
||||
end
|
||||
update_inventory_records()
|
||||
local same
|
||||
for _, record in inventory_records do
|
||||
if record.key == key then
|
||||
same = record
|
||||
break
|
||||
end
|
||||
end
|
||||
if same then
|
||||
update_item(same)
|
||||
else
|
||||
selected_item = nil
|
||||
end
|
||||
refresh = true
|
||||
end
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function validate_parameters()
|
||||
if not selected_item then
|
||||
post_button:Disable()
|
||||
return
|
||||
end
|
||||
if get_unit_buyout_price() > 0 and get_unit_start_price() > get_unit_buyout_price() then
|
||||
post_button:Disable()
|
||||
return
|
||||
end
|
||||
if get_unit_start_price() == 0 then
|
||||
post_button:Enable()
|
||||
return
|
||||
end
|
||||
if stack_count_slider:GetValue() == 0 then
|
||||
post_button:Disable()
|
||||
return
|
||||
end
|
||||
post_button:Enable()
|
||||
end
|
||||
|
||||
function update_item_configuration()
|
||||
if not selected_item then
|
||||
refresh_button:Disable()
|
||||
|
||||
item.texture:SetTexture(nil)
|
||||
item.count:SetText()
|
||||
item.name:SetTextColor(aux.color.label.enabled())
|
||||
item.name:SetText('No item selected')
|
||||
|
||||
unit_start_price_input:Hide()
|
||||
unit_buyout_price_input:Hide()
|
||||
stack_size_slider:Hide()
|
||||
stack_count_slider:Hide()
|
||||
deposit:Hide()
|
||||
duration_dropdown:Hide()
|
||||
hide_checkbox:Hide()
|
||||
else
|
||||
unit_start_price_input:Show()
|
||||
unit_buyout_price_input:Show()
|
||||
stack_size_slider:Show()
|
||||
stack_count_slider:Show()
|
||||
deposit:Show()
|
||||
duration_dropdown:Show()
|
||||
hide_checkbox:Show()
|
||||
|
||||
item.texture:SetTexture(selected_item.texture)
|
||||
item.name:SetText('[' .. selected_item.name .. ']')
|
||||
do
|
||||
local color = ITEM_QUALITY_COLORS[selected_item.quality]
|
||||
item.name:SetTextColor(color.r, color.g, color.b)
|
||||
end
|
||||
if selected_item.aux_quantity > 1 then
|
||||
item.count:SetText(selected_item.aux_quantity)
|
||||
else
|
||||
item.count:SetText()
|
||||
end
|
||||
|
||||
stack_size_slider.editbox:SetNumber(stack_size_slider:GetValue())
|
||||
stack_count_slider.editbox:SetNumber(stack_count_slider:GetValue())
|
||||
|
||||
do
|
||||
local deposit_factor = UnitFactionGroup'npc' and .05 or .25
|
||||
local duration_factor = UIDropDownMenu_GetSelectedValue(duration_dropdown) / 120
|
||||
local stack_size, stack_count = selected_item.max_charges and 1 or stack_size_slider:GetValue(), stack_count_slider:GetValue()
|
||||
local amount = floor(selected_item.unit_vendor_price * deposit_factor * stack_size) * stack_count * duration_factor
|
||||
deposit:SetText('Deposit: ' .. money.to_string(amount, nil, nil, aux.color.text.enabled))
|
||||
end
|
||||
|
||||
refresh_button:Enable()
|
||||
end
|
||||
end
|
||||
|
||||
function undercut(record, stack_size, stack)
|
||||
local price = ceil(record.unit_price * (stack and record.stack_size or stack_size))
|
||||
if not record.own then
|
||||
price = price - 1
|
||||
end
|
||||
return price / stack_size
|
||||
end
|
||||
|
||||
function quantity_update(maximize_count)
|
||||
if selected_item then
|
||||
local max_stack_count = selected_item.max_charges and selected_item.availability[stack_size_slider:GetValue()] or floor(selected_item.availability[0] / stack_size_slider:GetValue())
|
||||
stack_count_slider:SetMinMaxValues(1, max_stack_count)
|
||||
if maximize_count then
|
||||
stack_count_slider:SetValue(max_stack_count)
|
||||
end
|
||||
end
|
||||
refresh = true
|
||||
end
|
||||
|
||||
function unit_vendor_price(item_key)
|
||||
for slot in info.inventory() do
|
||||
T.temp(slot)
|
||||
local item_info = T.temp-info.container_item(unpack(slot))
|
||||
if item_info and item_info.item_key == item_key then
|
||||
if info.auctionable(item_info.tooltip, nil, true) and not item_info.lootable then
|
||||
ClearCursor()
|
||||
PickupContainerItem(unpack(slot))
|
||||
ClickAuctionSellItemButton()
|
||||
local auction_sell_item = T.temp-info.auction_sell_item()
|
||||
ClearCursor()
|
||||
ClickAuctionSellItemButton()
|
||||
ClearCursor()
|
||||
if auction_sell_item then
|
||||
return auction_sell_item.vendor_price / auction_sell_item.count
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function update_item(item)
|
||||
local settings = read_settings(item.key)
|
||||
|
||||
item.unit_vendor_price = unit_vendor_price(item.key)
|
||||
if not item.unit_vendor_price then
|
||||
settings.hidden = true
|
||||
write_settings(settings, item.key)
|
||||
refresh = true
|
||||
return
|
||||
end
|
||||
|
||||
scan.abort(scan_id)
|
||||
|
||||
selected_item = item
|
||||
|
||||
UIDropDownMenu_Initialize(duration_dropdown, initialize_duration_dropdown)
|
||||
UIDropDownMenu_SetSelectedValue(duration_dropdown, settings.duration)
|
||||
|
||||
hide_checkbox:SetChecked(settings.hidden)
|
||||
|
||||
if selected_item.max_charges then
|
||||
for i = selected_item.max_charges, 1, -1 do
|
||||
if selected_item.availability[i] > 0 then
|
||||
stack_size_slider:SetMinMaxValues(1, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
stack_size_slider:SetMinMaxValues(1, min(selected_item.max_stack, selected_item.aux_quantity))
|
||||
end
|
||||
stack_size_slider:SetValue(aux.huge)
|
||||
quantity_update(true)
|
||||
|
||||
unit_start_price_input:SetText(money.to_string(settings.start_price, true, nil, nil, true))
|
||||
unit_buyout_price_input:SetText(money.to_string(settings.buyout_price, true, nil, nil, true))
|
||||
|
||||
if not bid_records[selected_item.key] then
|
||||
refresh_entries()
|
||||
end
|
||||
|
||||
write_settings(settings, item.key)
|
||||
|
||||
refresh = true
|
||||
end
|
||||
|
||||
function update_inventory_records()
|
||||
local auctionable_map = T.temp-T.acquire()
|
||||
for slot in info.inventory() do
|
||||
T.temp(slot)
|
||||
local item_info = T.temp-info.container_item(unpack(slot))
|
||||
if item_info then
|
||||
local charge_class = item_info.charges or 0
|
||||
if info.auctionable(item_info.tooltip, nil, true) and not item_info.lootable then
|
||||
if not auctionable_map[item_info.item_key] then
|
||||
local availability = T.acquire()
|
||||
for i = 0, 10 do
|
||||
availability[i] = 0
|
||||
end
|
||||
availability[charge_class] = item_info.count
|
||||
auctionable_map[item_info.item_key] = T.map(
|
||||
'item_id', item_info.item_id,
|
||||
'suffix_id', item_info.suffix_id,
|
||||
'key', item_info.item_key,
|
||||
'itemstring', item_info.itemstring,
|
||||
'name', item_info.name,
|
||||
'texture', item_info.texture,
|
||||
'quality', item_info.quality,
|
||||
'aux_quantity', item_info.charges or item_info.count,
|
||||
'max_stack', item_info.max_stack,
|
||||
'max_charges', item_info.max_charges,
|
||||
'availability', availability
|
||||
)
|
||||
else
|
||||
local auctionable = auctionable_map[item_info.item_key]
|
||||
auctionable.availability[charge_class] = (auctionable.availability[charge_class] or 0) + item_info.count
|
||||
auctionable.aux_quantity = auctionable.aux_quantity + (item_info.charges or item_info.count)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
T.release(inventory_records)
|
||||
inventory_records = aux.values(auctionable_map)
|
||||
refresh = true
|
||||
end
|
||||
|
||||
function refresh_entries()
|
||||
if selected_item then
|
||||
local item_key = selected_item.key
|
||||
set_bid_selection()
|
||||
set_buyout_selection()
|
||||
bid_records[item_key], buyout_records[item_key] = nil, nil
|
||||
local query = scan_util.item_query(selected_item.item_id)
|
||||
status_bar:update_status(0, 0)
|
||||
status_bar:set_text('Scanning auctions...')
|
||||
|
||||
scan_id = scan.start{
|
||||
type = 'list',
|
||||
ignore_owner = true,
|
||||
queries = T.list(query),
|
||||
on_page_loaded = function(page, total_pages)
|
||||
status_bar:update_status(page / total_pages, 0) -- TODO
|
||||
status_bar:set_text(format('Scanning Page %d / %d', page, total_pages))
|
||||
end,
|
||||
on_auction = function(auction_record)
|
||||
if auction_record.item_key == item_key then
|
||||
record_auction(
|
||||
auction_record.item_key,
|
||||
auction_record.aux_quantity,
|
||||
auction_record.unit_blizzard_bid,
|
||||
auction_record.unit_buyout_price,
|
||||
auction_record.duration,
|
||||
auction_record.owner
|
||||
)
|
||||
end
|
||||
end,
|
||||
on_abort = function()
|
||||
bid_records[item_key], buyout_records[item_key] = nil, nil
|
||||
status_bar:update_status(1, 1)
|
||||
status_bar:set_text('Scan aborted')
|
||||
end,
|
||||
on_complete = function()
|
||||
bid_records[item_key] = bid_records[item_key] or T.acquire()
|
||||
buyout_records[item_key] = buyout_records[item_key] or T.acquire()
|
||||
refresh = true
|
||||
status_bar:update_status(1, 1)
|
||||
status_bar:set_text('Scan complete')
|
||||
end,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function record_auction(key, aux_quantity, unit_blizzard_bid, unit_buyout_price, duration, owner)
|
||||
bid_records[key] = bid_records[key] or T.acquire()
|
||||
do
|
||||
local entry
|
||||
for _, record in bid_records[key] do
|
||||
if unit_blizzard_bid == record.unit_price and aux_quantity == record.stack_size and duration == record.duration and info.is_player(owner) == record.own then
|
||||
entry = record
|
||||
end
|
||||
end
|
||||
if not entry then
|
||||
entry = T.map('stack_size', aux_quantity, 'unit_price', unit_blizzard_bid, 'duration', duration, 'own', info.is_player(owner), 'count', 0)
|
||||
tinsert(bid_records[key], entry)
|
||||
end
|
||||
entry.count = entry.count + 1
|
||||
end
|
||||
buyout_records[key] = buyout_records[key] or T.acquire()
|
||||
if unit_buyout_price == 0 then return end
|
||||
do
|
||||
local entry
|
||||
for _, record in buyout_records[key] do
|
||||
if unit_buyout_price == record.unit_price and aux_quantity == record.stack_size and duration == record.duration and info.is_player(owner) == record.own then
|
||||
entry = record
|
||||
end
|
||||
end
|
||||
if not entry then
|
||||
entry = T.map('stack_size', aux_quantity, 'unit_price', unit_buyout_price, 'duration', duration, 'own', info.is_player(owner), 'count', 0)
|
||||
tinsert(buyout_records[key], entry)
|
||||
end
|
||||
entry.count = entry.count + 1
|
||||
end
|
||||
end
|
||||
|
||||
function on_update()
|
||||
if refresh then
|
||||
refresh = false
|
||||
price_update()
|
||||
update_item_configuration()
|
||||
update_inventory_listing()
|
||||
update_auction_listings()
|
||||
end
|
||||
validate_parameters()
|
||||
end
|
||||
|
||||
function initialize_duration_dropdown()
|
||||
local function on_click()
|
||||
UIDropDownMenu_SetSelectedValue(duration_dropdown, this.value)
|
||||
local settings = read_settings()
|
||||
settings.duration = this.value
|
||||
write_settings(settings)
|
||||
refresh = true
|
||||
end
|
||||
UIDropDownMenu_AddButton{
|
||||
text = '2 Hours',
|
||||
value = DURATION_2,
|
||||
func = on_click,
|
||||
}
|
||||
UIDropDownMenu_AddButton{
|
||||
text = '8 Hours',
|
||||
value = DURATION_8,
|
||||
func = on_click,
|
||||
}
|
||||
UIDropDownMenu_AddButton{
|
||||
text = '24 Hours',
|
||||
value = DURATION_24,
|
||||
func = on_click,
|
||||
}
|
||||
end
|
||||
@@ -0,0 +1,326 @@
|
||||
module 'aux.tabs.post'
|
||||
|
||||
local aux = require 'aux'
|
||||
local info = require 'aux.util.info'
|
||||
local money = require 'aux.util.money'
|
||||
local gui = require 'aux.gui'
|
||||
local listing = require 'aux.gui.listing'
|
||||
local item_listing = require 'aux.gui.item_listing'
|
||||
local search_tab = require 'aux.tabs.search'
|
||||
|
||||
frame = CreateFrame('Frame', nil, aux.frame)
|
||||
frame:SetAllPoints()
|
||||
frame:SetScript('OnUpdate', on_update)
|
||||
frame:Hide()
|
||||
|
||||
frame.content = CreateFrame('Frame', nil, frame)
|
||||
frame.content:SetPoint('TOP', frame, 'TOP', 0, -8)
|
||||
frame.content:SetPoint('BOTTOMLEFT', aux.frame.content, 'BOTTOMLEFT', 0, 0)
|
||||
frame.content:SetPoint('BOTTOMRIGHT', aux.frame.content, 'BOTTOMRIGHT', 0, 0)
|
||||
|
||||
frame.inventory = gui.panel(frame.content)
|
||||
frame.inventory:SetWidth(212)
|
||||
frame.inventory:SetPoint('TOPLEFT', 0, 0)
|
||||
frame.inventory:SetPoint('BOTTOMLEFT', 0, 0)
|
||||
|
||||
frame.parameters = gui.panel(frame.content)
|
||||
frame.parameters:SetHeight(173)
|
||||
frame.parameters:SetPoint('TOPLEFT', frame.inventory, 'TOPRIGHT', 2.5, 0)
|
||||
frame.parameters:SetPoint('TOPRIGHT', 0, 0)
|
||||
|
||||
frame.bid_listing = gui.panel(frame.content)
|
||||
frame.bid_listing:SetHeight(228)
|
||||
frame.bid_listing:SetWidth(271.5)
|
||||
frame.bid_listing:SetPoint('BOTTOMLEFT', frame.inventory, 'BOTTOMRIGHT', 2.5, 0)
|
||||
|
||||
frame.buyout_listing = gui.panel(frame.content)
|
||||
frame.buyout_listing:SetHeight(228)
|
||||
frame.buyout_listing:SetWidth(271.5)
|
||||
frame.buyout_listing:SetPoint('BOTTOMRIGHT', 0, 0)
|
||||
|
||||
do
|
||||
local checkbox = gui.checkbox(frame.inventory)
|
||||
checkbox:SetPoint('TOPLEFT', 49, -15)
|
||||
checkbox:SetScript('OnClick', function()
|
||||
refresh = true
|
||||
end)
|
||||
local label = gui.label(checkbox, gui.font_size.small)
|
||||
label:SetPoint('LEFT', checkbox, 'RIGHT', 4, 1)
|
||||
label:SetText('Show hidden items')
|
||||
show_hidden_checkbox = checkbox
|
||||
end
|
||||
|
||||
gui.horizontal_line(frame.inventory, -45)
|
||||
|
||||
do
|
||||
local f = CreateFrame('Frame', nil, frame.inventory)
|
||||
f:SetPoint('TOPLEFT', 0, -51)
|
||||
f:SetPoint('BOTTOMRIGHT', 0, 0)
|
||||
inventory_listing = item_listing.new(
|
||||
f,
|
||||
function()
|
||||
if arg1 == 'LeftButton' then
|
||||
update_item(this.item_record)
|
||||
elseif arg1 == 'RightButton' then
|
||||
aux.set_tab(1)
|
||||
search_tab.set_filter(strlower(info.item(this.item_record.item_id).name) .. '/exact')
|
||||
search_tab.execute(nil, false)
|
||||
end
|
||||
end,
|
||||
function(item_record)
|
||||
return item_record == selected_item
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
bid_listing = listing.new(frame.bid_listing)
|
||||
bid_listing:SetColInfo{
|
||||
{name='Auctions', width=.17, align='CENTER'},
|
||||
{name='Time\nLeft', width=.11, align='CENTER'},
|
||||
{name='Stack\nSize', width=.11, align='CENTER'},
|
||||
{name='Auction Bid\n(per item)', width=.4, align='RIGHT'},
|
||||
{name='% Hist.\nValue', width=.21, align='CENTER'},
|
||||
}
|
||||
bid_listing:SetSelection(function(data)
|
||||
return data.record == get_bid_selection() or data.record.historical_value and get_bid_selection() and get_bid_selection().historical_value
|
||||
end)
|
||||
bid_listing:SetHandler('OnClick', function(table, row_data, column, button)
|
||||
if button == 'RightButton' and row_data.record == get_bid_selection() or row_data.record.historical_value and get_bid_selection() and get_bid_selection().historical_value then
|
||||
set_bid_selection()
|
||||
else
|
||||
set_bid_selection(row_data.record)
|
||||
end
|
||||
refresh = true
|
||||
end)
|
||||
bid_listing:SetHandler('OnDoubleClick', function(table, row_data, column, button)
|
||||
stack_size_slider:SetValue(row_data.record.stack_size)
|
||||
refresh = true
|
||||
end)
|
||||
|
||||
buyout_listing = listing.new(frame.buyout_listing)
|
||||
buyout_listing:SetColInfo{
|
||||
{name='Auctions', width=.17, align='CENTER'},
|
||||
{name='Time\nLeft', width=.11, align='CENTER'},
|
||||
{name='Stack\nSize', width=.12, align='CENTER'},
|
||||
{name='Auction Buyout\n(per item)', width=.4, align='RIGHT'},
|
||||
{name='% Hist.\nValue', width=.20, align='CENTER'},
|
||||
}
|
||||
buyout_listing:SetSelection(function(data)
|
||||
return data.record == get_buyout_selection() or data.record.historical_value and get_buyout_selection() and get_buyout_selection().historical_value
|
||||
end)
|
||||
buyout_listing:SetHandler('OnClick', function(table, row_data, column, button)
|
||||
if button == 'RightButton' and row_data.record == get_buyout_selection() or row_data.record.historical_value and get_buyout_selection() and get_buyout_selection().historical_value then
|
||||
set_buyout_selection()
|
||||
else
|
||||
set_buyout_selection(row_data.record)
|
||||
end
|
||||
refresh = true
|
||||
end)
|
||||
buyout_listing:SetHandler('OnDoubleClick', function(table, row_data, column, button)
|
||||
stack_size_slider:SetValue(row_data.record.stack_size)
|
||||
refresh = true
|
||||
end)
|
||||
|
||||
do
|
||||
status_bar = gui.status_bar(frame)
|
||||
status_bar:SetWidth(265)
|
||||
status_bar:SetHeight(25)
|
||||
status_bar:SetPoint('TOPLEFT', aux.frame.content, 'BOTTOMLEFT', 0, -6)
|
||||
status_bar:update_status(1, 1)
|
||||
status_bar:set_text('')
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame.parameters)
|
||||
btn:SetPoint('TOPLEFT', status_bar, 'TOPRIGHT', 5, 0)
|
||||
btn:SetText('Post')
|
||||
btn:SetScript('OnClick', post_auctions)
|
||||
post_button = btn
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame.parameters)
|
||||
btn:SetPoint('TOPLEFT', post_button, 'TOPRIGHT', 5, 0)
|
||||
btn:SetText('Refresh')
|
||||
btn:SetScript('OnClick', refresh_button_click)
|
||||
refresh_button = btn
|
||||
end
|
||||
do
|
||||
item = gui.item(frame.parameters)
|
||||
item:SetPoint('TOPLEFT', 10, -6)
|
||||
item.button:SetScript('OnEnter', function()
|
||||
if selected_item then
|
||||
info.set_tooltip(selected_item.itemstring, this, 'ANCHOR_RIGHT')
|
||||
end
|
||||
end)
|
||||
item.button:SetScript('OnLeave', function()
|
||||
GameTooltip:Hide()
|
||||
end)
|
||||
end
|
||||
do
|
||||
local slider = gui.slider(frame.parameters)
|
||||
slider:SetValueStep(1)
|
||||
slider:SetPoint('TOPLEFT', 13, -73)
|
||||
slider:SetWidth(190)
|
||||
slider:SetScript('OnValueChanged', function()
|
||||
quantity_update(true)
|
||||
end)
|
||||
slider.editbox.change = function()
|
||||
slider:SetValue(this:GetNumber())
|
||||
quantity_update(true)
|
||||
if selected_item then
|
||||
local settings = read_settings()
|
||||
write_settings(settings)
|
||||
end
|
||||
end
|
||||
slider.editbox:SetScript('OnTabPressed', function()
|
||||
if IsShiftKeyDown() then
|
||||
unit_buyout_price_input:SetFocus()
|
||||
elseif stack_count_slider.editbox:IsVisible() then
|
||||
stack_count_slider.editbox:SetFocus()
|
||||
else
|
||||
unit_start_price_input:SetFocus()
|
||||
end
|
||||
end)
|
||||
slider.editbox:SetNumeric(true)
|
||||
slider.editbox:SetMaxLetters(3)
|
||||
slider.label:SetText('Stack Size')
|
||||
stack_size_slider = slider
|
||||
end
|
||||
do
|
||||
local slider = gui.slider(frame.parameters)
|
||||
slider:SetValueStep(1)
|
||||
slider:SetPoint('TOPLEFT', stack_size_slider, 'BOTTOMLEFT', 0, -32)
|
||||
slider:SetWidth(190)
|
||||
slider:SetScript('OnValueChanged', function()
|
||||
quantity_update()
|
||||
end)
|
||||
slider.editbox.change = function()
|
||||
slider:SetValue(this:GetNumber())
|
||||
quantity_update()
|
||||
end
|
||||
slider.editbox:SetScript('OnTabPressed', function()
|
||||
if IsShiftKeyDown() then
|
||||
stack_size_slider.editbox:SetFocus()
|
||||
else
|
||||
unit_start_price_input:SetFocus()
|
||||
end
|
||||
end)
|
||||
slider.editbox:SetNumeric(true)
|
||||
slider.label:SetText('Stack Count')
|
||||
stack_count_slider = slider
|
||||
end
|
||||
do
|
||||
local dropdown = gui.dropdown(frame.parameters)
|
||||
dropdown:SetPoint('TOPLEFT', stack_count_slider, 'BOTTOMLEFT', 0, -22)
|
||||
dropdown:SetWidth(90)
|
||||
local label = gui.label(dropdown, gui.font_size.small)
|
||||
label:SetPoint('BOTTOMLEFT', dropdown, 'TOPLEFT', -2, -3)
|
||||
label:SetText('Duration')
|
||||
UIDropDownMenu_Initialize(dropdown, initialize_duration_dropdown)
|
||||
dropdown:SetScript('OnShow', function()
|
||||
UIDropDownMenu_Initialize(this, initialize_duration_dropdown)
|
||||
end)
|
||||
duration_dropdown = dropdown
|
||||
end
|
||||
do
|
||||
local checkbox = gui.checkbox(frame.parameters)
|
||||
checkbox:SetPoint('TOPRIGHT', -83, -6)
|
||||
checkbox:SetScript('OnClick', function()
|
||||
local settings = read_settings()
|
||||
settings.hidden = this:GetChecked()
|
||||
write_settings(settings)
|
||||
refresh = true
|
||||
end)
|
||||
local label = gui.label(checkbox, gui.font_size.small)
|
||||
label:SetPoint('LEFT', checkbox, 'RIGHT', 4, 1)
|
||||
label:SetText('Hide this item')
|
||||
hide_checkbox = checkbox
|
||||
end
|
||||
do
|
||||
local editbox = gui.editbox(frame.parameters)
|
||||
editbox:SetPoint('TOPRIGHT', -71, -60)
|
||||
editbox:SetWidth(180)
|
||||
editbox:SetHeight(22)
|
||||
editbox:SetAlignment('RIGHT')
|
||||
editbox:SetFontSize(17)
|
||||
editbox:SetScript('OnTabPressed', function()
|
||||
if IsShiftKeyDown() then
|
||||
stack_count_slider.editbox:SetFocus()
|
||||
else
|
||||
unit_buyout_price_input:SetFocus()
|
||||
end
|
||||
end)
|
||||
editbox.formatter = function() return money.to_string(get_unit_start_price(), true) end
|
||||
editbox.char = function() set_bid_selection(); set_buyout_selection(); set_unit_start_price(money.from_string(this:GetText())) end
|
||||
editbox.change = function() refresh = true end
|
||||
editbox.enter = function() this:ClearFocus() end
|
||||
editbox.focus_loss = function()
|
||||
this:SetText(money.to_string(get_unit_start_price(), true, nil, nil, true))
|
||||
end
|
||||
do
|
||||
local label = gui.label(editbox, gui.font_size.small)
|
||||
label:SetPoint('BOTTOMLEFT', editbox, 'TOPLEFT', -2, 1)
|
||||
label:SetText('Unit Starting Price')
|
||||
end
|
||||
do
|
||||
local label = gui.label(editbox, 14)
|
||||
label:SetPoint('LEFT', editbox, 'RIGHT', 8, 0)
|
||||
label:SetWidth(50)
|
||||
label:SetJustifyH('CENTER')
|
||||
start_price_percentage = label
|
||||
end
|
||||
unit_start_price_input = editbox
|
||||
end
|
||||
do
|
||||
local editbox = gui.editbox(frame.parameters)
|
||||
editbox:SetPoint('TOPRIGHT', unit_start_price_input, 'BOTTOMRIGHT', 0, -19)
|
||||
editbox:SetWidth(180)
|
||||
editbox:SetHeight(22)
|
||||
editbox:SetAlignment('RIGHT')
|
||||
editbox:SetFontSize(17)
|
||||
editbox:SetScript('OnTabPressed', function()
|
||||
if IsShiftKeyDown() then
|
||||
unit_start_price_input:SetFocus()
|
||||
else
|
||||
stack_size_slider.editbox:SetFocus()
|
||||
end
|
||||
end)
|
||||
editbox.formatter = function() return money.to_string(get_unit_buyout_price(), true) end
|
||||
editbox.char = function() set_buyout_selection(); set_unit_buyout_price(money.from_string(this:GetText())) end
|
||||
editbox.change = function() refresh = true end
|
||||
editbox.enter = function() this:ClearFocus() end
|
||||
editbox.focus_loss = function()
|
||||
this:SetText(money.to_string(get_unit_buyout_price(), true, nil, nil, true))
|
||||
end
|
||||
do
|
||||
local label = gui.label(editbox, gui.font_size.small)
|
||||
label:SetPoint('BOTTOMLEFT', editbox, 'TOPLEFT', -2, 1)
|
||||
label:SetText('Unit Buyout Price')
|
||||
end
|
||||
do
|
||||
local label = gui.label(editbox, 14)
|
||||
label:SetPoint('LEFT', editbox, 'RIGHT', 8, 0)
|
||||
label:SetWidth(50)
|
||||
label:SetJustifyH('CENTER')
|
||||
buyout_price_percentage = label
|
||||
end
|
||||
unit_buyout_price_input = editbox
|
||||
end
|
||||
do
|
||||
local label = gui.label(frame.parameters, gui.font_size.medium)
|
||||
label:SetPoint('TOPLEFT', unit_buyout_price_input, 'BOTTOMLEFT', 0, -24)
|
||||
deposit = label
|
||||
end
|
||||
|
||||
function aux.handle.LOAD()
|
||||
if not aux.account_data.post_bid then
|
||||
frame.bid_listing:Hide()
|
||||
frame.buyout_listing:SetPoint('BOTTOMLEFT', frame.inventory, 'BOTTOMRIGHT', 2.5, 0)
|
||||
buyout_listing:SetColInfo{
|
||||
{name='Auctions', width=.15, align='CENTER'},
|
||||
{name='Time Left', width=.15, align='CENTER'},
|
||||
{name='Stack Size', width=.15, align='CENTER'},
|
||||
{name='Auction Buyout (per item)', width=.4, align='RIGHT'},
|
||||
{name='% Hist. Value', width=.15, align='CENTER'},
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,85 @@
|
||||
module 'aux.tabs.search'
|
||||
|
||||
local aux = require 'aux'
|
||||
local info = require 'aux.util.info'
|
||||
|
||||
local tab = aux.tab 'Search'
|
||||
|
||||
StaticPopupDialogs.AUX_SEARCH_TABLE_FULL = {
|
||||
text = 'Table full!\nFurther results from this search will still be processed but no longer displayed in the table.',
|
||||
button1 = 'Ok',
|
||||
showAlert = 1,
|
||||
timeout = 0,
|
||||
hideOnEscape = 1,
|
||||
}
|
||||
|
||||
RESULTS, SAVED, FILTER = aux.enum(3)
|
||||
|
||||
function aux.handle.LOAD()
|
||||
set_subtab(SAVED)
|
||||
end
|
||||
|
||||
function tab.OPEN()
|
||||
frame:Show()
|
||||
update_search_listings()
|
||||
update_filter_display()
|
||||
end
|
||||
|
||||
function tab.CLOSE()
|
||||
current_search().table:SetSelectedRecord()
|
||||
frame:Hide()
|
||||
end
|
||||
|
||||
function tab.CLICK_LINK(item_info)
|
||||
set_filter(strlower(item_info.name) .. '/exact')
|
||||
execute(nil, false)
|
||||
end
|
||||
|
||||
function tab.USE_ITEM(item_info)
|
||||
set_filter(strlower(info.item(item_info.item_id).name) .. '/exact')
|
||||
execute(nil, false)
|
||||
end
|
||||
|
||||
function set_subtab(tab)
|
||||
CloseDropDownMenus()
|
||||
search_results_button:UnlockHighlight()
|
||||
saved_searches_button:UnlockHighlight()
|
||||
new_filter_button:UnlockHighlight()
|
||||
frame.results:Hide()
|
||||
frame.saved:Hide()
|
||||
frame.filter:Hide()
|
||||
|
||||
if tab == RESULTS then
|
||||
frame.results:Show()
|
||||
search_results_button:LockHighlight()
|
||||
elseif tab == SAVED then
|
||||
frame.saved:Show()
|
||||
saved_searches_button:LockHighlight()
|
||||
elseif tab == FILTER then
|
||||
frame.filter:Show()
|
||||
new_filter_button:LockHighlight()
|
||||
end
|
||||
end
|
||||
|
||||
function M.set_filter(filter_string)
|
||||
search_box:SetFocus()
|
||||
search_box:SetText(filter_string)
|
||||
end
|
||||
|
||||
function add_filter(filter_string)
|
||||
local old_filter_string = search_box:GetText()
|
||||
old_filter_string = aux.trim(old_filter_string)
|
||||
|
||||
if old_filter_string ~= '' then
|
||||
old_filter_string = old_filter_string .. ';'
|
||||
end
|
||||
|
||||
set_filter(old_filter_string .. filter_string)
|
||||
end
|
||||
|
||||
function blizzard_page_index(str)
|
||||
if tonumber(str) then
|
||||
return max(0, tonumber(str) - 1)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,395 @@
|
||||
module 'aux.tabs.search'
|
||||
|
||||
local T = require 'T'
|
||||
local aux = require 'aux'
|
||||
local info = require 'aux.util.info'
|
||||
local money = require 'aux.util.money'
|
||||
local filter_util = require 'aux.util.filter'
|
||||
|
||||
local post_filter = {}
|
||||
local post_filter_index = 0
|
||||
|
||||
function valid_level(str)
|
||||
local level = tonumber(str)
|
||||
return level and aux.bounded(1, 60, level)
|
||||
end
|
||||
|
||||
blizzard_query = setmetatable(T.acquire(), {
|
||||
__index = function(_, key)
|
||||
if key == 'name' then
|
||||
return name_input:GetText()
|
||||
elseif key == 'exact' then
|
||||
return exact_checkbox:GetChecked()
|
||||
elseif key == 'min_level' then
|
||||
return tonumber(min_level_input:GetText())
|
||||
elseif key == 'max_level' then
|
||||
return tonumber(max_level_input:GetText())
|
||||
elseif key == 'usable' then
|
||||
return usable_checkbox:GetChecked()
|
||||
elseif key == 'class' then
|
||||
local class_index = UIDropDownMenu_GetSelectedValue(class_dropdown)
|
||||
return class_index ~= 0 and class_index or nil
|
||||
elseif key == 'subclass' then
|
||||
local subclass_index = UIDropDownMenu_GetSelectedValue(subclass_dropdown)
|
||||
return subclass_index ~= 0 and subclass_index or nil
|
||||
elseif key == 'slot' then
|
||||
local slot_index = UIDropDownMenu_GetSelectedValue(slot_dropdown)
|
||||
return (slot_index or 0) > 0 and slot_index or nil
|
||||
elseif key == 'quality' then
|
||||
local quality_code = UIDropDownMenu_GetSelectedValue(quality_dropdown)
|
||||
return (quality_code or -1) >= 0 and quality_code or nil
|
||||
end
|
||||
end,
|
||||
__newindex = function(_, key, value)
|
||||
if key == 'name' then
|
||||
name_input:SetText(value)
|
||||
elseif key == 'exact' then
|
||||
exact_checkbox:SetChecked(value)
|
||||
elseif key == 'min_level' then
|
||||
min_level_input:SetText(value)
|
||||
elseif key == 'max_level' then
|
||||
max_level_input:SetText(value)
|
||||
elseif key == 'usable' then
|
||||
usable_checkbox:SetChecked(value)
|
||||
elseif key == 'class' then
|
||||
UIDropDownMenu_Initialize(class_dropdown, initialize_class_dropdown)
|
||||
UIDropDownMenu_SetSelectedValue(class_dropdown, value)
|
||||
elseif key == 'subclass' then
|
||||
UIDropDownMenu_Initialize(subclass_dropdown, initialize_subclass_dropdown)
|
||||
UIDropDownMenu_SetSelectedValue(subclass_dropdown, value)
|
||||
elseif key == 'slot' then
|
||||
UIDropDownMenu_Initialize(slot_dropdown, initialize_slot_dropdown)
|
||||
UIDropDownMenu_SetSelectedValue(slot_dropdown, value)
|
||||
elseif key == 'quality' then
|
||||
UIDropDownMenu_Initialize(quality_dropdown, initialize_quality_dropdown)
|
||||
UIDropDownMenu_SetSelectedValue(quality_dropdown, value)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
function update_form()
|
||||
if GetAuctionItemSubClasses(blizzard_query.class or 0) then
|
||||
subclass_dropdown.button:Enable()
|
||||
else
|
||||
subclass_dropdown.button:Disable()
|
||||
end
|
||||
|
||||
if blizzard_query.class == 2 then
|
||||
slot_dropdown.button:Enable()
|
||||
else
|
||||
slot_dropdown.button:Disable()
|
||||
end
|
||||
|
||||
if blizzard_query.exact then
|
||||
usable_checkbox:Disable()
|
||||
for key in T.temp-T.set('min_level', 'max_level') do
|
||||
_M[key .. '_input']:EnableMouse(false)
|
||||
_M[key .. '_input']:ClearFocus()
|
||||
end
|
||||
for key in T.temp-T.set('class', 'subclass', 'slot', 'quality') do
|
||||
_M[key .. '_dropdown'].button:Disable()
|
||||
end
|
||||
CloseDropDownMenus()
|
||||
else
|
||||
usable_checkbox:Enable()
|
||||
for key in T.temp-T.set('min_level', 'max_level') do
|
||||
_M[key .. '_input']:EnableMouse(true)
|
||||
end
|
||||
class_dropdown.button:Enable()
|
||||
quality_dropdown.button:Enable()
|
||||
end
|
||||
|
||||
if aux.any(T.temp-T.list('min_level', 'max_level', 'usable', 'class', 'subclass', 'slot', 'quality'), function(key) return blizzard_query[key] end) then
|
||||
exact_checkbox:Disable()
|
||||
else
|
||||
exact_checkbox:Enable()
|
||||
end
|
||||
end
|
||||
|
||||
function get_filter_builder_query()
|
||||
local filter_string
|
||||
|
||||
local function add(part)
|
||||
if part then
|
||||
filter_string = filter_string and filter_string .. '/' .. part or part
|
||||
end
|
||||
end
|
||||
|
||||
local name = blizzard_query.name
|
||||
if not aux.index(filter_util.parse_filter_string(name), 'blizzard', 'name') then
|
||||
name = filter_util.quote(name)
|
||||
end
|
||||
add((name ~= '' or blizzard_query.exact) and name)
|
||||
|
||||
add(blizzard_query.exact and 'exact')
|
||||
add(blizzard_query.min_level or blizzard_query.max_level and 1)
|
||||
add(blizzard_query.max_level)
|
||||
add(blizzard_query.usable and 'usable')
|
||||
|
||||
local classes = T.temp-T.list(GetAuctionItemClasses())
|
||||
if blizzard_query.class and blizzard_query.class > 0 then
|
||||
add(strlower(classes[blizzard_query.class]))
|
||||
end
|
||||
local subclasses = T.temp-T.list(GetAuctionItemSubClasses(blizzard_query.class or 0))
|
||||
if blizzard_query.subclass and blizzard_query.subclass > 0 then
|
||||
add(strlower(subclasses[blizzard_query.subclass]))
|
||||
end
|
||||
local slot_index = blizzard_query.slot
|
||||
if slot_index then
|
||||
local slots = T.temp-T.list(GetAuctionInvTypes(blizzard_query.class or 0, blizzard_query.subclass or 0))
|
||||
add(strlower(_G[slots[slot_index]]))
|
||||
end
|
||||
|
||||
local quality = blizzard_query.quality
|
||||
if quality and quality >= 0 then
|
||||
add(strlower(_G['ITEM_QUALITY' .. quality .. '_DESC']))
|
||||
end
|
||||
|
||||
local post_filter_string = filter_util.filter_string(post_filter)
|
||||
add(post_filter_string ~= '' and post_filter_string)
|
||||
|
||||
return filter_string or ''
|
||||
end
|
||||
|
||||
function set_form(filter)
|
||||
clear_form()
|
||||
for _, component in ipairs(filter.components) do
|
||||
if component[1] == 'blizzard' then
|
||||
blizzard_query[component[2]] = component[4]
|
||||
else
|
||||
add_component(component)
|
||||
end
|
||||
end
|
||||
update_filter_display()
|
||||
end
|
||||
|
||||
function clear_form()
|
||||
blizzard_query.name = ''
|
||||
name_input:ClearFocus()
|
||||
blizzard_query.exact = false
|
||||
blizzard_query.min_level = ''
|
||||
min_level_input:ClearFocus()
|
||||
blizzard_query.max_level = ''
|
||||
max_level_input:ClearFocus()
|
||||
blizzard_query.usable = false
|
||||
UIDropDownMenu_ClearAll(class_dropdown)
|
||||
UIDropDownMenu_ClearAll(subclass_dropdown)
|
||||
UIDropDownMenu_ClearAll(slot_dropdown)
|
||||
UIDropDownMenu_ClearAll(quality_dropdown)
|
||||
filter_parameter_input:ClearFocus()
|
||||
T.wipe(post_filter)
|
||||
post_filter_index = 0
|
||||
update_filter_display()
|
||||
end
|
||||
|
||||
function import_filter_string()
|
||||
local filter, error = filter_util.parse_filter_string(aux.select(3, strfind(search_box:GetText(), '^([^;]*)')))
|
||||
if filter or aux.print(error) then
|
||||
set_form(filter)
|
||||
end
|
||||
update_form()
|
||||
end
|
||||
|
||||
function export_filter_string()
|
||||
set_filter(get_filter_builder_query())
|
||||
end
|
||||
|
||||
function formatted_post_filter(components)
|
||||
local no_line_break
|
||||
local stack = T.temp-T.acquire()
|
||||
local str = ''
|
||||
|
||||
for i, component in ipairs(components) do
|
||||
local component = components[i]
|
||||
if no_line_break then
|
||||
str = str .. ' '
|
||||
end
|
||||
str = str .. '</p><p>'
|
||||
for _ = 1, getn(stack) + 1 do
|
||||
str = str .. aux.color.content.background'----'
|
||||
end
|
||||
no_line_break = component[1] == 'operator' and component[2] == 'not'
|
||||
|
||||
local filter_color = (post_filter_index == i and aux.color.gold or aux.color.orange)
|
||||
local component_text = filter_color(component[2])
|
||||
if component[1] == 'operator' and component[2] ~= 'not' then
|
||||
component_text = component_text .. filter_color(tonumber(component[3]) or '')
|
||||
tinsert(stack, component[3])
|
||||
elseif component[1] == 'filter' then
|
||||
local parameter = component[3]
|
||||
if parameter then
|
||||
if component[2] == 'item' then
|
||||
parameter = info.display_name(info.item_id(parameter)) or '[' .. parameter .. ']'
|
||||
elseif filter_util.filters[component[2]].input_type == 'money' then
|
||||
parameter = money.to_string(money.from_string(parameter), nil, true)
|
||||
end
|
||||
component_text = component_text .. filter_color(': ') .. parameter
|
||||
end
|
||||
while getn(stack) > 0 and stack[getn(stack)] do
|
||||
local top = tremove(stack)
|
||||
if tonumber(top) and top > 1 then
|
||||
tinsert(stack, top - 1)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
str = str .. data_link(i, component_text)
|
||||
end
|
||||
|
||||
return '<html><body><p>' .. data_link(0, 'Post Filter:') .. '</p><p>' .. str .. '</p></body></html>'
|
||||
end
|
||||
|
||||
function data_link(id, str)
|
||||
return format('<a href="%s">%s</a>', id, str)
|
||||
end
|
||||
|
||||
function data_link_click()
|
||||
local button = arg3
|
||||
local index = tonumber(arg1)
|
||||
if button == 'LeftButton' then
|
||||
post_filter_index = index
|
||||
elseif button == 'RightButton' and index > 0 then
|
||||
remove_component(index)
|
||||
end
|
||||
update_filter_display()
|
||||
end
|
||||
|
||||
function remove_component(index)
|
||||
tremove(post_filter, index)
|
||||
if post_filter_index >= index then
|
||||
post_filter_index = max(post_filter_index - 1, min(1, getn(post_filter)))
|
||||
end
|
||||
end
|
||||
|
||||
function add_component(component)
|
||||
post_filter_index = post_filter_index + 1
|
||||
tinsert(post_filter, post_filter_index, component)
|
||||
end
|
||||
|
||||
function add_form_component()
|
||||
local str = filter_input:GetText()
|
||||
if str then
|
||||
local filter = filter_util.filters[str]
|
||||
if filter then
|
||||
if filter.input_type ~= '' then
|
||||
str = str .. '/' .. filter_parameter_input:GetText()
|
||||
end
|
||||
end
|
||||
local components, error = filter_util.parse_filter_string(str)
|
||||
if components and getn(components.blizzard) == 0 and getn(components.post) == 1 then
|
||||
add_component(components.post[1])
|
||||
update_filter_display()
|
||||
filter_parameter_input:SetText('')
|
||||
filter_input:HighlightText()
|
||||
filter_input:SetFocus()
|
||||
elseif error then
|
||||
aux.print(error)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local text = ''
|
||||
function update_filter_display()
|
||||
text = formatted_post_filter(post_filter)
|
||||
filter_display:SetWidth(filter_display_size())
|
||||
set_filter_display_offset()
|
||||
filter_display:SetText(text)
|
||||
end
|
||||
function filter_display_size()
|
||||
local font, font_size = filter_display:GetFont()
|
||||
filter_display.measure:SetFont(font, font_size)
|
||||
local lines = 0
|
||||
local width = 0
|
||||
for line in string.gfind(text, '<p>(.-)</p>') do
|
||||
lines = lines + 1
|
||||
filter_display.measure:SetText(line)
|
||||
width = max(width, filter_display.measure:GetStringWidth())
|
||||
end
|
||||
return width, lines * (font_size + .5)
|
||||
end
|
||||
end
|
||||
|
||||
function set_filter_display_offset(x_offset, y_offset)
|
||||
local scroll_frame = filter_display:GetParent()
|
||||
x_offset, y_offset = x_offset or scroll_frame:GetHorizontalScroll(), y_offset or scroll_frame:GetVerticalScroll()
|
||||
local width, height = filter_display_size()
|
||||
local x_lower_bound = min(0, scroll_frame:GetWidth() - width - 10)
|
||||
local x_upper_bound = 0
|
||||
local y_lower_bound = 0
|
||||
local y_upper_bound = max(0, height - scroll_frame:GetHeight())
|
||||
scroll_frame:SetHorizontalScroll(aux.bounded(x_lower_bound, x_upper_bound, x_offset))
|
||||
scroll_frame:SetVerticalScroll(aux.bounded(y_lower_bound, y_upper_bound, y_offset))
|
||||
end
|
||||
|
||||
function initialize_filter_dropdown()
|
||||
for _, filter in ipairs(T.temp-T.list('and', 'or', 'not', 'price', 'profit', 'vendor-profit', 'disenchant-profit', 'percent', 'bid-price', 'bid-profit', 'bid-vendor-profit', 'bid-disenchant-profit', 'bid-percent', 'item', 'tooltip', 'min-level', 'max-level', 'rarity', 'left', 'utilizable', 'seller')) do
|
||||
UIDropDownMenu_AddButton(T.map(
|
||||
'text', filter,
|
||||
'value', filter,
|
||||
'func', function()
|
||||
filter_input:SetText(this.value)
|
||||
if aux.index(filter_util.filters[this.value], 'input_type') == '' or this.value == 'not' then
|
||||
add_form_component()
|
||||
elseif filter_util.filters[this.value] then
|
||||
filter_parameter_input:Show()
|
||||
filter_parameter_input:SetFocus()
|
||||
else
|
||||
filter_input:SetFocus()
|
||||
end
|
||||
end
|
||||
))
|
||||
end
|
||||
end
|
||||
|
||||
function initialize_class_dropdown()
|
||||
local function on_click()
|
||||
if this.value ~= blizzard_query.class then
|
||||
UIDropDownMenu_SetSelectedValue(class_dropdown, this.value)
|
||||
UIDropDownMenu_ClearAll(subclass_dropdown)
|
||||
UIDropDownMenu_Initialize(subclass_dropdown, initialize_subclass_dropdown)
|
||||
UIDropDownMenu_ClearAll(slot_dropdown)
|
||||
UIDropDownMenu_Initialize(slot_dropdown, initialize_slot_dropdown)
|
||||
update_form()
|
||||
end
|
||||
end
|
||||
UIDropDownMenu_AddButton(T.map('text', ALL, 'value', 0, 'func', on_click))
|
||||
for i, class in ipairs(T.temp-T.list(GetAuctionItemClasses())) do
|
||||
UIDropDownMenu_AddButton(T.map('text', class, 'value', i, 'func', on_click))
|
||||
end
|
||||
end
|
||||
|
||||
function initialize_subclass_dropdown()
|
||||
local function on_click()
|
||||
if this.value ~= blizzard_query.subclass then
|
||||
UIDropDownMenu_SetSelectedValue(subclass_dropdown, this.value)
|
||||
update_form()
|
||||
end
|
||||
end
|
||||
UIDropDownMenu_AddButton(T.map('text', ALL, 'value', 0, 'func', on_click))
|
||||
for i, subclass in ipairs(T.temp-T.list(GetAuctionItemSubClasses(blizzard_query.class or 0))) do
|
||||
UIDropDownMenu_AddButton(T.map('text', subclass, 'value', i, 'func', on_click))
|
||||
end
|
||||
end
|
||||
|
||||
function initialize_slot_dropdown()
|
||||
local function on_click()
|
||||
UIDropDownMenu_SetSelectedValue(slot_dropdown, this.value)
|
||||
update_form()
|
||||
end
|
||||
UIDropDownMenu_AddButton(T.map('text', ALL, 'value', 0, 'func', on_click))
|
||||
for i, slot in ipairs(T.temp-T.list(GetAuctionInvTypes(blizzard_query.class == 2 and 2 or 0, blizzard_query.subclass or 0))) do
|
||||
UIDropDownMenu_AddButton(T.map('text', _G[slot], 'value', i, 'func', on_click))
|
||||
end
|
||||
end
|
||||
|
||||
function initialize_quality_dropdown()
|
||||
local function on_click()
|
||||
UIDropDownMenu_SetSelectedValue(quality_dropdown, this.value)
|
||||
update_form()
|
||||
end
|
||||
UIDropDownMenu_AddButton(T.map('text', ALL, 'value', -1, 'func', on_click))
|
||||
for i = 0, 4 do
|
||||
UIDropDownMenu_AddButton(T.map('text', _G['ITEM_QUALITY' .. i .. '_DESC'], 'value', i, 'func', on_click))
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,559 @@
|
||||
module 'aux.tabs.search'
|
||||
|
||||
local T = require 'T'
|
||||
local aux = require 'aux'
|
||||
local info = require 'aux.util.info'
|
||||
local completion = require 'aux.util.completion'
|
||||
local filter_util = require 'aux.util.filter'
|
||||
local scan = require 'aux.core.scan'
|
||||
local gui = require 'aux.gui'
|
||||
local listing = require 'aux.gui.listing'
|
||||
local auction_listing = require 'aux.gui.auction_listing'
|
||||
|
||||
local FILTER_SPACING = 28.5
|
||||
|
||||
frame = CreateFrame('Frame', nil, aux.frame)
|
||||
frame:SetAllPoints()
|
||||
frame:SetScript('OnUpdate', on_update)
|
||||
frame:Hide()
|
||||
|
||||
frame.filter = gui.panel(frame)
|
||||
frame.filter:SetAllPoints(aux.frame.content)
|
||||
|
||||
frame.results = gui.panel(frame)
|
||||
frame.results:SetAllPoints(aux.frame.content)
|
||||
|
||||
frame.saved = CreateFrame('Frame', nil, frame)
|
||||
frame.saved:SetAllPoints(aux.frame.content)
|
||||
|
||||
frame.saved.favorite = gui.panel(frame.saved)
|
||||
frame.saved.favorite:SetWidth(393)
|
||||
frame.saved.favorite:SetPoint('TOPLEFT', 0, 0)
|
||||
frame.saved.favorite:SetPoint('BOTTOMLEFT', 0, 0)
|
||||
|
||||
frame.saved.recent = gui.panel(frame.saved)
|
||||
frame.saved.recent:SetWidth(364.5)
|
||||
frame.saved.recent:SetPoint('TOPRIGHT', 0, 0)
|
||||
frame.saved.recent:SetPoint('BOTTOMRIGHT', 0, 0)
|
||||
do
|
||||
local btn = gui.button(frame, 25)
|
||||
btn:SetPoint('TOPLEFT', 5, -8)
|
||||
btn:SetWidth(30)
|
||||
btn:SetHeight(25)
|
||||
btn:SetText('<')
|
||||
btn:SetScript('OnClick', previous_search)
|
||||
previous_button = btn
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame, 25)
|
||||
btn:SetPoint('LEFT', previous_button, 'RIGHT', 4, 0)
|
||||
btn:SetWidth(30)
|
||||
btn:SetHeight(25)
|
||||
btn:SetText('>')
|
||||
btn:SetScript('OnClick', next_search)
|
||||
next_button = btn
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame, gui.font_size.small)
|
||||
btn:SetHeight(25)
|
||||
btn:SetWidth(60)
|
||||
btn:SetText(aux.color.label.enabled'Range:')
|
||||
btn:SetScript('OnClick', function()
|
||||
update_real_time(true)
|
||||
end)
|
||||
range_button = btn
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame, gui.font_size.small)
|
||||
btn:SetHeight(25)
|
||||
btn:SetWidth(60)
|
||||
btn:Hide()
|
||||
btn:SetText(aux.color.label.enabled'Real Time')
|
||||
btn:SetScript('OnClick', function()
|
||||
update_real_time(false)
|
||||
end)
|
||||
real_time_button = btn
|
||||
end
|
||||
do
|
||||
local function change()
|
||||
local page = tonumber(this:GetText())
|
||||
local valid_input = page and tostring(max(1, page)) or ''
|
||||
if this:GetText() ~= valid_input then
|
||||
this:SetText(valid_input)
|
||||
end
|
||||
end
|
||||
do
|
||||
local editbox = gui.editbox(range_button)
|
||||
editbox:SetPoint('LEFT', range_button, 'RIGHT', 4, 0)
|
||||
editbox:SetWidth(40)
|
||||
editbox:SetHeight(25)
|
||||
editbox:SetAlignment('CENTER')
|
||||
editbox:SetNumeric(true)
|
||||
editbox:SetScript('OnTabPressed', function()
|
||||
if not IsShiftKeyDown() then
|
||||
last_page_input:SetFocus()
|
||||
end
|
||||
end)
|
||||
editbox.enter = execute
|
||||
editbox.change = change
|
||||
local label = gui.label(editbox, gui.font_size.medium)
|
||||
label:SetPoint('LEFT', editbox, 'RIGHT', 0, 0)
|
||||
label:SetTextColor(aux.color.label.enabled())
|
||||
label:SetText('-')
|
||||
first_page_input = editbox
|
||||
end
|
||||
do
|
||||
local editbox = gui.editbox(range_button)
|
||||
editbox:SetPoint('LEFT', first_page_input, 'RIGHT', 5.8, 0)
|
||||
editbox:SetWidth(40)
|
||||
editbox:SetHeight(25)
|
||||
editbox:SetAlignment('CENTER')
|
||||
editbox:SetNumeric(true)
|
||||
editbox:SetScript('OnTabPressed', function()
|
||||
if IsShiftKeyDown() then
|
||||
first_page_input:SetFocus()
|
||||
else
|
||||
search_box:SetFocus()
|
||||
end
|
||||
end)
|
||||
editbox.enter = execute
|
||||
editbox.change = change
|
||||
last_page_input = editbox
|
||||
end
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame)
|
||||
btn:SetHeight(25)
|
||||
btn:SetPoint('TOPRIGHT', -5, -8)
|
||||
btn:SetText('Search')
|
||||
btn:RegisterForClicks('LeftButtonUp', 'RightButtonUp')
|
||||
btn:SetScript('OnClick', function()
|
||||
if arg1 == 'RightButton' then
|
||||
set_filter(current_search().filter_string)
|
||||
end
|
||||
execute()
|
||||
end)
|
||||
start_button = btn
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame)
|
||||
btn:SetHeight(25)
|
||||
btn:SetPoint('TOPRIGHT', -5, -8)
|
||||
btn:SetText('Pause')
|
||||
btn:SetScript('OnClick', function()
|
||||
scan.abort(search_scan_id)
|
||||
end)
|
||||
stop_button = btn
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame)
|
||||
btn:SetHeight(25)
|
||||
btn:SetPoint('RIGHT', start_button, 'LEFT', -4, 0)
|
||||
btn:SetBackdropColor(aux.color.state.enabled())
|
||||
btn:SetText('Resume')
|
||||
btn:SetScript('OnClick', function()
|
||||
execute(true)
|
||||
end)
|
||||
resume_button = btn
|
||||
end
|
||||
do
|
||||
local editbox = gui.editbox(frame)
|
||||
editbox:EnableMouse(1)
|
||||
editbox.formatter = function(str)
|
||||
local queries = filter_util.queries(str)
|
||||
return queries and aux.join(aux.map(aux.copy(queries), function(query) return query.prettified end), ';') or aux.color.red(str)
|
||||
end
|
||||
editbox.complete = completion.complete_filter
|
||||
editbox.escape = function() this:SetText(current_search().filter_string or '') end
|
||||
editbox:SetHeight(25)
|
||||
editbox.char = function()
|
||||
this:complete()
|
||||
end
|
||||
editbox:SetScript('OnTabPressed', function()
|
||||
if IsShiftKeyDown() then
|
||||
last_page_input:SetFocus()
|
||||
else
|
||||
this:HighlightText(0, 0)
|
||||
end
|
||||
end)
|
||||
editbox.enter = execute
|
||||
search_box = editbox
|
||||
end
|
||||
do
|
||||
gui.horizontal_line(frame, -40)
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame, gui.font_size.large)
|
||||
btn:SetPoint('BOTTOMLEFT', aux.frame.content, 'TOPLEFT', 10, 8)
|
||||
btn:SetWidth(243)
|
||||
btn:SetHeight(22)
|
||||
btn:SetText('Search Results')
|
||||
btn:SetScript('OnClick', function() set_subtab(RESULTS) end)
|
||||
search_results_button = btn
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame, gui.font_size.large)
|
||||
btn:SetPoint('TOPLEFT', search_results_button, 'TOPRIGHT', 5, 0)
|
||||
btn:SetWidth(243)
|
||||
btn:SetHeight(22)
|
||||
btn:SetText('Saved Searches')
|
||||
btn:SetScript('OnClick', function() set_subtab(SAVED) end)
|
||||
saved_searches_button = btn
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame, gui.font_size.large)
|
||||
btn:SetPoint('TOPLEFT', saved_searches_button, 'TOPRIGHT', 5, 0)
|
||||
btn:SetWidth(243)
|
||||
btn:SetHeight(22)
|
||||
btn:SetText('Filter Builder')
|
||||
btn:SetScript('OnClick', function() set_subtab(FILTER) end)
|
||||
new_filter_button = btn
|
||||
end
|
||||
do
|
||||
local frame = CreateFrame('Frame', nil, frame)
|
||||
frame:SetWidth(265)
|
||||
frame:SetHeight(25)
|
||||
frame:SetPoint('TOPLEFT', aux.frame.content, 'BOTTOMLEFT', 0, -6)
|
||||
status_bar_frame = frame
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame.results)
|
||||
btn:SetPoint('TOPLEFT', status_bar_frame, 'TOPRIGHT', 5, 0)
|
||||
btn:SetText('Bid')
|
||||
btn:Disable()
|
||||
bid_button = btn
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame.results)
|
||||
btn:SetPoint('TOPLEFT', bid_button, 'TOPRIGHT', 5, 0)
|
||||
btn:SetText('Buyout')
|
||||
btn:Disable()
|
||||
buyout_button = btn
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame.results)
|
||||
btn:SetPoint('TOPLEFT', buyout_button, 'TOPRIGHT', 5, 0)
|
||||
btn:SetText('Clear')
|
||||
btn:SetScript('OnClick', function()
|
||||
while tremove(current_search().records) do end
|
||||
current_search().table:SetDatabase()
|
||||
end)
|
||||
end
|
||||
do
|
||||
local btn = gui.button(frame.saved)
|
||||
btn:SetPoint('TOPLEFT', status_bar_frame, 'TOPRIGHT', 5, 0)
|
||||
btn:SetText('Favorite')
|
||||
btn:SetScript('OnClick', function()
|
||||
add_favorite(search_box:GetText())
|
||||
end)
|
||||
end
|
||||
do
|
||||
local btn1 = gui.button(frame.filter)
|
||||
btn1:SetPoint('TOPLEFT', status_bar_frame, 'TOPRIGHT', 5, 0)
|
||||
btn1:SetText('Search')
|
||||
btn1:SetScript('OnClick', function()
|
||||
export_filter_string()
|
||||
execute()
|
||||
end)
|
||||
|
||||
local btn2 = gui.button(frame.filter)
|
||||
btn2:SetPoint('LEFT', btn1, 'RIGHT', 5, 0)
|
||||
btn2:SetText('Export')
|
||||
btn2:SetScript('OnClick', export_filter_string)
|
||||
|
||||
local btn3 = gui.button(frame.filter)
|
||||
btn3:SetPoint('LEFT', btn2, 'RIGHT', 5, 0)
|
||||
btn3:SetText('Import')
|
||||
btn3:SetScript('OnClick', import_filter_string)
|
||||
end
|
||||
do
|
||||
local editbox = gui.editbox(frame.filter)
|
||||
editbox.complete_item = completion.complete(function() return aux.account_data.auctionable_items end)
|
||||
editbox:SetPoint('TOPLEFT', 14, -FILTER_SPACING)
|
||||
editbox:SetWidth(260)
|
||||
editbox.char = function()
|
||||
if blizzard_query.exact then
|
||||
this:complete_item()
|
||||
end
|
||||
end
|
||||
editbox:SetScript('OnTabPressed', function()
|
||||
if blizzard_query.exact then
|
||||
return
|
||||
end
|
||||
if IsShiftKeyDown() then
|
||||
max_level_input:SetFocus()
|
||||
else
|
||||
min_level_input:SetFocus()
|
||||
end
|
||||
end)
|
||||
editbox.change = update_form
|
||||
editbox.enter = function() editbox:ClearFocus() end
|
||||
local label = gui.label(editbox, gui.font_size.small)
|
||||
label:SetPoint('BOTTOMLEFT', editbox, 'TOPLEFT', -2, 1)
|
||||
label:SetText('Name')
|
||||
name_input = editbox
|
||||
end
|
||||
do
|
||||
local checkbox = gui.checkbox(frame.filter)
|
||||
checkbox:SetPoint('TOPLEFT', name_input, 'TOPRIGHT', 16, 0)
|
||||
checkbox:SetScript('OnClick', update_form)
|
||||
local label = gui.label(checkbox, gui.font_size.small)
|
||||
label:SetPoint('BOTTOMLEFT', checkbox, 'TOPLEFT', -2, 1)
|
||||
label:SetText('Exact')
|
||||
exact_checkbox = checkbox
|
||||
end
|
||||
do
|
||||
local editbox = gui.editbox(frame.filter)
|
||||
editbox:SetPoint('TOPLEFT', name_input, 'BOTTOMLEFT', 0, -FILTER_SPACING)
|
||||
editbox:SetWidth(125)
|
||||
editbox:SetAlignment('CENTER')
|
||||
editbox:SetNumeric(true)
|
||||
editbox:SetScript('OnTabPressed', function()
|
||||
if IsShiftKeyDown() then
|
||||
name_input:SetFocus()
|
||||
else
|
||||
max_level_input:SetFocus()
|
||||
end
|
||||
end)
|
||||
editbox.enter = function() editbox:ClearFocus() end
|
||||
editbox.change = function()
|
||||
local valid_level = valid_level(this:GetText())
|
||||
if tostring(valid_level) ~= this:GetText() then
|
||||
this:SetText(valid_level or '')
|
||||
end
|
||||
update_form()
|
||||
end
|
||||
local label = gui.label(editbox, gui.font_size.small)
|
||||
label:SetPoint('BOTTOMLEFT', editbox, 'TOPLEFT', -2, 1)
|
||||
label:SetText('Level Range')
|
||||
min_level_input = editbox
|
||||
end
|
||||
do
|
||||
local editbox = gui.editbox(frame.filter)
|
||||
editbox:SetPoint('TOPLEFT', min_level_input, 'TOPRIGHT', 10, 0)
|
||||
editbox:SetWidth(125)
|
||||
editbox:SetAlignment('CENTER')
|
||||
editbox:SetNumeric(true)
|
||||
editbox:SetScript('OnTabPressed', function()
|
||||
if IsShiftKeyDown() then
|
||||
min_level_input:SetFocus()
|
||||
else
|
||||
name_input:SetFocus()
|
||||
end
|
||||
end)
|
||||
editbox.enter = function() editbox:ClearFocus() end
|
||||
editbox.change = function()
|
||||
local valid_level = valid_level(this:GetText())
|
||||
if tostring(valid_level) ~= this:GetText() then
|
||||
this:SetText(valid_level or '')
|
||||
end
|
||||
update_form()
|
||||
end
|
||||
local label = gui.label(editbox, gui.font_size.medium)
|
||||
label:SetPoint('RIGHT', editbox, 'LEFT', -3, 0)
|
||||
label:SetText('-')
|
||||
max_level_input = editbox
|
||||
end
|
||||
do
|
||||
local checkbox = gui.checkbox(frame.filter)
|
||||
checkbox:SetPoint('TOPLEFT', max_level_input, 'TOPRIGHT', 16, 0)
|
||||
checkbox:SetScript('OnClick', update_form)
|
||||
local label = gui.label(checkbox, gui.font_size.small)
|
||||
label:SetPoint('BOTTOMLEFT', checkbox, 'TOPLEFT', -2, 1)
|
||||
label:SetText('Usable')
|
||||
usable_checkbox = checkbox
|
||||
end
|
||||
do
|
||||
local dropdown = gui.dropdown(frame.filter)
|
||||
class_dropdown = dropdown
|
||||
dropdown:SetPoint('TOPLEFT', min_level_input, 'BOTTOMLEFT', 0, 5 - FILTER_SPACING)
|
||||
dropdown:SetWidth(300)
|
||||
local label = gui.label(dropdown, gui.font_size.small)
|
||||
label:SetPoint('BOTTOMLEFT', dropdown, 'TOPLEFT', -2, -3)
|
||||
label:SetText('Item Class')
|
||||
UIDropDownMenu_Initialize(dropdown, initialize_class_dropdown)
|
||||
dropdown:SetScript('OnShow', function()
|
||||
UIDropDownMenu_Initialize(this, initialize_class_dropdown)
|
||||
end)
|
||||
end
|
||||
do
|
||||
local dropdown = gui.dropdown(frame.filter)
|
||||
subclass_dropdown = dropdown
|
||||
dropdown:SetPoint('TOPLEFT', class_dropdown, 'BOTTOMLEFT', 0, 10 - FILTER_SPACING)
|
||||
dropdown:SetWidth(300)
|
||||
local label = gui.label(dropdown, gui.font_size.small)
|
||||
label:SetPoint('BOTTOMLEFT', dropdown, 'TOPLEFT', -2, -3)
|
||||
label:SetText('Item Subclass')
|
||||
UIDropDownMenu_Initialize(dropdown, initialize_subclass_dropdown)
|
||||
dropdown:SetScript('OnShow', function()
|
||||
UIDropDownMenu_Initialize(this, initialize_subclass_dropdown)
|
||||
end)
|
||||
end
|
||||
do
|
||||
local dropdown = gui.dropdown(frame.filter)
|
||||
slot_dropdown = dropdown
|
||||
dropdown:SetPoint('TOPLEFT', subclass_dropdown, 'BOTTOMLEFT', 0, 10 - FILTER_SPACING)
|
||||
dropdown:SetWidth(300)
|
||||
local label = gui.label(dropdown, gui.font_size.small)
|
||||
label:SetPoint('BOTTOMLEFT', dropdown, 'TOPLEFT', -2, -3)
|
||||
label:SetText('Item Slot')
|
||||
UIDropDownMenu_Initialize(dropdown, initialize_slot_dropdown)
|
||||
dropdown:SetScript('OnShow', function()
|
||||
UIDropDownMenu_Initialize(this, initialize_slot_dropdown)
|
||||
end)
|
||||
end
|
||||
do
|
||||
local dropdown = gui.dropdown(frame.filter)
|
||||
quality_dropdown = dropdown
|
||||
dropdown:SetPoint('TOPLEFT', slot_dropdown, 'BOTTOMLEFT', 0, 10 - FILTER_SPACING)
|
||||
dropdown:SetWidth(300)
|
||||
local label = gui.label(dropdown, gui.font_size.small)
|
||||
label:SetPoint('BOTTOMLEFT', dropdown, 'TOPLEFT', -2, -3)
|
||||
label:SetText('Min Quality')
|
||||
UIDropDownMenu_Initialize(dropdown, initialize_quality_dropdown)
|
||||
dropdown:SetScript('OnShow', function()
|
||||
UIDropDownMenu_Initialize(this, initialize_quality_dropdown)
|
||||
end)
|
||||
end
|
||||
gui.vertical_line(frame.filter, 332)
|
||||
do
|
||||
local dropdown = gui.dropdown(frame.filter)
|
||||
dropdown:SetPoint('TOPRIGHT', -174.5, -10)
|
||||
dropdown:SetWidth(150)
|
||||
UIDropDownMenu_Initialize(dropdown, initialize_filter_dropdown)
|
||||
dropdown:SetScript('OnShow', function()
|
||||
UIDropDownMenu_Initialize(this, initialize_filter_dropdown)
|
||||
end)
|
||||
_G[dropdown:GetName() .. 'Text']:Hide()
|
||||
local label = gui.label(dropdown, gui.font_size.medium)
|
||||
label:SetPoint('RIGHT', dropdown, 'LEFT', -15, 0)
|
||||
label:SetText('Component')
|
||||
filter_dropdown = dropdown
|
||||
end
|
||||
do
|
||||
local input = gui.editbox(frame.filter)
|
||||
input:SetPoint('CENTER', filter_dropdown, 'CENTER', 0, 0)
|
||||
input:SetWidth(150)
|
||||
input:SetScript('OnTabPressed', function() filter_parameter_input:SetFocus() end)
|
||||
input.complete = completion.complete(function() return T.temp-T.list('and', 'or', 'not', unpack(aux.keys(filter_util.filters))) end)
|
||||
input.char = function() this:complete() end
|
||||
input.change = function()
|
||||
local text = this:GetText()
|
||||
if filter_util.filters[text] and filter_util.filters[text].input_type ~= '' then
|
||||
local _, _, suggestions = filter_util.parse_filter_string(text .. '/')
|
||||
filter_parameter_input:SetNumeric(filter_util.filters[text].input_type == 'number')
|
||||
filter_parameter_input.complete = completion.complete(function() return suggestions or T.empty end)
|
||||
filter_parameter_input:Show()
|
||||
else
|
||||
filter_parameter_input:Hide()
|
||||
end
|
||||
end
|
||||
input.enter = function()
|
||||
if filter_parameter_input:IsVisible() then
|
||||
filter_parameter_input:SetFocus()
|
||||
else
|
||||
add_form_component()
|
||||
end
|
||||
end
|
||||
filter_input = input
|
||||
end
|
||||
do
|
||||
local input = gui.editbox(frame.filter)
|
||||
input:SetPoint('LEFT', filter_dropdown, 'RIGHT', 10, 0)
|
||||
input:SetWidth(150)
|
||||
input:SetScript('OnTabPressed', function()
|
||||
filter_input:SetFocus()
|
||||
end)
|
||||
input.char = function() this:complete() end
|
||||
input.enter = add_form_component
|
||||
input:Hide()
|
||||
filter_parameter_input = input
|
||||
end
|
||||
do
|
||||
local scroll_frame = CreateFrame('ScrollFrame', nil, frame.filter)
|
||||
scroll_frame:SetWidth(395)
|
||||
scroll_frame:SetHeight(270)
|
||||
scroll_frame:SetPoint('TOPLEFT', 348.5, -50)
|
||||
scroll_frame:EnableMouse(true)
|
||||
scroll_frame:EnableMouseWheel(true)
|
||||
scroll_frame:SetScript('OnMouseWheel', function()
|
||||
local child = this:GetScrollChild()
|
||||
child:SetFont('p', [[Fonts\ARIALN.TTF]], aux.bounded(gui.font_size.small, gui.font_size.large, aux.select(2, child:GetFont()) + arg1*2))
|
||||
update_filter_display()
|
||||
end)
|
||||
scroll_frame:RegisterForDrag('LeftButton')
|
||||
scroll_frame:SetScript('OnDragStart', function()
|
||||
this.x, this.y = GetCursorPosition()
|
||||
this.x_offset, this.y_offset = this:GetHorizontalScroll(), this:GetVerticalScroll()
|
||||
this.x_extra, this.y_extra = 0, 0
|
||||
this:SetScript('OnUpdate', function()
|
||||
local x, y = GetCursorPosition()
|
||||
local new_x_offset = this.x_offset + x - this.x
|
||||
local new_y_offset = this.y_offset + y - this.y
|
||||
|
||||
set_filter_display_offset(new_x_offset - this.x_extra, new_y_offset - this.y_extra)
|
||||
|
||||
this.x_extra = max(this.x_extra, new_x_offset)
|
||||
this.y_extra = min(this.y_extra, new_y_offset)
|
||||
end)
|
||||
end)
|
||||
scroll_frame:SetScript('OnDragStop', function()
|
||||
this:SetScript('OnUpdate', nil)
|
||||
end)
|
||||
gui.set_content_style(scroll_frame, -2, -2, -2, -2)
|
||||
local scroll_child = CreateFrame('SimpleHTML', nil, scroll_frame)
|
||||
scroll_frame:SetScrollChild(scroll_child)
|
||||
scroll_child:SetFont('p', [[Fonts\ARIALN.TTF]], gui.font_size.large)
|
||||
scroll_child:SetTextColor('p', aux.color.label.enabled())
|
||||
scroll_child:SetWidth(1)
|
||||
scroll_child:SetHeight(1)
|
||||
scroll_child:SetScript('OnHyperlinkClick', data_link_click)
|
||||
scroll_child.measure = scroll_child:CreateFontString()
|
||||
filter_display = scroll_child
|
||||
end
|
||||
|
||||
status_bars = {}
|
||||
tables = {}
|
||||
for _ = 1, 5 do
|
||||
local status_bar = gui.status_bar(frame)
|
||||
status_bar:SetAllPoints(status_bar_frame)
|
||||
status_bar:Hide()
|
||||
tinsert(status_bars, status_bar)
|
||||
|
||||
local table = auction_listing.new(frame.results, 16, auction_listing.search_columns)
|
||||
table:SetHandler('OnClick', function(row, button)
|
||||
if IsAltKeyDown() then
|
||||
if current_search().table:GetSelection().record == row.record then
|
||||
if button == 'LeftButton' then
|
||||
buyout_button:Click()
|
||||
elseif button == 'RightButton' then
|
||||
bid_button:Click()
|
||||
end
|
||||
end
|
||||
elseif button == 'RightButton' then
|
||||
aux.set_tab(1)
|
||||
set_filter(strlower(info.item(this.record.item_id).name) .. '/exact')
|
||||
execute(nil, false)
|
||||
end
|
||||
end)
|
||||
table:SetHandler('OnSelectionChanged', function(rt, datum)
|
||||
bid_button:Disable()
|
||||
buyout_button:Disable()
|
||||
if not datum then return end
|
||||
find_auction(datum.record)
|
||||
end)
|
||||
table:Hide()
|
||||
tinsert(tables, table)
|
||||
end
|
||||
|
||||
favorite_searches_listing = listing.new(frame.saved.favorite)
|
||||
favorite_searches_listing:SetColInfo{{name='Auto', width=.07, align='CENTER'}, {name='Favorite Searches', width=.93}}
|
||||
|
||||
recent_searches_listing = listing.new(frame.saved.recent)
|
||||
recent_searches_listing:SetColInfo{{name='Recent Searches', width=1}}
|
||||
|
||||
for listing in T.temp-T.set(favorite_searches_listing, recent_searches_listing) do
|
||||
for k, v in handlers do
|
||||
listing:SetHandler(k, v)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,443 @@
|
||||
module 'aux.tabs.search'
|
||||
|
||||
local T = require 'T'
|
||||
local aux = require 'aux'
|
||||
local info = require 'aux.util.info'
|
||||
local filter_util = require 'aux.util.filter'
|
||||
local scan_util = require 'aux.util.scan'
|
||||
local scan = require 'aux.core.scan'
|
||||
|
||||
search_scan_id = 0
|
||||
|
||||
function aux.handle.LOAD()
|
||||
new_search()
|
||||
end
|
||||
|
||||
function update_real_time(enable)
|
||||
if enable then
|
||||
range_button:Hide()
|
||||
real_time_button:Show()
|
||||
search_box:SetPoint('LEFT', real_time_button, 'RIGHT', 4, 0)
|
||||
else
|
||||
real_time_button:Hide()
|
||||
range_button:Show()
|
||||
search_box:SetPoint('LEFT', last_page_input, 'RIGHT', 4, 0)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local searches = {}
|
||||
local search_index = 1
|
||||
|
||||
function current_search()
|
||||
return searches[search_index]
|
||||
end
|
||||
|
||||
function update_search(index)
|
||||
searches[search_index].status_bar:Hide()
|
||||
searches[search_index].table:Hide()
|
||||
searches[search_index].table:SetSelectedRecord()
|
||||
|
||||
search_index = index
|
||||
|
||||
searches[search_index].status_bar:Show()
|
||||
searches[search_index].table:Show()
|
||||
|
||||
search_box:SetText(searches[search_index].filter_string or '')
|
||||
first_page_input:SetText(searches[search_index].first_page and searches[search_index].first_page + 1 or '')
|
||||
last_page_input:SetText(searches[search_index].last_page and searches[search_index].last_page + 1 or '')
|
||||
if search_index == 1 then
|
||||
previous_button:Disable()
|
||||
else
|
||||
previous_button:Enable()
|
||||
end
|
||||
if search_index == getn(searches) then
|
||||
next_button:Hide()
|
||||
range_button:SetPoint('LEFT', previous_button, 'RIGHT', 4, 0)
|
||||
real_time_button:SetPoint('LEFT', previous_button, 'RIGHT', 4, 0)
|
||||
else
|
||||
next_button:Show()
|
||||
range_button:SetPoint('LEFT', next_button, 'RIGHT', 4, 0)
|
||||
real_time_button:SetPoint('LEFT', next_button, 'RIGHT', 4, 0)
|
||||
end
|
||||
update_real_time(searches[search_index].real_time)
|
||||
update_start_stop()
|
||||
update_continuation()
|
||||
end
|
||||
|
||||
function new_search(filter_string, first_page, last_page, real_time)
|
||||
while getn(searches) > search_index do
|
||||
tremove(searches)
|
||||
end
|
||||
local search = T.map('records', T.acquire(), 'filter_string', filter_string, 'first_page', first_page, 'last_page', last_page, 'real_time', real_time)
|
||||
tinsert(searches, search)
|
||||
if getn(searches) > 5 then
|
||||
tremove(searches, 1)
|
||||
tinsert(status_bars, tremove(status_bars, 1))
|
||||
tinsert(tables, tremove(tables, 1))
|
||||
search_index = 4
|
||||
end
|
||||
|
||||
search.status_bar = status_bars[getn(searches)]
|
||||
search.status_bar:update_status(1, 1)
|
||||
search.status_bar:set_text('')
|
||||
|
||||
search.table = tables[getn(searches)]
|
||||
search.table:SetSort(1, 2, 3, 4, 5, 6, 7, 8, 9)
|
||||
search.table:Reset()
|
||||
search.table:SetDatabase(search.records)
|
||||
|
||||
update_search(getn(searches))
|
||||
end
|
||||
|
||||
function clear_control_focus()
|
||||
search_box:ClearFocus()
|
||||
first_page_input:ClearFocus()
|
||||
last_page_input:ClearFocus()
|
||||
end
|
||||
|
||||
function previous_search()
|
||||
clear_control_focus()
|
||||
update_search(search_index - 1)
|
||||
set_subtab(RESULTS)
|
||||
end
|
||||
|
||||
function next_search()
|
||||
clear_control_focus()
|
||||
update_search(search_index + 1)
|
||||
set_subtab(RESULTS)
|
||||
end
|
||||
end
|
||||
|
||||
function update_continuation()
|
||||
if current_search().continuation then
|
||||
resume_button:Show()
|
||||
search_box:SetPoint('RIGHT', resume_button, 'LEFT', -4, 0)
|
||||
else
|
||||
resume_button:Hide()
|
||||
search_box:SetPoint('RIGHT', start_button, 'LEFT', -4, 0)
|
||||
end
|
||||
end
|
||||
|
||||
function discard_continuation()
|
||||
scan.abort(search_scan_id)
|
||||
current_search().continuation = nil
|
||||
update_continuation()
|
||||
end
|
||||
|
||||
function update_start_stop()
|
||||
if current_search().active then
|
||||
stop_button:Show()
|
||||
start_button:Hide()
|
||||
else
|
||||
start_button:Show()
|
||||
stop_button:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
function start_real_time_scan(query, search, continuation)
|
||||
|
||||
local ignore_page
|
||||
if not search then
|
||||
search = current_search()
|
||||
query.blizzard_query.first_page = tonumber(continuation) or 0
|
||||
query.blizzard_query.last_page = tonumber(continuation) or 0
|
||||
ignore_page = not tonumber(continuation)
|
||||
end
|
||||
|
||||
local next_page
|
||||
local new_records = T.acquire()
|
||||
search_scan_id = scan.start{
|
||||
type = 'list',
|
||||
queries = {query},
|
||||
auto_buy_validator = search.auto_buy_validator,
|
||||
auto_bid_validator = search.auto_bid_validator,
|
||||
on_scan_start = function()
|
||||
search.status_bar:update_status(.9999, .9999)
|
||||
search.status_bar:set_text('Scanning last page ...')
|
||||
end,
|
||||
on_page_loaded = function(_, _, last_page)
|
||||
next_page = last_page
|
||||
if last_page == 0 then
|
||||
ignore_page = false
|
||||
end
|
||||
end,
|
||||
on_auction = function(auction_record)
|
||||
if not ignore_page then
|
||||
tinsert(new_records, auction_record)
|
||||
end
|
||||
end,
|
||||
on_complete = function()
|
||||
local map = T.temp-T.acquire()
|
||||
for _, record in search.records do
|
||||
map[record.sniping_signature] = record
|
||||
end
|
||||
for _, record in new_records do
|
||||
map[record.sniping_signature] = record
|
||||
end
|
||||
T.release(new_records)
|
||||
new_records = aux.values(map)
|
||||
|
||||
if getn(new_records) > 2000 then
|
||||
StaticPopup_Show('AUX_SEARCH_TABLE_FULL')
|
||||
else
|
||||
search.records = new_records
|
||||
search.table:SetDatabase(search.records)
|
||||
end
|
||||
|
||||
query.blizzard_query.first_page = next_page
|
||||
query.blizzard_query.last_page = next_page
|
||||
start_real_time_scan(query, search)
|
||||
end,
|
||||
on_abort = function()
|
||||
search.status_bar:update_status(1, 1)
|
||||
search.status_bar:set_text('Scan paused')
|
||||
|
||||
search.continuation = next_page or not ignore_page and query.blizzard_query.first_page or true
|
||||
|
||||
if current_search() == search then
|
||||
update_continuation()
|
||||
end
|
||||
|
||||
search.active = false
|
||||
update_start_stop()
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
function start_search(queries, continuation)
|
||||
local current_query, current_page, total_queries, start_query, start_page
|
||||
|
||||
local search = current_search()
|
||||
|
||||
total_queries = getn(queries)
|
||||
|
||||
if continuation then
|
||||
start_query, start_page = unpack(continuation)
|
||||
for i = 1, start_query - 1 do
|
||||
tremove(queries, 1)
|
||||
end
|
||||
queries[1].blizzard_query.first_page = (queries[1].blizzard_query.first_page or 0) + start_page - 1
|
||||
search.table:SetSelectedRecord()
|
||||
else
|
||||
start_query, start_page = 1, 1
|
||||
end
|
||||
|
||||
|
||||
search_scan_id = scan.start{
|
||||
type = 'list',
|
||||
queries = queries,
|
||||
auto_buy_validator = search.auto_buy_validator,
|
||||
auto_bid_validator = search.auto_bid_validator,
|
||||
on_scan_start = function()
|
||||
search.status_bar:update_status(0, 0)
|
||||
if continuation then
|
||||
search.status_bar:set_text('Resuming scan...')
|
||||
else
|
||||
search.status_bar:set_text('Scanning auctions...')
|
||||
end
|
||||
end,
|
||||
on_page_loaded = function(_, total_scan_pages)
|
||||
current_page = current_page + 1
|
||||
total_scan_pages = total_scan_pages + (start_page - 1)
|
||||
total_scan_pages = max(total_scan_pages, 1)
|
||||
current_page = min(current_page, total_scan_pages)
|
||||
search.status_bar:update_status((current_query - 1) / getn(queries), current_page / total_scan_pages)
|
||||
search.status_bar:set_text(format('Scanning %d / %d (Page %d / %d)', current_query, total_queries, current_page, total_scan_pages))
|
||||
end,
|
||||
on_page_scanned = function()
|
||||
search.table:SetDatabase()
|
||||
end,
|
||||
on_start_query = function(query)
|
||||
current_query = current_query and current_query + 1 or start_query
|
||||
current_page = current_page and 0 or start_page - 1
|
||||
end,
|
||||
on_auction = function(auction_record, ctrl)
|
||||
if getn(search.records) < 2000 then
|
||||
tinsert(search.records, auction_record)
|
||||
if getn(search.records) == 2000 then
|
||||
StaticPopup_Show('AUX_SEARCH_TABLE_FULL')
|
||||
end
|
||||
end
|
||||
end,
|
||||
on_complete = function()
|
||||
search.status_bar:update_status(1, 1)
|
||||
search.status_bar:set_text('Scan complete')
|
||||
|
||||
if current_search() == search and frame.results:IsVisible() and getn(search.records) == 0 then
|
||||
set_subtab(SAVED)
|
||||
end
|
||||
|
||||
search.active = false
|
||||
update_start_stop()
|
||||
end,
|
||||
on_abort = function()
|
||||
search.status_bar:update_status(1, 1)
|
||||
search.status_bar:set_text('Scan paused')
|
||||
|
||||
if current_query then
|
||||
search.continuation = {current_query, current_page + 1}
|
||||
else
|
||||
search.continuation = {start_query, start_page}
|
||||
end
|
||||
if current_search() == search then
|
||||
update_continuation()
|
||||
end
|
||||
|
||||
search.active = false
|
||||
update_start_stop()
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
function M.execute(resume, real_time)
|
||||
|
||||
if resume then
|
||||
real_time = current_search().real_time
|
||||
elseif real_time == nil then
|
||||
real_time = real_time_button:IsShown()
|
||||
end
|
||||
|
||||
if resume then
|
||||
search_box:SetText(current_search().filter_string)
|
||||
end
|
||||
local filter_string, first_page, last_page = search_box:GetText(), blizzard_page_index(first_page_input:GetText()), blizzard_page_index(last_page_input:GetText())
|
||||
|
||||
local queries, error = filter_util.queries(filter_string)
|
||||
if not queries then
|
||||
aux.print('Invalid filter:', error)
|
||||
return
|
||||
elseif real_time then
|
||||
if getn(queries) > 1 then
|
||||
aux.print('Error: The real time mode does not support multi-queries')
|
||||
return
|
||||
elseif queries[1].blizzard_query.first_page or queries[1].blizzard_query.last_page then
|
||||
aux.print('Error: The real time mode does not support page ranges')
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if resume then
|
||||
current_search().table:SetSelectedRecord()
|
||||
else
|
||||
if filter_string ~= current_search().filter_string then
|
||||
if current_search().filter_string then
|
||||
new_search(filter_string, first_page, last_page, real_time)
|
||||
else
|
||||
current_search().filter_string = filter_string
|
||||
end
|
||||
new_recent_search(filter_string, aux.join(aux.map(aux.copy(queries), function(filter) return filter.prettified end), ';'))
|
||||
else
|
||||
local search = current_search()
|
||||
search.records = T.acquire()
|
||||
search.table:Reset()
|
||||
search.table:SetDatabase(search.records)
|
||||
end
|
||||
local search = current_search()
|
||||
search.first_page = first_page
|
||||
search.last_page = last_page
|
||||
search.real_time = real_time
|
||||
search.auto_buy_validator = get_auto_buy_validator()
|
||||
search.auto_bid_validator = get_auto_bid_validator()
|
||||
end
|
||||
|
||||
local continuation = resume and current_search().continuation
|
||||
discard_continuation()
|
||||
current_search().active = true
|
||||
update_start_stop()
|
||||
clear_control_focus()
|
||||
set_subtab(RESULTS)
|
||||
if real_time then
|
||||
start_real_time_scan(queries[1], nil, continuation)
|
||||
else
|
||||
for _, query in queries do
|
||||
query.blizzard_query.first_page = current_search().first_page
|
||||
query.blizzard_query.last_page = current_search().last_page
|
||||
end
|
||||
start_search(queries, continuation)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local scan_id = 0
|
||||
local IDLE, SEARCHING, FOUND = aux.enum(3)
|
||||
local state = IDLE
|
||||
local found_index
|
||||
|
||||
function find_auction(record)
|
||||
local search = current_search()
|
||||
|
||||
if not search.table:ContainsRecord(record) or info.is_player(record.owner) then
|
||||
return
|
||||
end
|
||||
|
||||
scan.abort(scan_id)
|
||||
state = SEARCHING
|
||||
scan_id = scan_util.find(
|
||||
record,
|
||||
current_search().status_bar,
|
||||
function()
|
||||
state = IDLE
|
||||
end,
|
||||
function()
|
||||
state = IDLE
|
||||
search.table:RemoveAuctionRecord(record)
|
||||
end,
|
||||
function(index)
|
||||
if search.table:GetSelection() and search.table:GetSelection().record ~= record then
|
||||
return
|
||||
end
|
||||
|
||||
state = FOUND
|
||||
found_index = index
|
||||
|
||||
if not record.high_bidder then
|
||||
bid_button:SetScript('OnClick', function()
|
||||
if scan_util.test(record, index) and search.table:ContainsRecord(record) then
|
||||
aux.place_bid('list', index, record.bid_price, record.bid_price < record.buyout_price and function()
|
||||
info.bid_update(record)
|
||||
search.table:SetDatabase()
|
||||
end or function() search.table:RemoveAuctionRecord(record) end)
|
||||
end
|
||||
end)
|
||||
bid_button:Enable()
|
||||
else
|
||||
bid_button:Disable()
|
||||
end
|
||||
|
||||
if record.buyout_price > 0 then
|
||||
buyout_button:SetScript('OnClick', function()
|
||||
if scan_util.test(record, index) and search.table:ContainsRecord(record) then
|
||||
aux.place_bid('list', index, record.buyout_price, function() search.table:RemoveAuctionRecord(record) end)
|
||||
end
|
||||
end)
|
||||
buyout_button:Enable()
|
||||
else
|
||||
buyout_button:Disable()
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
function on_update()
|
||||
if state == IDLE or state == SEARCHING then
|
||||
buyout_button:Disable()
|
||||
bid_button:Disable()
|
||||
end
|
||||
|
||||
if state == SEARCHING then return end
|
||||
|
||||
local selection = current_search().table:GetSelection()
|
||||
if not selection then
|
||||
state = IDLE
|
||||
elseif selection and state == IDLE then
|
||||
find_auction(selection.record)
|
||||
elseif state == FOUND and not scan_util.test(selection.record, found_index) then
|
||||
buyout_button:Disable()
|
||||
bid_button:Disable()
|
||||
if not aux.bid_in_progress() then
|
||||
state = IDLE
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,181 @@
|
||||
module 'aux.tabs.search'
|
||||
|
||||
local T = require 'T'
|
||||
local aux = require 'aux'
|
||||
local filter_util = require 'aux.util.filter'
|
||||
local gui = require 'aux.gui'
|
||||
|
||||
function aux.handle.LOAD()
|
||||
recent_searches, favorite_searches = aux.realm_data.recent_searches, aux.realm_data.favorite_searches
|
||||
end
|
||||
|
||||
function update_search_listings()
|
||||
local favorite_search_rows = T.acquire()
|
||||
for i = 1, getn(favorite_searches) do
|
||||
local search = favorite_searches[i]
|
||||
local name = strsub(search.prettified, 1, 250)
|
||||
tinsert(favorite_search_rows, T.map(
|
||||
'cols', T.list(T.map('value', search.auto_buy and aux.color.red'X' or search.auto_bid and aux.color.red'Y' or ''), T.map('value', name)),
|
||||
'search', search,
|
||||
'index', i
|
||||
))
|
||||
end
|
||||
favorite_searches_listing:SetData(favorite_search_rows)
|
||||
|
||||
local recent_search_rows = T.acquire()
|
||||
for i = 1, getn(recent_searches) do
|
||||
local search = recent_searches[i]
|
||||
local name = strsub(search.prettified, 1, 250)
|
||||
tinsert(recent_search_rows, T.map(
|
||||
'cols', T.list(T.map('value', name)),
|
||||
'search', search,
|
||||
'index', i
|
||||
))
|
||||
end
|
||||
recent_searches_listing:SetData(recent_search_rows)
|
||||
end
|
||||
|
||||
function new_recent_search(filter_string, prettified)
|
||||
for i = getn(recent_searches), 1, -1 do
|
||||
if recent_searches[i].filter_string == filter_string then
|
||||
tremove(recent_searches, i)
|
||||
end
|
||||
end
|
||||
tinsert(recent_searches, 1, T.map(
|
||||
'filter_string', filter_string,
|
||||
'prettified', prettified
|
||||
))
|
||||
while getn(recent_searches) > 50 do
|
||||
tremove(recent_searches)
|
||||
end
|
||||
update_search_listings()
|
||||
end
|
||||
|
||||
handlers = {
|
||||
OnClick = function(st, data, _, button)
|
||||
if not data then return end
|
||||
if button == 'LeftButton' and IsShiftKeyDown() then
|
||||
set_filter(data.search.filter_string)
|
||||
elseif button == 'RightButton' and IsShiftKeyDown() then
|
||||
add_filter(data.search.filter_string)
|
||||
elseif button == 'LeftButton' then
|
||||
set_filter(data.search.filter_string)
|
||||
execute()
|
||||
elseif button == 'RightButton' then
|
||||
local u = update_search_listings
|
||||
if st == recent_searches_listing then
|
||||
tinsert(favorite_searches, 1, data.search)
|
||||
u(d)
|
||||
elseif st == favorite_searches_listing then
|
||||
local auto_buy = data.search.auto_buy
|
||||
local auto_bid = data.search.auto_bid
|
||||
gui.menu(
|
||||
(auto_buy and 'Disable' or 'Enable') .. ' Auto Buy', function() if auto_buy then data.search.auto_buy = nil else enable_auto_buy(data.search) end u() end,
|
||||
(auto_bid and 'Disable' or 'Enable') .. ' Auto Bid', function() if auto_bid then data.search.auto_bid = nil else enable_auto_bid(data.search) end u() end,
|
||||
'Move Up', function() move_up(favorite_searches, data.index); u() end,
|
||||
'Move Down', function() move_down(favorite_searches, data.index); u() end,
|
||||
'Delete', function() tremove(favorite_searches, data.index); u() end
|
||||
)
|
||||
end
|
||||
end
|
||||
end,
|
||||
OnEnter = function(st, data, self)
|
||||
if not data then return end
|
||||
GameTooltip_SetDefaultAnchor(GameTooltip, UIParent)
|
||||
GameTooltip:AddLine(gsub(data.search.prettified, ';', '\n\n'), 255/255, 254/255, 250/255, true)
|
||||
GameTooltip:Show()
|
||||
end,
|
||||
OnLeave = function()
|
||||
GameTooltip:ClearLines()
|
||||
GameTooltip:Hide()
|
||||
end
|
||||
}
|
||||
|
||||
function get_auto_buy_validator()
|
||||
local validators = T.acquire()
|
||||
for _, search in favorite_searches do
|
||||
if search.auto_buy then
|
||||
local queries, error = filter_util.queries(search.filter_string)
|
||||
if queries then
|
||||
tinsert(validators, queries[1].validator)
|
||||
else
|
||||
aux.print('Invalid auto buy filter:', error)
|
||||
end
|
||||
end
|
||||
end
|
||||
return function(record)
|
||||
return aux.any(validators, function(validator) return validator(record) end)
|
||||
end
|
||||
end
|
||||
|
||||
function get_auto_bid_validator()
|
||||
local validators = T.acquire()
|
||||
for _, search in favorite_searches do
|
||||
if search.auto_bid then
|
||||
local queries, error = filter_util.queries(search.filter_string)
|
||||
if queries then
|
||||
tinsert(validators, queries[1].validator)
|
||||
else
|
||||
aux.print('Invalid auto bid filter:', error)
|
||||
end
|
||||
end
|
||||
end
|
||||
return function(record)
|
||||
return aux.any(validators, function(validator) return validator(record) end)
|
||||
end
|
||||
end
|
||||
|
||||
function add_favorite(filter_string)
|
||||
local queries, error = filter_util.queries(filter_string)
|
||||
if queries then
|
||||
tinsert(favorite_searches, 1, T.map(
|
||||
'filter_string', filter_string,
|
||||
'prettified', aux.join(aux.map(queries, function(query) return query.prettified end), ';')
|
||||
))
|
||||
update_search_listings()
|
||||
else
|
||||
aux.print('Invalid filter:', error)
|
||||
end
|
||||
end
|
||||
|
||||
function enable_auto_buy(search)
|
||||
local queries, error = filter_util.queries(search.filter_string)
|
||||
if queries then
|
||||
if getn(queries) > 1 then
|
||||
aux.print('Error: Auto Buy does not support multi-queries')
|
||||
elseif aux.size(queries[1].blizzard_query) > 0 and not filter_util.parse_filter_string(search.filter_string).blizzard.exact then
|
||||
aux.print('Error: Auto Buy does not support Blizzard filters')
|
||||
else
|
||||
search.auto_buy = true
|
||||
end
|
||||
else
|
||||
aux.print('Invalid filter:', error)
|
||||
end
|
||||
end
|
||||
|
||||
function enable_auto_bid(search)
|
||||
local queries, error = filter_util.queries(search.filter_string)
|
||||
if queries then
|
||||
if getn(queries) > 1 then
|
||||
aux.print('Error: Auto Bid does not support multi-queries')
|
||||
elseif aux.size(queries[1].blizzard_query) > 0 and not filter_util.parse_filter_string(search.filter_string).blizzard.exact then
|
||||
aux.print('Error: Auto Bid does not support Blizzard filters')
|
||||
else
|
||||
search.auto_bid = true
|
||||
end
|
||||
else
|
||||
aux.print('Invalid filter:', error)
|
||||
end
|
||||
end
|
||||
|
||||
function move_up(list, index)
|
||||
if list[index - 1] then
|
||||
list[index], list[index - 1] = list[index - 1], list[index]
|
||||
end
|
||||
end
|
||||
|
||||
function move_down(list, index)
|
||||
if list[index + 1] then
|
||||
list[index], list[index + 1] = list[index + 1], list[index]
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user