initial commit

This commit is contained in:
Gitea
2020-11-13 14:13:12 -05:00
commit 05df49ff60
368 changed files with 128754 additions and 0 deletions

340
Core/UI/CraftingUI/Core.lua Normal file
View File

@@ -0,0 +1,340 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local CraftingUI = TSM.UI:NewPackage("CraftingUI")
local L = TSM.Include("Locale").GetTable()
local FSM = TSM.Include("Util.FSM")
local Event = TSM.Include("Util.Event")
local ScriptWrapper = TSM.Include("Util.ScriptWrapper")
local Settings = TSM.Include("Service.Settings")
local UIElements = TSM.Include("UI.UIElements")
local private = {
settings = nil,
topLevelPages = {},
fsm = nil,
craftOpen = nil,
tradeSkillOpen = nil,
defaultUISwitchBtn = nil,
isVisible = false,
}
local MIN_FRAME_SIZE = { width = 650, height = 587 }
local BEAST_TRAINING_DE = "Bestienausbildung"
local BEAST_TRAINING_ES = "Entrenamiento de bestias"
local BEAST_TRAINING_RUS = "Воспитание питомца"
local IGNORED_PROFESSIONS = {
[53428] = true, -- Runeforging
[158756] = true, -- Skinning Skills
[193290] = true, -- Herbalism Skills
[7620] = true, -- Fishing Skills (shows up as Fishing)
}
-- ============================================================================
-- Module Functions
-- ============================================================================
function CraftingUI.OnInitialize()
private.settings = Settings.NewView()
:AddKey("global", "craftingUIContext", "showDefault")
:AddKey("global", "craftingUIContext", "frame")
private.FSMCreate()
TSM.Crafting.ProfessionScanner.SetDisabled(private.settings.showDefault)
end
function CraftingUI.OnDisable()
-- hide the frame
if private.isVisible then
TSM.Crafting.ProfessionScanner.SetDisabled(false)
private.fsm:ProcessEvent("EV_FRAME_TOGGLE")
end
end
function CraftingUI.RegisterTopLevelPage(name, callback)
tinsert(private.topLevelPages, { name = name, callback = callback })
end
function CraftingUI.Toggle()
private.settings.showDefault = false
TSM.Crafting.ProfessionScanner.SetDisabled(false)
private.fsm:ProcessEvent("EV_FRAME_TOGGLE")
end
function CraftingUI.IsProfessionIgnored(name)
if TSM.IsWowClassic() then
if name == GetSpellInfo(5149) or name == BEAST_TRAINING_DE or name == BEAST_TRAINING_ES or name == BEAST_TRAINING_RUS then -- Beast Training
return true
elseif name == GetSpellInfo(7620) then -- Fishing
return true
elseif name == GetSpellInfo(2366) then -- Herb Gathering
return true
elseif name == GetSpellInfo(8613) then -- Skinning
return true
end
end
for i in pairs(IGNORED_PROFESSIONS) do
local ignoredName = GetSpellInfo(i)
if ignoredName == name then
return true
end
end
end
function CraftingUI.IsVisible()
return private.isVisible
end
-- ============================================================================
-- Main Frame
-- ============================================================================
function private.CreateMainFrame()
TSM.UI.AnalyticsRecordPathChange("crafting")
local frame = UIElements.New("LargeApplicationFrame", "base")
:SetParent(UIParent)
:SetSettingsContext(private.settings, "frame")
:SetMinResize(MIN_FRAME_SIZE.width, MIN_FRAME_SIZE.height)
:SetStrata("HIGH")
:AddPlayerGold()
:AddAppStatusIcon()
:AddSwitchButton(private.SwitchBtnOnClick)
:SetScript("OnHide", private.BaseFrameOnHide)
for _, info in ipairs(private.topLevelPages) do
frame:AddNavButton(info.name, info.callback)
end
return frame
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.BaseFrameOnHide()
TSM.UI.AnalyticsRecordClose("crafting")
private.fsm:ProcessEvent("EV_FRAME_HIDE")
end
function private.SwitchBtnOnClick(button)
private.settings.showDefault = button ~= private.defaultUISwitchBtn
TSM.Crafting.ProfessionScanner.SetDisabled(private.settings.showDefault)
private.fsm:ProcessEvent("EV_SWITCH_BTN_CLICKED")
end
function private.SwitchButtonOnEnter(button)
button:SetTextColor("TEXT")
:Draw()
end
function private.SwitchButtonOnLeave(button)
button:SetTextColor("TEXT_ALT")
:Draw()
end
-- ============================================================================
-- FSM
-- ============================================================================
function private.FSMCreate()
if TSM.IsWowClassic() then
Event.Register("CRAFT_SHOW", function()
CloseTradeSkill()
private.craftOpen = true
TSM.Crafting.ProfessionState.SetCraftOpen(true)
private.fsm:ProcessEvent("EV_TRADE_SKILL_SHOW")
end)
Event.Register("CRAFT_CLOSE", function()
private.craftOpen = false
TSM.Crafting.ProfessionState.SetCraftOpen(false)
if not private.tradeSkillOpen then
private.fsm:ProcessEvent("EV_TRADE_SKILL_CLOSED")
end
end)
end
Event.Register("TRADE_SKILL_SHOW", function()
if TSM.IsWowClassic() then
CloseCraft()
end
private.tradeSkillOpen = true
private.fsm:ProcessEvent("EV_TRADE_SKILL_SHOW")
end)
Event.Register("TRADE_SKILL_CLOSE", function()
private.tradeSkillOpen = false
if not private.craftOpen then
private.fsm:ProcessEvent("EV_TRADE_SKILL_CLOSED")
end
end)
-- we'll implement UIParent's event handler directly when necessary for TRADE_SKILL_SHOW
if TSM.IsWowClassic() then
UIParent:UnregisterEvent("CRAFT_SHOW")
end
UIParent:UnregisterEvent("TRADE_SKILL_SHOW")
local fsmContext = {
frame = nil,
}
local function UpdateDefaultCraftButton()
if CraftFrame and CraftCreateButton and private.craftOpen then
CraftCreateButton:SetParent(CraftFrame)
CraftCreateButton:ClearAllPoints()
CraftCreateButton:SetPoint("CENTER", CraftFrame, "TOPLEFT", 224, -422)
CraftCreateButton:SetFrameLevel(2)
CraftCreateButton:EnableDrawLayer("BACKGROUND")
CraftCreateButton:EnableDrawLayer("ARTWORK")
CraftCreateButton:SetHighlightTexture("Interface\\Buttons\\UI-Panel-Button-Highlight")
CraftCreateButton:GetHighlightTexture():SetTexCoord(0, 0.625, 0, 0.6875)
end
end
local function DefaultFrameOnHide()
private.fsm:ProcessEvent("EV_FRAME_HIDE")
end
private.fsm = FSM.New("CRAFTING_UI")
:AddState(FSM.NewState("ST_CLOSED")
:AddTransition("ST_DEFAULT_OPEN")
:AddTransition("ST_FRAME_OPEN")
:AddEvent("EV_FRAME_TOGGLE", function(context)
assert(not private.settings.showDefault)
TSM.Crafting.ProfessionScanner.SetDisabled(false)
return "ST_FRAME_OPEN"
end)
:AddEvent("EV_TRADE_SKILL_SHOW", function(context)
TSM.Crafting.ProfessionScanner.SetDisabled(private.settings.showDefault)
local name = TSM.Crafting.ProfessionUtil.GetCurrentProfessionName()
if CraftingUI.IsProfessionIgnored(name) then
return "ST_DEFAULT_OPEN", true
elseif private.settings.showDefault then
return "ST_DEFAULT_OPEN"
else
return "ST_FRAME_OPEN"
end
end)
)
:AddState(FSM.NewState("ST_DEFAULT_OPEN")
:SetOnEnter(function(context, isIgnored)
if private.craftOpen then
UIParent_OnEvent(UIParent, "CRAFT_SHOW")
UpdateDefaultCraftButton()
else
UIParent_OnEvent(UIParent, "TRADE_SKILL_SHOW")
end
if not private.defaultUISwitchBtn then
private.defaultUISwitchBtn = UIElements.New("ActionButton", "switchBtn")
:SetSize(60, TSM.IsWowClassic() and 16 or 15)
:AddAnchor("TOPRIGHT", TSM.IsWowClassic() and -60 or -27, TSM.IsWowClassic() and -16 or -4)
:SetRelativeLevel(3)
:DisableClickCooldown()
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["TSM4"])
:SetScript("OnClick", private.SwitchBtnOnClick)
:SetScript("OnEnter", private.SwitchButtonOnEnter)
:SetScript("OnLeave", private.SwitchButtonOnLeave)
private.defaultUISwitchBtn:_GetBaseFrame():SetParent(TradeSkillFrame)
end
private.defaultUISwitchBtn:_GetBaseFrame():SetParent(private.craftOpen and CraftFrame or TradeSkillFrame)
if isIgnored then
TSM.Crafting.ProfessionScanner.SetDisabled(true)
private.defaultUISwitchBtn:Hide()
else
private.defaultUISwitchBtn:Show()
private.defaultUISwitchBtn:Draw()
end
if private.craftOpen then
ScriptWrapper.Set(CraftFrame, "OnHide", DefaultFrameOnHide)
else
ScriptWrapper.Set(TradeSkillFrame, "OnHide", DefaultFrameOnHide)
end
if not TSM.IsWowClassic() then
local linked, linkedName = TSM.Crafting.ProfessionUtil.IsLinkedProfession()
if TSM.Crafting.ProfessionUtil.IsDataStable() and not TSM.Crafting.ProfessionUtil.IsGuildProfession() and (not linked or (linked and linkedName == UnitName("player"))) then
TradeSkillFrame:OnEvent("TRADE_SKILL_DATA_SOURCE_CHANGED")
TradeSkillFrame:OnEvent("TRADE_SKILL_LIST_UPDATE")
end
end
end)
:SetOnExit(function(context)
if private.craftOpen then
if CraftFrame then
ScriptWrapper.Clear(CraftFrame, "OnHide")
HideUIPanel(CraftFrame)
end
else
if TradeSkillFrame then
ScriptWrapper.Clear(TradeSkillFrame, "OnHide")
HideUIPanel(TradeSkillFrame)
end
end
end)
:AddTransition("ST_CLOSED")
:AddTransition("ST_FRAME_OPEN")
:AddTransition("ST_DEFAULT_OPEN")
:AddEvent("EV_FRAME_HIDE", function(context)
TSM.Crafting.ProfessionUtil.CloseTradeSkill(false, private.craftOpen)
return "ST_CLOSED"
end)
:AddEvent("EV_TRADE_SKILL_SHOW", function(context)
if CraftingUI.IsProfessionIgnored(TSM.Crafting.ProfessionUtil.GetCurrentProfessionName()) then
return "ST_DEFAULT_OPEN", true
else
if private.settings.showDefault then
return "ST_DEFAULT_OPEN"
else
TSM.Crafting.ProfessionScanner.SetDisabled(private.settings.showDefault)
return "ST_FRAME_OPEN"
end
end
end)
:AddEventTransition("EV_TRADE_SKILL_CLOSED", "ST_CLOSED")
:AddEventTransition("EV_SWITCH_BTN_CLICKED", "ST_FRAME_OPEN")
)
:AddState(FSM.NewState("ST_FRAME_OPEN")
:SetOnEnter(function(context)
assert(not context.frame)
context.frame = private.CreateMainFrame()
context.frame:Show()
if TSM.Crafting.ProfessionUtil.GetCurrentProfessionName() then
context.frame:GetElement("titleFrame.switchBtn"):Show()
else
context.frame:GetElement("titleFrame.switchBtn"):Hide()
end
context.frame:Draw()
private.isVisible = true
end)
:SetOnExit(function(context)
context.frame:Hide()
context.frame:Release()
context.frame = nil
private.isVisible = false
if TSM.IsWowClassic() then
UpdateDefaultCraftButton()
end
end)
:AddTransition("ST_CLOSED")
:AddTransition("ST_DEFAULT_OPEN")
:AddEvent("EV_FRAME_HIDE", function(context)
TSM.Crafting.ProfessionUtil.CloseTradeSkill(true)
return "ST_CLOSED"
end)
:AddEvent("EV_TRADE_SKILL_SHOW", function(context)
if CraftingUI.IsProfessionIgnored(TSM.Crafting.ProfessionUtil.GetCurrentProfessionName()) then
return "ST_DEFAULT_OPEN", true
end
context.frame:GetElement("titleFrame.switchBtn"):Show()
context.frame:GetElement("titleFrame"):Draw()
end)
:AddEventTransition("EV_TRADE_SKILL_CLOSED", "ST_CLOSED")
:AddEventTransition("EV_SWITCH_BTN_CLICKED", "ST_DEFAULT_OPEN")
:AddEventTransition("EV_FRAME_TOGGLE", "ST_CLOSED")
)
:Init("ST_CLOSED", fsmContext)
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,673 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local CraftingReports = TSM.UI.CraftingUI:NewPackage("CraftingReports")
local L = TSM.Include("Locale").GetTable()
local Math = TSM.Include("Util.Math")
local Log = TSM.Include("Util.Log")
local Money = TSM.Include("Util.Money")
local String = TSM.Include("Util.String")
local ItemString = TSM.Include("Util.ItemString")
local Theme = TSM.Include("Util.Theme")
local ItemInfo = TSM.Include("Service.ItemInfo")
local Settings = TSM.Include("Service.Settings")
local UIElements = TSM.Include("UI.UIElements")
local private = {
settings = nil,
craftsQuery = nil,
matsQuery = nil,
filterText = "",
craftProfessions = {},
matProfessions = {},
}
local MAT_PRICE_SOURCES = {ALL, L["Default Price"], L["Custom Price"]}
-- ============================================================================
-- Module Functions
-- ============================================================================
function CraftingReports.OnInitialize()
private.settings = Settings.NewView()
:AddKey("global", "craftingUIContext", "craftsScrollingTable")
:AddKey("global", "craftingUIContext", "matsScrollingTable")
:AddKey("factionrealm", "internalData", "mats")
:AddKey("global", "craftingOptions", "defaultMatCostMethod")
TSM.UI.CraftingUI.RegisterTopLevelPage(L["Reports"], private.GetCraftingReportsFrame)
end
-- ============================================================================
-- CraftingReports UI
-- ============================================================================
function private.GetCraftingReportsFrame()
TSM.UI.AnalyticsRecordPathChange("crafting", "crafting_reports")
if not private.craftsQuery then
private.craftsQuery = TSM.Crafting.CreateCraftsQuery()
private.craftsQuery:VirtualField("firstOperation", "string", private.FirstOperationVirtualField, "itemString")
end
private.craftsQuery:ResetFilters()
private.craftsQuery:ResetOrderBy()
private.craftsQuery:OrderBy("itemName", true)
private.matsQuery = private.matsQuery or TSM.Crafting.CreateMatItemQuery()
private.matsQuery:ResetFilters()
private.matsQuery:ResetOrderBy()
private.matsQuery:OrderBy("name", true)
return UIElements.New("Frame", "craftingReportsContent")
:SetLayout("VERTICAL")
:SetPadding(0, 0, 6, 0)
:SetBackgroundColor("PRIMARY_BG_ALT")
:AddChild(UIElements.New("TabGroup", "buttons")
:SetNavCallback(private.GetTabElements)
:AddPath(L["Crafts"], true)
:AddPath(L["Materials"])
)
end
function private.GetTabElements(self, path)
if path == L["Crafts"] then
TSM.UI.AnalyticsRecordPathChange("crafting", "crafting_reports", "crafts")
private.filterText = ""
wipe(private.craftProfessions)
tinsert(private.craftProfessions, L["All Professions"])
for _, player, profession in TSM.Crafting.PlayerProfessions.Iterator() do
tinsert(private.craftProfessions, format("%s - %s", profession, player))
end
private.craftsQuery:ResetFilters()
return UIElements.New("Frame", "crafts")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Frame", "filters")
:SetLayout("HORIZONTAL")
:SetHeight(72)
:SetPadding(10, 10, 8, 16)
:AddChild(UIElements.New("Frame", "search")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Text", "label")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["Filter by Keyword"])
)
:AddChild(UIElements.New("Input", "input")
:SetHeight(24)
:AllowItemInsert()
:SetIconTexture("iconPack.18x18/Search")
:SetClearButtonEnabled(true)
:SetHintText(L["Enter Keyword"])
:SetScript("OnValueChanged", private.CraftsInputOnValueChanged)
)
)
:AddChild(UIElements.New("Frame", "profession")
:SetLayout("VERTICAL")
:SetMargin(16, 16, 0, 0)
:AddChild(UIElements.New("Text", "label")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["Filter by Profession"])
)
:AddChild(UIElements.New("SelectionDropdown", "dropdown")
:SetHeight(24)
:SetItems(private.craftProfessions)
:SetSelectedItem(private.craftProfessions[1], true)
:SetScript("OnSelectionChanged", private.CraftsDropdownOnSelectionChanged)
)
)
:AddChild(UIElements.New("Frame", "craftable")
:SetLayout("HORIZONTAL")
:SetSize(176, 24)
:SetMargin(0, 0, 24, 0)
:AddChild(UIElements.New("Checkbox", "checkbox")
:SetWidth(24)
:SetFont("BODY_BODY2")
:SetScript("OnValueChanged", private.CheckboxOnValueChanged)
)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY2")
:SetText(L["Only show craftable"])
)
)
)
:AddChild(UIElements.New("QueryScrollingTable", "crafts")
:SetSettingsContext(private.settings, "craftsScrollingTable")
:GetScrollingTableInfo()
:SetMenuInfo(private.CraftsMatsMenuIterator, private.CraftsMenuClickHandler)
:NewColumn("queued")
:SetTitleIcon("iconPack.18x18/Queue")
:SetFont("TABLE_TABLE1")
:SetJustifyH("CENTER")
:SetTextInfo("num")
:SetSortInfo("num")
:Commit()
:NewColumn("craftName")
:SetTitle(L["Name"])
:SetIconSize(12)
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo(nil, private.CraftsGetCraftNameText)
:SetIconInfo("itemString", ItemInfo.GetTexture)
:SetTooltipInfo("itemString")
:SetSortInfo("itemName")
:DisableHiding()
:Commit()
:NewColumn("operation")
:SetTitle(L["Operation"])
:SetFont("BODY_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("firstOperation")
:SetSortInfo("firstOperation")
:Commit()
:NewColumn("bags")
:SetTitle(L["Bag"])
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetTextInfo("bagQuantity", private.CraftsGetBagsText)
:SetSortInfo("bagQuantity")
:Commit()
:NewColumn("ah")
:SetTitle(L["AH"])
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetTextInfo("auctionQuantity", private.CraftsGetAHText)
:SetSortInfo("auctionQuantity")
:Commit()
:NewColumn("craftingCost")
:SetTitle(L["Crafting Cost"])
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetTextInfo("craftingCost", private.CraftsGetCostItemValueText)
:SetSortInfo("craftingCost")
:Commit()
:NewColumn("itemValue")
:SetTitle(L["Item Value"])
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetTextInfo("itemValue", private.CraftsGetCostItemValueText)
:SetSortInfo("itemValue")
:Commit()
:NewColumn("profit")
:SetTitle(L["Profit"])
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetTextInfo("profit", private.CraftsGetProfitText)
:SetSortInfo("profit")
:Commit()
:NewColumn("profitPct")
:SetTitle("%")
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetTextInfo("profitPct", private.GetProfitPctText)
:SetSortInfo("profitPct")
:Commit()
:NewColumn("saleRate")
:SetTitleIcon("iconPack.18x18/SaleRate")
:SetFont("TABLE_TABLE1")
:SetJustifyH("CENTER")
:SetTextInfo("saleRate", private.CraftsGetSaleRateText)
:SetSortInfo("saleRate")
:Commit()
:Commit()
:SetQuery(private.craftsQuery)
:SetSelectionDisabled(true)
:SetScript("OnRowClick", private.CraftsOnRowClick)
)
elseif path == L["Materials"] then
TSM.UI.AnalyticsRecordPathChange("crafting", "crafting_reports", "materials")
wipe(private.matProfessions)
tinsert(private.matProfessions, L["All Professions"])
for _, _, profession in TSM.Crafting.PlayerProfessions.Iterator() do
if not private.matProfessions[profession] then
tinsert(private.matProfessions, profession)
private.matProfessions[profession] = true
end
end
private.matsQuery:ResetFilters()
return UIElements.New("Frame", "materials")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Frame", "filters")
:SetLayout("HORIZONTAL")
:SetHeight(72)
:SetPadding(10, 10, 8, 16)
:AddChild(UIElements.New("Frame", "search")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Text", "label")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["Filter by Keyword"])
)
:AddChild(UIElements.New("Input", "input")
:SetHeight(24)
:AllowItemInsert()
:SetIconTexture("iconPack.18x18/Search")
:SetClearButtonEnabled(true)
:SetHintText(L["Enter Keyword"])
:SetScript("OnValueChanged", private.MatsInputOnValueChanged)
)
)
:AddChild(UIElements.New("Frame", "profession")
:SetLayout("VERTICAL")
:SetMargin(16, 0, 0, 0)
:AddChild(UIElements.New("Text", "label")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["Filter by Profession"])
)
:AddChild(UIElements.New("SelectionDropdown", "dropdown")
:SetHeight(24)
:SetItems(private.matProfessions)
:SetSelectedItem(private.matProfessions[1], true)
:SetScript("OnSelectionChanged", private.MatsDropdownOnSelectionChanged)
)
)
:AddChild(UIElements.New("Frame", "priceSource")
:SetLayout("VERTICAL")
:SetMargin(16, 0, 0, 0)
:AddChild(UIElements.New("Text", "label")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["Filter by Price Source"])
)
:AddChild(UIElements.New("SelectionDropdown", "dropdown")
:SetHeight(24)
:SetItems(MAT_PRICE_SOURCES)
:SetSelectedItem(MAT_PRICE_SOURCES[1], true)
:SetScript("OnSelectionChanged", private.MatsDropdownOnSelectionChanged)
)
)
)
:AddChild(UIElements.New("QueryScrollingTable", "mats")
:SetSettingsContext(private.settings, "matsScrollingTable")
:GetScrollingTableInfo()
:SetMenuInfo(private.CraftsMatsMenuIterator, private.MatsMenuClickHandler)
:NewColumn("name")
:SetTitle(L["Name"])
:SetIconSize(12)
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("itemString", private.MatsGetNameText)
:SetIconInfo("itemString", ItemInfo.GetTexture)
:SetTooltipInfo("itemString")
:SetSortInfo("name")
:DisableHiding()
:Commit()
:NewColumn("price")
:SetTitle(L["Mat Price"])
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetTextInfo("matCost", private.MatsGetPriceText)
:SetSortInfo("matCost")
:Commit()
:NewColumn("professions")
:SetTitle(L["Professions Used In"])
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("professions")
:SetSortInfo("professions")
:Commit()
:NewColumn("num")
:SetTitle(L["Number Owned"])
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetTextInfo("totalQuantity", private.MatsGetNumText)
:SetSortInfo("totalQuantity")
:Commit()
:Commit()
:SetQuery(private.matsQuery)
:SetSelectionDisabled(true)
:SetScript("OnRowClick", private.MatsOnRowClick)
)
else
error("Unknown path: "..tostring(path))
end
end
-- ============================================================================
-- ScrollingTable Functions
-- ============================================================================
function private.CraftsGetCraftNameText(row)
return TSM.UI.GetColoredItemName(row:GetField("itemString")) or row:GetField("name")
end
function private.CraftsGetBagsText(bagQuantity)
return bagQuantity or "0"
end
function private.CraftsGetAHText(bagQuantity)
return bagQuantity or "0"
end
function private.CraftsGetCostItemValueText(costItemValue)
if Math.IsNan(costItemValue) then
return ""
end
return Money.ToString(costItemValue)
end
function private.CraftsGetProfitText(profit)
if Math.IsNan(profit) then
return ""
end
return Money.ToString(profit, (profit >= 0 and Theme.GetFeedbackColor("GREEN") or Theme.GetFeedbackColor("RED")):GetTextColorPrefix())
end
function private.GetProfitPctText(profitPct)
if Math.IsNan(profitPct) then
return ""
end
local color = Theme.GetFeedbackColor(profitPct >= 0 and "GREEN" or "RED")
return color:ColorText(profitPct.."%") or ""
end
function private.CraftsGetSaleRateText(saleRate)
if Math.IsNan(saleRate) then
return ""
end
return format("%0.2f", saleRate)
end
function private.MatsGetNameText(itemString)
return TSM.UI.GetColoredItemName(itemString) or TSM.UI.GetColoredItemName(ItemString.GetUnknown())
end
function private.MatsGetPriceText(matCost)
if Math.IsNan(matCost) then
return ""
end
return Money.ToString(matCost)
end
function private.MatsGetNumText(totalQuantity)
return totalQuantity or "0"
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.CraftsInputOnValueChanged(input)
local text = input:GetValue()
if text == private.filterText then
return
end
private.filterText = text
private.UpdateCraftsQueryWithFilters(input:GetParentElement():GetParentElement())
end
function private.CraftsDropdownOnSelectionChanged(dropdown)
private.UpdateCraftsQueryWithFilters(dropdown:GetParentElement():GetParentElement())
end
function private.CheckboxOnValueChanged(checkbox)
private.UpdateCraftsQueryWithFilters(checkbox:GetParentElement():GetParentElement())
end
function private.CraftsOnRowClick(scrollingTable, record, mouseButton)
if mouseButton == "LeftButton" then
TSM.Crafting.Queue.Add(record:GetField("spellId"), 1)
elseif mouseButton == "RightButton" then
TSM.Crafting.Queue.Remove(record:GetField("spellId"), 1)
end
scrollingTable:Draw()
end
function private.MatsInputOnValueChanged(input)
private.UpdateMatsQueryWithFilters(input:GetParentElement():GetParentElement())
end
function private.MatsDropdownOnSelectionChanged(dropdown)
private.UpdateMatsQueryWithFilters(dropdown:GetParentElement():GetParentElement())
end
function private.MatsOnRowClick(scrollingTable, row)
local itemString = row:GetField("itemString")
local priceStr = private.settings.mats[itemString].customValue or private.settings.defaultMatCostMethod
scrollingTable:GetBaseElement():ShowDialogFrame(UIElements.New("Frame", "frame")
:SetLayout("VERTICAL")
:SetSize(478, 312)
:SetPadding(12)
:AddAnchor("CENTER")
:SetBackgroundColor("FRAME_BG", true)
:SetContext(itemString)
: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["Edit Material Price"])
)
:AddChild(UIElements.New("Button", "closeBtn")
:SetMargin(0, -4, 0, 0)
:SetBackgroundAndSize("iconPack.24x24/Close/Default")
:SetScript("OnClick", private.DialogCloseBtnOnClick)
)
)
:AddChild(UIElements.New("Frame", "item")
:SetLayout("HORIZONTAL")
:SetPadding(6)
:SetMargin(0, 0, 0, 10)
: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("Text", "desc")
:SetHeight(20)
:SetMargin(0, 0, 0, 6)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Material Price"])
)
:AddChild(UIElements.New("MultiLineInput", "input")
:SetMargin(0, 0, 0, 12)
:SetBackgroundColor("PRIMARY_BG_ALT")
:SetFont("BODY_BODY2_MEDIUM")
:SetValidateFunc("CUSTOM_PRICE")
:SetValue(Money.ToString(priceStr) or priceStr)
:SetScript("OnValueChanged", private.MatPriceInputOnValueChanged)
)
:AddChild(UIElements.New("Frame", "buttons")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("Button", "resetBtn")
:SetWidth("AUTO")
:SetFont("BODY_BODY3_MEDIUM")
:SetTextColor(private.settings.mats[itemString].customValue and "TEXT" or "TEXT_ALT")
:SetDisabled(not private.settings.mats[itemString].customValue)
:SetText(L["Reset to Default"])
:SetScript("OnClick", private.ResetButtonOnClick)
)
:AddChild(UIElements.New("Frame", "spacer"))
:AddChild(UIElements.New("ActionButton", "closeBtn")
:SetWidth(342)
:SetText(L["Save"])
:SetScript("OnClick", private.DialogCloseBtnOnClick)
)
)
)
end
function private.DialogCloseBtnOnClick(button)
button:GetBaseElement():HideDialog()
end
function private.MatPriceInputOnValueChanged(input)
local value = input:GetValue()
local itemString = input:GetParentElement():GetContext()
TSM.Crafting.SetMatCustomValue(itemString, value)
input:GetElement("__parent.buttons.resetBtn")
:SetTextColor("TEXT")
:SetDisabled(false)
:Draw()
end
function private.ResetButtonOnClick(button)
local itemString = button:GetParentElement():GetParentElement():GetContext()
TSM.Crafting.SetMatCustomValue(itemString, nil)
assert(not private.settings.mats[itemString].customValue)
button:SetTextColor("TEXT_ALT")
button:SetDisabled(true)
button:Draw()
button:GetElement("__parent.__parent.input")
:SetValue(Money.ToString(private.settings.defaultMatCostMethod) or private.settings.defaultMatCostMethod)
:Draw()
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.FirstOperationVirtualField(itemString)
return TSM.Operations.GetFirstOperationByItem("Crafting", itemString) or ""
end
function private.UpdateCraftsQueryWithFilters(frame)
private.craftsQuery:ResetFilters()
-- apply search filter
local filter = strtrim(frame:GetElement("search.input"):GetValue())
if filter ~= "" then
private.craftsQuery:Matches("itemName", String.Escape(filter))
end
-- apply dropdown filter
local professionPlayer = frame:GetElement("profession.dropdown"):GetSelectedItem()
if professionPlayer ~= private.craftProfessions[1] then
local profession, player = strmatch(professionPlayer, "^(.+) %- ([^ ]+)$")
private.craftsQuery
:Equal("profession", profession)
:Or()
:Equal("players", player)
:Matches("players", "^"..player..",")
:Matches("players", ","..player..",")
:Matches("players", ","..player.."$")
:End()
end
-- apply craftable filter
local craftableOnly = frame:GetElement("craftable.checkbox"):IsChecked()
if craftableOnly then
private.craftsQuery:Custom(private.IsCraftableQueryFilter)
end
frame:GetElement("__parent.crafts"):SetQuery(private.craftsQuery, true)
end
function private.IsCraftableQueryFilter(record)
return TSM.Crafting.ProfessionUtil.GetNumCraftableFromDB(record:GetField("spellId")) > 0
end
function private.UpdateMatsQueryWithFilters(frame)
private.matsQuery:ResetFilters()
-- apply search filter
local filter = strtrim(frame:GetElement("search.input"):GetValue())
if filter ~= "" then
private.matsQuery:Custom(private.MatItemNameQueryFilter, strlower(String.Escape(filter)))
end
-- apply dropdown filters
local profession = frame:GetElement("profession.dropdown"):GetSelectedItem()
if profession ~= private.matProfessions[1] then
private.matsQuery
:Or()
:Equal("professions", profession)
:Matches("professions", "^"..profession..",")
:Matches("professions", ","..profession..",")
:Matches("professions", ","..profession.."$")
:End()
end
local priceSource = frame:GetElement("priceSource.dropdown"):GetSelectedItem()
if priceSource == MAT_PRICE_SOURCES[2] then
private.matsQuery:Equal("customValue", "")
elseif priceSource == MAT_PRICE_SOURCES[3] then
private.matsQuery:NotEqual("customValue", "")
end
frame:GetElement("__parent.mats"):SetQuery(private.matsQuery, true)
end
function private.MatItemNameQueryFilter(row, filter)
local name = ItemInfo.GetName(row:GetField("itemString"))
if not name then return end
return strmatch(strlower(name), filter)
end
function private.CraftsMatsMenuIterator(scrollingTable, prevIndex)
if prevIndex == "CREATE_GROUPS" then
-- we're done
return
else
return "CREATE_GROUPS", L["Create Groups from Table"]
end
end
function private.CraftsMenuClickHandler(scrollingTable, index1, index2)
if index1 == "CREATE_GROUPS" then
assert(not index2)
scrollingTable:GetBaseElement():HideDialog()
local numCreated, numAdded = 0, 0
for _, row in private.craftsQuery:Iterator() do
local itemString = row:GetField("itemString")
local groupPath = TSM.Groups.Path.Join(L["Crafted Items"], row:GetField("profession"))
if not TSM.Groups.Exists(groupPath) then
TSM.Groups.Create(groupPath)
numCreated = numCreated + 1
end
if not TSM.Groups.IsItemInGroup(itemString) and not ItemInfo.IsSoulbound(itemString) then
TSM.Groups.SetItemGroup(itemString, groupPath)
numAdded = numAdded + 1
end
end
Log.PrintfUser(L["%d groups were created and %d items were added from the table."], numCreated, numAdded)
else
error("Unexpected index1: "..tostring(index1))
end
end
function private.MatsMenuClickHandler(scrollingTable, index1, index2)
if index1 == "CREATE_GROUPS" then
assert(not index2)
scrollingTable:GetBaseElement():HideDialog()
local numCreated, numAdded = 0, 0
for _, row in private.matsQuery:Iterator() do
local itemString = row:GetField("itemString")
local groupPath = L["Materials"]
if not TSM.Groups.Exists(groupPath) then
TSM.Groups.Create(groupPath)
numCreated = numCreated + 1
end
if not TSM.Groups.IsItemInGroup(itemString) and not ItemInfo.IsSoulbound(itemString) then
TSM.Groups.SetItemGroup(itemString, groupPath)
numAdded = numAdded + 1
end
end
Log.PrintfUser(L["%d groups were created and %d items were added from the table."], numCreated, numAdded)
else
error("Unexpected index1: "..tostring(index1))
end
end

