-- ------------------------------------------------------------------------------ -- -- 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