TradeSkillMaster/Core/UI/VendoringUI/Buy.lua

527 lines
17 KiB
Lua
Raw Normal View History

2020-11-13 14:13:12 -05:00
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Buy = TSM.UI.VendoringUI:NewPackage("Buy")
local L = TSM.Include("Locale").GetTable()
local Money = TSM.Include("Util.Money")
local String = TSM.Include("Util.String")
local Log = TSM.Include("Util.Log")
local TempTable = TSM.Include("Util.TempTable")
local Theme = TSM.Include("Util.Theme")
local ItemString = TSM.Include("Util.ItemString")
local ItemInfo = TSM.Include("Service.ItemInfo")
local Settings = TSM.Include("Service.Settings")
local UIElements = TSM.Include("UI.UIElements")
local private = {
settings = nil,
query = nil,
filterText = "",
}
-- ============================================================================
-- Module Functions
-- ============================================================================
function Buy.OnInitialize()
private.settings = Settings.NewView()
:AddKey("global", "vendoringUIContext", "buyScrollingTable")
TSM.UI.VendoringUI.RegisterTopLevelPage(L["Buy"], private.GetFrame)
end
function Buy.UpdateCurrency(frame)
if not GetMerchantCurrencies() or frame:GetSelectedNavButton() ~= L["Buy"] then
return
end
frame:GetElement("content.buy.footer.altCost")
:SetText(private.GetCurrencyText())
frame:GetElement("content.buy.footer")
:Draw()
end
-- ============================================================================
-- Buy UI
-- ============================================================================
function private.GetFrame()
TSM.UI.AnalyticsRecordPathChange("vendoring", "buy")
private.filterText = ""
if not private.query then
private.query = TSM.Vendoring.Buy.CreateMerchantQuery()
:InnerJoin(ItemInfo.GetDBForJoin(), "itemString")
end
private.query:ResetFilters()
private.query:NotEqual("numAvailable", 0)
private.query:ResetOrderBy()
private.query:OrderBy("name", true)
local altCost = not TSM.IsWowClassic() and GetMerchantCurrencies()
local frame = UIElements.New("Frame", "buy")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Frame", "filters")
:SetLayout("HORIZONTAL")
:SetHeight(40)
:SetPadding(8)
:SetBackgroundColor("PRIMARY_BG_ALT")
:AddChild(UIElements.New("Input", "searchInput")
:SetMargin(0, 8, 0, 0)
:SetIconTexture("iconPack.18x18/Search")
:SetClearButtonEnabled(true)
:AllowItemInsert()
:SetHintText(L["Search Vendor"])
:SetScript("OnValueChanged", private.InputOnValueChanged)
)
:AddChild(UIElements.New("Button", "filterBtn")
:SetWidth("AUTO")
:SetMargin(0, 4, 0, 0)
:SetFont("BODY_BODY3_MEDIUM")
:SetText(FILTERS)
-- TODO
-- :SetScript("OnClick", private.FilterButtonOnClick)
)
:AddChild(UIElements.New("Button", "filterBtnIcon")
:SetBackgroundAndSize("iconPack.14x14/Filter")
-- TODO
-- :SetScript("OnClick", private.FilterButtonOnClick)
)
)
:AddChild(UIElements.New("QueryScrollingTable", "items")
:SetSettingsContext(private.settings, "buyScrollingTable")
:GetScrollingTableInfo()
:NewColumn("qty")
:SetTitle(L["Qty"])
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetTextInfo("stackSize")
:SetSortInfo("stackSize")
:Commit()
:NewColumn("item")
:SetTitle(L["Item"])
:SetIconSize(12)
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo(nil, private.GetItemText)
:SetIconInfo("itemString", ItemInfo.GetTexture)
:SetTooltipInfo("itemString")
:SetSortInfo("name")
:SetTooltipLinkingDisabled(true)
:DisableHiding()
:Commit()
:NewColumn("ilvl")
:SetTitle(L["ilvl"])
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetTextInfo("itemString", ItemInfo.GetItemLevel)
:Commit()
:NewColumn("cost")
:SetTitle(L["Cost"])
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetTextInfo(nil, private.GetCostText)
:SetTooltipInfo("firstCostItemString", private.GetCostTooltip)
:SetSortInfo("price")
:SetTooltipLinkingDisabled(true)
:Commit()
:SetCursor("BUY_CURSOR")
:Commit()
:SetQuery(private.query)
:SetScript("OnRowClick", private.RowOnClick)
)
:AddChild(UIElements.New("Texture", "line")
:SetHeight(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Frame", "footer")
:SetLayout("HORIZONTAL")
:SetHeight(40)
:SetPadding(8)
:SetBackgroundColor("PRIMARY_BG_ALT")
:AddChild(UIElements.New("Frame", "gold")
:SetLayout("HORIZONTAL")
:SetWidth(166)
:SetMargin(0, 8, 0, 0)
:SetPadding(4)
:AddChild(UIElements.New("PlayerGoldText", "text"))
)
:AddChild(UIElements.New("Texture", "line")
:SetSize(2, 22)
:SetMargin(0, 8, 0, 0)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Button", "altCost")
:SetWidth("AUTO")
:SetMargin(0, 16, 0, 0)
:SetFont("TABLE_TABLE1")
:SetText(private.GetCurrencyText())
:SetTooltip(altCost and "currency:"..altCost or nil)
)
:AddChild(UIElements.New("ActionButton", "repairBtn")
:SetDisabled(not TSM.Vendoring.Buy.NeedsRepair())
:SetText(L["Repair"])
:SetModifierText(L["Repair from Guild Bank"], "ALT")
:SetTooltip(private.GetRepairTooltip)
:SetScript("OnClick", private.RepairOnClick)
)
)
if not altCost then
frame:GetElement("footer.line")
:Hide()
frame:GetElement("footer.altCost")
:Hide()
end
return frame
end
function private.GetItemText(row)
local itemString, numAvailable = row:GetFields("itemString", "numAvailable")
local itemName = TSM.UI.GetColoredItemName(itemString) or "?"
if numAvailable == -1 then
return itemName
elseif numAvailable > 0 then
return itemName..Theme.GetFeedbackColor("RED"):ColorText(" ("..numAvailable..")")
else
error("Invalid numAvailable: "..numAvailable)
end
end
function private.GetCostText(row)
local index, costItemsText, price, stackSize = row:GetFields("index", "costItemsText", "price", "stackSize")
local color = TSM.Vendoring.Buy.GetMaxCanAfford(index) < stackSize and Theme.GetFeedbackColor("RED"):GetTextColorPrefix()
if costItemsText == "" then
-- just a price
return Money.ToString(price, color)
elseif price == 0 then
-- just an extended cost string
return costItemsText
else
-- both
return Money.ToString(price, color).." "..costItemsText
end
end
function private.GetCostTooltip(itemString)
return itemString ~= "" and itemString or nil
end
function private.GetRepairTooltip()
local tooltipLines = TempTable.Acquire()
local repairAllCost, canRepair = GetRepairAllCost()
if canRepair and repairAllCost > 0 then
tinsert(tooltipLines, REPAIR_ALL_ITEMS)
if IsAltKeyDown() then
local amount = GetGuildBankWithdrawMoney()
local guildBankMoney = GetGuildBankMoney()
if amount == -1 then
amount = guildBankMoney
else
amount = min(amount, guildBankMoney)
end
tinsert(tooltipLines, GUILDBANK_REPAIR)
tinsert(tooltipLines, Money.ToString(amount))
if repairAllCost > amount then
local personalAmount = repairAllCost - amount
local personalMoney = GetMoney()
if personalMoney >= personalAmount then
tinsert(tooltipLines, GUILDBANK_REPAIR_PERSONAL)
tinsert(tooltipLines, Money.ToString(personalAmount))
else
tinsert(tooltipLines, Theme.GetFeedbackColor("RED"):ColorText(GUILDBANK_REPAIR_INSUFFICIENT_FUNDS))
end
end
else
tinsert(tooltipLines, Money.ToString(repairAllCost))
local personalMoney = GetMoney()
if repairAllCost > personalMoney then
tinsert(tooltipLines, Theme.GetFeedbackColor("RED"):ColorText(GUILDBANK_REPAIR_INSUFFICIENT_FUNDS))
end
tinsert(tooltipLines, L["Hold ALT to repair from the guild bank."])
end
end
return strjoin("\n", TempTable.UnpackAndRelease(tooltipLines))
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.InputOnValueChanged(input)
local text = input:GetValue()
if text == private.filterText then
return
end
private.filterText = text
private.query:ResetFilters()
private.query:NotEqual("numAvailable", 0)
if text ~= "" then
private.query:Matches("name", String.Escape(text))
end
input:GetElement("__parent.__parent.items"):UpdateData(true)
end
function private.RowOnClick(scrollingTable, row, mouseButton)
if IsShiftKeyDown() then
local itemString = row:GetField("itemString")
local dialogFrame = UIElements.New("Frame", "frame")
:SetLayout("VERTICAL")
:SetSize(328, 214)
:SetPadding(12)
:AddAnchor("CENTER")
:SetContext(row)
: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(L["Purchase Item"])
)
:AddChild(UIElements.New("Button", "closeBtn")
:SetMargin(0, -4, 0, 0)
:SetBackgroundAndSize("iconPack.24x24/Close/Default")
:SetScript("OnClick", private.PurchaseCloseBtnOnClick)
)
)
: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))
)
)
:AddChild(UIElements.New("Frame", "qty")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, 0, 16)
:AddChild(UIElements.New("Text", "text")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Quantity"]..":")
)
:AddChild(UIElements.New("Input", "input")
:SetWidth(156)
:SetMargin(12, 8, 0, 0)
:SetBackgroundColor("PRIMARY_BG_ALT")
:SetJustifyH("CENTER")
:SetSubAddEnabled(true)
:SetValidateFunc("NUMBER", "1:99999")
:SetValue(1)
:SetScript("OnValidationChanged", private.InputQtyOnValidationChanged)
:SetScript("OnValueChanged", private.InputQtyOnValueChanged)
:SetScript("OnEnterPressed", private.InputQtyOnEnterPressed)
)
:AddChild(UIElements.New("ActionButton", "max")
:SetText(L["Max"])
:SetScript("OnClick", private.MaxBtnOnClick)
)
)
:AddChild(UIElements.New("Frame", "cost")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 16)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetMargin(0, 8, 0, 0)
:SetJustifyH("RIGHT")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Current Price"]..":")
)
:AddChild(UIElements.New("Button", "text")
:SetWidth("AUTO")
:SetJustifyH("RIGHT")
:SetFont("TABLE_TABLE1")
:SetText(private.GetAltCostText(row, 1))
:SetTooltip(private.GetAltCostTooltip(row))
)
)
:AddChild(UIElements.New("ActionButton", "purchaseBtn")
:SetHeight(24)
:SetText(L["Purchase"])
:SetDisabled(TSM.Vendoring.Buy.GetMaxCanAfford(row:GetField("index")) < 1)
:SetScript("OnClick", private.PurchaseBtnOnClick)
)
scrollingTable:GetBaseElement():ShowDialogFrame(dialogFrame)
dialogFrame:GetElement("qty.input"):SetFocused(true)
elseif mouseButton == "RightButton" then
TSM.Vendoring.Buy.BuyItemIndex(row:GetFields("index", "stackSize"))
end
end
function private.PurchaseCloseBtnOnClick(button)
button:GetBaseElement():HideDialog()
end
function private.InputQtyOnValidationChanged(input)
local row = input:GetElement("__parent.__parent"):GetContext()
if input:IsValid() and tonumber(input:GetValue()) <= TSM.Vendoring.Buy.GetMaxCanAfford(row:GetField("index")) then
input:GetElement("__parent.__parent.purchaseBtn")
:SetDisabled(false)
:Draw()
else
input:GetElement("__parent.__parent.purchaseBtn")
:SetDisabled(true)
:Draw()
end
end
function private.InputQtyOnValueChanged(input)
local row = input:GetElement("__parent.__parent"):GetContext()
local value = tonumber(input:GetValue())
input:GetElement("__parent.__parent.cost.text")
:SetText(private.GetAltCostText(row, value))
input:GetElement("__parent.__parent.cost")
:Draw()
if input:IsValid() and value <= TSM.Vendoring.Buy.GetMaxCanAfford(row:GetField("index")) then
input:GetElement("__parent.__parent.purchaseBtn")
:SetDisabled(false)
:Draw()
else
input:GetElement("__parent.__parent.purchaseBtn")
:SetDisabled(true)
:Draw()
end
end
function private.InputQtyOnEnterPressed(input)
input:GetElement("__parent.__parent.purchaseBtn"):Click()
end
function private.MaxBtnOnClick(button)
local row = button:GetElement("__parent.__parent"):GetContext()
local value = max(1, min(TSM.Vendoring.Buy.GetMaxCanAfford(row:GetField("index")), ItemInfo.GetMaxStack(row:GetField("itemString")) * CalculateTotalNumberOfFreeBagSlots()))
button:GetElement("__parent.input")
:SetValue(value)
:Draw()
private.InputQtyOnValidationChanged(button:GetElement("__parent.input"))
button:GetElement("__parent.__parent.cost.text")
:SetText(private.GetAltCostText(row, tonumber(value)))
button:GetElement("__parent.__parent.cost")
:Draw()
end
function private.GetAltCostText(row, quantity)
local index, costItemsText, price, stackSize = row:GetFields("index", "costItemsText", "price", "stackSize")
local color = TSM.Vendoring.Buy.GetMaxCanAfford(index) < quantity and Theme.GetFeedbackColor("RED"):GetTextColorPrefix()
price = price * quantity / stackSize
if costItemsText == "" then
-- just a price
return Money.ToString(price, color)
elseif price == 0 then
-- just an extended cost string
return private.GetItemAltCostText(row, quantity)
else
-- both
return Money.ToString(price, color).." "..private.GetItemAltCostText(row, quantity)
end
end
function private.GetAltCostTooltip(row)
return row:GetField("firstCostItemString") or nil
end
function private.GetItemAltCostText(row, quantity)
local index = row:GetField("index")
local _, _, _, stackSize, _, _, _, extendedCost = GetMerchantItemInfo(index)
local numAltCurrencies = GetMerchantItemCostInfo(index)
-- bug with big keech vendor returning extendedCost = true for gold only items
if numAltCurrencies == 0 then
extendedCost = false
end
local costItemsText = ""
if extendedCost then
assert(numAltCurrencies > 0)
local costItems = TempTable.Acquire()
for j = 1, numAltCurrencies do
local _, costNum, costItemLink = GetMerchantItemCostItem(index, j)
costNum = costNum * quantity / stackSize
local costItemString = ItemString.Get(costItemLink)
local texture = nil
if costItemString then
texture = ItemInfo.GetTexture(costItemString)
elseif not TSM.IsWowClassic() and strmatch(costItemLink, "currency:") then
if TSM.IsShadowlands() then
texture = C_CurrencyInfo.GetCurrencyInfoFromLink(costItemLink).iconFileID
else
_, _, texture = GetCurrencyInfo(costItemLink)
end
else
error(format("Unknown item cost (%d, %d, %s)", index, costNum, tostring(costItemLink)))
end
if TSM.Vendoring.Buy.GetMaxCanAfford(index) < quantity then
costNum = Theme.GetFeedbackColor("RED"):ColorText(costNum)
end
tinsert(costItems, costNum.." |T"..(texture or "")..":12|t")
end
costItemsText = table.concat(costItems, " ")
TempTable.Release(costItems)
end
return costItemsText
end
function private.PurchaseBtnOnClick(button)
local row = button:GetElement("__parent"):GetContext()
TSM.Vendoring.Buy.BuyItemIndex(row:GetField("index"), button:GetElement("__parent.qty.input"):GetValue())
button:GetBaseElement():HideDialog()
end
function private.GetCurrencyText()
local name, amount, texturePath = "", nil, nil
if TSM.IsShadowlands() then
local firstCurrency = GetMerchantCurrencies()
if firstCurrency then
local info = C_CurrencyInfo.GetCurrencyInfo(firstCurrency)
name = info.name
amount = info.quantity
texturePath = info.iconFileID
end
elseif not TSM.IsWowClassic() then
name, amount, texturePath = GetCurrencyInfo(GetMerchantCurrencies() or "")
end
local text = ""
if name ~= "" and amount and texturePath then
text = amount.." |T"..texturePath..":12|t"
end
return text
end
function private.RepairOnClick(button)
PlaySound(SOUNDKIT.ITEM_REPAIR)
button:SetDisabled(true)
if IsAltKeyDown() then
if not TSM.Vendoring.Buy.CanGuildRepair() then
Log.PrintfUser(L["Cannot repair from the guild bank!"])
return
end
TSM.Vendoring.Buy.DoGuildRepair()
else
TSM.Vendoring.Buy.DoRepair()
end
end