View File

@@ -0,0 +1,354 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Gathering = TSM.UI.CraftingUI:NewPackage("Gathering")
local L = TSM.Include("Locale").GetTable()
local TempTable = TSM.Include("Util.TempTable")
local Table = TSM.Include("Util.Table")
local ItemInfo = TSM.Include("Service.ItemInfo")
local Settings = TSM.Include("Service.Settings")
local UIElements = TSM.Include("UI.UIElements")
local private = {
settings = nil,
frame = nil,
query = nil,
}
local SOURCE_LIST = {
"vendor",
"guildBank",
"alt",
"altGuildBank",
"craftProfit",
"craftNoProfit",
"auction",
"auctionDE",
"auctionCrafting"
}
local SOURCE_TEXT_LIST = {
L["Vendor"],
L["Guild Bank"],
L["Alts"],
L["Alt Guild Bank"],
L["Craft (Profitable)"],
L["Craft (Unprofitable)"],
L["AH"],
L["AH (Disenchanting)"],
L["AH (Crafting)"],
}
if TSM.IsWowClassic() then
Table.RemoveByValue(SOURCE_LIST, "guildBank")
Table.RemoveByValue(SOURCE_LIST, "altGuildBank")
Table.RemoveByValue(SOURCE_TEXT_LIST, L["Guild Bank"])
Table.RemoveByValue(SOURCE_TEXT_LIST, L["Alt Guild Bank"])
end
assert(#SOURCE_LIST == #SOURCE_TEXT_LIST)
-- ============================================================================
-- Module Functions
-- ============================================================================
function Gathering.OnInitialize()
private.settings = Settings.NewView()
:AddKey("global", "craftingUIContext", "gatheringDividedContainer")
:AddKey("global", "craftingUIContext", "gatheringScrollingTable")
:AddKey("profile", "gatheringOptions", "sources")
TSM.UI.CraftingUI.RegisterTopLevelPage(L["Gathering"], private.GetGatheringFrame)
TSM.Crafting.Gathering.SetContextChangedCallback(private.ContextChangedCallback)
TSM.UI.TaskListUI.RegisterUpdateCallback(private.UpdateButtonState)
end
-- ============================================================================
-- Gathering UI
-- ============================================================================
function private.GetGatheringFrame()
TSM.UI.AnalyticsRecordPathChange("crafting", "gathering")
assert(not private.query)
private.query = TSM.Crafting.Gathering.CreateQuery()
:SetUpdateCallback(private.UpdateButtonState)
local frame = UIElements.New("DividedContainer", "gathering")
:SetMinWidth(284, 200)
:SetBackgroundColor("PRIMARY_BG")
:SetSettingsContext(private.settings, "gatheringDividedContainer")
:SetLeftChild(UIElements.New("ScrollFrame", "setup")
:SetPadding(12)
:SetBackgroundColor("PRIMARY_BG_ALT")
:AddChild(UIElements.New("Text", "title")
:SetHeight(20)
:SetMargin(0, 0, 0, 8)
:SetFont("BODY_BODY1_BOLD")
:SetText(L["Gathering Setup"])
)
:AddChild(UIElements.New("Text", "crafterDropdownLabel")
:SetHeight(20)
:SetMargin(0, 0, 0, 2)
:SetFont("BODY_BODY3_MEDIUM")
:SetTextColor("INDICATOR")
:SetText(L["Crafter"])
)
:AddChild(UIElements.New("SelectionDropdown", "crafterDropdown")
:SetHeight(24)
:SetMargin(0, 0, 0, 8)
:SetHintText(L["Select crafter"])
:SetScript("OnSelectionChanged", private.CrafterDropdownOnSelectionChanged)
)
:AddChild(UIElements.New("Text", "professionDropdownLabel")
:SetHeight(20)
:SetMargin(0, 0, 0, 2)
:SetFont("BODY_BODY3_MEDIUM")
:SetTextColor("INDICATOR")
:SetText(L["Profession"])
)
:AddChild(UIElements.New("MultiselectionDropdown", "professionDropdown")
:SetHeight(24)
:SetMargin(0, 0, 0, 24)
:SetHintText(L["Select professions"])
:SetSelectionText(L["No Professions"], L["%d Professions"], L["All Professions"])
:SetScript("OnSelectionChanged", private.ProfessionDropdownOnSelectionChanged)
)
:AddChild(UIElements.New("Text", "sourcesCategoryText")
:SetHeight(20)
:SetMargin(0, 0, 0, 2)
:SetFont("BODY_BODY3_MEDIUM")
:SetTextColor("INDICATOR")
:SetText(L["Sources"])
)
:AddChild(UIElements.New("Text", "sourcesDesc")
:SetHeight(28)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY3_MEDIUM")
:SetTextColor("TEXT_ALT")
:SetText(L["Define what priority Gathering gives certain sources."])
)
:AddChildrenWithFunction(private.CreateSourceRows)
)
:SetRightChild(UIElements.New("Frame", "mats")
:SetLayout("VERTICAL")
:SetBackgroundColor("PRIMARY_BG_ALT")
:AddChild(UIElements.New("Text", "title")
:SetHeight(20)
:SetMargin(0, 0, 8, 8)
:SetFont("BODY_BODY1_BOLD")
:SetJustifyH("CENTER")
:SetText(L["Materials to Gather"])
)
:AddChild(UIElements.New("QueryScrollingTable", "table")
:SetSettingsContext(private.settings, "gatheringScrollingTable")
:GetScrollingTableInfo()
:NewColumn("name")
:SetTitle(NAME)
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetIconSize(12)
:SetTextInfo("itemString", TSM.UI.GetColoredItemName)
:SetIconInfo("itemString", ItemInfo.GetTexture)
:SetTooltipInfo("itemString")
:SetSortInfo("name")
:DisableHiding()
:Commit()
:NewColumn("sources")
:SetTitle(L["Sources"])
:SetFont("BODY_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("sourcesStr", private.MatsGetSourcesStrText)
:SetSortInfo("sourcesStr")
:Commit()
:NewColumn("have")
:SetTitle(L["Have"])
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetTextInfo("numHave")
:SetSortInfo("numHave")
:Commit()
:NewColumn("need")
:SetTitle(NEED)
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetTextInfo("numNeed")
:SetSortInfo("numNeed")
:Commit()
:Commit()
:SetQuery(TSM.Crafting.Gathering.CreateQuery()
:InnerJoin(ItemInfo.GetDBForJoin(), "itemString")
:OrderBy("name", true)
)
:SetSelectionDisabled(true)
:SetAutoReleaseQuery(true)
)
:AddChild(UIElements.New("Texture", "headerTopLine")
:SetHeight(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("ActionButton", "openTaskListBtn")
:SetHeight(26)
:SetMargin(8)
:SetScript("OnClick", TSM.UI.TaskListUI.Toggle)
)
)
:SetScript("OnUpdate", private.FrameOnUpdate)
:SetScript("OnHide", private.FrameOnHide)
private.frame = frame
return frame
end
function private.MatsGetSourcesStrText(str)
str = gsub(str, "/[^,]+", "")
for i = 1, #SOURCE_LIST do
str = gsub(str, SOURCE_LIST[i], SOURCE_TEXT_LIST[i])
end
return str
end
function private.CreateSourceRows(frame)
for i = 1, #SOURCE_LIST do
frame:AddChild(UIElements.New("Frame", "sourceFrame"..i)
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, 8, 0)
:AddChild(UIElements.New("Text", "label")
:SetFont("BODY_BODY3_MEDIUM")
:SetTextColor((i > #private.settings.sources + 1) and "TEXT_ALT+DISABLED" or "TEXT_ALT")
:SetFormattedText(L["SOURCE %d"], i)
)
:AddChild(UIElements.New("SelectionDropdown", "dropdown")
:SetWidth(188)
:SetContext(i)
:SetHintText(L["Select a Source"])
:SetScript("OnSelectionChanged", private.SourceDropdownOnSelectionChanged)
)
)
end
private.UpdateSourceRows(frame)
end
function private.UpdateSourceRows(setupFrame)
if TSM.IsWowClassic() then
Table.RemoveByValue(private.settings.sources, "guildBank")
Table.RemoveByValue(private.settings.sources, "altGuildBank")
end
local texts = TempTable.Acquire()
local sources = TempTable.Acquire()
for i = 1, #SOURCE_LIST do
wipe(texts)
wipe(sources)
for j = 1, #SOURCE_LIST do
local index = Table.KeyByValue(private.settings.sources, SOURCE_LIST[j])
if not index or index >= i then
tinsert(texts, SOURCE_TEXT_LIST[j])
tinsert(sources, SOURCE_LIST[j])
end
end
if i <= #private.settings.sources then
tinsert(texts, "<"..strupper(REMOVE)..">")
tinsert(sources, "")
end
setupFrame:GetElement("sourceFrame"..i..".label")
:SetTextColor((i > #private.settings.sources + 1) and "TEXT_ALT+DISABLED" or "TEXT_ALT")
setupFrame:GetElement("sourceFrame"..i..".dropdown")
:SetItems(texts, sources)
:SetDisabled(i > #private.settings.sources + 1)
:SetHintText(L["Select a Source"])
:SetSelectedItemByKey(private.settings.sources[i], true)
end
TempTable.Release(texts)
TempTable.Release(sources)
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.FrameOnUpdate(frame)
private.UpdateButtonState()
frame:SetScript("OnUpdate", nil)
private.ContextChangedCallback()
end
function private.FrameOnHide(frame)
assert(frame == private.frame)
private.frame = nil
private.query:Release()
private.query = nil
end
function private.CrafterDropdownOnSelectionChanged(dropdown)
TSM.Crafting.Gathering.SetCrafter(dropdown:GetSelectedItem() or "")
dropdown:GetElement("__parent.professionDropdown")
:SetItems(TSM.Crafting.Gathering.GetProfessionList())
:SetSelectedItems(TSM.Crafting.Gathering.GetProfessions())
:Draw()
end
function private.ProfessionDropdownOnSelectionChanged(dropdown)
local professions = TempTable.Acquire()
dropdown:GetSelectedItems(professions)
TSM.Crafting.Gathering.SetProfessions(professions)
TempTable.Release(professions)
end
function private.SourceDropdownOnSelectionChanged(dropdown)
local index = dropdown:GetContext()
local source = dropdown:GetSelectedItemKey()
if source == "" then
tremove(private.settings.sources, index)
else
private.settings.sources[index] = source
for i = #private.settings.sources, index + 1, -1 do
if private.settings.sources[i] == source then
tremove(private.settings.sources, i)
end
end
end
local setupFrame = dropdown:GetParentElement():GetParentElement()
private.UpdateSourceRows(setupFrame)
setupFrame:Draw()
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.ContextChangedCallback()
if not private.frame then
return
end
private.frame:GetElement("setup.crafterDropdown")
:SetItems(TSM.Crafting.Gathering.GetCrafterList())
:SetSelectedItem(TSM.Crafting.Gathering.GetCrafter())
:Draw()
private.frame:GetElement("setup.professionDropdown")
:SetItems(TSM.Crafting.Gathering.GetProfessionList())
:SetSelectedItems(TSM.Crafting.Gathering.GetProfessions())
:Draw()
end
function private.UpdateButtonState()
if not private.frame then
return
end
local button = private.frame:GetElement("mats.openTaskListBtn")
if private.query:Count() == 0 then
button:SetText(L["No Materials to Gather"])
button:SetDisabled(true)
elseif TSM.UI.TaskListUI.IsVisible() then
button:SetText(L["Tasks Added to Task List"])
button:SetDisabled(true)
else
button:SetText(L["Open Task List"])
button:SetDisabled(false)
end
button:Draw()
end