2062 lines
68 KiB
Lua
2062 lines
68 KiB
Lua
--[[
|
|
Auctioneer - Search UI
|
|
Version: 5.9.4961 (WhackyWallaby)
|
|
Revision: $Id: SearchMain.lua 4933 2010-10-13 17:16:14Z Nechckn $
|
|
URL: http://auctioneeraddon.com/
|
|
|
|
This Addon provides a Search tab on the AH interface, which allows
|
|
Auctioneer users to use Searcher plug-ins to search for good deals
|
|
in the auction house. It searches the "snapshot", which requires
|
|
having data from recent auction house scans.
|
|
|
|
License:
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program(see GPL.txt); if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
Note:
|
|
This AddOn's source code is specifically designed to work with
|
|
World of Warcraft's interpreted AddOn system.
|
|
You have an implicit license to use this AddOn with these facilities
|
|
since that is its designated purpose as per:
|
|
http://www.fsf.org/licensing/licenses/gpl-faq.html#InterpreterIncompat
|
|
--]]
|
|
|
|
local libType, libName = "Util", "SearchUI"
|
|
local AucAdvanced = AucAdvanced
|
|
local lib,parent,private = AucAdvanced.NewModule(libType, libName)
|
|
if not lib then return end
|
|
local print,decode,_,_,replicate,_,get,set,default,debugPrint,fill = AucAdvanced.GetModuleLocals()
|
|
local debugPrint = AucAdvanced.Debug.DebugPrint
|
|
|
|
local empty = wipe
|
|
local ipairs,pairs,type,select = ipairs,pairs,type,select
|
|
local tostring,tonumber = tostring,tonumber
|
|
local floor,ceil,abs = floor,ceil,abs
|
|
local strmatch,format = strmatch,format
|
|
local tinsert,tremove = tinsert,tremove
|
|
-- GLOBALS: CreateFrame, GameTooltip
|
|
|
|
-- Our official name:
|
|
AucSearchUI = lib
|
|
|
|
function lib.GetName()
|
|
return libName
|
|
end
|
|
|
|
local Const = AucAdvanced.Const
|
|
local gui
|
|
private.data = {}
|
|
private.sheetData = {}
|
|
private.sheetStyle = {}
|
|
private.isSearching = false
|
|
local coSearch
|
|
local SettingCache = {}
|
|
local currentSettings = {}
|
|
local hasUnsaved = nil
|
|
|
|
local TAB_NAME = "Search"
|
|
|
|
private.tleft = {
|
|
"|cff000001|cffe5e5e530m", -- 30m
|
|
"|cff000002|cffe5e5e52h", --2h
|
|
"|cff000003|cffe5e5e512h", --12h
|
|
"|cff000004|cffe5e5e548h" --48h
|
|
}
|
|
|
|
lib.CleanTable = wipe -- for compatibility
|
|
|
|
local resources = {}
|
|
lib.Resources = resources
|
|
local flagResourcesUpdateRequired = false
|
|
local flagScanStats = false
|
|
|
|
-- Faction Resources
|
|
-- Commonly used values which change depending whether you are at home or neutral Auctionhouse
|
|
-- Modules should expect these to always contain valid values; nil tests should not be required
|
|
resources.Realm = GetRealmName() -- will not change during session
|
|
function private.UpdateFactionResources()
|
|
local serverKey, _, Faction = AucAdvanced.GetFaction()
|
|
if serverKey ~= resources.serverKey then
|
|
-- store new settings
|
|
resources.Faction = Faction
|
|
resources.faction = Faction:lower() -- lowercase for GetDepositCost
|
|
resources.serverKey = serverKey
|
|
resources.CutAdjust = 1 - AucAdvanced.cutRate -- multiply price by .CutAdjust to subtract the AH brokerage fees
|
|
-- notify the change
|
|
lib.NotifyCallbacks("resources", "faction", serverKey)
|
|
end
|
|
end
|
|
-- todo: we really should update when Zone changes, but there in't a processor event for that
|
|
|
|
-- Selectbox Resources
|
|
--[[ Usages:
|
|
gui:AddControl(id, "Selectbox", column, indent, resources.selectorPriceModels, "searcher.model")
|
|
gui:AddControl(id, "Selectbox", column, indent, resources.selectorPriceModelsEnx, "searcher.model")
|
|
gui:AddControl(id, "Selectbox", column, indent, resources.selectorAuctionLength, "searcher.deplength")
|
|
local price, seen, curModel = resources.lookupPriceModel[model](model, link || itemID [, serverKey]) ~ price, seen or curModel may be nil
|
|
local price, seen, curModel = resources.GetPrice(model, link || itemID [, serverKey]) ~ simplified wrapper function for lookupPriceModel
|
|
if not resources.isValidPriceModel(get("searcher.model")) then <code to report warning...>
|
|
--]]
|
|
do -- limit scope of locals
|
|
resources.selectorAuctionLength = AucAdvanced.selectorAuctionLength
|
|
lib.AucLengthSelector = AucAdvanced.selectorAuctionLength -- for compatibility
|
|
resources.selectorPriceModels = AucAdvanced.selectorPriceModels
|
|
|
|
local pricemodelsenx
|
|
function resources.selectorPriceModelsEnx()
|
|
if not pricemodelsenx then
|
|
pricemodelsenx = replicate(resources.selectorPriceModels())
|
|
if resources.isEnchantrixLoaded then
|
|
tinsert(pricemodelsenx, 1, {"Enchantrix", "Enchantrix"})
|
|
end
|
|
end
|
|
return pricemodelsenx
|
|
end
|
|
function private.ResetPriceModelEnx()
|
|
pricemodelsenx = nil
|
|
end
|
|
|
|
function resources.isValidPriceModel(testmodel)
|
|
local pricemodels = resources.selectorPriceModelsEnx() -- make sure table is up to date
|
|
local found -- default return value nil
|
|
for pos, model in ipairs(pricemodels) do
|
|
if model[1] == testmodel then
|
|
found = model[2]
|
|
break
|
|
end
|
|
end
|
|
return found
|
|
end
|
|
|
|
-- lookup functions
|
|
local function UnknownFunc() end -- return nil
|
|
|
|
local function MarketFunc(model, link, serverKey)
|
|
local price, seen = AucAdvanced.API.GetMarketValue(link, serverKey)
|
|
return price, seen, model
|
|
end
|
|
|
|
local function AppraiserFunc(model, link, serverKey)
|
|
local market, bid, _, seen, curModel = AucAdvanced.Modules.Util.Appraiser.GetPrice(link, serverKey)
|
|
if not market or market == 0 then
|
|
market = bid -- fallback to bid price if no market
|
|
end
|
|
return market, seen, curModel
|
|
end
|
|
|
|
local function EnchantrixFunc(model, link, serverKey)
|
|
-- GetReagentPrice does not handle serverKey, and it does not return a seen count
|
|
local extra, mkt, five, _
|
|
_, extra = Enchantrix.Util.GetPricingModel()
|
|
_, _, mkt, five = Enchantrix.Util.GetReagentPrice(link, extra)
|
|
return five or mkt, nil, extra or model
|
|
end
|
|
|
|
local function AlgorithmFunc(model, link, serverKey)
|
|
local market, seen = AucAdvanced.API.GetAlgorithmValue(model, link, serverKey)
|
|
return market, seen, model
|
|
end
|
|
|
|
local function indexFunc(lookup, model)
|
|
local func
|
|
if model == "Appraiser" and AucAdvanced.Modules.Util.Appraiser then
|
|
func = AppraiserFunc
|
|
elseif model == "Enchantrix" and resources.isEnchantrixLoaded then
|
|
func = EnchantrixFunc
|
|
elseif AucAdvanced.API.IsValidAlgorithm(model) then
|
|
func = AlgorithmFunc
|
|
end
|
|
if func then
|
|
rawset(lookup, model, func)
|
|
return func
|
|
end
|
|
return UnknownFunc
|
|
end
|
|
|
|
local lookuppricemodel = setmetatable({market = MarketFunc}, {__index = indexFunc})
|
|
|
|
resources.lookupPriceModel = lookuppricemodel
|
|
function resources.GetPrice(model, link, serverKey) -- simplified wrapper
|
|
return lookuppricemodel[model](model, link, serverKey)
|
|
end
|
|
end
|
|
|
|
-- Enchantrix Load detection
|
|
if Enchantrix and Enchantrix.Storage and Enchantrix.Util then
|
|
resources.isEnchantrixLoaded = true
|
|
else
|
|
local _, _, _, enabled, loadable = GetAddOnInfo("Enchantrix") -- check it's actually possible to load
|
|
if enabled and loadable then
|
|
Stubby.RegisterAddOnHook("Enchantrix", "Auc-Util-SearchUI", function()
|
|
if Enchantrix and Enchantrix.Storage and Enchantrix.Util then
|
|
Stubby.UnregisterAddOnHook("Enchantrix", "Auc-Util-SearchUI")
|
|
resources.isEnchantrixLoaded = true
|
|
private.ResetPriceModelEnx()
|
|
lib.NotifyCallbacks("onload", "enchantrix")
|
|
end
|
|
end)
|
|
end
|
|
end
|
|
|
|
function lib.OnLoad(addon)
|
|
-- Notify that SearchUI is fully loaded
|
|
resources.isSearchUILoaded = true
|
|
lib.NotifyCallbacks("onload", addon)
|
|
|
|
-- Initialize
|
|
private.UpdateFactionResources()
|
|
end
|
|
|
|
function lib.Processor(callbackType, ...)
|
|
if callbackType == "load" then
|
|
private.ResetPriceModelEnx()
|
|
elseif (callbackType == "auctionclose") then
|
|
if private.isAttached then
|
|
lib.DetachFromAH()
|
|
end
|
|
flagResourcesUpdateRequired = true
|
|
elseif callbackType == "auctionopen" then
|
|
flagResourcesUpdateRequired = true
|
|
elseif (callbackType == "auctionui") then
|
|
if lib.Searchers.RealTime then
|
|
lib.Searchers.RealTime.HookAH()
|
|
end
|
|
|
|
--we need to make sure that the GUI is made by the time the AH opens, as RealTime could be trying to add lines to it.
|
|
if not gui then
|
|
lib.MakeGuiConfig()
|
|
end
|
|
|
|
lib.CreateAuctionFrames()
|
|
elseif (callbackType == "pagefinished") then
|
|
if lib.Searchers.RealTime then
|
|
lib.Searchers.RealTime.FinishedPage(...)
|
|
end
|
|
elseif (callbackType == "bidcancelled") then --bid was cancelled, we need to ignore auction for current session
|
|
private.bidcancelled(...)
|
|
elseif (callbackType == "tooltip") then
|
|
lib.ProcessTooltip(...)
|
|
elseif callbackType == "scanstats" then
|
|
-- pass the message in next OnUpdate
|
|
flagScanStats = true
|
|
elseif callbackType == "scanprogress" and private.UpdateScanProgress then
|
|
private.UpdateScanProgress(...)
|
|
elseif callbackType == "buyqueue" and private.UpdateBuyQueue then
|
|
private.UpdateBuyQueue()
|
|
end
|
|
end
|
|
|
|
lib.Processors = {}
|
|
function lib.Processors.load(callbackType, ...)
|
|
private.ResetPriceModelEnx()
|
|
end
|
|
|
|
function lib.Processors.auctionclose(callbackType, ...)
|
|
if private.isAttached then
|
|
lib.DetachFromAH()
|
|
end
|
|
flagResourcesUpdateRequired = true
|
|
end
|
|
|
|
function lib.Processors.auctionopen(callbackType, ...)
|
|
flagResourcesUpdateRequired = true
|
|
end
|
|
|
|
function lib.Processors.auctionui(callbackType, ...)
|
|
if lib.Searchers.RealTime then
|
|
lib.Searchers.RealTime.HookAH()
|
|
end
|
|
|
|
--we need to make sure that the GUI is made by the time the AH opens, as RealTime could be trying to add lines to it.
|
|
if not gui then
|
|
lib.MakeGuiConfig()
|
|
end
|
|
|
|
lib.CreateAuctionFrames()
|
|
end
|
|
|
|
function lib.Processors.pagefinished(callbackType, ...)
|
|
if lib.Searchers.RealTime then
|
|
lib.Searchers.RealTime.FinishedPage(...)
|
|
end
|
|
end
|
|
|
|
function lib.Processors.bidcancelled(callbackType, ...)
|
|
private.bidcancelled(...)
|
|
end
|
|
|
|
function lib.Processors.tooltip(callbackType, ...)
|
|
lib.ProcessTooltip(...)
|
|
end
|
|
|
|
function lib.Processors.scanstats(callbackType, ...)
|
|
-- pass the message in next OnUpdate
|
|
flagScanStats = true
|
|
end
|
|
|
|
function lib.Processors.scanprogress(callbackType, ...)
|
|
if private.UpdateScanProgress then
|
|
private.UpdateScanProgress(...)
|
|
end
|
|
end
|
|
|
|
function lib.Processors.buyqueue(callbackType, ...)
|
|
if private.UpdateBuyQueue then
|
|
private.UpdateBuyQueue()
|
|
end
|
|
end
|
|
|
|
function lib.ProcessTooltip(tooltip, name, hyperlink, quality, quantity, cost, additional)
|
|
if not additional or additional.event ~= "SetAuctionItem" then
|
|
--this isn't an auction, so we're not interested
|
|
return
|
|
end
|
|
if not lib.GetSetting("debug.show") then
|
|
--we're not interested in adding debug
|
|
return
|
|
end
|
|
local button = GetMouseFocus():GetParent() --Note: check that it works without CompactUI
|
|
local id = button.id --CompactUI's layout
|
|
if not id then
|
|
id = button:GetID() + FauxScrollFrame_GetOffset(BrowseScrollFrame) --without CompactUI
|
|
end
|
|
|
|
local name, _, count, _, canUse, level, minBid, minInc, buyout, curBid, isHigh, owner = GetAuctionItemInfo("list", id)
|
|
local price
|
|
if curBid > 0 then
|
|
price = curBid + minInc
|
|
if buyout > 0 and price > buyout then
|
|
price = buyout
|
|
end
|
|
elseif minBid > 0 then
|
|
price = minBid
|
|
else
|
|
price = 1
|
|
end
|
|
owner = owner or ""
|
|
local timeleft = GetAuctionItemTimeLeft("list", id)
|
|
local _, _, _, iLevel, _, iType, iSubType, stack, iEquip = GetItemInfo(hyperlink)
|
|
iEquip = Const.EquipEncode[iEquip]
|
|
local _, itemid, suffix, factor, enchant, seed = AucAdvanced.DecodeLink(hyperlink)
|
|
local ItemTable = {}
|
|
-- put the data into a table laid out the same way as the AAdv Scandata, as that's what the searchers need
|
|
ItemTable[Const.LINK] = hyperlink
|
|
ItemTable[Const.ILEVEL] = iLevel
|
|
ItemTable[Const.ITYPE] = iType
|
|
ItemTable[Const.ISUB] = iSubType
|
|
ItemTable[Const.IEQUIP] = iEquip
|
|
ItemTable[Const.PRICE] = price
|
|
ItemTable[Const.TLEFT] = timeleft
|
|
ItemTable[Const.NAME] = name
|
|
ItemTable[Const.COUNT] = count
|
|
ItemTable[Const.QUALITY] = quality
|
|
ItemTable[Const.CANUSE] = canUse
|
|
ItemTable[Const.ULEVEL] = level
|
|
ItemTable[Const.MINBID] = minBid
|
|
ItemTable[Const.MININC] = minInc
|
|
ItemTable[Const.BUYOUT] = buyout
|
|
ItemTable[Const.CURBID] = curBid
|
|
ItemTable[Const.AMHIGH] = isHigh
|
|
ItemTable[Const.SELLER] = owner
|
|
ItemTable[Const.ITEMID] = itemid
|
|
ItemTable[Const.SUFFIX] = suffix
|
|
ItemTable[Const.FACTOR] = factor
|
|
ItemTable[Const.ENCHANT] = enchant
|
|
ItemTable[Const.SEED] = seed
|
|
|
|
tooltip:AddLine("SearchUI:", 1, 0.7, 0.3)
|
|
|
|
local active = false
|
|
for name, searcher in pairs(lib.Searchers) do
|
|
if lib.GetSetting("debug."..name) then
|
|
active = true
|
|
local success, returnvalue, value = lib.SearchItem(name, ItemTable, true, true)
|
|
if success then
|
|
if value then
|
|
tooltip:AddLine(" "..name.." profit:"..floor(100*returnvalue/value).."%:", returnvalue, 1, 0.7, 0.3)
|
|
elseif returnvalue then
|
|
tooltip:AddLine(" "..name.." profit:", returnvalue, 1, 0.7, 0.3)
|
|
else
|
|
tooltip:AddLine(" "..name.." success", 1, 0.7, 0.3)
|
|
end
|
|
else
|
|
tooltip:AddLine(" "..name..":"..returnvalue, 1, 0.7, 0.3)
|
|
end
|
|
end
|
|
end
|
|
if not active then --if it hasn't changed, we're not enabled for any searcher
|
|
tooltip:AddLine(" No debugging enabled", 1, 0.7, 0.3)
|
|
end
|
|
end
|
|
|
|
-- Default setting values
|
|
local settingDefaults = {
|
|
["processpriority"] = 80,
|
|
["reserve"] = 0,
|
|
["reserve.enable"] = false,
|
|
["global.createtab"] = true,
|
|
["maxprice"] = 10000000,
|
|
["maxprice.enable"] = false,
|
|
["tooltiphelp.show"] = true,
|
|
--Scrollframe defaults
|
|
["columnwidth.Item"] = 120,
|
|
["columnwidth.Pct"] = 30,
|
|
["columnwidth.Profit"] = 85,
|
|
["columnwidth.Stk"] = 30,
|
|
["columnwidth.Buyout"] = 85,
|
|
["columnwidth.Bid"] = 85,
|
|
["columnwidth.Reason"] = 85,
|
|
["columnwidth.Seller"] = 75,
|
|
["columnwidth.Left"] = 40,
|
|
["columnwidth.Buy/ea"] = 85,
|
|
["columnwidth.Bid/ea"] = 85,
|
|
["columnwidth.MinBid"] = 85,
|
|
["columnwidth.CurBid"] = 85,
|
|
["columnwidth.Min/ea"] = 85,
|
|
["columnwidth.Cur/ea"] = 85,
|
|
}
|
|
|
|
local function getDefault(setting)
|
|
return settingDefaults[setting]
|
|
end
|
|
|
|
function lib.GetDefault(setting)
|
|
return getDefault(setting)
|
|
end
|
|
|
|
function lib.SetDefault(setting, default)
|
|
settingDefaults[setting] = default
|
|
end
|
|
|
|
local function initData()
|
|
local data = AucAdvancedData.UtilSearchUiData
|
|
if not data then
|
|
data = {}
|
|
data.Version = 1
|
|
AucAdvancedData.UtilSearchUiData = data
|
|
end
|
|
if not data.SavedSearches then data.SavedSearches = {} end
|
|
if not data.Current then data.Current = {} end
|
|
if not data.Global then data.Global = {} end
|
|
end
|
|
|
|
local function isGlobalSetting(setting)
|
|
local a,b,c = strsplit(".", setting)
|
|
if a == "configator" then return true end
|
|
if a == "global" then return true end
|
|
return
|
|
end
|
|
|
|
local function setter(setting, value)
|
|
AucAdvancedData.UtilSearchUI = nil -- Remove old settings
|
|
initData()
|
|
|
|
local db = currentSettings
|
|
|
|
-- turn value into a canonical true or false
|
|
if value == 'on' then
|
|
value = true
|
|
elseif value == 'off' then
|
|
value = false
|
|
end
|
|
|
|
if (isGlobalSetting(setting)) then
|
|
AucAdvancedData.UtilSearchUiData.Global[setting] = value
|
|
return
|
|
end
|
|
|
|
-- for defaults, just remove the value and it'll fall through
|
|
if (value == 'default') or (value == getDefault(setting)) then
|
|
-- Don't save default values
|
|
value = nil
|
|
end
|
|
|
|
if db[setting] == value then
|
|
if type(value) == "table" then
|
|
-- same table as before
|
|
-- call UpdateSave to check if the *contents* of the table have changed
|
|
-- but don't send Processor message as *setting* is the same (consistent with Core version of 'setter')
|
|
hasUnsaved = true
|
|
lib.UpdateSave()
|
|
end
|
|
return
|
|
end
|
|
db[setting] = value
|
|
|
|
hasUnsaved = true
|
|
lib.UpdateSave()
|
|
|
|
AucAdvanced.SendProcessorMessage("configchanged", setting, value)
|
|
lib.NotifyCallbacks('config', 'changed', setting, value)
|
|
end
|
|
|
|
function lib.SetSetting(...)
|
|
setter(...)
|
|
if (gui) then
|
|
gui:Refresh()
|
|
end
|
|
end
|
|
|
|
local function getter(setting)
|
|
initData()
|
|
local db = currentSettings
|
|
|
|
if (isGlobalSetting(setting)) then
|
|
local value = AucAdvancedData.UtilSearchUiData.Global[setting]
|
|
if value ~= nil then return value end
|
|
return getDefault(setting)
|
|
end
|
|
|
|
if ( db[setting] ~= nil ) then
|
|
return db[setting]
|
|
else
|
|
return getDefault(setting)
|
|
end
|
|
end
|
|
|
|
function lib.GetSetting(setting, default)
|
|
--use settings cache during a search
|
|
if private.isSearching then
|
|
if SettingCache[setting]~=nil then
|
|
return SettingCache[setting]
|
|
end
|
|
end
|
|
local option = getter(setting)
|
|
if ( option ~= nil ) then
|
|
if private.isSearching then
|
|
SettingCache[setting] = option
|
|
end
|
|
return option
|
|
else
|
|
if private.isSearching then
|
|
SettingCache[setting] = default
|
|
end
|
|
return default
|
|
end
|
|
end
|
|
|
|
function lib.Show()
|
|
if not gui then --no need to make the GUI if it already exists
|
|
lib.MakeGuiConfig()
|
|
end
|
|
gui:Show()
|
|
private.UpdateFactionResources()
|
|
end
|
|
|
|
function lib.Hide()
|
|
if (gui) then
|
|
gui:Hide()
|
|
end
|
|
end
|
|
|
|
function lib.Toggle()
|
|
if private.isAttached then return end
|
|
if (gui and gui:IsShown()) then
|
|
lib.Hide()
|
|
else
|
|
lib.Show()
|
|
end
|
|
end
|
|
|
|
private.callbacks = {}
|
|
function lib.AddCallback(name, callback)
|
|
if private.callbacks[name] then -- prevent overwriting an exisiting callback
|
|
error("AucSearchUI.AddCallback Error:\nCallback for "..name.." already exists", 2) -- level 2 is calling function
|
|
end
|
|
private.callbacks[name] = callback
|
|
-- fire certain callbacks, that have already happened, to new callback function
|
|
if resources.isEnchantrixLoaded then
|
|
callback("onload", "enchantrix")
|
|
end
|
|
if resources.isSearchUILoaded then
|
|
callback("onload", "auc-util-searchui")
|
|
end
|
|
if gui then
|
|
callback("guiconfig", gui)
|
|
end
|
|
end
|
|
|
|
function lib.NotifyCallbacks(msg, ...)
|
|
for name, callback in pairs(private.callbacks) do
|
|
callback(msg, ...)
|
|
end
|
|
|
|
for name, searcher in pairs(lib.Searchers) do
|
|
local processor = searcher.Processor
|
|
if processor then
|
|
local pType = type(processor)
|
|
if pType == "table" then
|
|
processor = processor[msg]
|
|
if type(processor) == "function" then
|
|
processor(...)
|
|
end
|
|
elseif pType == "function" then
|
|
processor(msg, ...)
|
|
end
|
|
end
|
|
end
|
|
for name, filter in pairs(lib.Filters) do
|
|
local processor = filter.Processor
|
|
if processor then
|
|
local pType = type(processor)
|
|
if pType == "table" then
|
|
processor = processor[msg]
|
|
if type(processor) == "function" then
|
|
processor(...)
|
|
end
|
|
elseif pType == "function" then
|
|
processor(msg, ...)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function lib.RemoveCallback(name, callback)
|
|
if callback and private.callbacks[name] == callback then
|
|
private.callbacks[name] = nil
|
|
return true
|
|
end
|
|
end
|
|
|
|
local searcherKit = {}
|
|
function searcherKit:GetName()
|
|
return self.name
|
|
end
|
|
|
|
lib.Searchers = {}
|
|
function lib.NewSearcher(searcherName)
|
|
if not lib.Searchers[searcherName] then
|
|
local searcher = {}
|
|
searcher.name = searcherName
|
|
for k,v in pairs(searcherKit) do
|
|
searcher[k] = v
|
|
end
|
|
|
|
lib.Searchers[searcherName] = searcher
|
|
return searcher, lib, {}
|
|
end
|
|
end
|
|
|
|
local filterKit = {}
|
|
function filterKit:GetName()
|
|
return self.name
|
|
end
|
|
|
|
lib.Filters = {}
|
|
function lib.NewFilter(filterName)
|
|
if not lib.Filters[filterName] then
|
|
local filter = {}
|
|
filter.name = filterName
|
|
for k,v in pairs(filterKit) do
|
|
filter[k] = v
|
|
end
|
|
|
|
lib.Filters[filterName] = filter
|
|
return filter, lib, {}
|
|
end
|
|
end
|
|
|
|
function lib.GetSearchLocals()
|
|
return lib.GetSetting, lib.SetSetting, lib.SetDefault, Const, resources
|
|
end
|
|
|
|
function private.removeline()
|
|
local selected = gui.sheet.selected
|
|
--find the place in the sort list, so we can select the next one.
|
|
for i,j in ipairs(gui.sheet.sort) do
|
|
if j == selected then
|
|
selected = i
|
|
break
|
|
end
|
|
end
|
|
tremove(private.sheetData, gui.sheet.selected)
|
|
--regenerate style elements, to match shorter data table
|
|
local total = #private.sheetData
|
|
for i = gui.sheet.selected, total do
|
|
private.sheetStyle[i] = private.sheetStyle[i+1]
|
|
if i == total then private.sheetStyle[i+1] = nil end --remove extra style
|
|
end
|
|
--gui.frame.remove:Disable()
|
|
gui.sheet.selected = nil
|
|
gui.sheet:SetData(private.sheetData, private.sheetStyle)
|
|
lib.UpdateControls()
|
|
gui.sheet.selected = gui.sheet.sort[selected]
|
|
gui.sheet:Render() --need to redraw, so the selection looks right
|
|
lib.UpdateControls()
|
|
end
|
|
|
|
function private.removeall()
|
|
empty(private.sheetData)
|
|
empty(private.sheetStyle)
|
|
gui.sheet.selected = nil
|
|
gui.sheet:SetData(private.sheetData, private.sheetStyle)
|
|
gui.sheet:Render() --need to redraw, so the selection looks right
|
|
lib.UpdateControls()
|
|
end
|
|
|
|
function private.repaintSheet()
|
|
local wasEmpty = #gui.sheet.data < 1
|
|
gui.sheet:SetData(private.sheetData, private.sheetStyle)
|
|
if wasEmpty then --sheet was empty, so select the just added auction
|
|
gui.sheet.selected = 1
|
|
gui.sheet:Render() --need to redraw, so the selection looks right
|
|
lib.UpdateControls()
|
|
end
|
|
end
|
|
|
|
function private.cropreason(reason)
|
|
if reason then
|
|
reason = strsplit(":", reason)
|
|
return reason
|
|
end
|
|
end
|
|
|
|
function private.buyauction()
|
|
AucAdvanced.Buy.QueueBuy(private.data.link, private.data.seller, private.data.stack, private.data.minbid, private.data.buyout, private.data.buyout, private.cropreason(private.data.reason))
|
|
private.removeline()
|
|
end
|
|
|
|
function private.bidauction()
|
|
local bid = MoneyInputFrame_GetCopper(gui.frame.bidbox)
|
|
AucAdvanced.Buy.QueueBuy(private.data.link, private.data.seller, private.data.stack, private.data.minbid, private.data.buyout, bid, private.cropreason(private.data.reason))
|
|
private.removeline()
|
|
end
|
|
|
|
function private.buyfirst()
|
|
gui.sheet.selected = gui.sheet.sort[1]
|
|
if not gui.sheet.selected then
|
|
return
|
|
end
|
|
lib.UpdateControls()
|
|
if strmatch(private.data.reason, ":buy") then
|
|
AucAdvanced.Buy.QueueBuy(private.data.link, private.data.seller, private.data.stack, private.data.minbid, private.data.buyout, private.data.buyout, private.cropreason(private.data.reason))
|
|
elseif strmatch(private.data.reason, ":bid") then
|
|
AucAdvanced.Buy.QueueBuy(private.data.link, private.data.seller, private.data.stack, private.data.minbid, private.data.buyout, private.data.bid, private.cropreason(private.data.reason))
|
|
elseif private.data.buyout > 0 then
|
|
AucAdvanced.Buy.QueueBuy(private.data.link, private.data.seller, private.data.stack, private.data.minbid, private.data.buyout, private.data.buyout, private.cropreason(private.data.reason))
|
|
else
|
|
AucAdvanced.Buy.QueueBuy(private.data.link, private.data.seller, private.data.stack, private.data.minbid, private.data.buyout, private.data.bid, private.cropreason(private.data.reason))
|
|
end
|
|
private.removeline()
|
|
end
|
|
|
|
--private.purchase
|
|
--Will buy/bid selected auction based on "reason" column
|
|
function private.purchase()
|
|
if not gui.sheet.selected then
|
|
return
|
|
end
|
|
local enableres = lib.GetSetting("reserve.enable")
|
|
local reserve = lib.GetSetting("reserve") or 1
|
|
local bidqueue = gui.frame.cancel.value or 0
|
|
local balance = GetMoney()
|
|
balance = balance - bidqueue --account for money we've already "spent"
|
|
|
|
local price = 0
|
|
if strmatch(private.data.reason, ":buy") then
|
|
price = private.data.buyout
|
|
elseif strmatch(private.data.reason, ":bid") then
|
|
price = private.data.bid
|
|
elseif private.data.buyout > 0 then
|
|
price = private.data.buyout
|
|
else
|
|
price = private.data.bid
|
|
end
|
|
if ((balance-price) > reserve or not enableres) then
|
|
AucAdvanced.Buy.QueueBuy(private.data.link, private.data.seller, private.data.stack, private.data.minbid, private.data.buyout, price, private.cropreason(private.data.reason))
|
|
else
|
|
print("Purchase cancelled: Reserve reached")
|
|
end
|
|
private.removeline()
|
|
end
|
|
--Will buy/bid ALL auctions based on "reason" column
|
|
function private.purchaseall()
|
|
gui.sheet.selected = gui.sheet.sort[1]
|
|
if not gui.sheet.selected then
|
|
return
|
|
end
|
|
lib.UpdateControls()
|
|
local count = 0
|
|
while #gui.sheet.sort > 0 and (gui.sheet.sort[1] or count < 5000 ) do
|
|
count = count+1--emergency break routine
|
|
local enableres = lib.GetSetting("reserve.enable")
|
|
local reserve = lib.GetSetting("reserve") or 1
|
|
local bidqueue = gui.frame.cancel.value or 0
|
|
local balance = GetMoney()
|
|
balance = balance - bidqueue --account for money we've already "spent"
|
|
|
|
local price = 0
|
|
if strmatch(private.data.reason, ":buy") then
|
|
price = private.data.buyout
|
|
elseif strmatch(private.data.reason, ":bid") then
|
|
price = private.data.bid
|
|
elseif private.data.buyout > 0 then
|
|
price = private.data.buyout
|
|
else
|
|
price = private.data.bid
|
|
end
|
|
if ((balance-price) > reserve or not enableres) then
|
|
AucAdvanced.Buy.QueueBuy(private.data.link, private.data.seller, private.data.stack, private.data.minbid, private.data.buyout, price, private.cropreason(private.data.reason))
|
|
else
|
|
print("Purchase cancelled: Reserve reached")
|
|
end
|
|
private.removeline()
|
|
end
|
|
end
|
|
function private.ignore()
|
|
local sig = AucAdvanced.API.GetSigFromLink(private.data.link)
|
|
local price
|
|
if strmatch(private.data.reason, ":buy") then
|
|
price = private.data.buyout
|
|
elseif strmatch(private.data.reason, ":bid") then
|
|
price = private.data.bid
|
|
elseif private.data.buyout > 0 then
|
|
price = private.data.buyout
|
|
else
|
|
price = private.data.bid
|
|
end
|
|
local count = private.data.stack or 1
|
|
price = floor(price/count)
|
|
AucSearchUI.Filters.ItemPrice.AddIgnore(sig, price)
|
|
print("SearchUI now ignoring "..private.data.link.." at "..AucAdvanced.Coins(price, true))
|
|
private.removeline()
|
|
end
|
|
|
|
function private.ignoreperm()
|
|
local sig = AucAdvanced.API.GetSigFromLink(private.data.link)
|
|
AucSearchUI.Filters.ItemPrice.AddIgnore(sig, 0)
|
|
print("SearchUI now ignoring "..private.data.link.." at any price")
|
|
private.removeline()
|
|
end
|
|
|
|
--a bid was cancelled, so ignore for session
|
|
function private.bidcancelled(callbackstring)
|
|
local link, price, count = strsplit(";", callbackstring)
|
|
local sig = AucAdvanced.API.GetSigFromLink(link)
|
|
local price = floor(price/count) - 1
|
|
if AucSearchUI.Filters.ItemPrice then
|
|
AucSearchUI.Filters.ItemPrice.AddIgnore(sig, price, true)
|
|
print("SearchUI now ignoring "..link.." at "..AucAdvanced.Coins(price, true).." for the session")
|
|
end
|
|
|
|
end
|
|
|
|
function private.ignoretemp()
|
|
local sig = AucAdvanced.API.GetSigFromLink(private.data.link)
|
|
local price
|
|
if strmatch(private.data.reason, ":buy") then
|
|
price = private.data.buyout
|
|
elseif strmatch(private.data.reason, ":bid") then
|
|
price = private.data.bid
|
|
elseif private.data.buyout > 0 then
|
|
price = private.data.buyout
|
|
else
|
|
price = private.data.bid
|
|
end
|
|
local count = private.data.stack or 1
|
|
price = floor(price/count)
|
|
AucSearchUI.Filters.ItemPrice.AddIgnore(sig, price, true)
|
|
print("SearchUI now ignoring "..private.data.link.." at "..AucAdvanced.Coins(price, true).." for the session")
|
|
private.removeline()
|
|
end
|
|
|
|
function private.snatch()
|
|
local link = private.data.link
|
|
local price
|
|
if strmatch(private.data.reason, ":buy") then
|
|
price = private.data.buyout
|
|
elseif strmatch(private.data.reason, ":bid") then
|
|
price = private.data.bid
|
|
elseif private.data.buyout > 0 then
|
|
price = private.data.buyout
|
|
else
|
|
price = private.data.bid
|
|
end
|
|
local count = private.data.stack or 1
|
|
price = floor(price/count) + 1 -- +1 so the current item also matches the search
|
|
lib.Searchers.Snatch.AddSnatch(link,price)
|
|
print("SearchUI will now snatch "..private.data.link.." at "..AucAdvanced.Coins(price, true))
|
|
end
|
|
|
|
local function keyPairs(t,f)
|
|
local a, i = {}, 0
|
|
for n in pairs(t) do tinsert(a, n) end
|
|
table.sort(a, f)
|
|
local iter = function ()
|
|
i = i + 1
|
|
if a[i] == nil then return nil
|
|
else return a[i], t[a[i]] end
|
|
end
|
|
return iter
|
|
end
|
|
|
|
local function isEqual(a, b, l)
|
|
if not l then l = 0
|
|
elseif l > 10 then return false end
|
|
|
|
local ta, tb = type(a), type(b)
|
|
if ta ~= tb then return false end
|
|
if ta == 'table' then
|
|
for k,v in pairs(a) do
|
|
if not isEqual(v, b[k], l+1) then return false end
|
|
end
|
|
for k,v in pairs(b) do
|
|
if not isEqual(v, a[k], l+1) then return false end
|
|
end
|
|
else
|
|
if tostring(a) ~= tostring(b) then
|
|
return false
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
lib.IsEqual = isEqual
|
|
|
|
function lib.LoadCurrent()
|
|
initData()
|
|
local name = gui.saves.name:GetText()
|
|
currentSettings = AucAdvancedData.UtilSearchUiData.Current
|
|
if not currentSettings then
|
|
lib.LoadSearch()
|
|
return
|
|
end
|
|
|
|
local existing = AucAdvancedData.UtilSearchUiData.SavedSearches[name]
|
|
if not existing then
|
|
hasUnsaved = true
|
|
elseif not isEqual(currentSettings, existing) then
|
|
hasUnsaved = true
|
|
else
|
|
hasUnsaved = nil
|
|
end
|
|
lib.UpdateSave()
|
|
gui:Refresh()
|
|
lib.NotifyCallbacks('config', 'loaded', nil)
|
|
end
|
|
|
|
function lib.LoadSearch()
|
|
initData()
|
|
local name = gui.saves.name:GetText()
|
|
if not AucAdvancedData.UtilSearchUiData.SavedSearches[name] then
|
|
message("SearchUI warning:\nThat search does not exist, please select an available search from the menu.")
|
|
return
|
|
end
|
|
currentSettings = replicate(AucAdvancedData.UtilSearchUiData.SavedSearches[name])
|
|
AucAdvancedData.UtilSearchUiData.Current = currentSettings
|
|
AucAdvancedData.UtilSearchUiData.Selected = name
|
|
hasUnsaved = nil
|
|
lib.UpdateSave()
|
|
gui:Refresh()
|
|
lib.NotifyCallbacks('config', 'loaded', name)
|
|
end
|
|
|
|
function lib.SaveSearch()
|
|
initData()
|
|
local name = gui.saves.name:GetText()
|
|
AucAdvancedData.UtilSearchUiData.SavedSearches[name] = replicate(currentSettings)
|
|
AucAdvancedData.UtilSearchUiData.Selected = name
|
|
hasUnsaved = nil
|
|
lib.UpdateSave()
|
|
gui:Refresh()
|
|
lib.NotifyCallbacks('config', 'saved', name)
|
|
end
|
|
|
|
function lib.DeleteSearch()
|
|
initData()
|
|
local name = gui.saves.name:GetText()
|
|
AucAdvancedData.UtilSearchUiData.SavedSearches[name] = nil
|
|
hasUnsaved = nil
|
|
AucAdvancedData.UtilSearchUiData.Selected = ""
|
|
gui.saves.name:SetText("")
|
|
lib.UpdateSave()
|
|
gui:Refresh()
|
|
lib.NotifyCallbacks('config', 'deleted', name)
|
|
end
|
|
|
|
function lib.ResetSearch()
|
|
initData()
|
|
currentSettings = {}
|
|
AucAdvancedData.UtilSearchUiData.Current = currentSettings
|
|
hasUnsaved = nil
|
|
AucAdvancedData.UtilSearchUiData.Selected = ""
|
|
gui.saves.name:SetText("")
|
|
lib.UpdateSave()
|
|
gui:Refresh()
|
|
lib.NotifyCallbacks('config', 'reset')
|
|
end
|
|
|
|
local curColor = "white"
|
|
function lib.UpdateSave()
|
|
if not (gui and AucAdvancedData.UtilSearchUiData) then return end
|
|
|
|
local name = gui.saves.name:GetText()
|
|
|
|
if hasUnsaved then
|
|
local saved = AucAdvancedData.UtilSearchUiData.SavedSearches[name]
|
|
if saved and isEqual(currentSettings, saved) then
|
|
hasUnsaved = false
|
|
end
|
|
end
|
|
|
|
if AucAdvancedData.UtilSearchUiData.Selected ~= name then
|
|
if curColor ~= "white" then
|
|
gui.saves.name:SetTextColor(1, 1, 1, 1)
|
|
curColor = "white"
|
|
end
|
|
elseif hasUnsaved then
|
|
if curColor ~= "red" then
|
|
gui.saves.name:SetTextColor(1, 0.5, 0.1, 1)
|
|
curColor = "red"
|
|
end
|
|
else
|
|
if curColor ~= "green" then
|
|
gui.saves.name:SetTextColor(0.3, 1, 0.3, 1)
|
|
curColor = "green"
|
|
end
|
|
end
|
|
end
|
|
|
|
function lib.AddSearcher(gui, searchType, searchDetail, searchPos)
|
|
if not gui.searchers[searchPos] then gui.searchers[searchPos] = {} end
|
|
gui.searchers[searchPos][searchType] = searchDetail
|
|
end
|
|
|
|
function lib.AttachToAH()
|
|
if private.isAttached then return end
|
|
local height, width = 410, 830
|
|
gui.buttonTop = -30
|
|
gui:SetPosition(gui.AuctionFrame, width, height, 5, 7+height)
|
|
gui:HideBackdrop()
|
|
gui:EnableMouse(false)
|
|
gui:RealSetScale(0.9999)
|
|
gui:RealSetScale(1.0)
|
|
gui:Show()
|
|
private.isAttached = true
|
|
end
|
|
|
|
function lib.DetachFromAH()
|
|
if not private.isAttached then return end
|
|
gui.buttonTop = 0
|
|
gui:SetPosition()
|
|
gui:EnableMouse(true)
|
|
gui:ShowBackdrop()
|
|
gui:RealSetScale(0.9999)
|
|
gui:RealSetScale(private.scale or 1)
|
|
gui:Hide()
|
|
private.isAttached = nil
|
|
end
|
|
|
|
function lib.CreateAuctionFrames()
|
|
if not lib.GetSetting("global.createtab") then return end
|
|
|
|
local frame = CreateFrame("Frame", "AucAdvSearchUiAuctionFrame", AuctionFrame)
|
|
gui.AuctionFrame = frame
|
|
|
|
frame:SetParent(AuctionFrame)
|
|
frame:SetPoint("TOPLEFT", AuctionFrame, "TOPLEFT")
|
|
frame:SetPoint("BOTTOMRIGHT", AuctionFrame, "BOTTOMRIGHT")
|
|
|
|
frame.title = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
|
|
frame.title:SetPoint("TOP", frame, "TOP", 20, -17)
|
|
frame.title:SetText("SearchUI - Auction search interface")
|
|
|
|
local myTabName = "AuctionFrameTabUtilSearchUi"
|
|
frame.tab = CreateFrame("Button", myTabName, AuctionFrame, "AuctionTabTemplate")
|
|
frame.tab:SetText(TAB_NAME)
|
|
frame.tab:Show()
|
|
|
|
function frame.tab.OnClick(self, button, down)
|
|
local index = self:GetID()
|
|
local tab = _G["AuctionFrameTab"..index]
|
|
if (tab and tab:GetName() == myTabName) then
|
|
AuctionFrameTopLeft:SetTexture("Interface\\AddOns\\Auc-Advanced\\Textures\\AuctionFrameTopLeft")
|
|
AuctionFrameTop:SetTexture("Interface\\AddOns\\Auc-Advanced\\Textures\\AuctionFrameTopMid")
|
|
AuctionFrameTopRight:SetTexture("Interface\\AddOns\\Auc-Advanced\\Textures\\AuctionFrameTopRight")
|
|
AuctionFrameBotLeft:SetTexture("Interface\\AddOns\\Auc-Advanced\\Textures\\AuctionFrameBotLeft")
|
|
AuctionFrameBot:SetTexture("Interface\\AddOns\\Auc-Advanced\\Textures\\AuctionFrameBotMid")
|
|
AuctionFrameBotRight:SetTexture("Interface\\AddOns\\Auc-Advanced\\Textures\\AuctionFrameBotRight")
|
|
AuctionFrameMoneyFrame:Hide()
|
|
frame:Show()
|
|
lib.AttachToAH()
|
|
else
|
|
AuctionFrameMoneyFrame:Show()
|
|
frame:Hide()
|
|
lib.DetachFromAH()
|
|
end
|
|
end
|
|
|
|
PanelTemplates_DeselectTab(frame.tab)
|
|
AucAdvanced.AddTab(frame.tab, frame)
|
|
|
|
hooksecurefunc("AuctionFrameTab_OnClick", frame.tab.OnClick)
|
|
|
|
frame.money = frame:CreateTexture(nil, "ARTWORK")
|
|
frame.money:SetTexture("Interface\\AddOns\\Auc-Advanced\\Textures\\GoldMoney")
|
|
frame.money:SetPoint("TOPLEFT", frame, "BOTTOMLEFT", 18, 34)
|
|
frame.money:SetWidth(256)
|
|
frame.money:SetHeight(32)
|
|
|
|
frame.backing = CreateFrame("Frame", nil, frame)
|
|
frame.backing:SetPoint("TOPLEFT", frame, "TOPLEFT", 17, -70)
|
|
frame.backing:SetPoint("BOTTOMRIGHT", frame.money, "TOPLEFT", 145, 50)
|
|
frame.backing:SetBackdrop({ bgFile="Interface\\AddOns\\Auc-Advanced\\Textures\\BlackBack", edgeFile="Interface\\AddOns\\Auc-Advanced\\Textures\\WhiteCornerBorder", tile=1, tileSize=8, edgeSize=8, insets={left=3, right=3, top=3, bottom=3} })
|
|
frame.backing:SetBackdropColor(0,0,0, 0.60)
|
|
|
|
frame.scanslabel = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
frame.scanslabel:SetPoint("TOPLEFT", frame, "TOPLEFT", 72, -20)
|
|
frame.scanslabel:SetText("Pending Scans")
|
|
frame.scanscount = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
frame.scanscount:ClearAllPoints()
|
|
frame.scanscount:SetPoint("LEFT", frame.scanslabel, "RIGHT", 5, 0)
|
|
frame.scanscount:SetText("0")
|
|
frame.scanscount:SetJustifyH("RIGHT")
|
|
frame.scanscount.last = 0
|
|
function private.UpdateScanProgress(_, _, _, _, _, _, _, scansQueued)
|
|
if AucAdvanced.Scan.IsScanning() then
|
|
scansQueued = scansQueued + 1
|
|
end
|
|
if scansQueued ~= frame.scanscount.last then
|
|
frame.scanscount.last = scansQueued
|
|
frame.scanscount:SetText(scansQueued)
|
|
end
|
|
end
|
|
end
|
|
|
|
function lib.MakeGuiConfig()
|
|
if gui then return end
|
|
|
|
local Configator = LibStub("Configator")
|
|
local ScrollSheet = LibStub("ScrollSheet")
|
|
local id, last, cont
|
|
local selected
|
|
|
|
gui = Configator:Create(setter,getter, 900, 500, 5, 350, 20, 5)
|
|
gui:SetBackdropColor(0,0,0,1)
|
|
|
|
gui.expandGap = 25
|
|
gui.expandOnActivate = true
|
|
gui.autoScrollTabs = true
|
|
|
|
gui.searchers = {}
|
|
gui.AddSearcher = function (self, searchType, searchDetail, searchPos)
|
|
lib.AddSearcher(self, searchType, searchDetail, searchPos)
|
|
end
|
|
|
|
-- Only set scale if the gui isn't attached to the AH frame
|
|
gui.RealSetScale = gui.SetScale
|
|
function gui:SetScale(scale)
|
|
private.scale = scale
|
|
if private.isAttached then return end
|
|
gui:RealSetScale(scale)
|
|
end
|
|
|
|
-- hook ActivateTab to notify callback
|
|
gui.RealActivateTab = gui.ActivateTab
|
|
function gui:ActivateTab(...)
|
|
gui:RealActivateTab(...)
|
|
local newtab = gui.config.selectedTab
|
|
if newtab ~= gui.LastActiveTab then
|
|
gui.LastActiveTab = newtab
|
|
lib.NotifyCallbacks("selecttab", newtab)
|
|
end
|
|
gui.Search.updateDisplay()
|
|
end
|
|
|
|
private.gui = gui
|
|
|
|
-- common functions and scripthandlers, used by various buttons and frames
|
|
local function showTooltipText(button)
|
|
if lib.GetSetting("tooltiphelp.show") then
|
|
GameTooltip:SetOwner(button, "ANCHOR_BOTTOMRIGHT")
|
|
GameTooltip:SetText(button.TooltipText)
|
|
end
|
|
end
|
|
local function hideTooltip()
|
|
GameTooltip:Hide()
|
|
end
|
|
|
|
gui.frame = CreateFrame("Frame", nil, gui)
|
|
gui.frame:SetPoint("TOP", gui, "TOP", 0, -115)
|
|
gui.frame:SetPoint("BOTTOMRIGHT", gui.Done, "TOPRIGHT", 0,25)
|
|
gui.frame:SetPoint("LEFT", gui:GetButton(1), "RIGHT", 5,0)
|
|
gui.frame:SetBackdrop({
|
|
bgFile = "Interface/Tooltips/ChatBubble-Background",
|
|
edgeFile = "Interface/Tooltips/ChatBubble-BackDrop",
|
|
tile = true, tileSize = 32, edgeSize = 32,
|
|
insets = { left = 32, right = 32, top = 32, bottom = 32 }
|
|
})
|
|
gui.frame:SetBackdropColor(0, 0, 0, 1)
|
|
|
|
gui.saves = CreateFrame("Frame", nil, gui)
|
|
gui.saves:SetPoint("TOPRIGHT", gui, "TOPRIGHT", -5,-7)
|
|
gui.saves:SetPoint("LEFT", gui:GetButton(1), "RIGHT", 10,0)
|
|
gui.saves:SetHeight(28)
|
|
-- gui.saves:SetBackdrop({
|
|
-- bgFile = "Interface/Tooltips/ChatBubble-Background",
|
|
-- edgeFile = "Interface/Tooltips/ChatBubble-BackDrop",
|
|
-- tile = true, tileSize = 32, edgeSize = 18,
|
|
-- insets = { left = 20, right = 20, top = 20, bottom = 20 }
|
|
-- })
|
|
-- gui.saves:SetBackdropColor(0, 0, 0, 1)
|
|
|
|
gui.saves.title = gui.saves:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
gui.saves.title:SetPoint("LEFT", gui.saves, "LEFT", 10,0)
|
|
gui.saves.title:SetText("Saved searches:")
|
|
|
|
gui.saves.name = CreateFrame("EditBox", "SearchUiSaveName", gui.saves, "InputBoxTemplate")
|
|
gui.saves.name:SetPoint("LEFT", gui.saves.title, "RIGHT", 10,0)
|
|
gui.saves.name:SetAutoFocus(false)
|
|
gui.saves.name:SetWidth(200)
|
|
gui.saves.name:SetHeight(18)
|
|
gui.saves.name:SetScript("OnTextChanged", function() lib.UpdateSave() end)
|
|
if AucAdvancedData.UtilSearchUiData then
|
|
local curSearch = AucAdvancedData.UtilSearchUiData.Selected or ""
|
|
if AucAdvancedData.UtilSearchUiData.SavedSearches[curSearch] then
|
|
gui.saves.name:SetText(curSearch)
|
|
else
|
|
gui.saves.name:SetText("")
|
|
end
|
|
lib.LoadCurrent()
|
|
end
|
|
|
|
local SelectBox = LibStub:GetLibrary("SelectBox")
|
|
|
|
gui.saves.select = SelectBox:Create("SearchUiSaveSelect", gui.saves, 220, function(pos, key, value)
|
|
gui.saves.name:SetText(value)
|
|
end, function ()
|
|
local saves = AucAdvancedData.UtilSearchUiData.SavedSearches
|
|
local items = {}
|
|
if (saves) then
|
|
for name, sdata in keyPairs(saves) do
|
|
tinsert(items, name)
|
|
end
|
|
end
|
|
return items
|
|
end, "")
|
|
gui.saves.select:SetParent(gui.saves)
|
|
gui.saves.select:SetScale(0.999)
|
|
gui.saves.select:SetScale(1.0)
|
|
gui.saves.select:SetPoint("RIGHT", gui.saves.name, "RIGHT", 38,-4)
|
|
gui.saves.select:SetInputHidden(true)
|
|
|
|
gui.saves.load = CreateFrame("Button", nil, gui.saves, "OptionsButtonTemplate")
|
|
gui.saves.load:SetPoint("LEFT", gui.saves.name, "RIGHT", 25, 0)
|
|
gui.saves.load:SetWidth(70)
|
|
gui.saves.load:SetHeight(20)
|
|
gui.saves.load:SetText("Load")
|
|
gui.saves.load:SetScript("OnClick", function() lib.LoadSearch() end)
|
|
|
|
gui.saves.save = CreateFrame("Button", nil, gui.saves, "OptionsButtonTemplate")
|
|
gui.saves.save:SetPoint("LEFT", gui.saves.load, "RIGHT", 5, 0)
|
|
gui.saves.save:SetWidth(70)
|
|
gui.saves.save:SetHeight(20)
|
|
gui.saves.save:SetText("Save")
|
|
gui.saves.save:SetScript("OnClick", function() lib.SaveSearch() end)
|
|
|
|
gui.saves.delete = CreateFrame("Button", nil, gui.saves, "OptionsButtonTemplate")
|
|
gui.saves.delete:SetPoint("LEFT", gui.saves.save, "RIGHT", 5, 0)
|
|
gui.saves.delete:SetWidth(70)
|
|
gui.saves.delete:SetHeight(20)
|
|
gui.saves.delete:SetText("Delete")
|
|
gui.saves.delete:SetScript("OnClick", function() lib.DeleteSearch() end)
|
|
|
|
gui.saves.reset = CreateFrame("Button", nil, gui.saves, "OptionsButtonTemplate")
|
|
gui.saves.reset:SetPoint("LEFT", gui.saves.delete, "RIGHT", 10, 0)
|
|
gui.saves.reset:SetWidth(70)
|
|
gui.saves.reset:SetHeight(20)
|
|
gui.saves.reset:SetText("Reset")
|
|
gui.saves.reset:SetScript("OnClick", function()
|
|
if IsShiftKeyDown() and IsControlKeyDown() and IsAltKeyDown() then
|
|
lib.ResetSearch()
|
|
print("All searchUI settings have been reset.")
|
|
else
|
|
print("This resets all searchUI settings, you must hold CTRL + SHIFT + ALT when clicking this button")
|
|
end
|
|
end)
|
|
|
|
function lib.UpdateControls()
|
|
if gui.sheet.selected then
|
|
gui.frame.ignore:Enable()
|
|
gui.frame.ignoreperm:Enable()
|
|
gui.frame.notnow:Enable()
|
|
gui.frame.snatch:Enable()
|
|
else
|
|
gui.frame.ignore:Disable()
|
|
gui.frame.ignoreperm:Disable()
|
|
gui.frame.notnow:Disable()
|
|
gui.frame.snatch:Disable()
|
|
end
|
|
if selected ~= gui.sheet.selected then
|
|
selected = gui.sheet.selected
|
|
local data = gui.sheet:GetSelection()
|
|
if not data then
|
|
empty(private.data)
|
|
else
|
|
private.data.link = data[1]
|
|
private.data.seller = data[8]
|
|
private.data.stack = data[4]
|
|
private.data.bid = data[6]
|
|
private.data.minbid = data[12]
|
|
private.data.curbid = data[13]
|
|
private.data.buyout = data[5]
|
|
private.data.reason = data[7]
|
|
end
|
|
if private.data.buyout and (private.data.buyout > 0) then
|
|
gui.frame.buyout:Enable()
|
|
gui.frame.buyoutbox:SetText(AucAdvanced.Coins(private.data.buyout, true))
|
|
else
|
|
gui.frame.buyout:Disable()
|
|
gui.frame.buyoutbox:SetText(AucAdvanced.Coins(0, true))
|
|
end
|
|
|
|
if private.data.bid then
|
|
MoneyInputFrame_SetCopper(gui.frame.bidbox, private.data.bid)
|
|
gui.frame.bid:Enable()
|
|
else
|
|
MoneyInputFrame_SetCopper(gui.frame.bidbox, 0)
|
|
gui.frame.bid:Disable()
|
|
end
|
|
elseif private.data.curbid then--bid price was changed, so make sure that it's allowable
|
|
if MoneyInputFrame_GetCopper(gui.frame.bidbox) < ceil(private.data.curbid*1.05) then
|
|
MoneyInputFrame_SetCopper(gui.frame.bidbox, ceil(private.data.curbid*1.05))
|
|
end
|
|
gui.frame.bid:Enable()
|
|
end
|
|
--if bid >= buyout, it's going to be a buyout anyway, so disable bid button to indicate that
|
|
if private.data.buyout and (private.data.buyout > 0) and (MoneyInputFrame_GetCopper(gui.frame.bidbox) >= private.data.buyout) then
|
|
MoneyInputFrame_SetCopper(gui.frame.bidbox, private.data.buyout)
|
|
gui.frame.bid:Disable()
|
|
end
|
|
gui.frame.purchase.updateEnable()
|
|
end
|
|
|
|
function lib.OnEnterSheet(button, row, index)
|
|
if gui.sheet.rows[row][index]:IsShown() then --Hide tooltip for hidden cells
|
|
local link, count
|
|
link = gui.sheet.rows[row][index]:GetText()
|
|
if link and link:find("\124Hitem:%d") then
|
|
if gui.sheet.order then
|
|
for i, label in pairs(gui.sheet.labels) do
|
|
if label:GetText() == "Stk" then --need to localize this when we localize the rest of searchUI
|
|
count = tonumber(gui.sheet.rows[row][i]:GetText())
|
|
break
|
|
end
|
|
end
|
|
else
|
|
count = tonumber(gui.sheet.rows[row][4]:GetText() )
|
|
end
|
|
|
|
GameTooltip:SetOwner(button, "ANCHOR_RIGHT")
|
|
AucAdvanced.ShowItemLink(GameTooltip, link, count)
|
|
end
|
|
end
|
|
end
|
|
|
|
function lib.OnClickSheet(button, row, index)
|
|
index = index - (index%15-1)
|
|
if IsShiftKeyDown() then --Add the item link to chat
|
|
local link = gui.sheet.rows[row][index]:GetText()
|
|
if not link then
|
|
return
|
|
end
|
|
ChatEdit_InsertLink(link)
|
|
elseif IsAltKeyDown() then --Search for the item in browse tab.
|
|
local name = gui.sheet.rows[row][index]:GetText()
|
|
if not name then
|
|
return
|
|
end
|
|
name = GetItemInfo(name)
|
|
QueryAuctionItems(name)
|
|
end
|
|
end
|
|
--records the column width changes
|
|
--store width by header name, that way if column reorginizing is added we apply size to proper column
|
|
function private.OnResizeSheet(self, column, width)
|
|
if not width then
|
|
lib.SetSetting("columnwidth."..self.labels[column]:GetText(), "default") --reset column if no width is passed. We use CTRL+rightclick to reset column
|
|
self.labels[column].button:SetWidth(lib.GetSetting("columnwidth."..self.labels[column]:GetText()))
|
|
else
|
|
lib.SetSetting("columnwidth."..self.labels[column]:GetText(), width)
|
|
end
|
|
end
|
|
|
|
gui.sheet = ScrollSheet:Create(gui.frame, {
|
|
{ "Item", "TOOLTIP", lib.GetSetting("columnwidth.Item") }, --120
|
|
{ "Pct", "INT", lib.GetSetting("columnwidth.Pct") }, --30
|
|
{ "Profit", "COIN", lib.GetSetting("columnwidth.Profit") , { DESCENDING=true } }, --85
|
|
{ "Stk", "INT", lib.GetSetting("columnwidth.Stk") }, --30
|
|
{ "Buyout", "COIN", lib.GetSetting("columnwidth.Buyout"), { DESCENDING=true } }, --85
|
|
{ "Bid", "COIN", lib.GetSetting("columnwidth.Bid"), { DESCENDING=true } }, --85
|
|
{ "Reason", "TEXT", lib.GetSetting("columnwidth.Reason") }, --85
|
|
{ "Seller", "TEXT", lib.GetSetting("columnwidth.Seller") }, --75
|
|
{ "Left", "TEXT", lib.GetSetting("columnwidth.Left") }, --40
|
|
{ "Buy/ea", "COIN", lib.GetSetting("columnwidth.Buy/ea"), { DESCENDING=true, DEFAULT=true } }, --85
|
|
{ "Bid/ea", "COIN", lib.GetSetting("columnwidth.Bid/ea"), { DESCENDING=true, DEFAULT=true } }, --85
|
|
{ "MinBid", "COIN", lib.GetSetting("columnwidth.MinBid"), { DESCENDING=true } }, --85
|
|
{ "CurBid", "COIN", lib.GetSetting("columnwidth.CurBid"), { DESCENDING=true } }, --85
|
|
{ "Min/ea", "COIN", lib.GetSetting("columnwidth.Min/ea"), { DESCENDING=true } }, --85
|
|
{ "Cur/ea", "COIN", lib.GetSetting("columnwidth.Cur/ea"), { DESCENDING=true } }, --85
|
|
})
|
|
gui.sheet:EnableSelect(true)
|
|
gui.sheet:EnableVerticalScrollReset(false) --tells scrollframes we do NOT want to reset position when rendering a new data table
|
|
|
|
--If we have a saved order reapply
|
|
if lib.GetSetting("columnorder") then
|
|
--print("saved order applied")
|
|
gui.sheet:SetOrder(lib.GetSetting("columnorder") )
|
|
end
|
|
--Apply last column sort used
|
|
if lib.GetSetting("columnsortcurSort") then
|
|
gui.sheet.curSort = lib.GetSetting("columnsortcurSort") or 1
|
|
gui.sheet.curDir = lib.GetSetting("columnsortcurDir") or 1
|
|
gui.sheet:PerformSort()
|
|
end
|
|
--After we have finished creating the scrollsheet and all saved settings have been applied set our event processor
|
|
function gui.sheet.Processor(callback, self, button, column, row, order, curDir, ...)
|
|
if (callback == "ColumnOrder") then
|
|
lib.SetSetting("columnorder", order)
|
|
elseif (callback == "ColumnWidthSet") then
|
|
private.OnResizeSheet(self, column, button:GetWidth() )
|
|
elseif (callback == "ColumnWidthReset") then
|
|
private.onResize(self, column, nil)
|
|
elseif (callback == "OnEnterCell") then
|
|
lib.OnEnterSheet(button, row, column)
|
|
elseif (callback == "OnLeaveCell") then
|
|
GameTooltip:Hide()
|
|
elseif (callback == "OnClickCell") then
|
|
lib.OnClickSheet(button, row, column)
|
|
elseif (callback == "ColumnSort") then
|
|
lib.SetSetting("columnsortcurDir", curDir)
|
|
lib.SetSetting("columnsortcurSort", column)
|
|
elseif (callback == "OnMouseDownCell") then
|
|
lib.UpdateControls()
|
|
end
|
|
end
|
|
|
|
gui.Search = CreateFrame("Button", "AucSearchUISearchButton", gui, "OptionsButtonTemplate")
|
|
gui.Search:SetPoint("BOTTOMLEFT", gui, "BOTTOMLEFT", 30, 50)
|
|
gui.Search:SetText("Search")
|
|
gui.Search:SetScript("OnClick", lib.PerformSearch)
|
|
gui.Search:SetFrameLevel(11)
|
|
gui.Search.TooltipText = "Search Snapshot using current Searcher"
|
|
gui.Search:SetScript("OnEnter", showTooltipText)
|
|
gui.Search:SetScript("OnLeave", hideTooltip)
|
|
gui.Search:Disable()
|
|
gui.Search.updateDisplay = function()
|
|
if gui.config.selectedCat == "Searchers" then
|
|
gui.Search:Enable()
|
|
else
|
|
gui.Search:Disable()
|
|
end
|
|
end
|
|
|
|
|
|
gui:AddCat("Welcome")
|
|
|
|
id = gui:AddTab("About")
|
|
gui.aboutTab = id
|
|
gui:MakeScrollable(id)
|
|
gui:AddControl(id, "Subhead", 0, "About the SearchUI")
|
|
|
|
gui:AddCat("Searchers", nil, nil, true)
|
|
gui:AddCat("Filters")
|
|
|
|
gui:AddCat("Options")
|
|
id = gui:AddTab("General Options", "Options")
|
|
gui:MakeScrollable(id)
|
|
gui:AddControl(id, "Header", 0, "Setup general options")
|
|
gui:AddControl(id, "WideSlider", 0, 1, "processpriority", 10, 100, 10, "Search process priority: %s")
|
|
gui:AddControl(id, "Subhead", 0, "Purchase Settings")
|
|
gui:AddControl(id, "Checkbox", 0, 1, "reserve.enable", "Enable reserve amount:")
|
|
gui:AddControl(id, "MoneyFramePinned", 0, 2, "reserve", 0, 99999999, "Reserve Amount")
|
|
gui:AddTip(id, "Sets the amount that you don't want your cash-on-hand to fall below")
|
|
gui:AddControl(id, "Checkbox", 0, 1, "maxprice.enable", "Enable maximum price:")
|
|
gui:AddControl(id, "MoneyFramePinned", 0, 2, "maxprice", 1, 99999999, "Maximum Price")
|
|
gui:AddTip(id, "Sets the amount that you don't want to spend more than")
|
|
|
|
id = gui:AddTab("Global Settings", "Settings")
|
|
gui:MakeScrollable(id)
|
|
gui:AddControl(id, "Header", 0, "Setup global options")
|
|
|
|
gui:AddControl(id, "Subhead", 0, "Tooltip")
|
|
gui:AddControl(id, "Checkbox", 0, 1, "tooltiphelp.show", "Show tooltip help over buttons")
|
|
gui:AddControl(id, "Checkbox", 0, 1, "debug.show", "Show debug line in tooltip for auctions")
|
|
for name, searcher in pairs(lib.Searchers) do
|
|
if searcher and searcher.Search then
|
|
gui:AddControl(id, "Checkbox", 0, 2, "debug."..name, "Show debug for "..name)
|
|
gui:AddTip(id, "Show a debug line in the tooltip over auctions for searcher: "..name)
|
|
end
|
|
end
|
|
|
|
gui:AddControl(id, "Subhead", 0, "Integration")
|
|
gui:AddControl(id, "Checkbox", 0, 1, "global.createtab", "Create tab in auction house (requires restart)")
|
|
|
|
--gui:SetScript("OnKeyDown", lib.UpdateControls)
|
|
|
|
gui.frame.purchase = CreateFrame("Button", nil, gui.frame, "OptionsButtonTemplate")
|
|
gui.frame.purchase:SetPoint("BOTTOMLEFT", gui, "BOTTOMLEFT", 170, 35)
|
|
gui.frame.purchase:SetText("Purchase")
|
|
gui.frame.purchase:SetScript("OnClick", private.purchase)
|
|
gui.frame.purchase:Disable()
|
|
gui.frame.purchase.TooltipText = "Bid/BuyOut selected auction\nbased on 'reason' column. \nHold CTRL+ALT+SHIFT to purchase all items."
|
|
gui.frame.purchase:SetScript("OnEnter", showTooltipText)
|
|
gui.frame.purchase:SetScript("OnLeave", hideTooltip)
|
|
gui.frame.purchase.toggleAll = false
|
|
gui.frame.purchase.updateEnable = function()
|
|
if gui.frame.purchase.toggleAll then
|
|
if gui.sheet.sort[1] then
|
|
gui.frame.purchase:Enable()
|
|
else
|
|
gui.frame.purchase:Disable()
|
|
end
|
|
else
|
|
if (gui.frame.bid:IsEnabled()==1) or (gui.frame.buyout:IsEnabled()==1) then
|
|
gui.frame.purchase:Enable()
|
|
else
|
|
gui.frame.purchase:Disable()
|
|
end
|
|
end
|
|
end
|
|
gui.frame.purchase.updateDisplay = function()
|
|
local all = IsShiftKeyDown() and IsControlKeyDown() and IsAltKeyDown()
|
|
if all ~= gui.frame.purchase.toggleAll then
|
|
gui.frame.purchase.toggleAll = all
|
|
if all then
|
|
gui.frame.purchase:SetText("Purchase All")
|
|
gui.frame.purchase:SetScript("OnClick", private.purchaseall)
|
|
else
|
|
gui.frame.purchase:SetText("Purchase")
|
|
gui.frame.purchase:SetScript("OnClick", private.purchase)
|
|
end
|
|
end
|
|
gui.frame.purchase.updateEnable()
|
|
end
|
|
Stubby.RegisterEventHook("MODIFIER_STATE_CHANGED", "Auc-Util-SearchUI", gui.frame.purchase.updateDisplay)
|
|
|
|
|
|
gui.frame.notnow = CreateFrame("Button", nil, gui.frame, "OptionsButtonTemplate")
|
|
gui.frame.notnow:SetPoint("BOTTOMLEFT", gui, "BOTTOMLEFT", 260, 35)
|
|
gui.frame.notnow:SetText("Not Now")
|
|
gui.frame.notnow:SetScript("OnClick", private.ignoretemp)
|
|
gui.frame.notnow:Disable()
|
|
gui.frame.notnow.TooltipText = "Ignore selected auction for session"
|
|
gui.frame.notnow:SetScript("OnEnter", showTooltipText)
|
|
gui.frame.notnow:SetScript("OnLeave", hideTooltip)
|
|
|
|
gui.frame.ignore = CreateFrame("Button", nil, gui.frame, "OptionsButtonTemplate")
|
|
gui.frame.ignore:SetPoint("BOTTOMLEFT", gui, "BOTTOMLEFT", 400, 35)
|
|
gui.frame.ignore:SetText("Ignore Price")
|
|
gui.frame.ignore:SetScript("OnClick", private.ignore)
|
|
gui.frame.ignore:Disable()
|
|
gui.frame.ignore.TooltipText = "Ignore selected auction at listed price"
|
|
gui.frame.ignore:SetScript("OnEnter", showTooltipText)
|
|
gui.frame.ignore:SetScript("OnLeave", hideTooltip)
|
|
|
|
gui.frame.ignoreperm = CreateFrame("Button", nil, gui.frame, "OptionsButtonTemplate")
|
|
gui.frame.ignoreperm:SetPoint("BOTTOMLEFT", gui, "BOTTOMLEFT", 490, 35)
|
|
gui.frame.ignoreperm:SetText("Ignore")
|
|
gui.frame.ignoreperm:SetScript("OnClick", private.ignoreperm)
|
|
gui.frame.ignoreperm:Disable()
|
|
gui.frame.ignoreperm.TooltipText = "Ignore selected auction at any price"
|
|
gui.frame.ignoreperm:SetScript("OnEnter", showTooltipText)
|
|
gui.frame.ignoreperm:SetScript("OnLeave", hideTooltip)
|
|
|
|
gui.frame.snatch = CreateFrame("Button", nil, gui.frame, "OptionsButtonTemplate")
|
|
gui.frame.snatch:SetPoint("BOTTOMLEFT", gui, "BOTTOMLEFT", 630, 35)
|
|
gui.frame.snatch:SetText("Snatch")
|
|
gui.frame.snatch:SetScript("OnClick", private.snatch)
|
|
gui.frame.snatch:Disable()
|
|
gui.frame.snatch.TooltipText = "Add selected auction to snatch list"
|
|
gui.frame.snatch:SetScript("OnEnter", showTooltipText)
|
|
gui.frame.snatch:SetScript("OnLeave", hideTooltip)
|
|
|
|
gui.frame.clear = CreateFrame("Button", nil, gui.frame, "OptionsButtonTemplate")
|
|
gui.frame.clear:SetPoint("BOTTOMLEFT", gui, "BOTTOMLEFT", 170, 10)
|
|
gui.frame.clear:SetText("Clear")
|
|
gui.frame.clear:SetScript("OnClick", private.removeall)
|
|
gui.frame.clear:Enable()
|
|
gui.frame.clear.TooltipText = "Clear results list"
|
|
gui.frame.clear:SetScript("OnEnter", showTooltipText)
|
|
gui.frame.clear:SetScript("OnLeave", hideTooltip)
|
|
|
|
gui.frame.cancel = CreateFrame("Button", "AucAdvSearchUICancelButton", gui.frame, "OptionsButtonTemplate")
|
|
gui.frame.cancel:SetPoint("BOTTOMLEFT", gui, "BOTTOMLEFT", 30, 30)
|
|
gui.frame.cancel:SetWidth(22)
|
|
gui.frame.cancel:SetHeight(18)
|
|
gui.frame.cancel:Disable()
|
|
gui.frame.cancel:SetScript("OnClick", function()
|
|
AucAdvanced.Buy.CancelBuyQueue(true)
|
|
gui.frame.cancel.value = 0
|
|
end)
|
|
gui.frame.cancel.value = 0
|
|
private.UpdateBuyQueue = function ()
|
|
local queuelen, queuecost, prompt, promptcost = AucAdvanced.Buy.GetQueueStatus()
|
|
if prompt then
|
|
queuelen = queuelen + 1
|
|
queuecost = queuecost + promptcost
|
|
end
|
|
if queuelen > 0 then
|
|
gui.frame.cancel.label:SetText(tostring(queuelen)..": "..AucAdvanced.Coins(queuecost, true))
|
|
gui.frame.cancel.value = queuecost
|
|
gui.frame.cancel:Enable()
|
|
gui.frame.cancel.tex:SetVertexColor(1.0, 0.9, 0.1)
|
|
else
|
|
gui.frame.cancel.label:SetText("")
|
|
gui.frame.cancel.value = 0
|
|
gui.frame.cancel:Disable()
|
|
gui.frame.cancel.tex:SetVertexColor(0.3, 0.3, 0.3)
|
|
end
|
|
end
|
|
gui.frame.cancel.tex = gui.frame.cancel:CreateTexture(nil, "OVERLAY")
|
|
gui.frame.cancel.tex:SetPoint("TOPLEFT", gui.frame.cancel, "TOPLEFT", 4, -2)
|
|
gui.frame.cancel.tex:SetPoint("BOTTOMRIGHT", gui.frame.cancel, "BOTTOMRIGHT", -4, 2)
|
|
gui.frame.cancel.tex:SetTexture("Interface\\Addons\\Auc-Advanced\\Textures\\NavButtons")
|
|
gui.frame.cancel.tex:SetTexCoord(0.25, 0.5, 0, 1)
|
|
gui.frame.cancel.tex:SetVertexColor(0.3, 0.3, 0.3)
|
|
gui.frame.cancel.label = gui.frame.cancel:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
gui.frame.cancel.label:SetPoint("LEFT", gui.frame.cancel, "RIGHT", 5, 0)
|
|
gui.frame.cancel.label:SetTextColor(1, 0.8, 0)
|
|
gui.frame.cancel.label:SetText("")
|
|
gui.frame.cancel.label:SetJustifyH("LEFT")
|
|
|
|
gui.frame.buyout = CreateFrame("Button", nil, gui.frame, "OptionsButtonTemplate")
|
|
gui.frame.buyout:SetPoint("BOTTOMLEFT", gui, "BOTTOMLEFT", 650, 10)
|
|
gui.frame.buyout:SetText("Buyout")
|
|
gui.frame.buyout:SetScript("OnClick", private.buyauction)
|
|
gui.frame.buyout:Disable()
|
|
gui.frame.buyout.TooltipText = "Buyout selected auction"
|
|
gui.frame.buyout:SetScript("OnEnter", showTooltipText)
|
|
gui.frame.buyout:SetScript("OnLeave", hideTooltip)
|
|
|
|
gui.frame.buyoutbox = gui.frame.buyout:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
gui.frame.buyoutbox:SetPoint("BOTTOMRIGHT", gui.frame.buyout, "BOTTOMLEFT", -4, 4)
|
|
gui.frame.buyoutbox:SetWidth(100)
|
|
|
|
gui.frame.bid = CreateFrame("Button", nil, gui.frame, "OptionsButtonTemplate")
|
|
gui.frame.bid:SetPoint("BOTTOMRIGHT", gui.frame.buyoutbox, "BOTTOMLEFT", -10, -4)
|
|
gui.frame.bid:SetText("Bid")
|
|
gui.frame.bid:SetScript("OnClick", private.bidauction)
|
|
gui.frame.bid:Disable()
|
|
gui.frame.bid.TooltipText = "Bid on selected auction using custom price"
|
|
gui.frame.bid:SetScript("OnEnter", showTooltipText)
|
|
gui.frame.bid:SetScript("OnLeave", hideTooltip)
|
|
|
|
gui.frame.bidbox = CreateFrame("Frame", "AucAdvSearchUIBidBox", gui.frame, "MoneyInputFrameTemplate")
|
|
gui.frame.bidbox:SetPoint("BOTTOMRIGHT", gui.frame.bid, "BOTTOMLEFT", -4, 4)
|
|
MoneyInputFrame_SetOnValueChangedFunc(gui.frame.bidbox, lib.UpdateControls)
|
|
|
|
gui.frame.progressbar = CreateFrame("STATUSBAR", nil, gui.frame, "TextStatusBar")
|
|
gui.frame.progressbar:SetWidth(400)
|
|
gui.frame.progressbar:SetHeight(30)
|
|
gui.frame.progressbar:SetPoint("BOTTOM", gui.frame, "BOTTOM", 0, 100)
|
|
gui.frame.progressbar:SetBackdrop({
|
|
bgFile="Interface\\Tooltips\\UI-Tooltip-Background",
|
|
edgeFile="Interface\\Tooltips\\UI-Tooltip-Border",
|
|
tile=1, tileSize=10, edgeSize=10,
|
|
insets={left=3, right=3, top=3, bottom=3}
|
|
})
|
|
gui.frame.progressbar:SetStatusBarTexture("Interface\\TargetingFrame\\UI-StatusBar")
|
|
gui.frame.progressbar:SetStatusBarColor(0.6, 0, 0, 0.4)
|
|
gui.frame.progressbar:SetMinMaxValues(0, 1000)
|
|
gui.frame.progressbar:SetValue(0)
|
|
gui.frame.progressbar:SetFrameLevel(10)
|
|
gui.frame.progressbar:Hide()
|
|
|
|
gui.frame.progressbar.text = gui.frame.progressbar:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
gui.frame.progressbar.text:SetPoint("CENTER", gui.frame.progressbar, "CENTER")
|
|
gui.frame.progressbar.text:SetText("AucAdv SearchUI: Searching")
|
|
gui.frame.progressbar.text:SetTextColor(1,1,1)
|
|
|
|
gui.frame.progressbar.cancel = CreateFrame("Button", nil, gui.frame.progressbar, "OptionsButtonTemplate")
|
|
gui.frame.progressbar.cancel:SetPoint("BOTTOMRIGHT", gui.frame.progressbar, "BOTTOMRIGHT", -5, 5)
|
|
gui.frame.progressbar.cancel:SetPoint("TOPLEFT", gui.frame.progressbar, "TOPRIGHT", -25, -5)
|
|
gui.frame.progressbar.cancel:SetText("X")
|
|
gui.frame.progressbar.cancel:SetScript("OnClick", private.cancelSearch)
|
|
|
|
-- Alert our searchers?
|
|
for name, searcher in pairs(lib.Searchers) do
|
|
if searcher.MakeGuiConfig then
|
|
searcher:MakeGuiConfig(gui)
|
|
end
|
|
end
|
|
--Alert our Filters
|
|
for name, filter in pairs(lib.Filters) do
|
|
if filter.MakeGuiConfig then
|
|
filter:MakeGuiConfig(gui)
|
|
end
|
|
end
|
|
|
|
lib.NotifyCallbacks('guiconfig', gui)
|
|
|
|
-- Add the welcome text now
|
|
local b = " |TInterface\\QuestFrame\\UI-Quest-BulletPoint.blp:13|t "
|
|
local w = ""
|
|
w=w.."The Auctioneer Search UI is here to assist you in finding the Auctions that are of special interest to you.\n"
|
|
w=w.."\n"
|
|
w=w.."It has 2 modes of operation:\n"
|
|
w=w..b.."Offline - Searches are applied against the current data\n"
|
|
w=w..b.."Realtime - Searches are applied against the realtime scans of the AH\n"
|
|
w=w.."\n"
|
|
w=w.."There are also 2 types of searching modules that exist in the Search UI:\n"
|
|
w=w..b.."Searchers - Searches for a specific set of criteria, only 1 searcher is active at once\n"
|
|
w=w..b.."Filters - All filters always apply their criteria, excluding non-matching items from the search.\n"
|
|
w=w.."\n"
|
|
w=w.."In order to begin using the Search UI, you should first setup your filters to exclude the items you don't wish to find, then select a searcher to perform a search.\n"
|
|
w=w.."\n"
|
|
w=w.."Here's a quick list of the searchers and filters that you may wish to investigate:\n"
|
|
for pos, sdata in keyPairs(gui.searchers) do
|
|
for searchType, searchDetail in keyPairs(sdata) do
|
|
w=w..b.."|cffffce00"..searchType.."|r - "..searchDetail.."\n"
|
|
end
|
|
end
|
|
|
|
gui:AddControl(gui.aboutTab, "Note", 0, 1, nil, nil, w)
|
|
gui:ActivateTab(gui.aboutTab)
|
|
end
|
|
|
|
if LibStub then
|
|
--Need to figure out if we're embedded first
|
|
local embedded = false
|
|
for _, module in ipairs(AucAdvanced.EmbeddedModules) do
|
|
if module == "Auc-Util-SearchUI" then
|
|
embedded = true
|
|
end
|
|
end
|
|
local sideIcon
|
|
if embedded then
|
|
sideIcon = "Interface\\AddOns\\Auc-Advanced\\Modules\\Auc-Util-SearchUI\\Textures\\SearchUIIcon"
|
|
else
|
|
sideIcon = "Interface\\AddOns\\Auc-Util-SearchUI\\Textures\\SearchUIIcon"
|
|
end
|
|
|
|
local LibDataBroker = LibStub:GetLibrary("LibDataBroker-1.1", true)
|
|
if LibDataBroker then
|
|
private.LDBButton = LibDataBroker:NewDataObject("Auc-Util-SearchUI", {
|
|
type = "launcher",
|
|
icon = sideIcon,
|
|
OnClick = function(self, button) lib.Toggle(self, button) end,
|
|
})
|
|
|
|
function private.LDBButton:OnTooltipShow()
|
|
self:AddLine("Auction SearchUI", 1,1,0.5, 1)
|
|
self:AddLine("Allows you to perform searches on the Auctioneer auction cache snapshot, even when away from the Auction House", 1,1,0.5, 1)
|
|
self:AddLine("|cff1fb3ff".."Click|r to open the Search UI.", 1,1,0.5, 1)
|
|
end
|
|
|
|
function private.LDBButton:OnEnter()
|
|
GameTooltip:SetOwner(self, "ANCHOR_NONE")
|
|
GameTooltip:SetPoint("TOPLEFT", self, "BOTTOMLEFT")
|
|
GameTooltip:ClearLines()
|
|
private.LDBButton.OnTooltipShow(GameTooltip)
|
|
GameTooltip:Show()
|
|
end
|
|
|
|
function private.LDBButton:OnLeave()
|
|
GameTooltip:Hide()
|
|
end
|
|
end
|
|
end
|
|
|
|
function private.FindSearcher(item)
|
|
if not gui.config.selectedTab then
|
|
return
|
|
end
|
|
for name, searcher in pairs(lib.Searchers) do
|
|
if searcher and searcher.tabname and searcher.tabname == gui.config.selectedTab and searcher.Search then
|
|
return searcher, name
|
|
end
|
|
end
|
|
end
|
|
|
|
function private.cancelSearch()
|
|
private.SearchCancel = true
|
|
end
|
|
|
|
--lib.SearchItem(searcherName, item, nodupes)
|
|
--purpose: handles sending the item to the specified searcher, and if necessary, adds it to the SearchUI results
|
|
--nodupes is boolean flag. If true, no duplicate checking is done. This flag is true for searching from the cache, but false for realtime.
|
|
--skipresults is boolean flag, If true, nothing gets added to the results list
|
|
--returns true, value, profit when successful
|
|
--returns false, reason when not
|
|
function lib.SearchItem(searcherName, item, nodupes, skipresults)
|
|
if not searcherName or not item or #item == 0 then
|
|
return
|
|
end
|
|
if item[Const.SELLER] == UnitName("player") then
|
|
return false, "Blocked: Can't buy own auction"
|
|
end
|
|
local searcher = lib.Searchers[searcherName]
|
|
if not searcher then
|
|
return
|
|
end
|
|
local debugstring
|
|
|
|
--next, pass the item through the filters
|
|
local isfiltered = false
|
|
for filtername, filter in pairs(lib.Filters) do
|
|
if filter.Filter then
|
|
local dofilter, filterreturn = filter.Filter(item, searcherName)
|
|
if dofilter then
|
|
return false, "Filter:"..filtername..": "..tostring(filterreturn)
|
|
end
|
|
end
|
|
end
|
|
|
|
--buyorbid must be either "bid", "buy", true, false, or nil
|
|
--if string is returned for buyorbid, value must be number or nil (in which case value will be Marketprice)
|
|
local buyorbid, value, pct, reason
|
|
buyorbid, value, pct, reason = searcher.Search(item)
|
|
if buyorbid then
|
|
--give the filters a second chance to filter out, based on bid/buy differences
|
|
for filtername, filter in pairs(lib.Filters) do
|
|
if filter.PostFilter then
|
|
local dofilter, filterreturn = filter.PostFilter(item, searcherName, buyorbid)
|
|
if dofilter then
|
|
return false, "Filtered by "..filtername..": "..filterreturn
|
|
end
|
|
end
|
|
end
|
|
|
|
local cost
|
|
if type(buyorbid) == "string" then
|
|
item["reason"] = searcher.tabname..":"..buyorbid
|
|
if reason then
|
|
item["reason"] = item["reason"]..":"..reason
|
|
end
|
|
if buyorbid == "bid" then
|
|
--don't show result if we're already the highest bidder
|
|
if item[Const.AMHIGH] then
|
|
return false, "Bid blocked: Already high bidder"
|
|
end
|
|
cost = item[Const.PRICE]
|
|
else
|
|
cost = item[Const.BUYOUT]
|
|
end
|
|
else --the searcher only returned that it matches the criteria, so assume buyout if possible.
|
|
item["reason"] = searcher.tabname
|
|
if item[Const.BUYOUT] and item[Const.BUYOUT] > 0 then
|
|
cost = item[Const.BUYOUT]
|
|
elseif item[Const.PRICE] and item[Const.PRICE] > 0 then
|
|
cost = item[Const.PRICE]
|
|
if item[Const.AMHIGH] then
|
|
return false, "Bid blocked: Already high bidder"
|
|
end
|
|
end
|
|
end
|
|
if not value then
|
|
local market = AucAdvanced.API.GetMarketValue(item[Const.LINK])
|
|
if market then -- needs a nil check
|
|
value = item[Const.COUNT]*market
|
|
end
|
|
end
|
|
if not value then
|
|
value = 0
|
|
end
|
|
if not cost then
|
|
return false, "Bid blocked: No valid price possible"
|
|
end
|
|
item["profit"] = value - cost
|
|
local enablemax = lib.GetSetting("maxprice.enable")
|
|
local maxprice = lib.GetSetting("maxprice") or 10000000
|
|
local enableres = lib.GetSetting("reserve.enable")
|
|
local reserve = lib.GetSetting("reserve") or 1
|
|
local bidqueue = gui.frame.cancel.value or 0
|
|
|
|
local balance = GetMoney()
|
|
balance = balance - bidqueue --account for money we've already "spent"
|
|
|
|
if (cost <= maxprice or not enablemax) and ((balance-cost) > reserve or not enableres) then
|
|
--Check to see whether the item already exists in the results table
|
|
local isdupe = false
|
|
if not nodupes then
|
|
|
|
if not private.sheetData then
|
|
private.sheetData = {}
|
|
private.sheetStyle = {}
|
|
end
|
|
for j,k in pairs(private.sheetData) do
|
|
if (k[1] == item[Const.LINK]) and (k[7] == item["reason"]) then
|
|
isdupe = true
|
|
end
|
|
end
|
|
|
|
end
|
|
if nodupes or (not isdupe) then
|
|
local level, _, r, g, b
|
|
pct = tonumber(pct) --make sure its not a string
|
|
if not pct and AucAdvanced.Modules.Util.PriceLevel then
|
|
local valueper
|
|
if value and value > 0 then
|
|
valueper = value/item[Const.COUNT]
|
|
end
|
|
if buyorbid == "bid" then
|
|
level, _, r, g, b = AucAdvanced.Modules.Util.PriceLevel.CalcLevel(item[Const.LINK], item[Const.COUNT], item[Const.PRICE], item[Const.PRICE], valueper)
|
|
else
|
|
level, _, r, g, b = AucAdvanced.Modules.Util.PriceLevel.CalcLevel(item[Const.LINK], item[Const.COUNT], item[Const.PRICE], item[Const.BUYOUT], valueper)
|
|
end
|
|
if not r or not b or not g then
|
|
--print("price level failure in searchUI")
|
|
--print(r,g,b, item[Const.LINK], item[Const.COUNT], item[Const.PRICE], item[Const.BUYOUT], valueper)
|
|
r,g,b = 1,1,1
|
|
end
|
|
local total = #private.sheetData+1
|
|
private.sheetStyle[total] = {}
|
|
private.sheetStyle[total][2] = {["textColor"] = {r, g, b}}
|
|
private.sheetStyle[total][1] = {["rowColor"] = {r, g, b, 0, 0.2, "Horizontal"}} --allow row coloring, needs config options
|
|
level = level or 0
|
|
pct = floor(level)
|
|
end
|
|
item["pct"] = pct
|
|
item["cost"] = cost
|
|
local count = item[Const.COUNT] or 1
|
|
local min = item[Const.MINBID] or 0
|
|
local cur = item[Const.CURBID] or 0
|
|
local buy = item[Const.BUYOUT] or 0
|
|
local price = item[Const.PRICE] or 0
|
|
if not skipresults then
|
|
tinsert(private.sheetData, {
|
|
item[Const.LINK],
|
|
item["pct"],
|
|
item["profit"],
|
|
count,
|
|
buy,
|
|
price,
|
|
item["reason"],
|
|
item[Const.SELLER],
|
|
private.tleft[item[Const.TLEFT]],
|
|
buy/count,
|
|
price/count,
|
|
min,
|
|
cur,
|
|
min/count,
|
|
cur/count
|
|
})
|
|
end
|
|
return true, item["profit"], value
|
|
end
|
|
elseif cost > maxprice and enablemax then
|
|
return false, "Price higher than maxprice"
|
|
else
|
|
return false, "Balance lower than reserve"
|
|
end
|
|
end
|
|
return false, value
|
|
end
|
|
|
|
local PerformSearch = function()
|
|
if gui.tabs.active then
|
|
gui:ContractFrame(gui.tabs.active)
|
|
end
|
|
gui:ClearFocus()
|
|
--Perform the search. We're not using API.QueryImage() because we need it to be a coroutine
|
|
local image = AucAdvanced.Scan.GetImageCopy()
|
|
local imagesize = #image
|
|
local speed = lib.GetSetting("processpriority") or 50
|
|
speed = (speed / 100)^2.5
|
|
local processingTime = speed * 0.1 + 0.02
|
|
local GetTime = GetTime
|
|
local nextPause = GetTime() + processingTime
|
|
|
|
local searcher, searcherName = private.FindSearcher()
|
|
if not searcher then
|
|
print("No valid Searches selected")
|
|
return
|
|
end
|
|
gui.frame.progressbar.text:SetText("AucAdv SearchUI: Searching |cffffcc19"..gui.config.selectedTab)
|
|
gui.frame.progressbar:Show()
|
|
|
|
--clear the results table
|
|
private.removeall()
|
|
local repaintSheet = false
|
|
local nextRepaint = 0 -- can do it immediately
|
|
|
|
private.isSearching = true
|
|
AucAdvanced.SendProcessorMessage("searchbegin", searcherName)
|
|
lib.NotifyCallbacks("search", "begin", searcherName)
|
|
for i, data in ipairs(image) do
|
|
if GetTime() > nextPause then
|
|
gui.frame.progressbar:SetValue((i/imagesize)*1000)
|
|
|
|
coroutine.yield()
|
|
|
|
nextPause = GetTime() + processingTime
|
|
if private.SearchCancel then
|
|
private.SearchCancel = nil
|
|
break
|
|
end
|
|
if repaintSheet and GetTime()>=nextRepaint then
|
|
local b=GetTime()
|
|
private.repaintSheet()
|
|
repaintSheet = false
|
|
local e=GetTime()
|
|
nextRepaint = e + ((e-b)*10) -- only let repainting consume 10% of our total CPU
|
|
end
|
|
end
|
|
if lib.SearchItem(searcher.name, data, true) then
|
|
repaintSheet = true
|
|
end
|
|
end
|
|
|
|
private.repaintSheet()
|
|
|
|
private.isSearching = false
|
|
empty(SettingCache)
|
|
gui.frame.progressbar:Hide()
|
|
AucAdvanced.SendProcessorMessage("searchcomplete", searcherName)
|
|
lib.NotifyCallbacks("search", "complete", searcherName)
|
|
end
|
|
|
|
function lib.IsSearching()
|
|
return private.isSearching
|
|
end
|
|
|
|
function lib.PerformSearch(searcher)
|
|
if (not coSearch) or (coroutine.status(coSearch) == "dead") then
|
|
coSearch = coroutine.create(PerformSearch)
|
|
local status, result = coroutine.resume(coSearch, searcher)
|
|
if not status and result then
|
|
error("Error in search coroutine: "..result.."\n\n{{{Coroutine Stack:}}}\n"..debugstack(coSearch));
|
|
end
|
|
else
|
|
print("coroutine already running: "..coroutine.status(coSearch))
|
|
end
|
|
end
|
|
|
|
function private.OnUpdate(self, elapsed)
|
|
if coSearch then
|
|
if coroutine.status(coSearch) == "suspended" then
|
|
local status, result = coroutine.resume(coSearch)
|
|
if not status and result then
|
|
error("Error in search coroutine: "..result.."\n\n{{{Coroutine Stack:}}}\n"..debugstack(coSearch));
|
|
end
|
|
elseif coroutine.status(coSearch) == "dead" then
|
|
coSearch = nil
|
|
end
|
|
end
|
|
if flagResourcesUpdateRequired then
|
|
-- Update Faction resources following Auctionhouse open or close (to handle Neutral AH)
|
|
-- Delayed until OnUpdate handler to give GetFaction time to update its own internal settings
|
|
flagResourcesUpdateRequired = false
|
|
private.UpdateFactionResources()
|
|
end
|
|
if flagScanStats then
|
|
flagScanStats = false
|
|
lib.NotifyCallbacks("postscanupdate")
|
|
end
|
|
end
|
|
|
|
private.updater = CreateFrame("Frame", nil, UIParent)
|
|
private.updater:SetScript("OnUpdate", private.OnUpdate)
|
|
|
|
AucAdvanced.RegisterRevision("$URL: http://svn.norganna.org/auctioneer/branches/5.9/Auc-Util-SearchUI/SearchMain.lua $", "$Rev: 4933 $")
|