TradeSkillMaster/Core/UI/BankingUI/Core.lua

557 lines
18 KiB
Lua

-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local BankingUI = TSM.UI:NewPackage("BankingUI")
local L = TSM.Include("Locale").GetTable()
local FSM = TSM.Include("Util.FSM")
local TempTable = TSM.Include("Util.TempTable")
local Log = TSM.Include("Util.Log")
local Settings = TSM.Include("Service.Settings")
local UIElements = TSM.Include("UI.UIElements")
local private = {
settings = nil,
fsm = nil,
groupSearch = "",
}
local MIN_FRAME_SIZE = { width = 325, height = 600 }
local MODULE_LIST = {
"Warehousing",
"Auctioning",
"Mailing",
}
local BUTTON_TEXT_LOOKUP = {
Warehousing = L["Warehousing"],
Auctioning = L["Auctioning"],
Mailing = L["Mailing"],
}
-- ============================================================================
-- Module Functions
-- ============================================================================
function BankingUI.OnInitialize()
private.settings = Settings.NewView()
:AddKey("global", "bankingUIContext", "frame")
:AddKey("global", "bankingUIContext", "isOpen")
:AddKey("global", "bankingUIContext", "tab")
:AddKey("char", "bankingUIContext", "warehousingGroupTree")
:AddKey("char", "bankingUIContext", "auctioningGroupTree")
:AddKey("char", "bankingUIContext", "mailingGroupTree")
private.FSMCreate()
end
function BankingUI.OnDisable()
-- hide the frame
private.fsm:ProcessEvent("EV_BANK_CLOSED")
end
function BankingUI.Toggle()
private.fsm:ProcessEvent("EV_TOGGLE")
end
-- ============================================================================
-- Main Frame
-- ============================================================================
function private.CreateMainFrame()
TSM.UI.AnalyticsRecordPathChange("banking")
local frame = UIElements.New("ApplicationFrame", "base")
:SetParent(UIParent)
:SetSettingsContext(private.settings, "frame")
:SetMinResize(MIN_FRAME_SIZE.width, MIN_FRAME_SIZE.height)
:SetStrata("HIGH")
:SetTitle(L["Banking"])
:SetScript("OnHide", private.BaseFrameOnHide)
:SetContentFrame(UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Frame", "navButtons")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(8)
:SetPadding(-4, 0, 0, 0) -- account for the left margin of the first button
)
:AddChild(UIElements.New("Frame", "search")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8, 8, 0, 12)
:AddChild(UIElements.New("Input", "input")
:SetIconTexture("iconPack.18x18/Search")
:AllowItemInsert(true)
:SetClearButtonEnabled(true)
:SetValue(private.groupSearch)
:SetHintText(L["Search Groups"])
:SetScript("OnValueChanged", private.GroupSearchOnValueChanged)
)
:AddChild(UIElements.New("Button", "expandAllBtn")
:SetSize(24, 24)
:SetMargin(8, 4, 0, 0)
:SetBackground("iconPack.18x18/Expand All")
:SetScript("OnClick", private.ExpandAllGroupsOnClick)
:SetTooltip(L["Expand / Collapse All Groups"])
)
:AddChild(UIElements.New("Button", "selectAllBtn")
:SetSize(24, 24)
:SetBackground("iconPack.18x18/Select All")
:SetScript("OnClick", private.SelectAllGroupsOnClick)
:SetTooltip(L["Select / Deselect All Groups"])
)
)
:AddChild(UIElements.New("ApplicationGroupTree", "groupTree")
:SetSettingsContext(private.settings, private.GetSettingsContextKey())
:SetQuery(TSM.Groups.CreateQuery(), private.settings.tab)
:SetSearchString(private.groupSearch)
)
:AddChild(UIElements.New("Texture", "line")
:SetHeight(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Frame", "footer")
:SetLayout("VERTICAL")
:SetHeight(170)
:SetPadding(8)
:SetBackgroundColor("PRIMARY_BG_ALT")
:AddChild(UIElements.New("ProgressBar", "progressBar")
:SetHeight(24)
:SetProgress(0)
:SetProgressIconHidden(true)
:SetText(L["Select Action"])
)
:AddChild(UIElements.New("Frame", "buttons")
:SetLayout("VERTICAL")
)
)
)
frame:GetElement("titleFrame.closeBtn"):SetScript("OnClick", private.CloseBtnOnClick)
for _, module in ipairs(MODULE_LIST) do
frame:GetElement("content.navButtons"):AddChild(UIElements.New("ActionButton", "navBtn_"..module)
:SetHeight(20)
:SetMargin(4, 0, 0, 0)
:SetFont("BODY_BODY3_MEDIUM")
:SetContext(module)
:SetText(BUTTON_TEXT_LOOKUP[module])
:SetScript("OnClick", private.NavBtnOnClick)
)
end
private.UpdateCurrentModule(frame)
return frame
end
function private.GetSettingsContextKey()
if private.settings.tab == "Warehousing" then
return "warehousingGroupTree"
elseif private.settings.tab == "Auctioning" then
return "auctioningGroupTree"
elseif private.settings.tab == "Mailing" then
return "mailingGroupTree"
else
error("Unexpected tab: "..tostring(private.settings.tab))
end
end
function private.UpdateCurrentModule(frame)
if not TSM.IsWowClassic() then
ReagentBankFrame_OnShow(ReagentBankFrame)
end
-- update nav buttons
local navButtonsFrame = frame:GetElement("content.navButtons")
for _, module in ipairs(MODULE_LIST) do
navButtonsFrame:GetElement("navBtn_"..module)
:SetPressed(module == private.settings.tab)
end
navButtonsFrame:Draw()
-- update group tree
frame:GetElement("content.groupTree")
:SetSettingsContext(private.settings, private.GetSettingsContextKey())
:SetQuery(TSM.Groups.CreateQuery(), private.settings.tab)
:UpdateData(true)
:Draw()
-- update footer buttons
local footerButtonsFrame = frame:GetElement("content.footer.buttons")
footerButtonsFrame:ReleaseAllChildren()
if private.settings.tab == "Warehousing" then
footerButtonsFrame:AddChild(UIElements.New("Frame", "row1")
:SetLayout("HORIZONTAL")
:AddChild(UIElements.New("ActionButton", "moveBankBtn")
:SetHeight(24)
:SetMargin(0, 8, 8, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Move to bank"])
:SetContext(TSM.Banking.Warehousing.MoveGroupsToBank)
:SetScript("OnClick", private.GroupBtnOnClick)
)
:AddChild(UIElements.New("ActionButton", "moveBagsBtn")
:SetHeight(24)
:SetMargin(0, 0, 8, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Move to bags"])
:SetContext(TSM.Banking.Warehousing.MoveGroupsToBags)
:SetScript("OnClick", private.GroupBtnOnClick)
)
)
footerButtonsFrame:AddChild(UIElements.New("ActionButton", "restockBagsBtn")
:SetHeight(24)
:SetMargin(0, 0, 8, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Restock bags"])
:SetContext(TSM.Banking.Warehousing.RestockBags)
:SetScript("OnClick", private.GroupBtnOnClick)
)
footerButtonsFrame:AddChild(UIElements.New("ActionButton", "depositReagentsBtn")
:SetHeight(24)
:SetMargin(0, 0, 8, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetDisabled(TSM.IsWowClassic())
:SetText(L["Deposit reagents"])
:SetScript("OnClick", private.WarehousingDepositReagentsBtnOnClick)
)
footerButtonsFrame:AddChild(UIElements.New("Frame", "row4")
:SetLayout("HORIZONTAL")
:AddChild(UIElements.New("ActionButton", "emptyBagsBtn")
:SetHeight(24)
:SetMargin(0, 8, 8, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Empty bags"])
:SetContext(TSM.Banking.EmptyBags)
:SetScript("OnClick", private.SimpleBtnOnClick)
)
:AddChild(UIElements.New("ActionButton", "restoreBagsBtn")
:SetHeight(24)
:SetMargin(0, 0, 8, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Restore bags"])
:SetContext(TSM.Banking.RestoreBags)
:SetScript("OnClick", private.SimpleBtnOnClick)
)
)
elseif private.settings.tab == "Auctioning" then
footerButtonsFrame:AddChild(UIElements.New("ActionButton", "moveBankBtn")
:SetHeight(24)
:SetMargin(0, 0, 8, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Move to bank"])
:SetContext(TSM.Banking.Auctioning.MoveGroupsToBank)
:SetScript("OnClick", private.GroupBtnOnClick)
)
footerButtonsFrame:AddChild(UIElements.New("ActionButton", "postCapBagsBtn")
:SetHeight(24)
:SetMargin(0, 0, 8, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Post cap to bags"])
:SetContext(TSM.Banking.Auctioning.PostCapToBags)
:SetScript("OnClick", private.GroupBtnOnClick)
)
footerButtonsFrame:AddChild(UIElements.New("ActionButton", "shortfallBagsBtn")
:SetHeight(24)
:SetMargin(0, 0, 8, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Shortfall to bags"])
:SetContext(TSM.Banking.Auctioning.ShortfallToBags)
:SetScript("OnClick", private.GroupBtnOnClick)
)
footerButtonsFrame:AddChild(UIElements.New("ActionButton", "maxExpBankBtn")
:SetHeight(24)
:SetMargin(0, 0, 8, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Max expires to bank"])
:SetContext(TSM.Banking.Auctioning.MaxExpiresToBank)
:SetScript("OnClick", private.GroupBtnOnClick)
)
elseif private.settings.tab == "Mailing" then
footerButtonsFrame:AddChild(UIElements.New("ActionButton", "moveBankBtn")
:SetHeight(24)
:SetMargin(0, 0, 8, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Move to bank"])
:SetContext(TSM.Banking.Mailing.MoveGroupsToBank)
:SetScript("OnClick", private.GroupBtnOnClick)
)
footerButtonsFrame:AddChild(UIElements.New("ActionButton", "nongroupBankBtn")
:SetHeight(24)
:SetMargin(0, 0, 8, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Nongroup to bank"])
:SetContext(TSM.Banking.Mailing.NongroupToBank)
:SetScript("OnClick", private.SimpleBtnOnClick)
)
footerButtonsFrame:AddChild(UIElements.New("ActionButton", "targetShortfallBagsBtn")
:SetHeight(24)
:SetMargin(0, 0, 8, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Target shortfall to bags"])
:SetContext(TSM.Banking.Mailing.TargetShortfallToBags)
:SetScript("OnClick", private.GroupBtnOnClick)
)
footerButtonsFrame:AddChild(UIElements.New("Frame", "row4")
:SetLayout("HORIZONTAL")
:AddChild(UIElements.New("ActionButton", "emptyBagsBtn")
:SetHeight(24)
:SetMargin(0, 8, 8, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Empty bags"])
:SetContext(TSM.Banking.EmptyBags)
:SetScript("OnClick", private.SimpleBtnOnClick)
)
:AddChild(UIElements.New("ActionButton", "restoreBagsBtn")
:SetHeight(24)
:SetMargin(0, 0, 8, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Restore bags"])
:SetContext(TSM.Banking.RestoreBags)
:SetScript("OnClick", private.SimpleBtnOnClick)
)
)
else
error("Unexpected module: "..tostring(private.settings.tab))
end
footerButtonsFrame:Draw()
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.BaseFrameOnHide()
TSM.UI.AnalyticsRecordClose("banking")
end
function private.CloseBtnOnClick(button)
Log.PrintUser(L["Hiding the TSM Banking UI. Type '/tsm bankui' to reopen it."])
button:GetParentElement():Hide()
private.fsm:ProcessEvent("EV_FRAME_HIDDEN")
end
function private.GroupSearchOnValueChanged(input)
private.groupSearch = strlower(input:GetValue())
input:GetElement("__parent.__parent.groupTree")
:SetSearchString(private.groupSearch)
:Draw()
end
function private.NavBtnOnClick(button)
private.settings.tab = button:GetContext()
private.UpdateCurrentModule(button:GetBaseElement())
private.fsm:ProcessEvent("EV_NAV_CHANGED")
end
function private.ExpandAllGroupsOnClick(button)
button:GetElement("__parent.__parent.groupTree")
:ToggleExpandAll()
end
function private.SelectAllGroupsOnClick(button)
button:GetElement("__parent.__parent.groupTree")
:ToggleSelectAll()
end
function private.WarehousingDepositReagentsBtnOnClick()
DepositReagentBank()
end
function private.SimpleBtnOnClick(button)
private.fsm:ProcessEvent("EV_BUTTON_CLICKED", button, button:GetContext())
end
function private.GroupBtnOnClick(button)
local groups = TempTable.Acquire()
for _, groupPath in button:GetElement("__base.content.groupTree"):SelectedGroupsIterator() do
groups[groupPath] = true
end
private.fsm:ProcessEvent("EV_BUTTON_CLICKED", button, button:GetContext(), groups)
TempTable.Release(groups)
end
-- ============================================================================
-- FSM
-- ============================================================================
function private.FSMCreate()
TSM.Banking.RegisterFrameCallback(function(openFrame)
private.fsm:ProcessEvent(openFrame and "EV_BANK_OPENED" or "EV_BANK_CLOSED")
end)
local fsmContext = {
frame = nil,
progress = nil,
activeButton = nil,
}
local function UpdateFrame(context)
if context.activeButton and not context.progress then
context.activeButton
:SetPressed(false)
:Draw()
context.activeButton = nil
end
-- update the nav button state
local navButtonsFrame = context.frame:GetElement("content.navButtons")
for _, module in ipairs(MODULE_LIST) do
navButtonsFrame:GetElement("navBtn_"..module)
:SetDisabled(context.progress)
end
navButtonsFrame:Draw()
-- update the progress bar
context.frame:GetElement("content.footer.progressBar")
:SetProgress(context.progress or 0)
:SetProgressIconHidden(not context.progress)
:SetText(context.progress and L["Moving"] or L["Select Action"])
:Draw()
-- update the action button state
local footerButtonsFrame = context.frame:GetElement("content.footer.buttons")
if private.settings.tab == "Warehousing" then
footerButtonsFrame:GetElement("row1.moveBankBtn")
:SetDisabled(context.progress)
footerButtonsFrame:GetElement("row1.moveBagsBtn")
:SetDisabled(context.progress)
footerButtonsFrame:GetElement("restockBagsBtn")
:SetDisabled(context.progress)
footerButtonsFrame:GetElement("depositReagentsBtn")
:SetDisabled(context.progress or TSM.IsWowClassic())
footerButtonsFrame:GetElement("row4.emptyBagsBtn")
:SetDisabled(context.progress)
footerButtonsFrame:GetElement("row4.restoreBagsBtn")
:SetDisabled(context.progress or not TSM.Banking.CanRestoreBags())
elseif private.settings.tab == "Auctioning" then
footerButtonsFrame:GetElement("moveBankBtn")
:SetDisabled(context.progress)
footerButtonsFrame:GetElement("postCapBagsBtn")
:SetDisabled(context.progress)
footerButtonsFrame:GetElement("shortfallBagsBtn")
:SetDisabled(context.progress)
footerButtonsFrame:GetElement("maxExpBankBtn")
:SetDisabled(context.progress)
elseif private.settings.tab == "Mailing" then
footerButtonsFrame:GetElement("moveBankBtn")
:SetDisabled(context.progress)
footerButtonsFrame:GetElement("nongroupBankBtn")
:SetDisabled(context.progress)
footerButtonsFrame:GetElement("targetShortfallBagsBtn")
:SetDisabled(context.progress)
footerButtonsFrame:GetElement("row4.emptyBagsBtn")
:SetDisabled(context.progress)
footerButtonsFrame:GetElement("row4.restoreBagsBtn")
:SetDisabled(context.progress or not TSM.Banking.CanRestoreBags())
else
error("Unexpected module: "..tostring(private.settings.tab))
end
footerButtonsFrame:Draw()
end
private.fsm = FSM.New("BANKING_UI")
:AddState(FSM.NewState("ST_CLOSED")
:SetOnEnter(function(context)
if context.frame then
context.frame:Hide()
context.frame:Release()
context.frame = nil
end
context.activeButton = nil
end)
:AddTransition("ST_CLOSED")
:AddTransition("ST_FRAME_OPEN")
:AddTransition("ST_FRAME_HIDDEN")
:AddEvent("EV_BANK_OPENED", function(context)
assert(not context.frame)
if not private.settings.isOpen then
return "ST_FRAME_HIDDEN"
end
return "ST_FRAME_OPEN"
end)
)
:AddState(FSM.NewState("ST_FRAME_HIDDEN")
:SetOnEnter(function(context)
private.settings.isOpen = false
if context.frame then
context.frame:Hide()
context.frame:Release()
context.frame = nil
end
context.activeButton = nil
end)
:AddTransition("ST_FRAME_OPEN")
:AddTransition("ST_CLOSED")
:AddEvent("EV_TOGGLE", function()
private.settings.isOpen = true
return "ST_FRAME_OPEN"
end)
)
:AddState(FSM.NewState("ST_FRAME_OPEN")
:SetOnEnter(function(context)
if not context.frame then
context.frame = private.CreateMainFrame()
context.frame:Show()
context.frame:Draw()
end
UpdateFrame(context)
end)
:AddTransition("ST_FRAME_OPEN")
:AddTransition("ST_FRAME_HIDDEN")
:AddTransition("ST_PROCESSING")
:AddTransition("ST_CLOSED")
:AddEventTransition("EV_BUTTON_CLICKED", "ST_PROCESSING")
:AddEventTransition("EV_TOGGLE", "ST_FRAME_HIDDEN")
:AddEventTransition("EV_FRAME_HIDDEN", "ST_FRAME_HIDDEN")
:AddEventTransition("EV_NAV_CHANGED", "ST_FRAME_OPEN")
)
:AddState(FSM.NewState("ST_PROCESSING")
:SetOnEnter(function(context, button, startFunc, ...)
context.activeButton = button
context.activeButton
:SetPressed(true)
:Draw()
context.progress = 0
startFunc(private.FSMThreadCallback, ...)
UpdateFrame(context)
end)
:SetOnExit(function(context)
context.progress = nil
end)
:AddTransition("ST_FRAME_OPEN")
:AddTransition("ST_FRAME_HIDDEN")
:AddTransition("ST_CLOSED")
:AddEvent("EV_THREAD_PROGRESS", function(context, progress)
context.progress = progress
UpdateFrame(context)
end)
:AddEvent("EV_THREAD_DONE", function(context)
if context.progress == 0 then
Log.PrintUser(L["Nothing to move."])
end
return "ST_FRAME_OPEN"
end)
:AddEventTransition("EV_TOGGLE", "ST_FRAME_HIDDEN")
)
:AddDefaultEventTransition("EV_BANK_CLOSED", "ST_CLOSED")
:Init("ST_CLOSED", fsmContext)
end
function private.FSMThreadCallback(event, ...)
if event == "PROGRESS" then
private.fsm:ProcessEvent("EV_THREAD_PROGRESS", ...)
elseif event == "DONE" then
private.fsm:ProcessEvent("EV_THREAD_DONE")
elseif event == "MOVED" then
-- ignore this event
else
error("Unexpected event: "..tostring(event))
end
end