TradeSkillMaster/Core/UI/AuctionUI/BuyUtil.lua

442 lines
15 KiB
Lua

-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local BuyUtil = TSM.UI.AuctionUI:NewPackage("BuyUtil")
local L = TSM.Include("Locale").GetTable()
local Money = TSM.Include("Util.Money")
local Log = TSM.Include("Util.Log")
local Math = TSM.Include("Util.Math")
local Theme = TSM.Include("Util.Theme")
local ItemInfo = TSM.Include("Service.ItemInfo")
local CustomPrice = TSM.Include("Service.CustomPrice")
local UIElements = TSM.Include("UI.UIElements")
local private = {
totalBuyout = nil,
isBuy = nil,
auctionScan = nil,
subRow = nil,
index = nil,
noSeller = nil,
baseFrame = nil,
dialogFrame = nil,
future = nil,
prepareQuantity = nil,
prepareSuccess = false,
marketValueFunc = nil,
}
-- ============================================================================
-- Module Functions
-- ============================================================================
function BuyUtil.ShowConfirmation(baseFrame, subRow, isBuy, auctionNum, numFound, maxQuantity, callback, auctionScan, index, noSeller, marketValueFunc)
auctionNum = min(auctionNum, numFound)
local buyout = subRow:GetBuyouts()
if not isBuy then
buyout = subRow:GetRequiredBid(subRow)
end
local quantity = subRow:GetQuantities()
local itemString = subRow:GetItemString()
local _, _, _, isHighBidder = subRow:GetBidInfo()
local isCommodity = not TSM.IsWowClassic() and subRow:IsCommodity()
local shouldConfirm = false
if isCommodity then
shouldConfirm = true
elseif isBuy and isHighBidder then
shouldConfirm = true
elseif TSM.db.global.shoppingOptions.buyoutConfirm then
shouldConfirm = ceil(buyout / quantity) >= (CustomPrice.GetValue(TSM.db.global.shoppingOptions.buyoutAlertSource, itemString) or 0)
end
if not shouldConfirm then
return false
end
baseFrame = baseFrame:GetBaseElement()
private.isBuy = isBuy
private.auctionScan = auctionScan
private.subRow = subRow
private.index = index
private.noSeller = noSeller
private.baseFrame = baseFrame
private.marketValueFunc = marketValueFunc
if private.dialogFrame then
return true
end
local defaultQuantity = isCommodity and numFound or 1
assert(not isCommodity or isBuy)
local displayItemBuyout, displayTotalBuyout = nil, nil
if isCommodity then
displayTotalBuyout = private.CommodityResultsByQuantity(itemString, defaultQuantity)
displayItemBuyout = Math.Ceil(displayTotalBuyout / defaultQuantity, COPPER_PER_SILVER)
else
displayItemBuyout = ceil(buyout / quantity)
displayTotalBuyout = TSM.IsWowClassic() and buyout or ceil(buyout / quantity)
end
private.dialogFrame = UIElements.New("Frame", "frame")
:SetLayout("VERTICAL")
:SetSize(isCommodity and 600 or 326, isCommodity and 272 or 262)
:SetPadding(12)
:AddAnchor("CENTER")
:SetContext(callback)
:SetMouseEnabled(true)
:SetBackgroundColor("FRAME_BG", true)
:AddChild(UIElements.New("Frame", "header")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, -4, 10)
:AddChild(UIElements.New("Spacer", "spacer")
:SetWidth(20)
)
:AddChild(UIElements.New("Text", "title")
:SetJustifyH("CENTER")
:SetFont("BODY_BODY1_BOLD")
:SetText(isCommodity and L["Order Confirmation"] or L["Buyout"])
)
:AddChild(UIElements.New("Button", "closeBtn")
:SetMargin(0, -4, 0, 0)
:SetBackgroundAndSize("iconPack.24x24/Close/Default")
:SetScript("OnClick", private.BuyoutConfirmCloseBtnOnClick)
)
)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:AddChild(UIElements.New("Frame", "left")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Frame", "item")
:SetLayout("HORIZONTAL")
:SetPadding(6)
:SetMargin(0, 0, 0, 16)
:SetBackgroundColor("PRIMARY_BG_ALT", true)
:AddChild(UIElements.New("Button", "icon")
:SetSize(36, 36)
:SetMargin(0, 8, 0, 0)
:SetBackground(ItemInfo.GetTexture(itemString))
:SetTooltip(itemString)
)
:AddChild(UIElements.New("Text", "name")
:SetHeight(36)
:SetFont("ITEM_BODY1")
:SetText(TSM.UI.GetColoredItemName(itemString))
)
)
:AddChildIf(isCommodity, UIElements.New("Frame", "quantity")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("Text", "desc")
:SetFont("BODY_BODY2")
:SetText(L["Quantity"]..":")
)
:AddChild(UIElements.New("Input", "input")
:SetWidth(140)
:SetJustifyH("RIGHT")
:SetBackgroundColor("PRIMARY_BG_ALT")
:SetValidateFunc("NUMBER", "1:"..maxQuantity)
:SetValue(tostring(defaultQuantity))
:SetContext(maxQuantity)
:SetScript("OnValueChanged", private.InputQtyOnValueChanged)
)
)
:AddChildIf(not isCommodity, UIElements.New("Frame", "stacks")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 10)
:AddChild(UIElements.New("Text", "desc")
:SetWidth("AUTO")
:SetFont("BODY_BODY2")
:SetText(isBuy and L["Purchasing Auction"]..":" or L["Bidding Auction"]..":")
)
:AddChild(UIElements.New("Text", "number")
:SetJustifyH("RIGHT")
:SetFont("TABLE_TABLE1")
:SetText(auctionNum.."/"..numFound)
)
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Frame", "price")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 10)
:AddChild(UIElements.New("Text", "desc")
:SetWidth("AUTO")
:SetFont("BODY_BODY2")
:SetText(L["Unit Price"]..":")
)
:AddChild(UIElements.New("Text", "money")
:SetJustifyH("RIGHT")
:SetFont("TABLE_TABLE1")
:SetContext(displayItemBuyout)
:SetText(private.GetUnitPriceMoneyStr(displayItemBuyout))
)
)
:AddChild(UIElements.New("Frame", "total")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 10)
:AddChild(UIElements.New("Text", "desc")
:SetWidth("AUTO")
:SetFont("BODY_BODY2")
:SetText(L["Total Price"]..":")
)
:AddChild(UIElements.New("Text", "money")
:SetJustifyH("RIGHT")
:SetFont("TABLE_TABLE1")
:SetText(Money.ToString(displayTotalBuyout, nil, "OPT_83_NO_COPPER"))
)
)
:AddChild(UIElements.New("Text", "warning")
:SetHeight(20)
:SetMargin(0, 0, 0, 10)
:SetFont("BODY_BODY3")
:SetJustifyH("CENTER")
:SetTextColor(Theme.GetFeedbackColor("YELLOW"))
:SetText("")
)
:AddChild(UIElements.NewNamed("ActionButton", "confirmBtn", "TSMBidBuyConfirmBtn")
:SetHeight(24)
:SetText(isCommodity and L["Buy Commodity"] or (isBuy and L["Buy Auction"] or L["Bid Auction"]))
:SetContext(not isCommodity and quantity or nil)
:SetDisabled(private.future and true or false)
:SetScript("OnClick", private.ConfirmBtnOnClick)
)
)
:AddChildIf(isCommodity, UIElements.New("Frame", "item")
:SetLayout("HORIZONTAL")
:SetWidth(266)
:SetMargin(12, 0, 0, 0)
:SetPadding(4, 4, 8, 8)
:SetBackgroundColor("PRIMARY_BG_ALT", true)
:AddChild(UIElements.New("CommodityList", "items")
:SetBackgroundColor("PRIMARY_BG_ALT")
:SetData(subRow:GetResultRow())
:SetMarketValueFunction(marketValueFunc)
:SetAlertThreshold(TSM.db.global.shoppingOptions.buyoutConfirm and (CustomPrice.GetValue(TSM.db.global.shoppingOptions.buyoutAlertSource, itemString) or 0) or nil)
:SelectQuantity(defaultQuantity)
:SetScript("OnRowClick", private.CommodityOnRowClick)
)
)
)
:SetScript("OnHide", private.DialogOnHide)
baseFrame:ShowDialogFrame(private.dialogFrame)
private.prepareQuantity = nil
private.Prepare(defaultQuantity)
return true
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.DialogOnHide()
if private.future then
private.future:Cancel()
private.future = nil
end
private.baseFrame = nil
private.dialogFrame = nil
private.isBuy = nil
private.auctionScan = nil
private.subRow = nil
private.index = nil
private.noSeller = nil
end
function private.BuyoutConfirmCloseBtnOnClick(button)
button:GetBaseElement():HideDialog()
end
function private.EnableFutureOnDone()
local result = private.future:GetValue()
private.future = nil
if not result or result ~= (private.subRow:IsCommodity() and private.totalBuyout or select(2, private.subRow:GetBuyouts())) then
-- the unit price changed
Log.PrintUser(L["Failed to buy auction."])
private.baseFrame:HideDialog()
return
end
local input = private.dialogFrame:GetElement("content.left.quantity.input")
private.prepareSuccess = tonumber(input:GetValue()) == private.prepareQuantity
private.UpdateConfirmButton()
end
function private.GetUnitPriceMoneyStr(itemBuyout)
local priceStr = Money.ToString(itemBuyout, nil, "OPT_83_NO_COPPER")
local marketValueStr = nil
local marketValue = private.marketValueFunc(private.subRow)
local pct = marketValue and marketValue > 0 and itemBuyout > 0 and Math.Round(100 * itemBuyout / marketValue) or nil
if pct then
local pctColor = Theme.GetAuctionPercentColor(pct)
if pct > 999 then
marketValueStr = pctColor:ColorText(">999%")
else
marketValueStr = pctColor:ColorText(pct.."%")
end
else
marketValueStr = "---"
end
return format("%s (%s)", priceStr, marketValueStr)
end
function private.CommodityResultsByQuantity(itemString, quantity)
local remainingQuantity = quantity
local totalPrice, maxPrice = 0, 0
for _, query in private.auctionScan:QueryIterator() do
for _, subRow in query:ItemSubRowIterator(itemString) do
if remainingQuantity > 0 then
local _, itemBuyout = subRow:GetBuyouts()
local _, numOwnerItems = subRow:GetOwnerInfo()
local quantityAvailable = subRow:GetQuantities() - numOwnerItems
local quantityToBuy = min(quantityAvailable, remainingQuantity)
totalPrice = totalPrice + (itemBuyout * quantityToBuy)
remainingQuantity = remainingQuantity - quantityToBuy
maxPrice = max(maxPrice, itemBuyout)
end
end
end
return totalPrice, maxPrice
end
function private.InputQtyOnValueChanged(input, noListUpdate)
local quantity = tonumber(input:GetValue())
input:SetValue(quantity)
local totalBuyout = private.subRow:IsCommodity() and private.CommodityResultsByQuantity(private.subRow:GetItemString(), quantity) or input:GetElement("__parent.__parent.price.money"):GetContext() * quantity
local totalQuantity = quantity
local itemBuyout = totalQuantity > 0 and Math.Ceil(totalBuyout / totalQuantity, COPPER_PER_SILVER) or 0
input:GetElement("__parent.__parent.price.money")
:SetContext(itemBuyout)
:SetText(private.GetUnitPriceMoneyStr(itemBuyout))
:Draw()
input:GetElement("__parent.__parent.total.money")
:SetText(Money.ToString(totalBuyout, nil, "OPT_83_NO_COPPER"))
:Draw()
if not noListUpdate then
input:GetElement("__parent.__parent.__parent.item.items")
:SelectQuantity(quantity)
end
if quantity ~= private.prepareQuantity then
private.prepareSuccess = false
private.prepareQuantity = nil
end
private.UpdateConfirmButton()
end
function private.CommodityOnRowClick(list, index)
local input = list:GetElement("__parent.__parent.left.quantity.input")
input:SetValue(list:GetTotalQuantity(index))
:Draw()
private.Prepare(tonumber(input:GetValue()))
private.InputQtyOnValueChanged(input, true)
end
function private.ConfirmBtnOnClick(button)
local inputQuantity = nil
if not TSM.IsWowClassic() and private.subRow:IsCommodity() then
local input = private.dialogFrame:GetElement("content.left.quantity.input")
inputQuantity = tonumber(input:GetValue())
if not private.prepareSuccess and not TSM.IsWowClassic() then
-- this is a prepare click
private.Prepare(inputQuantity)
return
end
assert(private.prepareQuantity == inputQuantity)
end
local isBuy = private.isBuy
local callbackQuantity = button:GetContext()
if callbackQuantity == nil then
assert(inputQuantity)
callbackQuantity = inputQuantity
end
local callback = button:GetElement("__parent.__parent.__parent"):GetContext()
button:GetBaseElement():HideDialog()
callback(isBuy, callbackQuantity)
end
function private.UpdateConfirmButton()
local confirmBtn = private.dialogFrame:GetElement("content.left.confirmBtn")
local text, disabled, requireManualClick = nil, false, false
if not TSM.IsWowClassic() and private.subRow:IsCommodity() then
local input = confirmBtn:GetElement("__parent.quantity.input")
local inputQuantity = tonumber(input:GetValue())
local minQuantity = 1
local maxQuantity = confirmBtn:GetElement("__parent.quantity.input"):GetContext()
local itemString = private.subRow:GetItemString()
local totalCost, maxCost = private.CommodityResultsByQuantity(itemString, inputQuantity)
local alertThreshold = TSM.db.global.shoppingOptions.buyoutConfirm and (CustomPrice.GetValue(TSM.db.global.shoppingOptions.buyoutAlertSource, itemString) or 0) or math.huge
if maxCost >= alertThreshold then
requireManualClick = true
confirmBtn:GetElement("__parent.warning")
:SetText(L["Contains auctions above your alert threshold!"])
:Draw()
else
confirmBtn:GetElement("__parent.warning")
:SetText("")
:Draw()
end
if GetMoney() < totalCost then
text = L["Not Enough Money"]
disabled = true
elseif totalCost <= 0 or inputQuantity < minQuantity or inputQuantity > maxQuantity then
text = L["Invalid Quantity"]
disabled = true
elseif private.prepareSuccess or TSM.IsWowClassic() then
text = L["Buy Commodity"]
disabled = false
elseif private.prepareQuantity then
text = L["Preparing..."]
disabled = true
else
text = private.isBuy and L["Prepare Buy"] or L["Prepare Bid"]
disabled = false
end
else
if GetMoney() < confirmBtn:GetElement("__parent.price.money"):GetContext() then
text = L["Not Enough Money"]
disabled = true
else
text = private.isBuy and L["Buy Auction"] or L["Bid Auction"]
disabled = false
end
end
confirmBtn:SetText(text)
:SetDisabled(disabled)
:SetRequireManualClick(requireManualClick)
:Draw()
end
function private.Prepare(quantity)
if quantity == private.prepareQuantity then
return
end
if private.future then
private.future:Cancel()
private.future = nil
end
private.prepareQuantity = quantity
private.prepareSuccess = false
local totalBuyout = not TSM.IsWowClassic() and private.subRow:IsCommodity() and private.CommodityResultsByQuantity(private.subRow:GetItemString(), quantity) or (select(2, private.subRow:GetBuyouts()))
local totalQuantity = quantity
private.totalBuyout = totalBuyout
local itemBuyout = totalQuantity > 0 and Math.Ceil(totalBuyout / totalQuantity, COPPER_PER_SILVER)
local result, future = private.auctionScan:PrepareForBidOrBuyout(private.index, private.subRow, private.noSeller, quantity, itemBuyout)
if not result then
private.prepareQuantity = nil
return
elseif future then
private.future = future
future:SetScript("OnDone", private.EnableFutureOnDone)
end
private.UpdateConfirmButton()
end