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

91
Core/UI/MainUI/Core.lua Normal file
View File

@@ -0,0 +1,91 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local MainUI = TSM:NewPackage("MainUI")
local Settings = TSM.Include("Service.Settings")
local UIElements = TSM.Include("UI.UIElements")
local private = {
settings = nil,
topLevelPages = {},
frame = nil,
}
local MIN_FRAME_SIZE = { width = 720, height = 588 }
-- ============================================================================
-- Module Functions
-- ============================================================================
function MainUI.OnInitialize()
private.settings = Settings.NewView()
:AddKey("global", "mainUIContext", "frame")
end
function MainUI.OnDisable()
-- hide the frame
if private.frame then
MainUI.Toggle()
end
end
function MainUI.RegisterTopLevelPage(name, callback)
tinsert(private.topLevelPages, { name = name, callback = callback })
end
function MainUI.Toggle()
if private.frame then
-- it's already shown, so hide it
private.frame:Hide()
assert(not private.frame)
else
private.frame = private.CreateMainFrame()
private.frame:Draw()
private.frame:Show()
end
end
-- ============================================================================
-- Main Frame
-- ============================================================================
function private.CreateMainFrame()
TSM.UI.AnalyticsRecordPathChange("main")
-- Always show the Dashboard first
private.settings.frame.page = 1
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()
:SetScript("OnHide", private.BaseFrameOnHide)
for _, info in ipairs(private.topLevelPages) do
frame:AddNavButton(info.name, info.callback)
end
local whatsNewDialog = TSM.UI.WhatsNew.GetDialog()
if whatsNewDialog then
frame:ShowDialogFrame(whatsNewDialog)
end
return frame
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.BaseFrameOnHide(frame)
assert(frame == private.frame)
frame:Release()
private.frame = nil
TSM.UI.AnalyticsRecordClose("main")
end

View File

@@ -0,0 +1,936 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Dashboard = TSM.MainUI:NewPackage("Dashboard")
local L = TSM.Include("Locale").GetTable()
local TempTable = TSM.Include("Util.TempTable")
local Money = TSM.Include("Util.Money")
local Math = TSM.Include("Util.Math")
local Theme = TSM.Include("Util.Theme")
local Analytics = TSM.Include("Util.Analytics")
local Settings = TSM.Include("Service.Settings")
local UIElements = TSM.Include("UI.UIElements")
local private = {
settings = nil,
characterGuilds = {},
tempTimeTable = {},
selectedTimeRange = nil,
}
local SECONDS_PER_DAY = 60 * 60 * 24
local MIN_GRAPH_STEP_SIZE = TSM.IsWowClassic() and COPPER_PER_GOLD or (COPPER_PER_GOLD * 1000)
local TIME_RANGE_LOOKUP = {
["1d"] = SECONDS_PER_DAY,
["1w"] = SECONDS_PER_DAY * 7,
["1m"] = SECONDS_PER_DAY * 30,
["3m"] = SECONDS_PER_DAY * 91,
["6m"] = SECONDS_PER_DAY * 183,
["1y"] = SECONDS_PER_DAY * 365,
["2y"] = SECONDS_PER_DAY * 730,
["all"] = -1,
}
-- ============================================================================
-- Module Functions
-- ============================================================================
function Dashboard.OnInitialize()
private.settings = Settings.NewView()
:AddKey("global", "mainUIContext", "dashboardDividedContainer")
:AddKey("global", "mainUIContext", "dashboardUnselectedCharacters")
:AddKey("global", "mainUIContext", "dashboardTimeRange")
private.selectedTimeRange = private.settings.dashboardTimeRange
TSM.MainUI.RegisterTopLevelPage(L["Dashboard"], private.GetDashboardFrame)
end
-- ============================================================================
-- Dashboard UI
-- ============================================================================
function private.GetDashboardFrame()
TSM.UI.AnalyticsRecordPathChange("main", "dashboard")
private.selectedTimeRange = private.settings.dashboardTimeRange
wipe(private.characterGuilds)
local prevUnselectedCharacters = TempTable.Acquire()
for characterGuild in pairs(private.settings.dashboardUnselectedCharacters) do
prevUnselectedCharacters[characterGuild] = true
end
wipe(private.settings.dashboardUnselectedCharacters)
for characterGuild in TSM.Accounting.GoldTracker.CharacterGuildIterator() do
tinsert(private.characterGuilds, characterGuild)
private.settings.dashboardUnselectedCharacters[characterGuild] = prevUnselectedCharacters[characterGuild] or nil
end
TempTable.Release(prevUnselectedCharacters)
local frame = UIElements.New("DividedContainer", "dashboard")
:SetSettingsContext(private.settings, "dashboardDividedContainer")
:SetMinWidth(200, 407)
:SetBackgroundColor("PRIMARY_BG")
:SetLeftChild(UIElements.New("Frame", "news")
:SetLayout("VERTICAL")
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Text", "text")
:SetSize("AUTO", 24)
:SetMargin(8)
:SetFont("BODY_BODY1_BOLD")
:SetText(L["News & Information"])
)
:AddChild(UIElements.New("ScrollFrame", "content")
:SetPadding(8, 8, 0, 0)
)
)
:SetRightChild(UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
:SetPadding(8)
:SetBackgroundColor("PRIMARY_BG")
:SetScript("OnUpdate", private.ContentOnUpdate)
:AddChild(UIElements.New("Frame", "goldHeader")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("Text", "text")
:SetWidth("AUTO")
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY1_BOLD")
:SetText(L["Player Gold"])
)
:AddChild(UIElements.New("MultiselectionDropdown", "playerDropdown")
:SetSize(157, 22)
:SetItems(private.characterGuilds, private.characterGuilds)
:SetUnselectedItemKeys(private.settings.dashboardUnselectedCharacters)
:SetSelectionText(L["No Players"], L["%d Players"], L["All Players"])
:SetScript("OnSelectionChanged", private.DropdownOnSelectionChanged)
)
:AddChild(UIElements.New("Spacer"))
:AddChild(UIElements.New("Text", "hoverTime")
:SetWidth("AUTO")
:SetFont("BODY_BODY3_MEDIUM")
:SetText("")
)
:AddChild(UIElements.New("Frame", "timeBtns")
:SetLayout("HORIZONTAL")
:AddChild(UIElements.New("Button", "1d")
:SetMargin(8, 0, 0, 0)
:SetSize(20, 20)
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetContext(TIME_RANGE_LOOKUP["1d"])
:SetText(L["1D"])
:SetScript("OnClick", private.TimeBtnOnClick)
)
:AddChild(UIElements.New("Button", "1w")
:SetMargin(8, 0, 0, 0)
:SetSize(20, 20)
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetContext(TIME_RANGE_LOOKUP["1w"])
:SetText(L["1W"])
:SetScript("OnClick", private.TimeBtnOnClick)
)
:AddChild(UIElements.New("Button", "1m")
:SetMargin(8, 0, 0, 0)
:SetSize(20, 20)
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetContext(TIME_RANGE_LOOKUP["1m"])
:SetText(L["1M"])
:SetScript("OnClick", private.TimeBtnOnClick)
)
:AddChild(UIElements.New("Button", "3m")
:SetMargin(8, 0, 0, 0)
:SetSize(20, 20)
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetContext(TIME_RANGE_LOOKUP["3m"])
:SetText(L["3M"])
:SetScript("OnClick", private.TimeBtnOnClick)
)
:AddChild(UIElements.New("Button", "6m")
:SetMargin(8, 0, 0, 0)
:SetSize(20, 20)
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetContext(TIME_RANGE_LOOKUP["6m"])
:SetText(L["6M"])
:SetScript("OnClick", private.TimeBtnOnClick)
)
:AddChild(UIElements.New("Button", "1y")
:SetMargin(8, 0, 0, 0)
:SetSize(20, 20)
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetContext(TIME_RANGE_LOOKUP["1y"])
:SetText(L["1Y"])
:SetScript("OnClick", private.TimeBtnOnClick)
)
:AddChild(UIElements.New("Button", "2y")
:SetMargin(8, 0, 0, 0)
:SetSize(20, 20)
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetContext(TIME_RANGE_LOOKUP["2y"])
:SetText(L["2Y"])
:SetScript("OnClick", private.TimeBtnOnClick)
)
:AddChild(UIElements.New("Button", "all")
:SetMargin(8, 0, 0, 0)
:SetSize(20, 20)
:SetFont("TABLE_TABLE1")
:SetTextColor("TEXT")
:SetContext(TIME_RANGE_LOOKUP["all"])
:SetText(ALL)
:SetScript("OnClick", private.TimeBtnOnClick)
)
:AddChild(UIElements.New("Button", "resetZoom")
:SetMargin(8, 0, 0, 0)
:SetSize(100, 20)
:SetFont("TABLE_TABLE1")
:SetTextColor("TEXT")
:SetContext(TIME_RANGE_LOOKUP["all"])
:SetText(L["Reset Zoom"])
:SetScript("OnClick", private.TimeBtnOnClick)
)
)
)
:AddChild(UIElements.New("Graph", "goldGraph")
:SetMargin(0, 0, 8, 8)
:SetAxisStepFunctions(private.GraphXStepFunc, private.GraphYStepFunc)
:SetXRange(TSM.Accounting.GoldTracker.GetGraphTimeRange(private.settings.dashboardUnselectedCharacters))
:SetYValueFunction(private.GetGraphYValue)
:SetFormatFunctions(private.GraphFormatX, private.GraphFormatY)
:SetScript("OnZoomChanged", private.GraphOnZoomChanged)
:SetScript("OnHoverUpdate", private.GraphOnHoverUpdate)
)
:AddChild(UIElements.New("Frame", "summary")
:SetLayout("HORIZONTAL")
:SetHeight(48)
:SetBackgroundColor("PRIMARY_BG_ALT", true)
:AddChild(UIElements.New("Frame", "range")
:SetLayout("VERTICAL")
:SetPadding(8, 8, 2, 2)
:AddChild(UIElements.New("Frame", "high")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetText(L["HIGH"])
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "value")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
)
)
:AddChild(UIElements.New("Frame", "low")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetText(L["LOW"])
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "value")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
)
)
)
:AddChild(UIElements.New("Texture", "line1")
:SetWidth(1)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Frame", "daily")
:SetLayout("VERTICAL")
:SetPadding(8, 8, 2, 2)
:AddChild(UIElements.New("Frame", "sales")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetText(L["DAILY SALES"])
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "value")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
)
)
:AddChild(UIElements.New("Frame", "purchases")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetText(L["DAILY PURCHASES"])
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "value")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
)
)
)
:AddChild(UIElements.New("Texture", "line2")
:SetWidth(1)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Frame", "top")
:SetLayout("VERTICAL")
:SetPadding(8, 8, 2, 2)
:AddChild(UIElements.New("Frame", "sale")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetText(L["TOP SALE"])
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "value")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
)
)
:AddChild(UIElements.New("Frame", "expense")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetText(L["TOP PURCHASE"])
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "value")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
)
)
)
)
:AddChild(UIElements.New("Frame", "details")
:SetLayout("VERTICAL")
:SetMargin(0, 0, 8, 0)
:SetPadding(8)
:SetBackgroundColor("PRIMARY_BG_ALT", true)
:AddChild(UIElements.New("Text", "salesLabel")
:SetHeight(20)
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetText(L["SALES"])
)
:AddChild(UIElements.New("Frame", "salesTotal")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Text", "text")
:SetWidth("AUTO")
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["Total Gold Earned"]..":")
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "amount")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
)
)
:AddChild(UIElements.New("Frame", "salesAvg")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 4, 0)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["Average Earned per Day"]..":")
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "amount")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
)
)
:AddChild(UIElements.New("Frame", "salesTop")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 4, 0)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["Top Item"]..":")
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Button", "item")
:SetWidth("AUTO")
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
)
)
:AddChild(UIElements.New("Texture", "line1")
:SetHeight(1)
:SetMargin(-8, -8, 4, 4)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Text", "expensesLabel")
:SetHeight(20)
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetText(L["EXPENSES"])
)
:AddChild(UIElements.New("Frame", "expensesTotal")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Text", "text")
:SetWidth("AUTO")
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["Total Gold Spent"]..":")
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "amount")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
)
)
:AddChild(UIElements.New("Frame", "expensesAvg")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 4, 0)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["Average Spent per Day"]..":")
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "amount")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
)
)
:AddChild(UIElements.New("Frame", "expensesTop")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 4, 0)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["Top Item"]..":")
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Button", "item")
:SetWidth("AUTO")
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
)
)
:AddChild(UIElements.New("Texture", "line2")
:SetHeight(1)
:SetMargin(-8, -8, 4, 4)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Text", "profitLabel")
:SetHeight(20)
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetText(L["PROFIT"])
)
:AddChild(UIElements.New("Frame", "profitTotal")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Text", "text")
:SetWidth("AUTO")
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["Total Profit"]..":")
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "amount")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
)
)
:AddChild(UIElements.New("Frame", "profitAvg")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 4, 0)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["Average Profit per Day"]..":")
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "amount")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
)
)
:AddChild(UIElements.New("Frame", "profitTop")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 4, 0)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["Top Item"]..":")
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Button", "item")
:SetWidth("AUTO")
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
)
)
)
)
frame:GetElement("content.goldHeader.timeBtns.resetZoom"):Hide()
frame:GetElement("content.goldHeader.hoverTime"):Hide()
local newsContent = frame:GetElement("news.content")
local newsEntries = TSM.GetAppNews()
if newsEntries then
for i, info in ipairs(newsEntries) do
newsContent:AddChild(UIElements.New("Frame", "news"..i)
:SetLayout("VERTICAL")
:SetPadding(0, 0, i == 1 and 6 or 12, 0)
:AddChild(UIElements.New("Text", "date")
:SetHeight(20)
:SetFont("BODY_BODY3")
:SetText(date("%b %d, %Y", info.timestamp))
)
:AddChild(UIElements.New("Text", "title")
:SetHeight(20)
:SetFont("BODY_BODY2_BOLD")
:SetText(info.title)
)
:AddChild(UIElements.New("Text", "content")
:SetHeight(80)
:SetPadding(0, 0, 4, 0)
:SetFont("BODY_BODY3")
:SetText(info.content)
)
:AddChild(UIElements.New("Text", "readMore")
:SetHeight(20)
:SetPadding(0, 0, 4, 0)
:SetFont("BODY_BODY3")
:SetTextColor("INDICATOR")
:SetText(L["Read More"])
)
)
:AddChildNoLayout(UIElements.New("Button", "btn")
:AddAnchor("TOPLEFT", "news"..i)
:AddAnchor("BOTTOMRIGHT", "news"..i)
:SetContext(info)
:SetScript("OnClick", private.ButtonOnClick)
)
end
end
return frame
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.ButtonOnClick(button)
local info = button:GetContext()
Analytics.Action("NEWS_READ_MORE", info.title)
button:GetBaseElement():ShowDialogFrame(UIElements.New("Frame", "frame")
:SetLayout("VERTICAL")
:SetSize(600, 450)
:AddAnchor("CENTER")
:SetBackgroundColor("FRAME_BG")
:SetBorderColor("ACTIVE_BG")
:AddChild(UIElements.New("Text", "title")
:SetHeight(44)
:SetMargin(16, 16, 16, 8)
:SetFont("BODY_BODY1_BOLD")
:SetJustifyH("CENTER")
:SetText(info.title)
)
:AddChild(UIElements.New("Input", "linkInput")
:SetHeight(26)
:SetMargin(16, 16, 0, 16)
:SetBackgroundColor("PRIMARY_BG_ALT")
:SetValidateFunc(private.LinkValidateFunc)
:SetContext(info.link)
:SetValue(info.link)
)
:AddChild(UIElements.New("Text", "content")
:SetMargin(16, 16, 0, 16)
:SetFont("BODY_BODY3")
:SetJustifyV("TOP")
:SetText(info.content)
)
:AddChild(UIElements.New("Frame", "buttons")
:SetLayout("HORIZONTAL")
:SetHeight(26)
:SetMargin(16, 16, 0, 16)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("ActionButton", "confirmBtn")
:SetWidth(126)
:SetText(CLOSE)
:SetScript("OnClick", private.DialogCloseBtnOnClick)
)
)
)
end
function private.LinkValidateFunc(input, value)
return value == input:GetContext()
end
function private.DialogCloseBtnOnClick(button)
button:GetBaseElement():HideDialog()
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.GraphFormatX(timestamp, suggestedStep)
if suggestedStep > SECONDS_PER_DAY * 14 then
return date("%b '%y", timestamp)
elseif suggestedStep > SECONDS_PER_DAY * 2 then
return date("%b %d", timestamp)
elseif suggestedStep > SECONDS_PER_DAY / 6 then
return date("%a", timestamp)
else
if GetCVar("timeMgrUseMilitaryTime") == "1" then
return date("%H:%M", timestamp)
else
return strtrim(date("%I %p", timestamp), "0")
end
end
end
function private.GraphFormatY(value, suggestedStep, isTooltip)
if isTooltip then
return Money.ToString(value, nil, "OPT_TRIM")
end
if TSM.IsWowClassic() and value < COPPER_PER_GOLD * 1000 then
-- "###g"
return floor(value / COPPER_PER_GOLD)..Money.GetGoldText()
elseif TSM.IsWowClassic() and value < COPPER_PER_GOLD * 1000 * 10 then
-- "#.##Kg"
return format("%.2f", value / (COPPER_PER_GOLD * 1000)).."k"..Money.GetGoldText()
elseif value < COPPER_PER_GOLD * 1000 * 1000 then
-- "###Kg"
return floor(value / (COPPER_PER_GOLD * 1000)).."k"..Money.GetGoldText()
elseif value < COPPER_PER_GOLD * 1000 * 1000 * 10 then
-- "#.##Mg"
return format("%.2f", value / (COPPER_PER_GOLD * 1000 * 1000)).."M"..Money.GetGoldText()
else
-- "###Mg"
return floor(value / (COPPER_PER_GOLD * 1000 * 1000)).."M"..Money.GetGoldText()
end
end
function private.GetGraphYValue(xValue)
return TSM.Accounting.GoldTracker.GetGoldAtTime(xValue, private.settings.dashboardUnselectedCharacters)
end
function private.ContentOnUpdate(contentFrame)
contentFrame:SetScript("OnUpdate", nil)
private.UpdateTimeButtons(contentFrame:GetElement("goldHeader.timeBtns"))
private.UpdateGraph(contentFrame)
end
function private.DropdownOnSelectionChanged(dropdown)
for _, key in ipairs(private.characterGuilds) do
private.settings.dashboardUnselectedCharacters[key] = not dropdown:ItemIsSelectedByKey(key) or nil
end
private.UpdateGraph(dropdown:GetParentElement():GetParentElement())
end
function private.TimeBtnOnClick(button)
local timeRange = button:GetContext()
assert(timeRange)
private.selectedTimeRange = timeRange
private.settings.dashboardTimeRange = timeRange
private.UpdateTimeButtons(button:GetParentElement())
private.UpdateGraph(button:GetParentElement():GetParentElement():GetParentElement())
end
function private.UpdateGraph(contentFrame)
-- update the graph
local minTime, maxTime = TSM.Accounting.GoldTracker.GetGraphTimeRange(private.settings.dashboardUnselectedCharacters)
local goldGraph = contentFrame:GetElement("goldGraph")
local zoomStart, zoomEnd = goldGraph:GetZoom()
if private.selectedTimeRange == TIME_RANGE_LOOKUP["all"] then
zoomStart = minTime
zoomEnd = maxTime
elseif private.selectedTimeRange then
zoomStart = max(time() - private.selectedTimeRange, minTime)
zoomEnd = time()
end
goldGraph:SetXRange(minTime, maxTime)
:SetZoom(zoomStart, zoomEnd)
:Draw()
private.PopulateDetails(contentFrame)
end
function private.GraphOnZoomChanged(graph)
private.selectedTimeRange = nil
private.settings.dashboardTimeRange = -1
private.UpdateTimeButtons(graph:GetElement("__parent.goldHeader.timeBtns"))
private.PopulateDetails(graph:GetElement("__parent"))
end
function private.GraphOnHoverUpdate(graph, hoverTime)
local goldHeader = graph:GetElement("__parent.goldHeader")
if hoverTime then
local timeStr = nil
if GetCVar("timeMgrUseMilitaryTime") == "1" then
timeStr = date("%H:%M %b %d, %Y", hoverTime)
else
timeStr = gsub(date("%I:%M %p %b %d, %Y", hoverTime), "^0", "")
end
goldHeader:GetElement("timeBtns"):Hide()
goldHeader:GetElement("hoverTime")
:SetText(timeStr)
:Show()
else
goldHeader:GetElement("timeBtns"):Show()
goldHeader:GetElement("hoverTime"):Hide()
private.UpdateTimeButtons(goldHeader:GetElement("timeBtns"))
end
goldHeader:Draw()
end
function private.UpdateTimeButtons(frame)
frame:ShowAllChildren()
local resetButton = frame:GetElement("resetZoom")
if private.selectedTimeRange then
for _, button in frame:LayoutChildrenIterator() do
if button ~= resetButton then
button:SetTextColor(private.selectedTimeRange == button:GetContext() and "TEXT" or "ACTIVE_BG_ALT")
end
end
resetButton:Hide()
else
for _, button in frame:LayoutChildrenIterator() do
button:Hide()
end
resetButton:Show()
end
frame:GetParentElement():Draw()
end
function private.GraphXStepFunc(prevValue, suggestedStep)
local year, day, month, hour, min, sec = strsplit(",", date("%Y,%d,%m,%H,%M,%S", prevValue))
private.tempTimeTable.year = tonumber(year)
private.tempTimeTable.day = tonumber(day)
private.tempTimeTable.month = tonumber(month)
private.tempTimeTable.hour = tonumber(hour)
private.tempTimeTable.min = tonumber(min)
private.tempTimeTable.sec = tonumber(sec)
if suggestedStep > SECONDS_PER_DAY * 14 then
private.tempTimeTable.month = private.tempTimeTable.month + 1
private.tempTimeTable.day = 1
private.tempTimeTable.hour = 0
private.tempTimeTable.min = 0
private.tempTimeTable.sec = 0
elseif suggestedStep > SECONDS_PER_DAY / 6 then
private.tempTimeTable.day = private.tempTimeTable.day + 1
if private.tempTimeTable.hour == 23 then
-- add an extra hour to avoid DST issues
private.tempTimeTable.hour = 1
else
private.tempTimeTable.hour = 0
end
private.tempTimeTable.min = 0
private.tempTimeTable.sec = 0
else
private.tempTimeTable.hour = private.tempTimeTable.hour + 1
private.tempTimeTable.min = 0
private.tempTimeTable.sec = 0
end
local newValue = time(private.tempTimeTable)
assert(newValue > prevValue)
return newValue
end
function private.GraphYStepFunc(mode, ...)
if mode == "RANGE" then
local yMin, yMax, maxNumSteps = ...
-- find the smallest 10^X step size which still looks good
local minStep = max((yMax - yMin) / maxNumSteps / 10, yMax / 200)
local stepSize = MIN_GRAPH_STEP_SIZE
while stepSize < minStep do
stepSize = stepSize * 10
end
yMin = Math.Floor(yMin, stepSize)
yMax = Math.Ceil(yMax + stepSize / 3, stepSize)
if yMin == yMax then
yMax = yMax + stepSize
end
return yMin, yMax
elseif mode == "NEXT" then
local prevValue, yMax = ...
local stepSize = MIN_GRAPH_STEP_SIZE
while stepSize < yMax / 1000 do
stepSize = stepSize * 10
end
return Math.Floor(prevValue, stepSize) + stepSize
else
error("Invalid mode")
end
end
function private.PopulateDetails(contentFrame)
local goldGraph = contentFrame:GetElement("goldGraph")
local unselectedCharacters = next(private.settings.dashboardUnselectedCharacters) and private.settings.dashboardUnselectedCharacters or nil
local timeFilterStart, timeFilterEnd, numDays = nil, nil, nil
if private.selectedTimeRange and private.selectedTimeRange ~= -1 then
timeFilterStart = time() - private.selectedTimeRange
timeFilterEnd = time()
numDays = ceil(private.selectedTimeRange / SECONDS_PER_DAY)
elseif not private.selectedTimeRange then
timeFilterStart, timeFilterEnd = goldGraph:GetZoom()
numDays = ceil((timeFilterEnd - timeFilterStart) / SECONDS_PER_DAY)
else
local timeStart, timeEnd = goldGraph:GetXRange()
numDays = ceil((timeEnd - timeStart) / SECONDS_PER_DAY)
end
numDays = max(numDays, 1)
local saleTotal, salePerDay, saleTopItem, saleTopValue, saleTotalQuantity = 0, nil, nil, 0, 0
local buyTotal, buyPerDay, buyTopItem, buyTopValue, buyTotalQuantity = 0, nil, nil, 0, 0
local profitTopItem = nil
local query = TSM.Accounting.GetSummaryQuery(timeFilterStart, timeFilterEnd, unselectedCharacters)
local saleNumDays, buyNumDays = 1, 1
local saleItemTotals = TempTable.Acquire()
local buyItemTotals = TempTable.Acquire()
local saleItemNum = TempTable.Acquire()
local buyItemNum = TempTable.Acquire()
for _, recordType, itemString, price, quantity, timestamp in query:Iterator() do
if recordType == "sale" then
local daysAgo = floor((time() - timestamp) / (24 * 60 * 60))
saleNumDays = max(saleNumDays, daysAgo)
saleItemTotals[itemString] = (saleItemTotals[itemString] or 0) + price * quantity
saleTopValue = max(saleTopValue, price)
saleTotalQuantity = saleTotalQuantity + quantity
saleItemNum[itemString] = (saleItemNum[itemString] or 0) + quantity
elseif recordType == "buy" then
local daysAgo = floor((time() - timestamp) / (24 * 60 * 60))
buyNumDays = max(buyNumDays, daysAgo)
buyItemTotals[itemString] = (buyItemTotals[itemString] or 0) + price * quantity
buyTopValue = max(buyTopValue, price)
buyTotalQuantity = buyTotalQuantity + quantity
buyItemNum[itemString] = (buyItemNum[itemString] or 0) + quantity
else
error("Invalid recordType: "..tostring(recordType))
end
end
query:Release()
local topSaleItemTotal = 0
for itemString, itemTotal in pairs(saleItemTotals) do
saleTotal = saleTotal + itemTotal
if itemTotal > topSaleItemTotal then
saleTopItem = itemString
topSaleItemTotal = itemTotal
end
end
salePerDay = Math.Round(saleTotal / saleNumDays)
local topBuyItemTotal = 0
for itemString, itemTotal in pairs(buyItemTotals) do
buyTotal = buyTotal + itemTotal
if itemTotal > topBuyItemTotal then
buyTopItem = itemString
topBuyItemTotal = itemTotal
end
end
buyPerDay = Math.Round(buyTotal / buyNumDays)
local topItemProfit = 0
for itemString in pairs(saleItemNum) do
if buyItemNum[itemString] then
local profit = (saleItemTotals[itemString] / saleItemNum[itemString] - buyItemTotals[itemString] / buyItemNum[itemString]) * min(saleItemNum[itemString], buyItemNum[itemString])
if profit > topItemProfit then
profitTopItem = itemString
topItemProfit = profit
end
end
end
TempTable.Release(saleItemTotals)
TempTable.Release(buyItemTotals)
TempTable.Release(saleItemNum)
TempTable.Release(buyItemNum)
local profitTotal = saleTotal - buyTotal
local profitPerDay = salePerDay - buyPerDay
local rangeLow, rangeHigh = goldGraph:GetYRange()
contentFrame:GetElement("summary.range.low.value")
:SetText(Money.ToString(rangeLow, nil, "OPT_TRIM") or "-")
contentFrame:GetElement("summary.range.high.value")
:SetText(Money.ToString(rangeHigh, nil, "OPT_TRIM") or "-")
contentFrame:GetElement("summary.daily.sales.value")
:SetText(saleTotalQuantity and Math.Round(saleTotalQuantity / numDays) or "-")
contentFrame:GetElement("summary.daily.purchases.value")
:SetText(buyTotalQuantity and Math.Round(buyTotalQuantity / numDays) or "-")
contentFrame:GetElement("summary.top.sale.value")
:SetText(Money.ToString(Math.Round(saleTopValue, TSM.IsWowClassic() and 1 or COPPER_PER_GOLD), nil, "OPT_TRIM") or "-")
contentFrame:GetElement("summary.top.expense.value")
:SetText(Money.ToString(Math.Round(buyTopValue, TSM.IsWowClassic() and 1 or COPPER_PER_GOLD), nil, "OPT_TRIM") or "-")
contentFrame:GetElement("details.salesTotal.amount")
:SetText(Money.ToString(saleTotal))
contentFrame:GetElement("details.salesAvg.amount")
:SetText(Money.ToString(salePerDay))
contentFrame:GetElement("details.salesTop.item")
:SetText(TSM.UI.GetColoredItemName(saleTopItem) or "-")
:SetTooltip(saleTopItem)
contentFrame:GetElement("details.expensesTotal.amount")
:SetText(Money.ToString(buyTotal))
contentFrame:GetElement("details.expensesAvg.amount")
:SetText(Money.ToString(buyPerDay))
contentFrame:GetElement("details.expensesTop.item")
:SetText(TSM.UI.GetColoredItemName(buyTopItem) or "-")
:SetTooltip(buyTopItem)
contentFrame:GetElement("details.profitTotal.amount")
:SetText(Money.ToString(profitTotal, profitTotal < 0 and Theme.GetFeedbackColor("RED"):GetTextColorPrefix() or nil))
contentFrame:GetElement("details.profitAvg.amount")
:SetText(Money.ToString(profitPerDay, profitPerDay < 0 and Theme.GetFeedbackColor("RED"):GetTextColorPrefix() or nil))
contentFrame:GetElement("details.profitTop.item")
:SetText(TSM.UI.GetColoredItemName(profitTopItem) or "-")
:SetTooltip(profitTopItem)
contentFrame:Draw()
end

1870
Core/UI/MainUI/Groups.lua Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,266 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Auctions = TSM.MainUI.Ledger.Common:NewPackage("Auctions")
local L = TSM.Include("Locale").GetTable()
local Table = TSM.Include("Util.Table")
local String = TSM.Include("Util.String")
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 SECONDS_PER_DAY = 24 * 60 * 60
local private = {
settings = nil,
query = nil,
characters = {},
characterFilter = {},
searchFilter = "",
groupFilter = {},
rarityList = {},
rarityFilter = {},
timeFrameFilter = 30 * SECONDS_PER_DAY,
type = nil
}
do
for i = 1, 4 do
tinsert(private.rarityList, _G[format("ITEM_QUALITY%d_DESC", i)])
private.rarityFilter[i] = true
end
end
local TIME_LIST = { L["All Time"], L["Last 3 Days"], L["Last 7 Days"], L["Last 14 Days"], L["Last 30 Days"], L["Last 60 Days"] }
local TIME_KEYS = { 0, 3 * SECONDS_PER_DAY, 7 * SECONDS_PER_DAY, 14 * SECONDS_PER_DAY, 30 * SECONDS_PER_DAY, 60 * SECONDS_PER_DAY }
-- ============================================================================
-- Module Functions
-- ============================================================================
function Auctions.OnInitialize()
private.settings = Settings.NewView()
:AddKey("global", "mainUIContext", "ledgerAuctionsScrollingTable")
TSM.MainUI.Ledger.FailedAuctions.RegisterPage(L["Expired"], private.DrawExpiredPage)
TSM.MainUI.Ledger.FailedAuctions.RegisterPage(L["Cancelled"], private.DrawCancelledPage)
end
-- ============================================================================
-- Auctions UIs
-- ============================================================================
function private.DrawExpiredPage()
TSM.UI.AnalyticsRecordPathChange("main", "ledger", "failed_auctions", "expired")
private.type = "expire"
return private.DrawAuctionsPage()
end
function private.DrawCancelledPage()
TSM.UI.AnalyticsRecordPathChange("main", "ledger", "failed_auctions", "cancelled")
private.type = "cancel"
return private.DrawAuctionsPage()
end
function private.DrawAuctionsPage()
private.query = private.query or TSM.Accounting.Auctions.CreateQuery()
private.query:Reset()
:Equal("type", "cancel")
:Distinct("player")
:Select("player")
wipe(private.characters)
for _, character in private.query:Iterator() do
tinsert(private.characters, character)
private.characterFilter[character] = true
end
private.query:Reset()
:InnerJoin(ItemInfo.GetDBForJoin(), "itemString")
:LeftJoin(TSM.Groups.GetItemDBForJoin(), "itemString")
:OrderBy("time", false)
private.UpdateQuery()
return UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Frame", "row1")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8)
:AddChild(UIElements.New("Input", "filter")
:SetMargin(0, 8, 0, 0)
:SetIconTexture("iconPack.18x18/Search")
:SetClearButtonEnabled(true)
:AllowItemInsert()
:SetHintText(L["Filter by keyword"])
:SetValue(private.searchFilter)
:SetScript("OnValueChanged", private.SearchFilterChanged)
)
:AddChild(UIElements.New("GroupSelector", "group")
:SetWidth(240)
:SetHintText(L["Filter by groups"])
:SetScript("OnSelectionChanged", private.GroupFilterChanged)
)
)
:AddChild(UIElements.New("Frame", "row2")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8, 8, 0, 8)
:AddChild(UIElements.New("MultiselectionDropdown", "rarity")
:SetMargin(0, 8, 0, 0)
:SetItems(private.rarityList)
:SetSettingInfo(private, "rarityFilter")
:SetSelectionText(L["No Rarities"], L["%d Rarities"], L["All Rarites"])
:SetScript("OnSelectionChanged", private.DropdownCommonOnSelectionChanged)
)
:AddChild(UIElements.New("MultiselectionDropdown", "character")
:SetMargin(0, 8, 0, 0)
:SetItems(private.characters, private.characters)
:SetSettingInfo(private, "characterFilter")
:SetSelectionText(L["No Characters"], L["%d Characters"], L["All Characters"])
:SetScript("OnSelectionChanged", private.DropdownCommonOnSelectionChanged)
)
:AddChild(UIElements.New("SelectionDropdown", "time")
:SetItems(TIME_LIST, TIME_KEYS)
:SetSelectedItemByKey(private.timeFrameFilter)
:SetSettingInfo(private, "timeFrameFilter")
:SetScript("OnSelectionChanged", private.DropdownCommonOnSelectionChanged)
)
)
:AddChild(UIElements.New("QueryScrollingTable", "scrollingTable")
:SetSettingsContext(private.settings, "ledgerAuctionsScrollingTable")
:GetScrollingTableInfo()
:NewColumn("item")
:SetTitle(L["Item"])
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("itemString", TSM.UI.GetColoredItemName)
:SetTooltipInfo("itemString")
:SetSortInfo("name")
:DisableHiding()
:Commit()
:NewColumn("player")
:SetTitle(PLAYER)
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("player")
:SetSortInfo("player")
:Commit()
:NewColumn("stackSize")
:SetTitle(L["Stack"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("stackSize")
:SetSortInfo("stackSize")
:Commit()
:NewColumn("quantity")
:SetTitle(L["Auctions"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo(nil, private.FormatAuctions)
:SetSortInfo("quantity")
:Commit()
:NewColumn("time")
:SetTitle(L["Time Frame"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("time", private.TableGetTimeframeText)
:SetSortInfo("time")
:Commit()
:Commit()
:SetQuery(private.query)
:SetScript("OnRowClick", private.TableSelectionChanged)
)
:AddChild(UIElements.New("Texture", "line")
:SetHeight(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Frame", "footer")
:SetLayout("HORIZONTAL")
:SetHeight(40)
:SetPadding(8)
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Text", "num")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(format(private.type == "expire" and L["%s Items Expired"] or L["%s Items Cancelled"], Theme.GetColor("INDICATOR"):ColorText(FormatLargeNumber(private.query:Sum("quantity") or 0))))
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
end
-- ============================================================================
-- Scrolling Table Helper Functions
-- ============================================================================
function private.TableGetTimeframeText(record)
return SecondsToTime(time() - record)
end
function private.FormatAuctions(row)
return row:GetField("quantity") / row:GetField("stackSize")
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.DropdownCommonOnSelectionChanged(dropdown)
private.UpdateQuery()
dropdown:GetElement("__parent.__parent.scrollingTable")
:UpdateData(true)
local footer = dropdown:GetElement("__parent.__parent.footer")
footer:GetElement("num"):SetText(format(private.type == "expire" and L["%s Items Expired"] or L["%s Items Cancelled"], Theme.GetColor("INDICATOR"):ColorText(FormatLargeNumber(private.query:Sum("quantity") or 0))))
footer:Draw()
end
function private.SearchFilterChanged(input)
private.searchFilter = input:GetValue()
private.DropdownCommonOnSelectionChanged(input)
end
function private.GroupFilterChanged(groupSelector)
wipe(private.groupFilter)
for groupPath in groupSelector:SelectedGroupIterator() do
private.groupFilter[groupPath] = true
end
private.DropdownCommonOnSelectionChanged(groupSelector)
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.UpdateQuery()
private.query:ResetFilters()
:Equal("type", private.type)
if private.searchFilter ~= "" then
private.query:Matches("name", String.Escape(private.searchFilter))
end
if Table.Count(private.rarityFilter) ~= #private.rarityList then
private.query:InTable("quality", private.rarityFilter)
end
if Table.Count(private.characterFilter) ~= #private.characters then
private.query:InTable("player", private.characterFilter)
end
if private.timeFrameFilter ~= 0 then
private.query:GreaterThanOrEqual("time", time() - private.timeFrameFilter)
end
if next(private.groupFilter) then
private.query:InTable("groupPath", private.groupFilter)
end
end
function private.TableSelectionChanged(scrollingTable, row)
TSM.MainUI.Ledger.ShowItemDetail(scrollingTable:GetParentElement():GetParentElement(), row:GetField("itemString"), "sale")
end

View File

@@ -0,0 +1,8 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
TSM.MainUI.Ledger:NewPackage("Common")

View File

@@ -0,0 +1,208 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Other = TSM.MainUI.Ledger.Common:NewPackage("Other")
local L = TSM.Include("Locale").GetTable()
local Table = TSM.Include("Util.Table")
local Money = TSM.Include("Util.Money")
local Settings = TSM.Include("Service.Settings")
local UIElements = TSM.Include("UI.UIElements")
local SECONDS_PER_DAY = 24 * 60 * 60
local private = {
settings = nil,
query = nil,
characters = {},
characterFilter = {},
typeFilter = {},
recordType = nil,
timeFrameFilter = 30 * SECONDS_PER_DAY,
}
local TIME_LIST = { L["All Time"], L["Last 3 Days"], L["Last 7 Days"], L["Last 14 Days"], L["Last 30 Days"], L["Last 60 Days"] }
local TIME_KEYS = { 0, 3 * SECONDS_PER_DAY, 7 * SECONDS_PER_DAY, 14 * SECONDS_PER_DAY, 30 * SECONDS_PER_DAY, 60 * SECONDS_PER_DAY }
local TYPE_LIST = {
expense = { L["Money Transfer"], L["Postage"], L["Repair Bill"] },
income = { L["Money Transfer"], L["Garrison"] },
}
local TYPE_KEYS = {
expense = { "Money Transfer", "Postage", "Repair Bill" },
income = { "Money Transfer", "Garrison" },
}
local TYPE_STR_LOOKUP = {}
do
-- populate lookup table
assert(#TYPE_LIST.expense == #TYPE_KEYS.expense)
for i = 1, #TYPE_LIST.expense do
TYPE_STR_LOOKUP[TYPE_KEYS.expense[i]] = TYPE_LIST.expense[i]
end
assert(#TYPE_LIST.income == #TYPE_KEYS.income)
for i = 1, #TYPE_LIST.income do
TYPE_STR_LOOKUP[TYPE_KEYS.income[i]] = TYPE_LIST.income[i]
end
end
-- ============================================================================
-- Module Functions
-- ============================================================================
function Other.OnInitialize()
private.settings = Settings.NewView()
:AddKey("global", "mainUIContext", "ledgerOtherScrollingTable")
TSM.MainUI.Ledger.Expenses.RegisterPage(OTHER, private.DrawOtherExpensesPage)
TSM.MainUI.Ledger.Revenue.RegisterPage(OTHER, private.DrawOtherRevenuePage)
end
-- ============================================================================
-- Other UIs
-- ============================================================================
function private.DrawOtherExpensesPage()
TSM.UI.AnalyticsRecordPathChange("main", "ledger", "expenses", "other")
return private.DrawOtherPage("expense")
end
function private.DrawOtherRevenuePage()
TSM.UI.AnalyticsRecordPathChange("main", "ledger", "revenue", "other")
return private.DrawOtherPage("income")
end
function private.DrawOtherPage(recordType)
wipe(private.characters)
for _, character in TSM.Accounting.Money.CharacterIterator(recordType) do
tinsert(private.characters, character)
private.characterFilter[character] = true
end
wipe(private.typeFilter)
for _, key in ipairs(TYPE_KEYS[recordType]) do
private.typeFilter[key] = true
end
if not private.query then
private.query = TSM.Accounting.Money.CreateQuery()
:OrderBy("time", false)
end
private.recordType = recordType
private.UpdateQuery()
return UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Frame", "row2")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8)
:AddChild(UIElements.New("MultiselectionDropdown", "type")
:SetMargin(0, 8, 0, 0)
:SetItems(TYPE_LIST[recordType], TYPE_KEYS[recordType])
:SetSettingInfo(private, "typeFilter")
:SetSelectionText(L["No Types"], L["%d Types"], L["All Types"])
:SetScript("OnSelectionChanged", private.DropdownChangedCommon)
)
:AddChild(UIElements.New("MultiselectionDropdown", "character")
:SetMargin(0, 8, 0, 0)
:SetItems(private.characters, private.characters)
:SetSettingInfo(private, "characterFilter")
:SetSelectionText(L["No Characters"], L["%d Characters"], L["All Characters"])
:SetScript("OnSelectionChanged", private.DropdownChangedCommon)
)
:AddChild(UIElements.New("SelectionDropdown", "time")
:SetItems(TIME_LIST, TIME_KEYS)
:SetSelectedItemByKey(private.timeFrameFilter)
:SetSettingInfo(private, "timeFrameFilter")
:SetScript("OnSelectionChanged", private.DropdownChangedCommon)
)
)
:AddChild(UIElements.New("QueryScrollingTable", "table")
:SetSettingsContext(private.settings, "ledgerOtherScrollingTable")
:GetScrollingTableInfo()
:NewColumn("type")
:SetTitle(L["Type"])
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("type", private.TableGetTypeText)
:SetSortInfo("type")
:Commit()
:NewColumn("character")
:SetTitle(L["Character"])
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("player")
:SetSortInfo("player")
:Commit()
:NewColumn("otherCharacter")
:SetTitle(L["Other Character"])
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("otherPlayer")
:SetSortInfo("otherPlayer")
:Commit()
:NewColumn("amount")
:SetTitle(L["Amount"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("amount", Money.ToString)
:SetSortInfo("amount")
:Commit()
:NewColumn("time")
:SetTitle(L["Time Frame"])
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("time", private.TableGetTimeText)
:SetSortInfo("time")
:Commit()
:Commit()
:SetQuery(private.query)
:SetSelectionDisabled(true)
)
end
-- ============================================================================
-- Scrolling Table Helper Functions
-- ============================================================================
function private.TableGetTypeText(typeValue)
return TYPE_STR_LOOKUP[typeValue]
end
function private.TableGetTimeText(timevalue)
return SecondsToTime(time() - timevalue)
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.DropdownChangedCommon(dropdown)
private.UpdateQuery()
dropdown:GetElement("__parent.__parent.table"):UpdateData(true)
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.UpdateQuery()
private.query:ResetFilters()
:Equal("recordType", private.recordType)
if Table.Count(private.typeFilter) ~= #TYPE_KEYS[private.recordType] then
private.query:InTable("type", private.typeFilter)
end
if Table.Count(private.characterFilter) ~= #private.characters then
private.query:InTable("player", private.characterFilter)
end
if private.timeFrameFilter ~= 0 then
private.query:GreaterThan("time", time() - private.timeFrameFilter)
end
end

View File

@@ -0,0 +1,329 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Transactions = TSM.MainUI.Ledger.Common:NewPackage("Transactions")
local L = TSM.Include("Locale").GetTable()
local Money = TSM.Include("Util.Money")
local String = TSM.Include("Util.String")
local Table = TSM.Include("Util.Table")
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 SECONDS_PER_DAY = 24 * 60 * 60
local private = {
settings = nil,
query = nil,
characters = {},
characterFilter = {},
typeFilter = {},
searchFilter = "",
groupFilter = {},
rarityList = {},
rarityFilter = {},
timeFrameFilter = 30 * SECONDS_PER_DAY,
type = nil
}
local TYPE_LIST = { L["Auction"], COD, TRADE, L["Vendor"] }
local TYPE_KEYS = { "Auction", "COD", "Trade", "Vendor" }
do
for _, key in ipairs(TYPE_KEYS) do
private.typeFilter[key] = true
end
for i = 1, 4 do
tinsert(private.rarityList, _G[format("ITEM_QUALITY%d_DESC", i)])
private.rarityFilter[i] = true
end
end
local TIME_LIST = { L["All Time"], L["Last 3 Days"], L["Last 7 Days"], L["Last 14 Days"], L["Last 30 Days"], L["Last 60 Days"] }
local TIME_KEYS = { 0, 3 * SECONDS_PER_DAY, 7 * SECONDS_PER_DAY, 14 * SECONDS_PER_DAY, 30 * SECONDS_PER_DAY, 60 * SECONDS_PER_DAY }
-- ============================================================================
-- Module Functions
-- ============================================================================
function Transactions.OnInitialize()
private.settings = Settings.NewView()
:AddKey("global", "mainUIContext", "ledgerTransactionsScrollingTable")
TSM.MainUI.Ledger.Expenses.RegisterPage(L["Purchases"], private.DrawPurchasesPage)
TSM.MainUI.Ledger.Revenue.RegisterPage(L["Sales"], private.DrawSalesPage)
end
-- ============================================================================
-- Transactions UIs
-- ============================================================================
function private.DrawPurchasesPage()
TSM.UI.AnalyticsRecordPathChange("main", "ledger", "expenses", "purchases")
private.type = "buy"
return private.DrawTransactionPage()
end
function private.DrawSalesPage()
TSM.UI.AnalyticsRecordPathChange("main", "ledger", "revenue", "sales")
private.type = "sale"
return private.DrawTransactionPage()
end
function private.DrawTransactionPage()
private.query = private.query or TSM.Accounting.Transactions.CreateQuery()
private.query:Reset()
:Equal("type", private.type)
:Distinct("player")
:Select("player")
wipe(private.characters)
for _, character in private.query:Iterator() do
tinsert(private.characters, character)
private.characterFilter[character] = true
end
private.query:Reset()
:InnerJoin(ItemInfo.GetDBForJoin(), "itemString")
:LeftJoin(TSM.Groups.GetItemDBForJoin(), "itemString")
:VirtualField("total", "number", private.GetTotal)
:VirtualField("auctions", "number", private.GetAuctions)
:OrderBy("time", false)
private.UpdateQuery()
local numItems = private.query:Sum("quantity") or 0
local total = private.query:Sum("total") or 0
return UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Frame", "row1")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8)
:AddChild(UIElements.New("Input", "filter")
:SetMargin(0, 8, 0, 0)
:SetIconTexture("iconPack.18x18/Search")
:SetClearButtonEnabled(true)
:AllowItemInsert()
:SetHintText(L["Filter by keyword"])
:SetValue(private.searchFilter)
:SetScript("OnValueChanged", private.SearchFilterChanged)
)
:AddChild(UIElements.New("GroupSelector", "group")
:SetWidth(240)
:SetHintText(L["Filter by groups"])
:SetScript("OnSelectionChanged", private.GroupFilterChanged)
)
)
:AddChild(UIElements.New("Frame", "row2")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8, 8, 0, 8)
:AddChild(UIElements.New("MultiselectionDropdown", "type")
:SetMargin(0, 8, 0, 0)
:SetItems(TYPE_LIST, TYPE_KEYS)
:SetSettingInfo(private, "typeFilter")
:SetSelectionText(L["No Types"], L["%d Types"], L["All Types"])
:SetScript("OnSelectionChanged", private.DropdownCommonOnSelectionChanged)
)
:AddChild(UIElements.New("MultiselectionDropdown", "rarity")
:SetMargin(0, 8, 0, 0)
:SetItems(private.rarityList)
:SetSettingInfo(private, "rarityFilter")
:SetSelectionText(L["No Rarities"], L["%d Rarities"], L["All Rarities"])
:SetScript("OnSelectionChanged", private.DropdownCommonOnSelectionChanged)
)
:AddChild(UIElements.New("MultiselectionDropdown", "character")
:SetMargin(0, 8, 0, 0)
:SetItems(private.characters, private.characters)
:SetSettingInfo(private, "characterFilter")
:SetSelectionText(L["No Characters"], L["%d Characters"], L["All Characters"])
:SetScript("OnSelectionChanged", private.DropdownCommonOnSelectionChanged)
)
:AddChild(UIElements.New("SelectionDropdown", "time")
:SetItems(TIME_LIST, TIME_KEYS)
:SetSelectedItemByKey(private.timeFrameFilter)
:SetSettingInfo(private, "timeFrameFilter")
:SetScript("OnSelectionChanged", private.DropdownCommonOnSelectionChanged)
)
)
:AddChild(UIElements.New("QueryScrollingTable", "scrollingTable")
:SetSettingsContext(private.settings, "ledgerTransactionsScrollingTable")
:GetScrollingTableInfo()
:NewColumn("item")
:SetTitle(L["Item"])
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("itemString", TSM.UI.GetColoredItemName)
:SetTooltipInfo("itemString")
:SetSortInfo("name")
:DisableHiding()
:Commit()
:NewColumn("player")
:SetTitle(PLAYER)
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("otherPlayer")
:SetSortInfo("otherPlayer")
:Commit()
:NewColumn("type")
:SetTitle(L["Type"])
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("source")
:SetSortInfo("source")
:Commit()
:NewColumn("stack")
:SetTitle(L["Stack"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("stackSize")
:SetSortInfo("stackSize")
:Commit()
:NewColumn("auctions")
:SetTitle(L["Auctions"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("auctions")
:SetSortInfo("auctions")
:Commit()
:NewColumn("perItem")
:SetTitle(L["Per Item"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("price", private.TableGetPriceText)
:SetSortInfo("price")
:Commit()
:NewColumn("total")
:SetTitle(L["Total"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("total", private.TableGetPriceText)
:SetSortInfo("total")
:Commit()
:NewColumn("time")
:SetTitle(L["Time Frame"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("time", private.TableGetTimeframeText)
:SetSortInfo("time")
:Commit()
:Commit()
:SetQuery(private.query)
:SetScript("OnRowClick", private.TableSelectionChanged)
)
:AddChild(UIElements.New("Texture", "line")
:SetHeight(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Frame", "footer")
:SetLayout("HORIZONTAL")
:SetHeight(40)
:SetPadding(8)
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Text", "num")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(format(private.type == "sale" and L["%s Items Sold"] or L["%s Items Bought"], Theme.GetColor("INDICATOR"):ColorText(FormatLargeNumber(numItems))))
)
:AddChild(UIElements.New("Texture", "line")
:SetMargin(4, 8, 0, 0)
:SetWidth(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Text", "profit")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(format(L["%s Total"], Money.ToString(total)))
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
end
-- ============================================================================
-- Scrolling Table Helper Functions
-- ============================================================================
function private.TableGetPriceText(price)
return Money.ToString(price)
end
function private.TableGetTimeframeText(record)
return SecondsToTime(time() - record)
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.DropdownCommonOnSelectionChanged(dropdown)
private.UpdateQuery()
local numItems = private.query:Sum("quantity") or 0
local total = private.query:Sum("total") or 0
dropdown:GetElement("__parent.__parent.scrollingTable")
:UpdateData(true)
local footer = dropdown:GetElement("__parent.__parent.footer")
footer:GetElement("num"):SetText(format(private.type == "sale" and L["%s Items Sold"] or L["%s Items Bought"], Theme.GetColor("INDICATOR"):ColorText(FormatLargeNumber(numItems))))
footer:GetElement("profit"):SetText(format(L["%s Total"], Money.ToString(total)))
footer:Draw()
end
function private.SearchFilterChanged(input)
private.searchFilter = input:GetValue()
private.DropdownCommonOnSelectionChanged(input)
end
function private.GroupFilterChanged(groupSelector)
wipe(private.groupFilter)
for groupPath in groupSelector:SelectedGroupIterator() do
private.groupFilter[groupPath] = true
end
private.DropdownCommonOnSelectionChanged(groupSelector)
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.GetTotal(row)
return row:GetField("price") * row:GetField("quantity")
end
function private.GetAuctions(row)
return row:GetField("quantity") / row:GetField("stackSize")
end
function private.UpdateQuery()
private.query:ResetFilters()
:Equal("type", private.type)
if private.searchFilter ~= "" then
private.query:Matches("name", String.Escape(private.searchFilter))
end
if Table.Count(private.typeFilter) ~= #TYPE_KEYS then
private.query:InTable("source", private.typeFilter)
end
if Table.Count(private.rarityFilter) ~= #private.rarityList then
private.query:InTable("quality", private.rarityFilter)
end
if Table.Count(private.characterFilter) ~= #private.characters then
private.query:InTable("player", private.characterFilter)
end
if private.timeFrameFilter ~= 0 then
private.query:GreaterThan("time", time() - private.timeFrameFilter)
end
if next(private.groupFilter) then
private.query:InTable("groupPath", private.groupFilter)
end
end
function private.TableSelectionChanged(scrollingTable, row)
TSM.MainUI.Ledger.ShowItemDetail(scrollingTable:GetParentElement():GetParentElement(), row:GetField("itemString"), private.type)
end

View File

@@ -0,0 +1,524 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Ledger = TSM.MainUI:NewPackage("Ledger")
local L = TSM.Include("Locale").GetTable()
local TempTable = TSM.Include("Util.TempTable")
local Table = TSM.Include("Util.Table")
local Money = TSM.Include("Util.Money")
local Theme = TSM.Include("Util.Theme")
local Log = TSM.Include("Util.Log")
local ItemInfo = TSM.Include("Service.ItemInfo")
local Settings = TSM.Include("Service.Settings")
local UIElements = TSM.Include("UI.UIElements")
local SECONDS_PER_DAY = 24 * 60 * 60
local private = {
settings = nil,
pages = {},
childPages = {},
callback = {},
contextPath = nil,
contextItemString = nil,
itemDetailType = "sale",
}
local NUM_TOP_PLAYERS = 3
local PAGE_PATH_SEP = "`"
-- ============================================================================
-- Module Functions
-- ============================================================================
function Ledger.OnInitialize()
private.settings = Settings.NewView()
:AddKey("global", "mainUIContext", "ledgerDetailScrollingTable")
TSM.MainUI.RegisterTopLevelPage(L["Ledger"], private.GetLedgerFrame)
end
function Ledger.RegisterPage(name, callback)
tinsert(private.pages, name)
private.callback[name] = callback
end
function Ledger.RegisterChildPage(parentName, childName, callback)
local path = parentName..PAGE_PATH_SEP..childName
private.childPages[parentName] = private.childPages[parentName] or {}
tinsert(private.childPages[parentName], childName)
private.callback[path] = callback
end
function Ledger.ShowItemDetail(frame, itemString, detailType)
assert(detailType == "sale" or detailType == "buy")
private.contextItemString = itemString
private.itemDetailType = detailType
frame:SetPath("itemDetail", true)
end
-- ============================================================================
-- Ledger UI
-- ============================================================================
function private.GetLedgerFrame()
TSM.UI.AnalyticsRecordPathChange("main", "ledger")
local defaultPage = private.pages[1]
local frame = UIElements.New("Frame", "ledger")
:SetLayout("HORIZONTAL")
:SetBackgroundColor("PRIMARY_BG_ALT")
:AddChild(UIElements.New("Frame", "navigation")
:SetLayout("VERTICAL")
:SetWidth(160)
:SetPadding(12, 12, 1, 9)
)
:AddChild(UIElements.New("Texture", "divider")
:SetWidth(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Frame", "contentFrame")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("ViewContainer", "content")
:SetNavCallback(private.ContentNavCallback)
:AddPath("itemDetail")
)
)
:SetScript("OnHide", private.NavButtonOnHide)
local content = frame:GetElement("contentFrame.content")
local navFrame = frame:GetElement("navigation")
for _, pageName in ipairs(private.pages) do
navFrame:AddChild(UIElements.New("Button", pageName)
:SetHeight(20)
:SetMargin(0, 0, 8, 0)
:SetFont("BODY_BODY2_BOLD")
:SetJustifyH("LEFT")
:SetContext(pageName)
:SetText(pageName)
:SetScript("OnClick", private.NavButtonOnClick)
)
content:AddPath(pageName, pageName == defaultPage)
if private.childPages[pageName] then
for _, childPageName in ipairs(private.childPages[pageName]) do
local path = pageName..PAGE_PATH_SEP..childPageName
navFrame:AddChild(UIElements.New("Button", path)
:SetHeight(20)
:SetMargin(9, 0, 8, 0)
:SetFont("BODY_BODY3_MEDIUM")
:SetJustifyH("LEFT")
:SetContext(path)
:SetText(childPageName)
:SetScript("OnClick", private.NavButtonOnClick)
)
content:AddPath(path, path == defaultPage)
end
end
end
-- make all the navigation align to the top
navFrame:AddChild(UIElements.New("Spacer", "spacer"))
private.UpdateNavFrame(navFrame, defaultPage)
private.contextPath = L["Inventory"]
return frame
end
function private.ContentNavCallback(self, path)
if path == "itemDetail" then
return private.GetItemDetail()
else
return private.callback[path]()
end
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.NavButtonOnClick(button)
local path = button:GetContext()
if private.contextPath == path then
return
end
if private.childPages[path] then
-- select the first child
path = path..PAGE_PATH_SEP..private.childPages[path][1]
end
local ledgerFrame = button:GetParentElement():GetParentElement()
local contentFrame = ledgerFrame:GetElement("contentFrame")
local navFrame = ledgerFrame:GetElement("navigation")
private.UpdateNavFrame(navFrame, path)
navFrame:Draw()
contentFrame:GetElement("content"):SetPath(path, private.contextPath ~= path)
private.contextPath = path
end
function private.NavButtonOnHide(button)
private.contextPath = nil
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.UpdateNavFrame(navFrame, selectedPath)
local selectedPage = strsplit(PAGE_PATH_SEP, selectedPath)
for _, pageName in ipairs(private.pages) do
navFrame:GetElement(pageName):SetTextColor(pageName == selectedPage and "TEXT" or "ACTIVE_BG_ALT")
if private.childPages[pageName] then
for _, childPageName in ipairs(private.childPages[pageName]) do
local path = pageName..PAGE_PATH_SEP..childPageName
if pageName == selectedPage then
navFrame:GetElement(path)
:SetTextColor(path == selectedPath and "INDICATOR" or "TEXT")
:Show()
else
navFrame:GetElement(path):Hide()
end
end
end
end
end
function private.GetItemDetail()
local query = TSM.Accounting.Transactions.CreateQuery()
:Equal("itemString", private.contextItemString)
:OrderBy("time", false)
local topPlayersQuantity = TempTable.Acquire()
local topPlayers = TempTable.Acquire()
for _, row in query:Iterator() do
local recordType, otherPlayer, quantity = row:GetFields("type", "otherPlayer", "quantity")
if recordType == private.itemDetailType then
if not topPlayersQuantity[otherPlayer] then
topPlayersQuantity[otherPlayer] = 0
tinsert(topPlayers, otherPlayer)
end
topPlayersQuantity[otherPlayer] = topPlayersQuantity[otherPlayer] + quantity
end
end
Table.SortWithValueLookup(topPlayers, topPlayersQuantity, true)
local numTopPlayers = min(#topPlayers, NUM_TOP_PLAYERS)
local topPlayersText = ""
if numTopPlayers > 0 then
for i = 1, numTopPlayers do
local player = topPlayers[i]
local quantity = topPlayersQuantity[player]
topPlayers[i] = player..Theme.GetColor("INDICATOR_ALT"):ColorText(" (" .. quantity .. ")")
end
topPlayersText = table.concat(topPlayers, ", ", 1, numTopPlayers)
else
topPlayersText = L["None"]
end
TempTable.Release(topPlayers)
TempTable.Release(topPlayersQuantity)
return UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Frame", "top")
:SetLayout("VERTICAL")
:SetPadding(8)
:SetBackgroundColor("PRIMARY_BG_ALT")
:AddChild(UIElements.New("Frame", "header")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("ActionButton", "button")
:SetWidth(64)
:SetIcon("iconPack.14x14/Chevron/Right@180")
:SetText(BACK)
:SetScript("OnClick", private.ItemDetailBackButtonOnClick)
)
:AddChild(UIElements.New("Button", "icon")
:SetSize(24, 24)
:SetMargin(14, 8, 0, 0)
:SetBackground(ItemInfo.GetTexture(private.contextItemString))
:SetTooltip(private.contextItemString)
)
:AddChild(UIElements.New("Text", "itemName")
:SetFont("ITEM_BODY1")
:SetText(TSM.UI.GetColoredItemName(private.contextItemString))
)
)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
:SetMargin(0, 0, 8, 0)
:SetPadding(12, 12, 8, 10)
:SetBackgroundColor("PRIMARY_BG_ALT", true)
:SetBorderColor("ACTIVE_BG")
:AddChild(UIElements.New("Frame", "heading")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Button", "saleBtn")
:SetWidth("AUTO")
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY2_BOLD")
:SetTextColor(private.itemDetailType == "sale" and "INDICATOR" or "ACTIVE_BG_ALT")
:SetContext("sale")
:SetText(L["Sale Data"])
:SetScript("OnClick", private.ItemDetailTabOnClick)
)
:AddChild(UIElements.New("Button", "buyBtn")
:SetWidth("AUTO")
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY2_BOLD")
:SetTextColor(private.itemDetailType == "buy" and "INDICATOR" or "ACTIVE_BG_ALT")
:SetContext("buy")
:SetText(L["Purchase Data"])
:SetScript("OnClick", private.ItemDetailTabOnClick)
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "total")
:SetWidth(120)
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY3_MEDIUM")
:SetJustifyH("RIGHT")
:SetText(L["Total"])
)
:AddChild(UIElements.New("Text", "last7")
:SetWidth(120)
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY3_MEDIUM")
:SetJustifyH("RIGHT")
:SetText(L["Last 7 Days"])
)
:AddChild(UIElements.New("Text", "last30")
:SetWidth(120)
:SetFont("BODY_BODY3_MEDIUM")
:SetJustifyH("RIGHT")
:SetText(L["Last 30 Days"])
)
)
:AddChild(UIElements.New("Frame", "quantity")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 8, 0)
:AddChild(UIElements.New("Text", "label")
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY3")
:SetTextColor("TEXT_ALT")
:SetText(private.itemDetailType == "sale" and L["Quantity Sold:"] or L["Quantity Purchased:"])
)
:AddChild(UIElements.New("Text", "total")
:SetWidth(120)
:SetMargin(0, 8, 0, 0)
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetText(TSM.Accounting.Transactions.GetQuantity(private.contextItemString, nil, private.itemDetailType))
)
:AddChild(UIElements.New("Text", "last7")
:SetWidth(120)
:SetMargin(0, 8, 0, 0)
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetText(TSM.Accounting.Transactions.GetQuantity(private.contextItemString, SECONDS_PER_DAY * 7, private.itemDetailType))
)
:AddChild(UIElements.New("Text", "last30")
:SetWidth(120)
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetText(TSM.Accounting.Transactions.GetQuantity(private.contextItemString, SECONDS_PER_DAY * 30, private.itemDetailType))
)
)
:AddChild(UIElements.New("Frame", "avgPrice")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 8, 0)
:AddChild(UIElements.New("Text", "label")
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY3")
:SetTextColor("TEXT_ALT")
:SetText(L["Average Prices:"])
)
:AddChild(UIElements.New("Text", "total")
:SetWidth(120)
:SetMargin(0, 8, 0, 0)
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetText(Money.ToString(TSM.Accounting.Transactions.GetAveragePrice(private.contextItemString, nil, private.itemDetailType)))
)
:AddChild(UIElements.New("Text", "last7")
:SetWidth(120)
:SetMargin(0, 8, 0, 0)
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetText(Money.ToString(TSM.Accounting.Transactions.GetAveragePrice(private.contextItemString, SECONDS_PER_DAY * 7, private.itemDetailType)))
)
:AddChild(UIElements.New("Text", "last30")
:SetWidth(120)
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetText(Money.ToString(TSM.Accounting.Transactions.GetAveragePrice(private.contextItemString, SECONDS_PER_DAY * 30, private.itemDetailType)))
)
)
:AddChild(UIElements.New("Frame", "totalPrice")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 8, 0)
:AddChild(UIElements.New("Text", "label")
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY3")
:SetTextColor("TEXT_ALT")
:SetText(L["Total Prices:"])
)
:AddChild(UIElements.New("Text", "total")
:SetWidth(120)
:SetMargin(0, 8, 0, 0)
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetText(Money.ToString(TSM.Accounting.Transactions.GetTotalPrice(private.contextItemString, nil, private.itemDetailType)))
)
:AddChild(UIElements.New("Text", "last7")
:SetWidth(120)
:SetMargin(0, 8, 0, 0)
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetText(Money.ToString(TSM.Accounting.Transactions.GetTotalPrice(private.contextItemString, SECONDS_PER_DAY * 7, private.itemDetailType)))
)
:AddChild(UIElements.New("Text", "last30")
:SetWidth(120)
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetText(Money.ToString(TSM.Accounting.Transactions.GetTotalPrice(private.contextItemString, SECONDS_PER_DAY * 30, private.itemDetailType)))
)
)
:AddChild(UIElements.New("Frame", "top")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 8, 0)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY3")
:SetTextColor("TEXT_ALT")
:SetText(private.itemDetailType == "sale" and L["Top Buyers"]..":" or L["Top Sellers"]..":")
)
:AddChild(UIElements.New("Text", "value")
:SetFont("BODY_BODY3")
:SetText(topPlayersText)
)
)
)
)
:AddChild(UIElements.New("QueryScrollingTable", "scrollingTable")
:SetSettingsContext(private.settings, "ledgerDetailScrollingTable")
:GetScrollingTableInfo()
:NewColumn("activityType")
:SetTitle(L["Activity Type"])
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("type", private.TableGetActivityTypeText)
:Commit()
:NewColumn("source")
:SetTitle(L["Source"])
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("source")
:Commit()
:NewColumn("buyerSeller")
:SetTitle(L["Buyer/Seller"])
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("otherPlayer")
:Commit()
:NewColumn("qty")
:SetTitle(L["Qty"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("quantity")
:Commit()
:NewColumn("perItem")
:SetTitle(L["Per Item"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo(nil, private.TableGetPerItemText)
:Commit()
:NewColumn("totalPrice")
:SetTitle(L["Total Price"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo(nil, private.TableGetTotalPriceText)
:Commit()
:NewColumn("time")
:SetTitle(L["Time"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("time", private.TableGetTimeframeText)
:Commit()
:Commit()
:SetQuery(query)
:SetAutoReleaseQuery(true)
:SetSelectionDisabled(true)
:SetScript("OnRowClick", private.ItemDetailScrollingTableOnRowClick)
)
end
function private.ItemDetailBackButtonOnClick(button)
button:GetParentElement():GetParentElement():GetParentElement():GetParentElement():SetPath(private.contextPath, true)
end
function private.ItemDetailTabOnClick(button)
private.itemDetailType = button:GetContext()
button:GetParentElement():GetParentElement():GetParentElement():GetParentElement():GetParentElement():ReloadContent()
end
function private.ItemDetailScrollingTableOnRowClick(scrollingTable, row, button)
if button ~= "RightButton" then
return
elseif not TSM.Accounting.Transactions.CanDeleteByUUID(row:GetUUID()) then
Log.PrintUser(L["This record belongs to another account and can only be deleted on that account."])
return
end
local subtitle = nil
local recordType, itemString, quantity, otherPlayer, price = row:GetFields("type", "itemString", "quantity", "otherPlayer", "price")
local name = TSM.UI.GetColoredItemName(itemString) or "?"
local amount = Money.ToString(price * quantity)
if recordType == "sale" then
subtitle = format(L["Sold %d of %s to %s for %s"], quantity, name, otherPlayer, amount)
elseif recordType == "buy" then
subtitle = format(L["Bought %d of %s from %s for %s"], quantity, name, otherPlayer, amount)
else
error("Unexpected Type: "..tostring(recordType))
end
scrollingTable:GetBaseElement():ShowConfirmationDialog(L["Delete Record?"], subtitle, private.DeleteRecordConfirmed, row:GetUUID())
end
function private.DeleteRecordConfirmed(uuid)
TSM.Accounting.Transactions.RemoveRowByUUID(uuid)
end
-- ============================================================================
-- Scrolling Table Helper Functions
-- ============================================================================
function private.TableGetActivityTypeText(recordType)
if recordType == "sale" then
return L["Sale"]
elseif recordType == "buy" then
return L["Buy"]
else
error("Unexpected Type: "..tostring(recordType))
end
end
function private.TableGetTimeframeText(timestamp)
return SecondsToTime(time() - timestamp)
end
function private.TableGetTotalPriceText(row)
return Money.ToString(row:GetField("price") * row:GetField("quantity"))
end
function private.TableGetPerItemText(row)
return Money.ToString(row:GetField("price"))
end

View File

@@ -0,0 +1,23 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Expenses = TSM.MainUI.Ledger:NewPackage("Expenses")
local L = TSM.Include("Locale").GetTable()
-- ============================================================================
-- Module Functions
-- ============================================================================
function Expenses.OnInitialize()
TSM.MainUI.Ledger.RegisterPage(L["Expenses"])
end
function Expenses.RegisterPage(name, callback)
TSM.MainUI.Ledger.RegisterChildPage(L["Expenses"], name, callback)
end

View File

@@ -0,0 +1,23 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local FailedAuctions = TSM.MainUI.Ledger:NewPackage("FailedAuctions")
local L = TSM.Include("Locale").GetTable()
-- ============================================================================
-- Module Functions
-- ============================================================================
function FailedAuctions.OnInitialize()
TSM.MainUI.Ledger.RegisterPage(L["Failed Auctions"])
end
function FailedAuctions.RegisterPage(name, callback)
TSM.MainUI.Ledger.RegisterChildPage(L["Failed Auctions"], name, callback)
end

View File

@@ -0,0 +1,329 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Inventory = TSM.MainUI.Ledger:NewPackage("Inventory")
local L = TSM.Include("Locale").GetTable()
local TempTable = TSM.Include("Util.TempTable")
local Money = TSM.Include("Util.Money")
local String = TSM.Include("Util.String")
local Math = TSM.Include("Util.Math")
local Database = TSM.Include("Util.Database")
local ItemInfo = TSM.Include("Service.ItemInfo")
local CustomPrice = TSM.Include("Service.CustomPrice")
local BagTracking = TSM.Include("Service.BagTracking")
local GuildTracking = TSM.Include("Service.GuildTracking")
local AuctionTracking = TSM.Include("Service.AuctionTracking")
local MailTracking = TSM.Include("Service.MailTracking")
local AltTracking = TSM.Include("Service.AltTracking")
local InventoryService = TSM.Include("Service.Inventory")
local Settings = TSM.Include("Service.Settings")
local UIElements = TSM.Include("UI.UIElements")
local private = {
settings = nil,
db = nil,
query = nil,
searchFilter = "",
groupFilter = {},
valuePriceSource = "dbmarket", -- luacheck: ignore 1005 - hidden modify via SetSettingInfo()
}
-- ============================================================================
-- Module Functions
-- ============================================================================
function Inventory.OnInitialize()
private.settings = Settings.NewView()
:AddKey("global", "mainUIContext", "ledgerInventoryScrollingTable")
TSM.MainUI.Ledger.RegisterPage(L["Inventory"], private.DrawInventoryPage)
end
function Inventory.OnEnable()
private.db = Database.NewSchema("LEDGER_INVENTORY")
:AddUniqueStringField("itemString")
:Commit()
private.query = private.db:NewQuery()
:VirtualField("bagQuantity", "number", BagTracking.GetBagsQuantityByBaseItemString, "itemString")
:VirtualField("guildQuantity", "number", private.GuildQuantityVirtualField, "itemString")
:VirtualField("auctionQuantity", "number", AuctionTracking.GetQuantityByBaseItemString, "itemString")
:VirtualField("mailQuantity", "number", MailTracking.GetQuantityByBaseItemString, "itemString")
:VirtualField("altQuantity", "number", AltTracking.GetQuantityByBaseItemString, "itemString")
:VirtualField("totalQuantity", "number", private.TotalQuantityVirtualField)
:VirtualField("totalValue", "number", private.TotalValueVirtualField)
:VirtualField("totalBankQuantity", "number", private.GetTotalBankQuantity)
:InnerJoin(ItemInfo.GetDBForJoin(), "itemString")
:LeftJoin(TSM.Groups.GetItemDBForJoin(), "itemString")
:OrderBy("name", true)
end
-- ============================================================================
-- Inventory UI
-- ============================================================================
function private.DrawInventoryPage()
TSM.UI.AnalyticsRecordPathChange("main", "ledger", "inventory")
local items = TempTable.Acquire()
for _, itemString in BagTracking.BaseItemIterator() do
items[itemString] = true
end
for _, itemString in GuildTracking.BaseItemIterator() do
items[itemString] = true
end
for _, itemString in AuctionTracking.BaseItemIterator() do
items[itemString] = true
end
for _, itemString in MailTracking.BaseItemIterator() do
items[itemString] = true
end
for _, itemString in AltTracking.BaseItemIterator() do
items[itemString] = true
end
private.db:TruncateAndBulkInsertStart()
for itemString in pairs(items) do
private.db:BulkInsertNewRow(itemString)
end
private.db:BulkInsertEnd()
TempTable.Release(items)
private.UpdateQuery()
return UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Frame", "row1")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8)
:AddChild(UIElements.New("Input", "filter")
:SetMargin(0, 8, 0, 0)
:SetIconTexture("iconPack.18x18/Search")
:SetClearButtonEnabled(true)
:AllowItemInsert()
:SetHintText(L["Filter by keyword"])
:SetValue(private.searchFilter)
:SetScript("OnValueChanged", private.SearchFilterChanged)
)
:AddChild(UIElements.New("GroupSelector", "group")
:SetWidth(240)
:SetHintText(L["Filter by groups"])
:SetScript("OnSelectionChanged", private.GroupFilterChanged)
)
)
:AddChild(UIElements.New("Frame", "row2")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8, 8, 0, 8)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3")
:SetText(L["Value Price Source"])
)
:AddChild(UIElements.New("Input", "input")
:SetMargin(4, 8, 0, 0)
:SetBackgroundColor("PRIMARY_BG_ALT")
:SetBorderColor("ACTIVE_BG")
:SetFont("TABLE_TABLE1")
:SetValidateFunc("CUSTOM_PRICE")
:SetSettingInfo(private, "valuePriceSource")
:SetScript("OnValueChanged", private.FilterChangedCommon)
)
:AddChild(UIElements.New("Frame", "value")
:SetLayout("HORIZONTAL")
:SetWidth(240)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3")
:SetMargin(0, 4, 0, 0)
:SetText(L["Total Value"]..":")
)
:AddChild(UIElements.New("Text", "value")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetText(Money.ToString(private.GetTotalValue()))
)
)
)
:AddChild(UIElements.New("Frame", "accountingScrollingTableFrame")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("QueryScrollingTable", "scrollingTable")
:SetSettingsContext(private.settings, "ledgerInventoryScrollingTable")
:GetScrollingTableInfo()
:NewColumn("item")
:SetTitle(L["Item"])
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("itemString", TSM.UI.GetColoredItemName)
:SetTooltipInfo("itemString")
:SetSortInfo("name")
:DisableHiding()
:Commit()
:NewColumn("totalItems")
:SetTitle(L["Total"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("totalQuantity")
:SetSortInfo("totalQuantity")
:Commit()
:NewColumn("bags")
:SetTitle(L["Bags"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("bagQuantity")
:SetSortInfo("bagQuantity")
:Commit()
:NewColumn("banks")
:SetTitle(L["Banks"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("totalBankQuantity")
:SetSortInfo("totalBankQuantity")
:Commit()
:NewColumn("mail")
:SetTitle(L["Mail"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("mailQuantity")
:SetSortInfo("mailQuantity")
:Commit()
:NewColumn("alts")
:SetTitle(L["Alts"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("altQuantity")
:SetSortInfo("altQuantity")
:Commit()
:NewColumn("guildVault")
:SetTitle(L["GVault"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("guildQuantity")
:SetSortInfo("guildQuantity")
:Commit()
:NewColumn("auctionHouse")
:SetTitle(L["AH"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("auctionQuantity")
:SetSortInfo("auctionQuantity")
:Commit()
:NewColumn("totalValue")
:SetTitle(L["Value"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("totalValue", private.TableGetTotalValueText)
:SetSortInfo("totalValue")
:Commit()
:Commit()
:SetSelectionDisabled(true)
:SetQuery(private.query)
)
)
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.FilterChangedCommon(element)
private.UpdateQuery()
element:GetElement("__parent.__parent.accountingScrollingTableFrame.scrollingTable")
:SetQuery(private.query, true)
element:GetElement("__parent.__parent.row2.value.value")
:SetText(Money.ToString(private.GetTotalValue()))
:Draw()
end
function private.SearchFilterChanged(input)
private.searchFilter = input:GetValue()
private.FilterChangedCommon(input)
end
function private.GroupFilterChanged(groupSelector)
wipe(private.groupFilter)
for groupPath in groupSelector:SelectedGroupIterator() do
private.groupFilter[groupPath] = true
end
private.FilterChangedCommon(groupSelector)
end
-- ============================================================================
-- Scrolling Table Helper Functions
-- ============================================================================
function private.TableGetTotalValueText(totalValue)
return Math.IsNan(totalValue) and "" or Money.ToString(totalValue)
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.GuildQuantityVirtualField(itemString)
local totalNum = 0
for guildName in pairs(TSM.db.factionrealm.internalData.guildVaults) do
local guildQuantity = InventoryService.GetGuildQuantity(itemString, guildName)
totalNum = totalNum + guildQuantity
end
return totalNum
end
function private.TotalQuantityVirtualField(row)
local bagQuantity, totalBankQuantity, guildQuantity, auctionQuantity, mailQuantity, altQuantity = row:GetFields("bagQuantity", "totalBankQuantity", "guildQuantity", "auctionQuantity", "mailQuantity", "altQuantity")
return bagQuantity + totalBankQuantity + guildQuantity + auctionQuantity + mailQuantity + altQuantity
end
function private.TotalValueVirtualField(row)
local itemString, totalQuantity = row:GetFields("itemString", "totalQuantity")
local price = CustomPrice.GetValue(private.valuePriceSource, itemString)
if not price then
return Math.GetNan()
end
return price * totalQuantity
end
function private.GetTotalBankQuantity(row)
local itemString = row:GetField("itemString")
local bankQuantity = BagTracking.GetBankQuantityByBaseItemString(itemString)
local reagentBankQuantity = BagTracking.GetReagentBankQuantityByBaseItemString(itemString)
return bankQuantity + reagentBankQuantity
end
function private.GetTotalValue()
-- can't lookup the value of items while the query is iteratoring, so grab the list of items first
local itemQuantities = TempTable.Acquire()
for _, row in private.query:Iterator() do
local itemString, total = row:GetFields("itemString", "totalQuantity")
itemQuantities[itemString] = total
end
local totalValue = 0
for itemString, total in pairs(itemQuantities) do
local price = CustomPrice.GetValue(private.valuePriceSource, itemString)
if price then
totalValue = totalValue + price * total
end
end
TempTable.Release(itemQuantities)
return totalValue
end
function private.UpdateQuery()
private.query:ResetFilters()
if private.searchFilter ~= "" then
private.query:Matches("name", String.Escape(private.searchFilter))
end
if next(private.groupFilter) then
private.query:InTable("groupPath", private.groupFilter)
end
end

View File

@@ -0,0 +1,23 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Revenue = TSM.MainUI.Ledger:NewPackage("Revenue")
local L = TSM.Include("Locale").GetTable()
-- ============================================================================
-- Module Functions
-- ============================================================================
function Revenue.OnInitialize()
TSM.MainUI.Ledger.RegisterPage(L["Revenue"])
end
function Revenue.RegisterPage(name, callback)
TSM.MainUI.Ledger.RegisterChildPage(L["Revenue"], name, callback)
end

View File

@@ -0,0 +1,299 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Resale = TSM.MainUI.Ledger.Revenue:NewPackage("Resale")
local L = TSM.Include("Locale").GetTable()
local Table = TSM.Include("Util.Table")
local Money = TSM.Include("Util.Money")
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 SECONDS_PER_DAY = 24 * 60 * 60
local private = {
settings = nil,
summaryQuery = nil,
characters = {},
characterFilter = {},
typeFilter = {},
rarityList = {},
rarityFilter = {},
groupFilter = {},
searchFilter = "",
timeFrameFilter = 30 * SECONDS_PER_DAY
}
local TYPE_LIST = { L["Auction"], COD, TRADE, L["Vendor"] }
local TYPE_KEYS = { "Auction", "COD", "Trade", "Vendor" }
do
for _, key in ipairs(TYPE_KEYS) do
private.typeFilter[key] = true
end
for i = 1, 4 do
tinsert(private.rarityList, _G[format("ITEM_QUALITY%d_DESC", i)])
private.rarityFilter[i] = true
end
end
local TIME_LIST = { L["All Time"], L["Last 3 Days"], L["Last 7 Days"], L["Last 14 Days"], L["Last 30 Days"], L["Last 60 Days"] }
local TIME_KEYS = { 0, 3 * SECONDS_PER_DAY, 7 * SECONDS_PER_DAY, 14 * SECONDS_PER_DAY, 30 * SECONDS_PER_DAY, 60 * SECONDS_PER_DAY }
-- ============================================================================
-- Module Functions
-- ============================================================================
function Resale.OnInitialize()
private.settings = Settings.NewView()
:AddKey("global", "mainUIContext", "ledgerResaleScrollingTable")
TSM.MainUI.Ledger.Revenue.RegisterPage(L["Resale"], private.DrawResalePage)
end
-- ============================================================================
-- Resale UI
-- ============================================================================
function private.DrawResalePage()
TSM.UI.AnalyticsRecordPathChange("main", "ledger", "revenue", "resale")
wipe(private.characters)
TSM.Accounting.Transactions.GetCharacters(private.characters)
for _, character in ipairs(private.characters) do
private.characterFilter[character] = true
end
private.summaryQuery = private.summaryQuery or TSM.Accounting.Transactions.CreateSummaryQuery()
:InnerJoin(ItemInfo.GetDBForJoin(), "itemString")
:OrderBy("name", true)
private.UpdateQuery()
local totalProfit = 0
local numItems = 0
for _, row in private.summaryQuery:Iterator() do
totalProfit = totalProfit + row:GetField("totalProfit")
numItems = numItems + min(row:GetFields("sold", "bought"))
end
return UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Frame", "row1")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8)
:AddChild(UIElements.New("Input", "filter")
:SetMargin(0, 8, 0, 0)
:SetIconTexture("iconPack.18x18/Search")
:SetClearButtonEnabled(true)
:AllowItemInsert()
:SetHintText(L["Filter by keyword"])
:SetValue(private.searchFilter)
:SetScript("OnValueChanged", private.SearchFilterChanged)
)
:AddChild(UIElements.New("GroupSelector", "group")
:SetWidth(240)
:SetHintText(L["Filter by groups"])
:SetScript("OnSelectionChanged", private.GroupFilterChanged)
)
)
:AddChild(UIElements.New("Frame", "row2")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8, 8, 0, 8)
:AddChild(UIElements.New("MultiselectionDropdown", "type")
:SetMargin(0, 8, 0, 0)
:SetItems(TYPE_LIST, TYPE_KEYS)
:SetSettingInfo(private, "typeFilter")
:SetSelectionText(L["No Types"], L["%d Types"], L["All Types"])
:SetScript("OnSelectionChanged", private.FilterChangedCommon)
)
:AddChild(UIElements.New("MultiselectionDropdown", "rarity")
:SetMargin(0, 8, 0, 0)
:SetItems(private.rarityList)
:SetSettingInfo(private, "rarityFilter")
:SetSelectionText(L["No Rarities"], L["%d Rarities"], L["All Rarities"])
:SetScript("OnSelectionChanged", private.FilterChangedCommon)
)
:AddChild(UIElements.New("MultiselectionDropdown", "character")
:SetMargin(0, 8, 0, 0)
:SetItems(private.characters, private.characters)
:SetSettingInfo(private, "characterFilter")
:SetSelectionText(L["No Characters"], L["%d Characters"], L["All Characters"])
:SetScript("OnSelectionChanged", private.FilterChangedCommon)
)
:AddChild(UIElements.New("SelectionDropdown", "time")
:SetItems(TIME_LIST, TIME_KEYS)
:SetSelectedItemByKey(private.timeFrameFilter)
:SetSettingInfo(private, "timeFrameFilter")
:SetScript("OnSelectionChanged", private.FilterChangedCommon)
)
)
:AddChild(UIElements.New("QueryScrollingTable", "scrollingTable")
:SetSettingsContext(private.settings, "ledgerResaleScrollingTable")
:GetScrollingTableInfo()
:NewColumn("item")
:SetTitle(L["Item"])
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo("itemString", TSM.UI.GetColoredItemName)
:SetSortInfo("name")
:SetTooltipInfo("itemString")
:DisableHiding()
:Commit()
:NewColumn("bought")
:SetTitle(L["Bought"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("bought")
:SetSortInfo("bought")
:Commit()
:NewColumn("avgBuyPrice")
:SetTitle(L["Avg Buy Price"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("avgBuyPrice", private.GetMoneyText)
:SetSortInfo("avgBuyPrice")
:Commit()
:NewColumn("sold")
:SetTitle(L["Sold"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("sold")
:SetSortInfo("sold")
:Commit()
:NewColumn("avgSellPrice")
:SetTitle(L["Avg Sell Price"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("avgSellPrice", private.GetMoneyText)
:SetSortInfo("avgSellPrice")
:Commit()
:NewColumn("avgProfit")
:SetTitle(L["Avg Profit"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("avgProfit", private.GetColoredMoneyText)
:SetSortInfo("avgProfit")
:Commit()
:NewColumn("totalProfit")
:SetTitle(L["Total Profit"])
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("totalProfit", private.GetColoredMoneyText)
:SetSortInfo("totalProfit")
:Commit()
:NewColumn("profitPct")
:SetTitle("%")
:SetFont("ITEM_BODY3")
:SetJustifyH("RIGHT")
:SetTextInfo("profitPct", private.GetPctText)
:SetSortInfo("profitPct")
:Commit()
:Commit()
:SetQuery(private.summaryQuery)
:SetScript("OnRowClick", private.TableSelectionChanged)
)
:AddChild(UIElements.New("Texture", "line")
:SetHeight(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Frame", "footer")
:SetLayout("HORIZONTAL")
:SetHeight(40)
:SetPadding(8)
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Text", "num")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(format(L["%s Items Resold"], Theme.GetColor("INDICATOR"):ColorText(FormatLargeNumber(numItems))))
)
:AddChild(UIElements.New("Texture", "line")
:SetMargin(4, 8, 0, 0)
:SetWidth(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Text", "profit")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(format(L["%s Total Profit"], Money.ToString(totalProfit)))
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
end
-- ============================================================================
-- Scrolling Table Helper Functions
-- ============================================================================
function private.GetMoneyText(value)
return Money.ToString(value)
end
function private.GetColoredMoneyText(value)
return Money.ToString(value, Theme.GetFeedbackColor(value >= 0 and "GREEN" or "RED"):GetTextColorPrefix())
end
function private.GetPctText(value)
return Theme.GetFeedbackColor(value >= 0 and "GREEN" or "RED"):ColorText(value.."%")
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.FilterChangedCommon(dropdown)
private.UpdateQuery()
local totalProfit = 0
local numItems = 0
for _, row in private.summaryQuery:Iterator() do
totalProfit = totalProfit + row:GetField("totalProfit")
numItems = numItems + min(row:GetFields("sold", "bought"))
end
dropdown:GetElement("__parent.__parent.scrollingTable"):UpdateData(true)
local footer = dropdown:GetElement("__parent.__parent.footer")
footer:GetElement("num"):SetText(format(L["%s Items Resold"], Theme.GetColor("INDICATOR"):ColorText(FormatLargeNumber(numItems))))
footer:GetElement("profit"):SetText(format(L["%s Total Profit"], Money.ToString(totalProfit)))
footer:Draw()
end
function private.SearchFilterChanged(input)
private.searchFilter = input:GetValue()
private.FilterChangedCommon(input)
end
function private.GroupFilterChanged(groupSelector)
wipe(private.groupFilter)
for groupPath in groupSelector:SelectedGroupIterator() do
private.groupFilter[groupPath] = true
end
private.FilterChangedCommon(groupSelector)
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.UpdateQuery()
private.summaryQuery:ResetFilters()
local groupFilter = next(private.groupFilter) and private.groupFilter or nil
local searchFilter = private.searchFilter ~= "" and private.searchFilter or nil
local typeFilter = Table.Count(private.typeFilter) ~= #TYPE_KEYS and private.typeFilter or nil
local characterFilter = Table.Count(private.characterFilter) ~= #private.characters and private.characterFilter or nil
local minTime = private.timeFrameFilter ~= 0 and (time() - private.timeFrameFilter) or nil
TSM.Accounting.Transactions.UpdateSummaryData(groupFilter, searchFilter, typeFilter, characterFilter, minTime)
if Table.Count(private.rarityFilter) ~= #private.rarityList then
private.summaryQuery:InTable("quality", private.rarityFilter)
end
end
function private.TableSelectionChanged(scrollingTable, row)
TSM.MainUI.Ledger.ShowItemDetail(scrollingTable:GetParentElement():GetParentElement(), row:GetField("itemString"), "sale")
end

View File

@@ -0,0 +1,360 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Auctioning = TSM.MainUI.Operations:NewPackage("Auctioning")
local L = TSM.Include("Locale").GetTable()
local String = TSM.Include("Util.String")
local Money = TSM.Include("Util.Money")
local Vararg = TSM.Include("Util.Vararg")
local CustomPrice = TSM.Include("Service.CustomPrice")
local UIElements = TSM.Include("UI.UIElements")
local private = {
currentOperationName = nil,
currentTab = nil,
}
local IGNORE_DURATION_OPTIONS = {
L["None"],
AUCTION_TIME_LEFT1.." ("..AUCTION_TIME_LEFT1_DETAIL..")",
AUCTION_TIME_LEFT2.." ("..AUCTION_TIME_LEFT2_DETAIL..")",
AUCTION_TIME_LEFT3.." ("..AUCTION_TIME_LEFT3_DETAIL..")",
}
local BELOW_MIN_ITEMS = { L["Don't Post Items"], L["Post at Minimum Price"], L["Post at Maximum Price"], L["Post at Normal Price"], L["Ignore Auctions Below Min"] }
local BELOW_MIN_KEYS = { "none", "minPrice", "maxPrice", "normalPrice", "ignore" }
local ABOVE_MAX_ITEMS = { L["Don't Post Items"], L["Post at Minimum Price"], L["Post at Maximum Price"], L["Post at Normal Price"] }
local ABOVE_MAX_KEYS = { "none", "minPrice", "maxPrice", "normalPrice" }
local BAD_PRICE_SOURCES = { auctioningopmin = true, auctioningopmax = true, auctioningopnormal = true }
-- ============================================================================
-- Module Functions
-- ============================================================================
function Auctioning.OnInitialize()
TSM.MainUI.Operations.RegisterModule("Auctioning", private.GetAuctioningOperationSettings)
end
-- ============================================================================
-- Auctioning Operation Settings UI
-- ============================================================================
function private.GetAuctioningOperationSettings(operationName)
TSM.UI.AnalyticsRecordPathChange("main", "operations", "auctioning")
private.currentOperationName = operationName
private.currentTab = private.currentTab or L["Details"]
return UIElements.New("TabGroup", "tabs")
:SetMargin(0, 0, 8, 0)
:SetNavCallback(private.GetAuctioningSettings)
:AddPath(L["Details"])
:AddPath(L["Posting"])
:AddPath(L["Canceling"])
:SetPath(private.currentTab)
end
function private.GetDetailsSettings()
TSM.UI.AnalyticsRecordPathChange("main", "operations", "auctioning", "details")
local operation = TSM.Operations.GetSettings("Auctioning", private.currentOperationName)
return UIElements.New("ScrollFrame", "settings")
:SetPadding(8, 8, 8, 0)
:SetBackgroundColor("PRIMARY_BG")
:AddChild(TSM.MainUI.Operations.CreateExpandableSection("Auctioning", "generalOptions", L["General Options"], L["Adjust some general settings."])
:AddChild(UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
:AddChildrenWithFunction(private.AddMaxStackSizeSetting)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("ignoreLowDuration", L["Ignore auctions by duration"])
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 16)
:AddChild(UIElements.New("SelectionDropdown", "dropdown")
:SetHeight(24)
:SetDisabled(TSM.Operations.HasRelationship("Auctioning", private.currentOperationName, "ignoreLowDuration"))
:SetItems(IGNORE_DURATION_OPTIONS)
:SetSelectedItemByKey(operation.ignoreLowDuration + 1, true)
:SetScript("OnSelectionChanged", private.IgnoreLowDurationOnSelectionChanged)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("blacklist", L["Blacklisted players"])
:SetLayout("VERTICAL")
:SetHeight(48)
:AddChild(UIElements.New("Input", "input")
:SetHeight(24)
:SetBackgroundColor("ACTIVE_BG")
:SetHintText(L["Enter player name"])
:SetDisabled(TSM.Operations.HasRelationship("Auctioning", private.currentOperationName, "blacklist"))
:SetScript("OnEnterPressed", private.BlacklistInputOnEnterPressed)
)
)
:AddChildrenWithFunction(private.AddBlacklistPlayers)
)
)
:AddChild(TSM.MainUI.Operations.GetOperationManagementElements("Auctioning", private.currentOperationName))
end
function private.AddMaxStackSizeSetting(frame)
if TSM.IsWowClassic() then
frame:AddChild(private.CreateToggleLine("matchStackSize", L["Match stack size"]))
end
end
function private.GetPostingSettings()
TSM.UI.AnalyticsRecordPathChange("main", "operations", "auctioning", "posting")
local operation = TSM.Operations.GetSettings("Auctioning", private.currentOperationName)
return UIElements.New("ScrollFrame", "settings")
:SetPadding(8, 8, 8, 0)
:SetBackgroundColor("PRIMARY_BG")
:AddChild(TSM.MainUI.Operations.CreateExpandableSection("Auctioning", "postingSettings", L["Posting Options"], L["Adjust the settings below to set how groups attached to this operation will be auctioned."])
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("duration", L["Auction duration"])
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("SelectionDropdown", "dropdown")
:SetHeight(24)
:SetDisabled(TSM.Operations.HasRelationship("Auctioning", private.currentOperationName, "duration"))
:SetItems(TSM.CONST.AUCTION_DURATIONS)
:SetSelectedItemByKey(operation.duration)
:SetScript("OnSelectionChanged", private.SetAuctioningDuration)
)
)
:AddChild(private.CreateInputLine("postCap", L["Post cap"], false, true))
:AddChildrenWithFunction(private.AddStackSizeSettings)
:AddChild(private.CreateInputLine("keepQuantity", L["Amount kept in bags"], false, true))
:AddChild(private.CreateInputLine("maxExpires", L["Don't post after this many expires"]))
)
:AddChild(TSM.MainUI.Operations.CreateExpandableSection("Auctioning", "priceSettings", L["Posting Price"], L["Adjust the settings below to set how groups attached to this operation will be priced."])
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("bidPercent", L["Set bid as percentage of buyout"])
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("Input", "input")
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG")
:SetValidateFunc(private.BidPercentValidateFunc)
:SetDisabled(TSM.Operations.HasRelationship("Auctioning", private.currentOperationName, "bidPercent"))
:SetValue((operation.bidPercent * 100).."%")
:SetScript("OnValueChanged", private.BidPercentOnValueChanged)
)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3")
:SetFormattedText(L["Enter a value from %d - %d%%"], 0, 100)
:SetTextColor(TSM.Operations.HasRelationship("Auctioning", private.currentOperationName, "bidPercent") and "TEXT_DISABLED" or "TEXT")
)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedPriceInput("undercut", L["Undercut amount"], 66, private.CheckUndercut)
:SetMargin(0, 0, 0, 12)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedPriceInput("minPrice", L["Minimum price"], 126, BAD_PRICE_SOURCES))
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("priceReset", L["When below minimum:"])
:SetMargin(0, 0, 12, 12)
:AddChild(UIElements.New("SelectionDropdown", "dropdown")
:SetWidth(240)
:SetDisabled(TSM.Operations.HasRelationship("Auctioning", private.currentOperationName, "priceReset"))
:SetItems(BELOW_MIN_ITEMS, BELOW_MIN_KEYS)
:SetSettingInfo(operation, "priceReset")
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedPriceInput("maxPrice", L["Maximum price"], 126, BAD_PRICE_SOURCES))
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("aboveMax", L["When above maximum:"])
:SetMargin(0, 0, 12, 12)
:AddChild(UIElements.New("SelectionDropdown", "dropdown")
:SetWidth(240)
:SetDisabled(TSM.Operations.HasRelationship("Auctioning", private.currentOperationName, "aboveMax"))
:SetItems(ABOVE_MAX_ITEMS, ABOVE_MAX_KEYS)
:SetSettingInfo(operation, "aboveMax")
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedPriceInput("normalPrice", L["Normal price"], 126, BAD_PRICE_SOURCES))
)
end
function private.AddStackSizeSettings(frame)
if not TSM.IsWowClassic() then
return
end
frame:AddChild(private.CreateInputLine("stackSize", L["Stack size"], false, true))
frame:AddChild(private.CreateToggleLine("stackSizeIsCap", L["Allow partial stack"]))
end
function private.GetCancelingSettings()
TSM.UI.AnalyticsRecordPathChange("main", "operations", "auctioning", "canceling")
return UIElements.New("ScrollFrame", "settings")
:SetPadding(8, 8, 8, 0)
:AddChild(TSM.MainUI.Operations.CreateExpandableSection("Auctioning", "priceSettings", L["Canceling Options"], L["Adjust the settings below to set how groups attached to this operation will be cancelled."])
:AddChild(private.CreateToggleLine("cancelUndercut", L["Cancel undercut auctions"]))
:AddChild(private.CreateToggleLine("cancelRepost", L["Cancel to repost higher"]))
:AddChild(TSM.MainUI.Operations.CreateLinkedPriceInput("cancelRepostThreshold", L["Repost threshold"], 66))
)
end
function private.GetAuctioningSettings(self, button)
private.currentTab = button
if button == L["Details"] then
return private.GetDetailsSettings()
elseif button == L["Posting"] then
return private.GetPostingSettings()
elseif button == L["Canceling"] then
return private.GetCancelingSettings()
else
error("Unknown button!")
end
end
function private.AddBlacklistPlayers(frame)
local operation = TSM.Operations.GetSettings("Auctioning", private.currentOperationName)
if operation.blacklist == "" then return end
local containerFrame = UIElements.New("Frame", "blacklistFrame")
:SetLayout("FLOW")
for index, player in Vararg.Iterator(strsplit(",", operation.blacklist)) do
containerFrame:AddChild(UIElements.New("Frame", "blacklist" .. index)
:SetLayout("HORIZONTAL")
:SetSize(100, 20)
:SetMargin(0, 12, 0, 0)
:AddChild(UIElements.New("Text", "text")
:SetWidth("AUTO")
:SetMargin(0, 2, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(player)
)
:AddChild(UIElements.New("Button", "removeBtn")
:SetBackgroundAndSize("iconPack.14x14/Close/Circle")
:SetContext(player)
:SetScript("OnClick", private.RemoveBlacklistOnClick)
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
end
frame:AddChild(containerFrame)
end
function private.CreateInputLine(key, label, disabled, margin)
local operation = TSM.Operations.GetSettings("Auctioning", private.currentOperationName)
local hasRelationship = TSM.Operations.HasRelationship("Auctioning", private.currentOperationName, key)
return TSM.MainUI.Operations.CreateLinkedSettingLine(key, label, disabled)
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, margin and 12 or 4)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("Input", "input")
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG")
:SetContext(key)
:SetDisabled(hasRelationship or disabled)
:SetValidateFunc("CUSTOM_PRICE")
:SetSettingInfo(operation, key)
)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3")
:SetTextColor((hasRelationship or disabled) and "TEXT_DISABLED" or "TEXT")
:SetFormattedText(L["Supported value range: %d - %d"], TSM.Operations.Auctioning.GetMinMaxValues(key))
)
)
end
function private.CreateToggleLine(key, label)
local operation = TSM.Operations.GetSettings("Auctioning", private.currentOperationName)
return TSM.MainUI.Operations.CreateLinkedSettingLine(key, label)
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("ToggleOnOff", "toggle")
:SetHeight(18)
:SetDisabled(TSM.Operations.HasRelationship("Auctioning", private.currentOperationName, key))
:SetSettingInfo(operation, key)
)
end
function private.CheckUndercut(_, value)
if not TSM.IsWowClassic() and Money.FromString(Money.ToString(value) or value) == 0 then
return true
elseif not TSM.IsWowClassic() and (Money.FromString(Money.ToString(value) or value) or math.huge) < COPPER_PER_SILVER then
return false, L["Invalid undercut. To post below the cheapest auction without a significant undercut, set your undercut to 0c."]
else
local isValid, err = CustomPrice.Validate(value)
if isValid then
return true
end
return false, L["Invalid custom price."].." "..err
end
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.IgnoreLowDurationOnSelectionChanged(self)
local operation = TSM.Operations.GetSettings("Auctioning", private.currentOperationName)
operation.ignoreLowDuration = self:GetSelectedItemKey() - 1
end
function private.BlacklistInputOnEnterPressed(input)
local newPlayer = input:GetValue()
if newPlayer == "" or strfind(newPlayer, ",") or newPlayer ~= String.Escape(newPlayer) then
-- this is an invalid player name
return
end
local operation = TSM.Operations.GetSettings("Auctioning", private.currentOperationName)
local found = false
for _, player in Vararg.Iterator(strsplit(",", operation.blacklist)) do
if newPlayer == player then
-- this player is already added
input:SetValue("")
found = true
end
end
if found then
return
end
operation.blacklist = (operation.blacklist == "") and newPlayer or (operation.blacklist..","..newPlayer)
input:GetElement("__parent.__parent.__parent.__parent.__parent.__parent"):ReloadContent()
end
function private.RemoveBlacklistOnClick(button)
local player = button:GetContext()
-- FIXME: This sort of logic should go within some Auctioning-specific operation setting wrapper code
local operation = TSM.Operations.GetSettings("Auctioning", private.currentOperationName)
if operation.blacklist == player then
operation.blacklist = ""
else
-- handle cases where this entry is at the start, in the middle, and at the end
operation.blacklist = gsub(operation.blacklist, "^"..player..",", "")
operation.blacklist = gsub(operation.blacklist, ","..player..",", ",")
operation.blacklist = gsub(operation.blacklist, ","..player.."$", "")
end
button:GetElement("__parent.__parent.__parent.__parent.__parent.__parent.__parent"):ReloadContent()
end
function private.SetAuctioningDuration(dropdown)
local operation = TSM.Operations.GetSettings("Auctioning", private.currentOperationName)
operation.duration = dropdown:GetSelectedItemKey()
end
function private.BidPercentValidateFunc(_, value)
value = strmatch(value, "^([0-9]+) *%%?$")
value = tonumber(value)
if not value or value < 0 or value > 100 then
return false, L["Bid percent must be between 0 and 100."]
end
return true
end
function private.BidPercentOnValueChanged(input)
local operation = TSM.Operations.GetSettings("Auctioning", private.currentOperationName)
local value = strmatch(input:GetValue(), "^([0-9]+) *%%?$")
value = tonumber(value) / 100
operation.bidPercent = value
end

View File

@@ -0,0 +1,867 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Operations = TSM.MainUI:NewPackage("Operations")
local L = TSM.Include("Locale").GetTable()
local Log = TSM.Include("Util.Log")
local Theme = TSM.Include("Util.Theme")
local Money = TSM.Include("Util.Money")
local TempTable = TSM.Include("Util.TempTable")
local Settings = TSM.Include("Service.Settings")
local UIElements = TSM.Include("UI.UIElements")
local private = {
settings = nil,
moduleNames = {},
moduleCollapsed = {},
moduleCallbacks = {},
currentModule = nil,
currentOperationName = nil,
playerList = {},
linkMenuEntries = {},
}
-- ============================================================================
-- Module Functions
-- ============================================================================
function Operations.OnInitialize()
private.settings = Settings.NewView()
:AddKey("global", "mainUIContext", "operationsDividedContainer")
:AddKey("global", "mainUIContext", "operationsSummaryScrollingTable")
TSM.MainUI.RegisterTopLevelPage(L["Operations"], private.GetOperationsFrame)
end
function Operations.RegisterModule(name, callback)
tinsert(private.moduleNames, name)
private.moduleCallbacks[name] = callback
end
function Operations.ShowOperationSettings(baseFrame, moduleName, operationName)
baseFrame:SetSelectedNavButton(L["Operations"], true)
baseFrame:GetElement("content.operations.selection.operationTree"):SetSelectedOperation(moduleName, operationName)
end
function Operations.GetOperationManagementElements(moduleName, operationName)
local operation = TSM.Operations.GetSettings(private.currentModule, private.currentOperationName)
wipe(private.playerList)
for factionrealm in TSM.db:GetConnectedRealmIterator("factionrealm") do
for _, character in TSM.db:FactionrealmCharacterIterator(factionrealm) do
tinsert(private.playerList, character.." - "..factionrealm)
end
end
return UIElements.New("Frame", "management")
:SetLayout("VERTICAL")
:AddChild(Operations.CreateExpandableSection(moduleName, "managementOptions", L["Management Options"], L["Below you can ignore this operation on certain characters or realms."])
:AddChild(Operations.CreateSettingLine("ignoreFactionRealms", L["Ignore operation on faction-realms"])
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("MultiselectionDropdown", "dropdown")
:SetHeight(24)
:SetItems(TSM.db:GetScopeKeys("factionrealm"), TSM.db:GetScopeKeys("factionrealm"))
:SetSelectionText(L["No Faction-Realms"], L["%d Faction-Realms"], L["All Faction-Realms"])
:SetSettingInfo(operation, "ignoreFactionrealm")
)
)
:AddChild(Operations.CreateSettingLine("ignoreCharacters", L["Ignore operation on characters"])
:SetLayout("VERTICAL")
:SetHeight(48)
:AddChild(UIElements.New("MultiselectionDropdown", "dropdown")
:SetHeight(24)
:SetItems(private.playerList, private.playerList)
:SetSelectionText(L["No Characters"], L["%d Characters"], L["All Characters"])
:SetSettingInfo(operation, "ignorePlayer")
)
)
)
:AddChild(Operations.CreateExpandableSection(moduleName, "groupManagement", L["Group Management"], L["Here you can add/remove what groups this operation is attached to."])
:AddChild(Operations.CreateSettingLine("applyNewGroup", L["Apply operation to group"])
:SetLayout("VERTICAL")
:SetHeight(48)
:AddChild(UIElements.New("GroupSelector", "group")
:SetHintText(L["Add operation to groups"])
:SetScript("OnSelectionChanged", private.GroupSelectionChanged)
)
)
:AddChildrenWithFunction(private.AddOperationGroups)
)
end
function Operations.CreateExpandableSection(moduleName, id, text, description)
return UIElements.New("CollapsibleContainer", id)
:SetLayout("VERTICAL")
:SetMargin(0, 0, 0, 8)
:SetContextTable(private.moduleCollapsed, moduleName..text)
:SetHeadingText(text)
:AddChild(UIElements.New("Text", "description")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:SetFont("BODY_BODY3")
:SetText(description)
)
end
function Operations.CreateLinkedSettingLine(settingKey, labelText, disabled, alternateName)
local relationshipSet = TSM.Operations.HasRelationship(private.currentModule, private.currentOperationName, settingKey)
return UIElements.New("Frame", alternateName or settingKey)
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, 0, 4)
:AddChild(UIElements.New("Frame", "line")
:SetLayout("HORIZONTAL")
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetTextColor((relationshipSet or disabled) and "TEXT_DISABLED" or "TEXT")
:SetText(labelText)
)
:AddChild(private.CreateLinkButton(disabled, settingKey))
:AddChild(UIElements.New("Spacer", "spacer"))
)
end
function Operations.CreateSettingLine(id, labelText, disabled)
return UIElements.New("Frame", id)
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, 0, 4)
:AddChild(UIElements.New("Text", "label")
:SetFont("BODY_BODY2_MEDIUM")
:SetTextColor(disabled and "TEXT_DISABLED" or "TEXT")
:SetText(labelText)
)
end
function Operations.CreateLinkedPriceInput(settingKey, label, height, validate, defaultValue)
local isDisabled = TSM.Operations.HasRelationship(private.currentModule, private.currentOperationName, settingKey)
local operation = TSM.Operations.GetSettings(private.currentModule, private.currentOperationName)
local value = operation[settingKey]
if defaultValue ~= nil and (not value or value == "") then
isDisabled = true
value = defaultValue
end
local validateFunc, validateContext = nil, nil
if type(validate) == "table" then
validateFunc = "CUSTOM_PRICE"
validateContext = validate
elseif type(validate) == "function" then
validateFunc = validate
elseif validate == nil then
validateFunc = "CUSTOM_PRICE"
else
error("Invalid validate: "..tostring(validate))
end
return Operations.CreateLinkedSettingLine(settingKey, label)
:SetLayout("VERTICAL")
:SetHeight(height)
:AddChild(UIElements.New("MultiLineInput", "input")
:SetHeight(height - 24)
:SetDisabled(isDisabled)
:SetValidateFunc(validateFunc, validateContext)
:SetSettingInfo(operation, settingKey)
:SetValue(Money.ToString(value) or value)
)
end
-- ============================================================================
-- Operations UI
-- ============================================================================
function private.GetOperationsFrame()
TSM.UI.AnalyticsRecordPathChange("main", "operations")
local frame = UIElements.New("DividedContainer", "operations")
:SetSettingsContext(private.settings, "operationsDividedContainer")
:SetMinWidth(250, 250)
:SetLeftChild(UIElements.New("Frame", "selection")
:SetLayout("VERTICAL")
:SetBackgroundColor("PRIMARY_BG_ALT")
:AddChild(UIElements.New("Input", "search")
:SetHeight(24)
:SetMargin(8, 8, 8, 16)
:SetIconTexture("iconPack.18x18/Search")
:SetClearButtonEnabled(true)
:AllowItemInsert(true)
:SetHintText(L["Search Operations"])
:SetScript("OnValueChanged", private.OperationSearchOnValueChanged)
)
:AddChild(UIElements.New("OperationTree", "operationTree")
:SetScript("OnOperationAdded", private.OperationTreeOnOperationAdded)
:SetScript("OnOperationDeleted", private.OperationTreeOnOperationConfirmDelete)
:SetScript("OnOperationSelected", private.OperationTreeOnOperationSelected)
)
)
:SetRightChild(UIElements.New("ViewContainer", "content")
:SetNavCallback(private.GetOperationsContent)
:AddPath("none", true)
:AddPath("summary")
:AddPath("operation")
)
return frame
end
function private.GetOperationsContent(_, path)
if path == "none" then
return UIElements.New("Frame", "settings")
:SetLayout("VERTICAL")
:SetWidth("EXPAND")
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Frame", "title")
:SetLayout("HORIZONTAL")
:SetHeight(40)
:SetPadding(8)
:AddChild(UIElements.New("Texture", "icon")
:SetMargin(0, 8, 0, 0)
:SetTextureAndSize(TSM.UI.TexturePacks.GetColoredKey("iconPack.18x18/Operation", "TEXT"))
)
:AddChild(UIElements.New("Text", "text")
:SetFont("BODY_BODY1_BOLD")
:SetText(L["No Operation Selected"])
)
)
:AddChild(UIElements.New("Spacer", "spacer"))
elseif path == "summary" then
return UIElements.New("Frame", "settings")
:SetLayout("VERTICAL")
:SetWidth("EXPAND")
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Frame", "title")
:SetLayout("HORIZONTAL")
:SetHeight(40)
:SetPadding(8)
:AddChild(UIElements.New("Text", "text")
:SetWidth("AUTO")
:SetFont("BODY_BODY1_BOLD")
)
:AddChild(UIElements.New("Spacer"))
:AddChild(UIElements.New("Button", "addBtn")
:SetWidth("AUTO")
:SetMargin(12, 12, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetIcon("iconPack.14x14/Add/Circle", "LEFT")
:SetText(L["Create New"])
:SetScript("OnClick", private.CreateNewOperationOnClick)
)
)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
-- will be filled in by the operation selection callback
)
elseif path == "operation" then
return UIElements.New("Frame", "settings")
:SetLayout("VERTICAL")
:SetWidth("EXPAND")
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Frame", "title")
:SetLayout("HORIZONTAL")
:SetHeight(40)
:SetPadding(8)
:AddChild(UIElements.New("Texture", "icon")
:SetMargin(0, 8, 0, 0)
:SetTextureAndSize(TSM.UI.TexturePacks.GetColoredKey("iconPack.18x18/Operation", "TEXT"))
)
:AddChild(UIElements.New("EditableText", "text")
:SetWidth("AUTO")
:AllowItemInsert(true)
:SetFont("BODY_BODY1_BOLD")
:SetText(L["No Operation Selected"])
:SetScript("OnValueChanged", private.OperationNameChanged)
:SetScript("OnEditingChanged", private.NameOnEditingChanged)
)
:AddChild(UIElements.New("Spacer"))
:AddChild(UIElements.New("Button", "renameBtn")
:SetWidth("AUTO")
:SetMargin(12, 12, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetIcon("iconPack.14x14/Edit", "LEFT")
:SetText(L["Rename"])
:SetScript("OnClick", private.RenameOperationOnClick)
)
:AddChild(UIElements.New("Button", "resetBtn")
:SetWidth("AUTO")
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetIcon("iconPack.14x14/Reset", "LEFT")
:SetText(L["Reset"])
:SetScript("OnClick", private.ResetOperationOnClick)
)
)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
-- will be filled in by the operation selection callback
)
else
error("Invalid path: "..tostring(path))
end
end
function private.GetSummaryContent()
local query = TSM.Operations.CreateQuery()
:Equal("moduleName", private.currentModule)
:VirtualField("numGroups", "number", private.NumGroupsVirtualField)
:VirtualField("numItems", "number", private.NumItemsVirtualField)
:OrderBy("operationName", true)
local mostGroupsName, mostGroupsValue = "---", -math.huge
local leastGroupsName, leastGroupsValue = "---", math.huge
local mostItemsName, mostItemsValue = "---", -math.huge
local leastItemsName, leastItemsValue = "---", math.huge
for _, row in query:Iterator() do
local operationName, numGroups, numItems = row:GetFields("operationName", "numGroups", "numItems")
if numGroups > mostGroupsValue then
mostGroupsValue = numGroups
mostGroupsName = operationName
end
if numGroups < leastGroupsValue then
leastGroupsValue = numGroups
leastGroupsName = operationName
end
if numItems > mostItemsValue then
mostItemsValue = numItems
mostItemsName = operationName
end
if numItems < leastItemsValue then
leastItemsValue = numItems
leastItemsName = operationName
end
end
return UIElements.New("Frame", "summary")
:SetLayout("VERTICAL")
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Frame", "summary")
:SetLayout("HORIZONTAL")
:SetHeight(48)
:SetMargin(8, 8, 0, 16)
:SetBackgroundColor("PRIMARY_BG_ALT", true)
:AddChild(UIElements.New("Frame", "groups")
:SetLayout("VERTICAL")
:SetPadding(8, 8, 2, 2)
:AddChild(UIElements.New("Frame", "most")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetText(L["MOST GROUPS"])
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "value")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetText(mostGroupsName)
)
)
:AddChild(UIElements.New("Frame", "least")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetText(L["LEAST GROUPS"])
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "value")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetText(leastGroupsName)
)
)
)
:AddChild(UIElements.New("Texture", "line1")
:SetWidth(1)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Frame", "items")
:SetLayout("VERTICAL")
:SetPadding(8, 8, 2, 2)
:AddChild(UIElements.New("Frame", "most")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetText(L["MOST ITEMS"])
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "value")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetText(mostItemsName)
)
)
:AddChild(UIElements.New("Frame", "least")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetTextColor("ACTIVE_BG_ALT")
:SetText(L["LEAST ITEMS"])
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "value")
:SetWidth("AUTO")
:SetFont("TABLE_TABLE1")
:SetJustifyH("RIGHT")
:SetText(leastItemsName)
)
)
)
)
:AddChild(UIElements.New("SelectionScrollingTable", "list")
:SetSettingsContext(private.settings, "operationsSummaryScrollingTable")
:GetScrollingTableInfo()
:NewColumn("name")
:SetTitle(L["Operation"])
:SetFont("TABLE_TABLE1")
:SetJustifyH("LEFT")
:SetTextInfo("operationName")
:SetSortInfo("operationName")
:SetActionIconInfo(1, 12, private.GetConfigureIcon, true)
:SetActionIconClickHandler(private.OnConfigureIconClick)
:DisableHiding()
:Commit()
:NewColumn("groups")
:SetTitle(L["Groups Using"])
:SetFont("TABLE_TABLE1")
:SetJustifyH("LEFT")
:SetTextInfo("numGroups")
:SetSortInfo("numGroups")
:Commit()
:NewColumn("items")
:SetTitle(L["Items Using"])
:SetFont("TABLE_TABLE1")
:SetJustifyH("LEFT")
:SetTextInfo("numItems", private.GetNumItemsText)
:SetSortInfo("numItems")
:SetTooltipInfo("numItems", private.GetNumItemsTooltip)
:Commit()
:Commit()
:SetQuery(query)
:SetContext(query)
:SetAutoReleaseQuery(true)
:SetScript("OnSelectionChanged", private.OperationListOnSelectionChanged)
)
: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("ActionButton", "deleteSelected")
:SetHeight(24)
:SetMargin(0, 8, 0, 0)
:SetDisabled(true)
:SetText(L["Delete Operations"])
:SetScript("OnClick", private.DeleteSelectedOnClick)
)
:AddChild(UIElements.New("Button", "selectAll")
:SetSize("AUTO", 20)
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["Select All"])
:SetScript("OnClick", private.SelectAllOnClick)
)
:AddChild(UIElements.New("Texture", "line")
:SetSize(2, 20)
:SetMargin(0, 8, 0, 0)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Button", "clearAll")
:SetSize("AUTO", 20)
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["Clear All"])
:SetDisabled(true)
:SetScript("OnClick", private.ClearAllOnClick)
)
)
end
function private.AddOperationGroups(frame)
for _, groupPath in TSM.Operations.GroupIterator(private.currentModule, private.currentOperationName, true) do
frame:AddChild(private.CreateGroupOperationLine(groupPath))
end
end
function private.CreateGroupOperationLine(groupPath)
local groupName = groupPath == TSM.CONST.ROOT_GROUP_PATH and L["Base Group"] or TSM.Groups.Path.GetName(groupPath)
local level = select('#', strsplit(TSM.CONST.GROUP_SEP, groupPath))
return UIElements.New("Frame", "group")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(2, 0, 0, 0)
:AddChild(UIElements.New("Text", "text")
:SetWidth("AUTO")
:SetFont("BODY_BODY2")
:SetTextColor(Theme.GetGroupColor(level))
:SetText(groupName)
)
:AddChild(UIElements.New("Button", "viewBtn")
:SetMargin(2, 2, 0, 0)
:SetBackgroundAndSize("iconPack.14x14/Groups")
:SetContext(groupPath)
:SetScript("OnClick", private.ViewGroupOnClick)
)
:AddChild(UIElements.New("Button", "removeBtn")
:SetBackgroundAndSize("iconPack.14x14/Close/Default")
:SetContext(groupPath)
:SetScript("OnClick", private.RemoveOperationGroupOnClick)
)
:AddChild(UIElements.New("Spacer", "spacer"))
end
function private.CreateLinkButton(disabled, settingKey)
local relationshipSet = TSM.Operations.HasRelationship(private.currentModule, private.currentOperationName, settingKey)
local linkTexture = nil
if disabled and relationshipSet then
linkTexture = TSM.UI.TexturePacks.GetColoredKey("iconPack.14x14/Link", "INDICATOR_DISABLED")
elseif disabled then
linkTexture = TSM.UI.TexturePacks.GetColoredKey("iconPack.14x14/Link", "TEXT_DISABLED")
elseif relationshipSet then
linkTexture = TSM.UI.TexturePacks.GetColoredKey("iconPack.14x14/Link", "INDICATOR")
else
linkTexture = TSM.UI.TexturePacks.GetColoredKey("iconPack.14x14/Link", "TEXT")
end
return UIElements.New("Button", "linkBtn")
:SetMargin(4, 4, 0, 0)
:SetBackgroundAndSize(linkTexture)
:SetDisabled(disabled)
:SetContext(settingKey)
:SetScript("OnClick", private.LinkBtnOnClick)
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.OperationSearchOnValueChanged(input)
local filter = strlower(input:GetValue())
input:GetElement("__parent.operationTree"):SetOperationNameFilter(filter)
end
function private.OperationTreeOnOperationAdded(operationTree, moduleName, operationName, copyOperationName)
-- clear the filter
operationTree:GetElement("__parent.search")
:SetValue("")
:Draw()
operationTree:SetOperationNameFilter("")
TSM.Operations.Create(moduleName, operationName)
if copyOperationName then
TSM.Operations.Copy(moduleName, operationName, copyOperationName)
end
end
function private.OperationTreeOnOperationConfirmDelete(self, moduleName, operationName)
self:GetBaseElement():ShowConfirmationDialog(L["Delete Operation?"], L["Are you sure you want to delete this operation?"], private.OperationTreeOnOperationDeleted, self, moduleName, operationName)
end
function private.OperationTreeOnOperationDeleted(self, moduleName, operationName)
TSM.Operations.Delete(moduleName, operationName)
local operationTree = self:GetElement("__parent.operationTree")
operationTree:SetSelectedOperation(moduleName, nil)
:Draw()
end
function private.OperationTreeOnOperationSelected(self, moduleName, operationName)
private.currentModule = moduleName
private.currentOperationName = operationName
local viewContainer = self:GetParentElement():GetParentElement():GetElement("content")
if moduleName and operationName then
TSM.Operations.Update(moduleName, operationName)
viewContainer:SetPath("operation")
viewContainer:GetElement("settings.title.text"):SetText(operationName)
local contentFrame = viewContainer:GetElement("settings.content")
contentFrame:ReleaseAllChildren()
contentFrame:AddChild(private.moduleCallbacks[moduleName](operationName))
elseif moduleName then
local numOperations = 0
for _ in TSM.Operations.OperationIterator(moduleName) do
numOperations = numOperations + 1
end
TSM.UI.AnalyticsRecordPathChange("main", "operations", "summary")
viewContainer:SetPath("summary")
viewContainer:GetElement("settings.title.text"):SetText(format(L["%s %s Operations"], Theme.GetColor("INDICATOR"):ColorText(numOperations), moduleName))
local contentFrame = viewContainer:GetElement("settings.content")
contentFrame:ReleaseAllChildren()
contentFrame:AddChild(private.GetSummaryContent())
else
TSM.UI.AnalyticsRecordPathChange("main", "operations", "none")
viewContainer:SetPath("none")
viewContainer:GetElement("settings.title.text"):SetText(L["No Operation Selected"])
end
viewContainer:Draw()
end
function private.CreateNewOperationOnClick(button)
local operationName = "New Operation"
local num = 1
while TSM.Operations.Exists(private.currentModule, operationName.." "..num) do
num = num + 1
end
operationName = operationName .. " " .. num
TSM.Operations.Create(private.currentModule, operationName)
button:GetElement("__parent.__parent.__parent.__parent.selection.operationTree")
:SetSelectedOperation(private.currentModule, operationName)
:Draw()
end
function private.OperationNameChanged(text, newValue)
newValue = strtrim(newValue)
if newValue == private.currentOperationName then
-- didn't change
text:Draw()
elseif newValue == "" then
Log.PrintUser(L["Invalid operation name."])
text:Draw()
elseif TSM.Operations.Exists(private.currentModule, newValue) then
Log.PrintUser(L["Group already exists."])
text:Draw()
else
TSM.Operations.Rename(private.currentModule, private.currentOperationName, newValue)
text:GetElement("__parent.__parent.__parent.__parent.selection.operationTree")
:SetSelectedOperation(private.currentModule, newValue)
:Draw()
end
end
function private.NameOnEditingChanged(text, editing)
if editing then
text:GetElement("__parent.renameBtn"):Hide()
else
text:GetElement("__parent.renameBtn"):Show()
end
end
function private.RenameOperationOnClick(button)
button:GetElement("__parent.text"):SetEditing(true)
end
function private.ResetOperationOnClick(button)
button:GetBaseElement():ShowConfirmationDialog(L["Reset Operation?"], L["Resetting the operation will return all inputs back to default and cannot be unddone. Click confirm to reset."], private.ConfirmResetOnClick, button)
end
function private.ConfirmResetOnClick(button)
TSM.Operations.Reset(private.currentModule, private.currentOperationName)
local settingsFrame = button:GetBaseElement():GetElement("content.operations.content.settings")
local contentFrame = settingsFrame:GetElement("content")
contentFrame:ReleaseAllChildren()
TSM.Operations.Update(private.currentModule, private.currentOperationName)
contentFrame:AddChild(private.moduleCallbacks[private.currentModule](private.currentOperationName))
button:GetBaseElement():HideDialog()
settingsFrame:Draw()
Log.PrintfUser(L["%s - %s has been reset to default values."], private.currentModule, Theme.GetColor("INDICATOR_ALT"):ColorText(private.currentOperationName))
end
function private.GroupSelectionChanged(groupSelector)
for groupPath in groupSelector:SelectedGroupIterator() do
if not TSM.Operations.GroupHasOperation(private.currentModule, groupPath, private.currentOperationName) then
local parentElement = groupSelector:GetParentElement():GetParentElement()
if groupPath ~= TSM.CONST.ROOT_GROUP_PATH then
TSM.Groups.SetOperationOverride(groupPath, private.currentModule, true)
end
local numOperations = 0
local lastOperationName = nil
for _, groupOperationName in TSM.Groups.OperationIterator(groupPath, private.currentModule) do
lastOperationName = groupOperationName
numOperations = numOperations + 1
end
if numOperations == TSM.Operations.GetMaxNumber(private.currentModule) then
-- replace the last operation since we're already at the max number of operations
TSM.Groups.RemoveOperation(groupPath, private.currentModule, numOperations)
Log.PrintfUser(L["%s previously had the max number of operations, so removed %s."], Log.ColorUserAccentText(TSM.Groups.Path.Format(groupPath)), Log.ColorUserAccentText(lastOperationName))
end
TSM.Groups.AppendOperation(groupPath, private.currentModule, private.currentOperationName)
Log.PrintfUser(L["Added %s to %s."], Log.ColorUserAccentText(private.currentOperationName), Log.ColorUserAccentText(groupPath == TSM.CONST.ROOT_GROUP_PATH and L["Base Group"] or TSM.Groups.Path.Format(groupPath)))
parentElement:AddChild(private.CreateGroupOperationLine(groupPath))
end
end
groupSelector:ClearSelectedGroups(true)
groupSelector:GetParentElement():GetParentElement():GetParentElement():GetParentElement():GetParentElement():GetParentElement():Draw()
end
function private.ViewGroupOnClick(button)
local baseFrame = button:GetBaseElement()
TSM.MainUI.Groups.ShowGroupSettings(baseFrame, button:GetContext())
end
function private.RemoveOperationGroupOnClick(self)
local groupPath = self:GetContext()
TSM.Groups.RemoveOperationByName(groupPath, private.currentModule, private.currentOperationName)
-- remove the line for this group
local removeElement = self:GetParentElement()
local removeElementParent = removeElement:GetParentElement()
removeElementParent:RemoveChild(removeElement)
removeElement:Release()
removeElementParent:GetParentElement():GetParentElement():GetParentElement():Draw()
end
function private.LinkBtnOnClick(button)
local settingKey = button:GetContext()
wipe(private.linkMenuEntries)
for _, operationName in TSM.Operations.OperationIterator(private.currentModule) do
if operationName ~= private.currentOperationName and not TSM.Operations.IsCircularRelationship(private.currentModule, private.currentOperationName, settingKey) then
tinsert(private.linkMenuEntries, operationName)
end
end
sort(private.linkMenuEntries)
button:GetBaseElement():ShowDialogFrame(UIElements.New("PopupFrame", "linkDialog")
:SetLayout("VERTICAL")
:SetSize(263, 243)
:AddAnchor("TOPRIGHT", button:_GetBaseFrame(), "BOTTOM", 22, -16)
:AddChild(UIElements.New("Frame", "titleFrame")
:SetLayout("VERTICAL")
:SetHeight(37)
:AddChild(UIElements.New("Text", "title")
:SetFont("BODY_BODY2_MEDIUM")
:SetJustifyH("CENTER")
:SetText(L["Link to Another Operation"])
)
)
:AddChild(UIElements.New("Texture", "line")
:SetHeight(2)
:SetTexture("TEXT")
)
:AddChild(UIElements.New("SelectionList", "list")
:SetContext(settingKey)
:SetMargin(2, 2, 0, 3)
:SetEntries(private.linkMenuEntries, TSM.Operations.GetRelationship(private.currentModule, private.currentOperationName, settingKey))
:SetScript("OnEntrySelected", private.ListOnEntrySelected)
)
)
end
function private.ListOnEntrySelected(list, operationName)
local settingKey = list:GetContext()
local previousValue = TSM.Operations.GetRelationship(private.currentModule, private.currentOperationName, settingKey)
if operationName == previousValue then
TSM.Operations.SetRelationship(private.currentModule, private.currentOperationName, settingKey, nil)
else
TSM.Operations.SetRelationship(private.currentModule, private.currentOperationName, settingKey, operationName)
end
local baseFrame = list:GetBaseElement()
baseFrame:HideDialog()
Operations.ShowOperationSettings(baseFrame, private.currentModule, private.currentOperationName)
end
function private.OperationListOnSelectionChanged(scrollingTable)
local selectionCleared = scrollingTable:IsSelectionCleared()
local numSelected = 0
for _ in scrollingTable:SelectionIterator() do
numSelected = numSelected + 1
end
local footer = scrollingTable:GetElement("__parent.footer")
footer:GetElement("deleteSelected")
:SetText(numSelected > 0 and format(L["Delete %d Operations"], numSelected) or L["Delete Operations"])
:SetDisabled(selectionCleared)
footer:GetElement("selectAll")
:SetDisabled(scrollingTable:IsAllSelected())
footer:GetElement("clearAll")
:SetDisabled(selectionCleared)
footer:Draw()
end
function private.SelectAllOnClick(button)
button:GetElement("__parent.__parent.list"):SelectAll()
end
function private.ClearAllOnClick(button)
button:GetElement("__parent.__parent.list"):ClearSelection()
end
function private.DeleteSelectedOnClick(button)
local scrollingTable = button:GetElement("__parent.__parent.list")
button:GetBaseElement():ShowConfirmationDialog(L["Delete Operations?"], L["Are you sure you want to delete the selected operations?"], private.DeleteSelectedOperations, scrollingTable)
end
function private.DeleteSelectedOperations(scrollingTable)
local toDelete = TempTable.Acquire()
for _, row in scrollingTable:SelectionIterator() do
local moduleName, operationName = row:GetFields("moduleName", "operationName")
assert(moduleName == private.currentModule)
tinsert(toDelete, operationName)
end
TSM.Operations.DeleteList(private.currentModule, toDelete)
TempTable.Release(toDelete)
scrollingTable:UpdateData(true)
private.OperationListOnSelectionChanged(scrollingTable)
scrollingTable:GetElement("__parent.__parent.__parent.__parent.__parent.selection.operationTree"):UpdateData(true)
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.NumGroupsVirtualField(row)
local num = 0
for _ in TSM.Operations.GroupIterator(row:GetField("moduleName"), row:GetField("operationName")) do
num = num + 1
end
return num
end
function private.NumItemsVirtualField(row)
local includesBaseGroup = false
local num = 0
for _, groupPath in TSM.Operations.GroupIterator(row:GetField("moduleName"), row:GetField("operationName")) do
if groupPath == TSM.CONST.ROOT_GROUP_PATH then
includesBaseGroup = true
else
num = num + TSM.Groups.GetNumItems(groupPath)
end
end
if includesBaseGroup then
num = num + 0.9
end
return num
end
function private.GetConfigureIcon(_, _, iconIndex)
assert(iconIndex == 1)
return true, "iconPack.12x12/Popout", false
end
function private.OnConfigureIconClick(scrollingTable, data, iconIndex)
assert(iconIndex == 1)
local operationName = scrollingTable:GetContext():GetResultRowByUUID(data):GetField("operationName")
scrollingTable:GetElement("__parent.__parent.__parent.__parent.__parent.selection.operationTree")
:SetSelectedOperation(private.currentModule, operationName)
end
function private.GetNumItemsText(numItems)
if numItems == floor(numItems) then
return numItems
else
return floor(numItems).."*"
end
end
function private.GetNumItemsTooltip(numItems)
if numItems == floor(numItems) then
return nil
end
return L["This operation is applied to the base group which includes every item not in another group."]
end

View File

@@ -0,0 +1,159 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Crafting = TSM.MainUI.Operations:NewPackage("Crafting")
local L = TSM.Include("Locale").GetTable()
local UIElements = TSM.Include("UI.UIElements")
local private = {
currentOperationName = nil,
}
local BAD_CRAFT_VALUE_PRICE_SOURCES = {
crafting = true,
}
-- ============================================================================
-- Module Functions
-- ============================================================================
function Crafting.OnInitialize()
TSM.MainUI.Operations.RegisterModule("Crafting", private.GetCraftingOperationSettings)
end
-- ============================================================================
-- Crafting Operation Settings UI
-- ============================================================================
function private.GetCraftingOperationSettings(operationName)
TSM.UI.AnalyticsRecordPathChange("main", "operations", "crafting")
private.currentOperationName = operationName
local operation = TSM.Operations.GetSettings("Crafting", private.currentOperationName)
local frame = UIElements.New("ScrollFrame", "settings")
:SetPadding(8, 8, 8, 0)
:AddChild(TSM.MainUI.Operations.CreateExpandableSection("Crafting", "restockQuantity", L["Restock Options"], L["Adjust how crafted items are restocked."])
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("minRestock", L["Min restock quantity"])
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("Input", "input")
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG")
:SetValidateFunc("CUSTOM_PRICE")
:SetSettingInfo(operation, "minRestock")
:SetDisabled(TSM.Operations.HasRelationship("Crafting", private.currentOperationName, "minRestock"))
)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3")
:SetTextColor(TSM.Operations.HasRelationship("Crafting", private.currentOperationName, "minRestock") and "TEXT_DISABLED" or "TEXT")
:SetFormattedText(L["Supported range: %d - %d"], TSM.Operations.Crafting.GetRestockRange())
)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("maxRestock", L["Max restock quantity"])
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("Input", "input")
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG")
:SetValidateFunc("CUSTOM_PRICE")
:SetSettingInfo(operation, "maxRestock")
:SetDisabled(TSM.Operations.HasRelationship("Crafting", private.currentOperationName, "maxRestock"))
)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3")
:SetTextColor(TSM.Operations.HasRelationship("Crafting", private.currentOperationName, "maxRestock") and "TEXT_DISABLED" or "TEXT")
:SetFormattedText(L["Supported range: %d - %d"], TSM.Operations.Crafting.GetRestockRange())
)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("minProfit", L["Set min profit"], nil, "minProfitToggle")
:SetLayout("VERTICAL")
:SetHeight(42)
:AddChild(UIElements.New("ToggleOnOff", "toggle")
:SetHeight(18)
:SetValue(operation.minProfit ~= "")
:SetDisabled(TSM.Operations.HasRelationship("Crafting", private.currentOperationName, "minProfit"))
:SetScript("OnValueChanged", private.MinProfitToggleOnValueChanged)
)
)
)
:AddChild(TSM.MainUI.Operations.CreateExpandableSection("Crafting", "priceSettings", L["Crafting Value"], L["Adjust how TSM values crafted items when calculating profit."])
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("craftPriceMethod", L["Override default craft value"], nil, "craftPriceMethodToggle")
:SetLayout("VERTICAL")
:SetHeight(42)
:AddChild(UIElements.New("ToggleOnOff", "toggle")
:SetHeight(18)
:SetValue(operation.craftPriceMethod ~= "")
:SetDisabled(TSM.Operations.HasRelationship("Crafting", private.currentOperationName, "craftPriceMethod"))
:SetScript("OnValueChanged", private.CraftPriceToggleOnValueChanged)
)
)
)
:AddChild(TSM.MainUI.Operations.GetOperationManagementElements("Crafting", private.currentOperationName))
if operation.minProfit ~= "" then
frame:GetElement("restockQuantity.content.minProfitToggle"):SetMargin(0, 0, 0, 12)
frame:GetElement("restockQuantity"):AddChild(TSM.MainUI.Operations.CreateLinkedPriceInput("minProfit", L["Min profit amount"], 80))
end
if operation.craftPriceMethod ~= "" then
frame:GetElement("priceSettings.content.craftPriceMethodToggle"):SetMargin(0, 0, 0, 12)
frame:GetElement("priceSettings"):AddChild(TSM.MainUI.Operations.CreateLinkedPriceInput("craftPriceMethod", L["Craft Value"], 80, BAD_CRAFT_VALUE_PRICE_SOURCES, TSM.db.global.craftingOptions.defaultCraftPriceMethod))
end
return frame
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.MinProfitToggleOnValueChanged(toggle, value)
local operation = TSM.Operations.GetSettings("Crafting", private.currentOperationName)
local defaultValue = TSM.Operations.GetSettingDefault("Crafting", "minProfit")
operation.minProfit = value and defaultValue or ""
local settingsFrame = toggle:GetParentElement():GetParentElement()
if value then
settingsFrame:GetElement("minProfitToggle"):SetMargin(0, 0, 0, 12)
settingsFrame:GetParentElement():AddChild(TSM.MainUI.Operations.CreateLinkedPriceInput("minProfit", L["Min profit amount"], 80))
else
settingsFrame:GetElement("minProfitToggle"):SetMargin(0, 0, 0, 0)
local linkedPriceLine = settingsFrame:GetElement("minProfit")
settingsFrame:RemoveChild(linkedPriceLine)
linkedPriceLine:Release()
end
settingsFrame:GetParentElement():GetParentElement():Draw()
end
function private.CraftPriceToggleOnValueChanged(toggle, value)
local operation = TSM.Operations.GetSettings("Crafting", private.currentOperationName)
operation.craftPriceMethod = value and TSM.db.global.craftingOptions.defaultCraftPriceMethod or ""
local settingsFrame = toggle:GetParentElement():GetParentElement()
if value then
settingsFrame:GetElement("craftPriceMethodToggle"):SetMargin(0, 0, 0, 12)
settingsFrame:GetParentElement():AddChild(TSM.MainUI.Operations.CreateLinkedPriceInput("craftPriceMethod", L["Craft Value"], 80, BAD_CRAFT_VALUE_PRICE_SOURCES, TSM.db.global.craftingOptions.defaultCraftPriceMethod))
else
settingsFrame:GetElement("craftPriceMethodToggle"):SetMargin(0, 0, 0, 0)
local linkedPriceLine = settingsFrame:GetElement("craftPriceMethod")
settingsFrame:RemoveChild(linkedPriceLine)
linkedPriceLine:Release()
end
settingsFrame:GetParentElement():GetParentElement():Draw()
end

View File

@@ -0,0 +1,220 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Mailing = TSM.MainUI.Operations:NewPackage("Mailing")
local PlayerInfo = TSM.Include("Service.PlayerInfo")
local L = TSM.Include("Locale").GetTable()
local UIElements = TSM.Include("UI.UIElements")
local private = {
currentOperationName = nil,
}
-- ============================================================================
-- Module Functions
-- ============================================================================
function Mailing.OnInitialize()
TSM.MainUI.Operations.RegisterModule("Mailing", private.GetMailingOperationSettings)
end
-- ============================================================================
-- Mailing Operation Settings UI
-- ============================================================================
function private.GetMailingOperationSettings(operationName)
TSM.UI.AnalyticsRecordPathChange("main", "operations", "mailing")
private.currentOperationName = operationName
local operation = TSM.Operations.GetSettings("Mailing", private.currentOperationName)
return UIElements.New("ScrollFrame", "content")
:SetPadding(8, 8, 8, 0)
:AddChild(TSM.MainUI.Operations.CreateExpandableSection("Mailing", "generalOptions", L["General Options"], L["Adjust how items are mailed."])
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("target", L["Target character"])
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:AddChild(UIElements.New("Input", "input")
:SetHeight(24)
:SetMargin(0, 8, 0, 0)
:SetHintText(L["Enter player name"])
:SetAutoComplete(PlayerInfo.GetConnectedAlts())
:SetClearButtonEnabled(true)
:SetDisabled(TSM.Operations.HasRelationship("Mailing", private.currentOperationName, "target"))
:SetSettingInfo(operation, "target")
)
:AddChild(UIElements.New("ActionButton", "contacts")
:SetSize(152, 24)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Contacts"])
:SetScript("OnClick", private.ContactsBtnOnClick)
)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("keepQty", L["Keep this amount"])
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("Input", "input")
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG")
:SetValidateFunc("NUMBER", "0:50000")
:SetSettingInfo(operation, "keepQty")
:SetDisabled(TSM.Operations.HasRelationship("Mailing", private.currentOperationName, "keepQty"))
)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3")
:SetTextColor(TSM.Operations.HasRelationship("Mailing", private.currentOperationName, "keepQty") and "TEXT_DISABLED" or "TEXT")
:SetFormattedText(L["Enter a value from %d - %d"], 0, 50000)
)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("maxQtyEnabled", L["Set max quantity"])
:SetLayout("VERTICAL")
:SetHeight(42)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("ToggleOnOff", "toggle")
:SetHeight(18)
:SetSettingInfo(operation, "maxQtyEnabled")
:SetDisabled(TSM.Operations.HasRelationship("Mailing", private.currentOperationName, "maxQtyEnabled"))
:SetScript("OnValueChanged", private.MaxQuantityToggleOnValueChanged)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("maxQty", L["Max quantity"], not operation.maxQtyEnabled)
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("Input", "input")
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG")
:SetValidateFunc("NUMBER", "1:50000")
:SetDisabled(TSM.Operations.HasRelationship("Mailing", private.currentOperationName, "maxQty") or not operation.maxQtyEnabled)
:SetSettingInfo(operation, "maxQty")
)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3")
:SetTextColor((TSM.Operations.HasRelationship("Mailing", private.currentOperationName, "maxQty") or not operation.maxQtyEnabled) and "TEXT_DISABLED" or "TEXT")
:SetFormattedText(L["Enter a value from %d - %d"], 1, 50000)
)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("restock", L["Restock target to max quantity"], not operation.maxQtyEnabled)
:SetLayout("VERTICAL")
:SetHeight(42)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("ToggleOnOff", "toggle")
:SetHeight(18)
:SetSettingInfo(operation, "restock")
:SetDisabled(TSM.Operations.HasRelationship("Mailing", private.currentOperationName, "restock") or not operation.maxQtyEnabled)
:SetScript("OnValueChanged", private.RestockToggleOnValueChanged)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("restockSources", L["Sources to include for restock"], not operation.restock or not operation.maxQtyEnabled)
:SetLayout("VERTICAL")
:SetHeight(48)
:AddChild(UIElements.New("MultiselectionDropdown", "dropdown")
:SetHeight(24)
:AddItem(BANK, "bank")
:AddItem(GUILD, "guild")
:SetSettingInfo(operation, "restockSources")
:SetSelectionText(L["No Sources"], L["%d Sources"], L["All Sources"])
:SetDisabled(TSM.Operations.HasRelationship("Mailing", private.currentOperationName, "restockSources") or not operation.restock or not operation.maxQtyEnabled)
)
)
)
:AddChild(TSM.MainUI.Operations.GetOperationManagementElements("Mailing", private.currentOperationName))
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.ContactsBtnOnClick(button)
TSM.UI.Util.Contacts.ShowDialog(button, button:GetElement("__parent.input"))
end
function private.MaxQuantityToggleOnValueChanged(toggle, value)
local settingsFrame = toggle:GetElement("__parent.__parent")
local restockValue = settingsFrame:GetElement("restock.toggle"):GetValue()
local relationshipSet, linkTexture, textColor = TSM.Operations.GetRelationshipColors("Mailing", private.currentOperationName, "maxQty", value)
settingsFrame:GetElement("maxQty.line.linkBtn")
:SetBackground(linkTexture)
:SetDisabled(not value)
settingsFrame:GetElement("maxQty.line.label")
:SetTextColor(textColor)
settingsFrame:GetElement("maxQty.content.label")
:SetTextColor(textColor)
settingsFrame:GetElement("maxQty.content.input")
:SetDisabled(relationshipSet or not value)
relationshipSet, linkTexture, textColor = TSM.Operations.GetRelationshipColors("Mailing", private.currentOperationName, "restock", value)
settingsFrame:GetElement("restock.line.linkBtn")
:SetBackground(linkTexture)
:SetDisabled(not value)
settingsFrame:GetElement("restock.line.label")
:SetTextColor(textColor)
settingsFrame:GetElement("restock.toggle")
:SetDisabled(relationshipSet or not value)
relationshipSet = TSM.Operations.HasRelationship("Mailing", private.currentOperationName, "restockSources")
if relationshipSet and value and restockValue then
linkTexture = TSM.UI.TexturePacks.GetColoredKey("iconPack.14x14/Link", "INDICATOR")
elseif (relationshipSet and not value and restockValue) or (relationshipSet and value and not restockValue) or (relationshipSet and not value and not restockValue) then
linkTexture = TSM.UI.TexturePacks.GetColoredKey("iconPack.14x14/Link", "INDICATOR_DISABLED")
elseif (value and not restockValue) or (not value and restockValue) or (not value and not restockValue) then
linkTexture = TSM.UI.TexturePacks.GetColoredKey("iconPack.14x14/Link", "TEXT_DISABLED")
else
linkTexture = TSM.UI.TexturePacks.GetColoredKey("iconPack.14x14/Link", "TEXT")
end
settingsFrame:GetElement("restockSources.line.linkBtn")
:SetBackground(linkTexture)
:SetDisabled(not value)
settingsFrame:GetElement("restockSources.line.label")
:SetTextColor(relationshipSet and "TEXT_DISABLED" or ((value and restockValue) and "TEXT" or "TEXT_DISABLED"))
settingsFrame:GetElement("restockSources.dropdown")
:SetDisabled(relationshipSet or not value or not restockValue)
settingsFrame:Draw()
end
function private.RestockToggleOnValueChanged(toggle, value)
local settingsFrame = toggle:GetElement("__parent.__parent")
local maxQtyEnabled = settingsFrame:GetElement("maxQtyEnabled.toggle"):GetValue()
local relationshipSet = TSM.Operations.HasRelationship("Mailing", private.currentOperationName, "restockSources")
local linkTexture = nil
if relationshipSet and value and maxQtyEnabled then
linkTexture = TSM.UI.TexturePacks.GetColoredKey("iconPack.14x14/Link", "INDICATOR")
elseif (relationshipSet and not value and maxQtyEnabled) or (relationshipSet and value and not maxQtyEnabled) or (relationshipSet and not value and not maxQtyEnabled) then
linkTexture = TSM.UI.TexturePacks.GetColoredKey("iconPack.14x14/Link", "INDICATOR_DISABLED")
elseif (value and not maxQtyEnabled) or (not value and maxQtyEnabled) or (not value and not maxQtyEnabled) then
linkTexture = TSM.UI.TexturePacks.GetColoredKey("iconPack.14x14/Link", "TEXT_DISABLED")
else
linkTexture = TSM.UI.TexturePacks.GetColoredKey("iconPack.14x14/Link", "TEXT")
end
settingsFrame:GetElement("restockSources.line.linkBtn")
:SetBackground(linkTexture)
:SetDisabled(not value)
settingsFrame:GetElement("restockSources.line.label")
:SetTextColor(relationshipSet and "TEXT_DISABLED" or ((value and maxQtyEnabled) and "TEXT" or "TEXT_DISABLED"))
settingsFrame:GetElement("restockSources.dropdown")
:SetDisabled(relationshipSet or not value or not maxQtyEnabled)
settingsFrame:Draw()
end

View File

@@ -0,0 +1,88 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Shopping = TSM.MainUI.Operations:NewPackage("Shopping")
local L = TSM.Include("Locale").GetTable()
local UIElements = TSM.Include("UI.UIElements")
local private = {
currentOperationName = nil,
}
local RESTOCK_SOURCES = { L["Alts"], L["Auctions"], BANK, GUILD }
local RESTOCK_SOURCES_KEYS = { "alts", "auctions", "bank", "guild" }
local BAD_PRICE_SOURCES = { shoppingopmax = true }
-- ============================================================================
-- Module Functions
-- ============================================================================
function Shopping.OnInitialize()
TSM.MainUI.Operations.RegisterModule("Shopping", private.GetShoppingOperationSettings)
end
-- ============================================================================
-- Shopping Operation Settings UI
-- ============================================================================
function private.GetShoppingOperationSettings(operationName)
TSM.UI.AnalyticsRecordPathChange("main", "operations", "shopping")
private.currentOperationName = operationName
local operation = TSM.Operations.GetSettings("Shopping", private.currentOperationName)
return UIElements.New("ScrollFrame", "settings")
:SetPadding(8, 8, 8, 0)
:SetBackgroundColor("PRIMARY_BG")
:AddChild(TSM.MainUI.Operations.CreateExpandableSection("Shopping", "generalOptions", L["General Options"], L["Set what items are shown during a Shopping scan."])
:AddChild(TSM.MainUI.Operations.CreateLinkedPriceInput("maxPrice", L["Maximum auction price"], 124, BAD_PRICE_SOURCES))
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("showAboveMaxPrice", L["Show auctions above max price"])
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 12, 12)
:AddChild(UIElements.New("ToggleOnOff", "toggle")
:SetHeight(18)
:SetSettingInfo(operation, "showAboveMaxPrice")
:SetDisabled(TSM.Operations.HasRelationship("Shopping", private.currentOperationName, "showAboveMaxPrice"))
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("restockQuantity", L["Maximum restock quantity"])
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("Input", "input")
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG")
:SetValidateFunc("CUSTOM_PRICE")
:SetSettingInfo(operation, "restockQuantity")
:SetDisabled(TSM.Operations.HasRelationship("Shopping", private.currentOperationName, "restockQuantity"))
)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3")
:SetTextColor(TSM.Operations.HasRelationship("Shopping", private.currentOperationName, "restockQuantity") and "TEXT_DISABLED" or "TEXT")
:SetFormattedText(L["Supported range: %d - %d"], TSM.Operations.Shopping.GetRestockRange())
)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("restockSources", L["Sources to include for restock"])
:SetLayout("VERTICAL")
:SetHeight(48)
:AddChild(UIElements.New("MultiselectionDropdown", "dropdown")
:SetHeight(24)
:SetItems(RESTOCK_SOURCES, RESTOCK_SOURCES_KEYS)
:SetSettingInfo(operation, "restockSources")
:SetSelectionText(L["No Sources"], L["%d Sources"], L["All Sources"])
:SetDisabled(TSM.Operations.HasRelationship("Shopping", private.currentOperationName, "restockSources"))
)
)
)
:AddChild(TSM.MainUI.Operations.GetOperationManagementElements("Shopping", private.currentOperationName))
end

View File

@@ -0,0 +1,42 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Sniper = TSM.MainUI.Operations:NewPackage("Sniper")
local L = TSM.Include("Locale").GetTable()
local UIElements = TSM.Include("UI.UIElements")
local private = {
currentOperationName = nil,
}
local BAD_PRICE_SOURCES = { sniperopmax = true }
-- ============================================================================
-- Module Functions
-- ============================================================================
function Sniper.OnInitialize()
TSM.MainUI.Operations.RegisterModule("Sniper", private.GetSniperOperationSettings)
end
-- ============================================================================
-- Sniper Operation Settings UI
-- ============================================================================
function private.GetSniperOperationSettings(operationName)
TSM.UI.AnalyticsRecordPathChange("main", "operations", "sniper")
private.currentOperationName = operationName
return UIElements.New("ScrollFrame", "settings")
:SetPadding(8, 8, 8, 0)
:SetBackgroundColor("PRIMARY_BG")
:AddChild(TSM.MainUI.Operations.CreateExpandableSection("Sniper", "settings", L["General Options"], L["Set what items are shown during a Sniper scan."])
:AddChild(TSM.MainUI.Operations.CreateLinkedPriceInput("belowPrice", L["Maximum price"], 124, BAD_PRICE_SOURCES))
)
:AddChild(TSM.MainUI.Operations.GetOperationManagementElements("Sniper", private.currentOperationName))
end

View File

@@ -0,0 +1,268 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Vendoring = TSM.MainUI.Operations:NewPackage("Vendoring")
local L = TSM.Include("Locale").GetTable()
local UIElements = TSM.Include("UI.UIElements")
local private = {
currentOperationName = nil,
}
local RESTOCK_SOURCES = { BANK, GUILD, L["Alts"], L["Alts AH"], L["AH"], L["Mail"] }
local RESTOCK_SOURCES_KEYS = { "bank", "guild", "alts", "alts_ah", "ah", "mail" }
local SETTING_INFO = {
restockQty = "INPUT_LABEL",
restockSources = "DROPDOWN",
keepQty = "INPUT_LABEL",
sellAfterExpired = "INPUT_LABEL",
vsMarketValue = "INPUT",
vsMaxMarketValue = "INPUT",
vsDestroyValue = "INPUT",
vsMaxDestroyValue = "INPUT",
sellSoulbound = "TOGGLE",
}
-- ============================================================================
-- Module Functions
-- ============================================================================
function Vendoring.OnInitialize()
TSM.MainUI.Operations.RegisterModule("Vendoring", private.GetVendoringOperationSettings)
end
-- ============================================================================
-- Vendoring Operation Settings UI
-- ============================================================================
function private.GetVendoringOperationSettings(operationName)
TSM.UI.AnalyticsRecordPathChange("main", "operations", "vendoring")
private.currentOperationName = operationName
local operation = TSM.Operations.GetSettings("Vendoring", private.currentOperationName)
return UIElements.New("ScrollFrame", "settings")
:SetPadding(8, 8, 8, 0)
:AddChild(TSM.MainUI.Operations.CreateExpandableSection("Vendoring", "buyOptionsHeading", L["Buy Options"], L["Set what is bought from a vendor."])
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("enableBuy", L["Enable buying"])
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("ToggleOnOff", "toggle")
:SetHeight(18)
:SetSettingInfo(operation, "enableBuy")
:SetDisabled(TSM.Operations.HasRelationship("Vendoring", private.currentOperationName, "enableBuy"))
:SetScript("OnValueChanged", private.EnableBuyingToggleOnValueChanged)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("restockQty", L["Restock quantity"], not operation.enableBuy)
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("Input", "input")
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG")
:SetValidateFunc("NUMBER", "0:50000")
:SetSettingInfo(operation, "restockQty")
:SetDisabled(TSM.Operations.HasRelationship("Vendoring", private.currentOperationName, "restockQty") or not operation.enableBuy)
)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3")
:SetTextColor((TSM.Operations.HasRelationship("Vendoring", private.currentOperationName, "restockQty") or not operation.enableBuy) and "TEXT_DISABLED" or "TEXT")
:SetFormattedText(L["Enter a value from %d - %d"], 0, 50000)
)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("restockSources", L["Sources to include for restock"], not operation.enableBuy)
:SetLayout("VERTICAL")
:SetHeight(48)
:AddChild(UIElements.New("MultiselectionDropdown", "dropdown")
:SetHeight(24)
:SetItems(RESTOCK_SOURCES, RESTOCK_SOURCES_KEYS)
:SetSettingInfo(operation, "restockSources")
:SetSelectionText(L["No Sources"], L["%d Sources"], L["All Sources"])
:SetDisabled(TSM.Operations.HasRelationship("Vendoring", private.currentOperationName, "restockSources") or not operation.enableBuy)
)
)
)
:AddChild(TSM.MainUI.Operations.CreateExpandableSection("Vendoring", "sellOptionsHeading", L["Sell Options"], L["Set what is sold to a vendor."])
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("enableSell", L["Enable selling"])
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("ToggleOnOff", "toggle")
:SetHeight(18)
:SetSettingInfo(operation, "enableSell")
:SetScript("OnValueChanged", private.EnableSellingToggleOnValueChanged)
:SetDisabled(TSM.Operations.HasRelationship("Vendoring", private.currentOperationName, "enableSell"))
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("keepQty", L["Keep quantity"], not operation.enableSell)
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("Input", "input")
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG")
:SetValidateFunc("NUMBER", "0:50000")
:SetSettingInfo(operation, "keepQty")
:SetDisabled(TSM.Operations.HasRelationship("Vendoring", private.currentOperationName, "keepQty") or not operation.enableSell)
)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3")
:SetTextColor((TSM.Operations.HasRelationship("Vendoring", private.currentOperationName, "keepQty") or not operation.enableSell) and "TEXT_DISABLED" or "TEXT")
:SetFormattedText(L["Enter a value from %d - %d"], 0, 50000)
)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("sellAfterExpired", L["Min number of expires"], not operation.enableSell)
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("Input", "input")
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG")
:SetValidateFunc("NUMBER", "0:50000")
:SetSettingInfo(operation, "sellAfterExpired")
:SetDisabled(TSM.Operations.HasRelationship("Vendoring", private.currentOperationName, "sellAfterExpired") or not operation.enableSell)
)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3")
:SetTextColor((TSM.Operations.HasRelationship("Vendoring", private.currentOperationName, "sellAfterExpired") or not operation.enableSell) and "TEXT_DISABLED" or "TEXT")
:SetFormattedText(L["Enter a value from %d - %d"], 0, 50000)
)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("vsMarketValue", L["Market value"], not operation.enableSell)
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Input", "input")
:SetHeight(24)
:SetBackgroundColor("ACTIVE_BG")
:SetValidateFunc("CUSTOM_PRICE")
:SetSettingInfo(operation, "vsMarketValue")
:SetDisabled(TSM.Operations.HasRelationship("Vendoring", private.currentOperationName, "vsMarketValue") or not operation.enableSell)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("vsMaxMarketValue", L["Max market value (Enter '0c' to disable)"], not operation.enableSell)
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Input", "input")
:SetHeight(24)
:SetBackgroundColor("ACTIVE_BG")
:SetValidateFunc("CUSTOM_PRICE")
:SetSettingInfo(operation, "vsMaxMarketValue")
:SetDisabled(TSM.Operations.HasRelationship("Vendoring", private.currentOperationName, "vsMaxMarketValue") or not operation.enableSell)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("vsDestroyValue", L["Destroy value"], not operation.enableSell)
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Input", "input")
:SetHeight(24)
:SetBackgroundColor("ACTIVE_BG")
:SetValidateFunc("CUSTOM_PRICE")
:SetSettingInfo(operation, "vsDestroyValue")
:SetDisabled(TSM.Operations.HasRelationship("Vendoring", private.currentOperationName, "vsDestroyValue") or not operation.enableSell)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("vsMaxDestroyValue", L["Max destroy value (Enter '0c' to disable)"], not operation.enableSell)
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Input", "input")
:SetHeight(24)
:SetBackgroundColor("ACTIVE_BG")
:SetValidateFunc("CUSTOM_PRICE")
:SetSettingInfo(operation, "vsMaxDestroyValue")
:SetDisabled(TSM.Operations.HasRelationship("Vendoring", private.currentOperationName, "vsMaxDestroyValue") or not operation.enableSell)
)
)
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine("sellSoulbound", L["Sell soulbound items"], not operation.enableSell)
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 0)
:AddChild(UIElements.New("ToggleOnOff", "toggle")
:SetHeight(18)
:SetSettingInfo(operation, "sellSoulbound")
:SetDisabled(TSM.Operations.HasRelationship("Vendoring", private.currentOperationName, "sellSoulbound") or not operation.enableSell)
)
)
)
:AddChild(TSM.MainUI.Operations.GetOperationManagementElements("Vendoring", private.currentOperationName))
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.UpdateSettingState(settingsFrame, key, operation, value)
local relationshipSet, linkTexture, textColor = TSM.Operations.GetRelationshipColors("Vendoring", private.currentOperationName, key, value)
local settingKeyFrame = settingsFrame:GetElement(key)
settingKeyFrame:GetElement("line.linkBtn")
:SetBackground(linkTexture)
:SetDisabled(not value)
settingKeyFrame:GetElement("line.label")
:SetTextColor(textColor)
local settingType = SETTING_INFO[key]
if settingType == "INPUT_LABEL" then
settingKeyFrame:GetElement("content.input")
:SetDisabled(relationshipSet or not value)
:SetValue(operation[key] or "")
settingKeyFrame:GetElement("content.label")
:SetTextColor(textColor)
elseif settingType == "INPUT" then
settingKeyFrame:GetElement("input")
:SetDisabled(relationshipSet or not value)
elseif settingType == "TOGGLE" then
settingKeyFrame:GetElement("toggle")
:SetDisabled(relationshipSet or not value)
elseif settingType == "DROPDOWN" then
settingKeyFrame:GetElement("dropdown")
:SetDisabled(relationshipSet or not value)
else
error("Invalid settingType: "..tostring(settingType))
end
end
function private.EnableBuyingToggleOnValueChanged(toggle, value)
local operation = TSM.Operations.GetSettings("Vendoring", private.currentOperationName)
local settingsFrame = toggle:GetElement("__parent.__parent")
private.UpdateSettingState(settingsFrame, "restockQty", operation, value)
private.UpdateSettingState(settingsFrame, "restockSources", operation, value)
settingsFrame:Draw()
end
function private.EnableSellingToggleOnValueChanged(toggle, value)
local operation = TSM.Operations.GetSettings("Vendoring", private.currentOperationName)
local settingsFrame = toggle:GetElement("__parent.__parent")
for key in pairs(SETTING_INFO) do
if key ~= "restockQty" and key ~= "restockSources" then
private.UpdateSettingState(settingsFrame, key, operation, value)
end
end
settingsFrame:Draw()
end

View File

@@ -0,0 +1,108 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Warehousing = TSM.MainUI.Operations:NewPackage("Warehousing")
local L = TSM.Include("Locale").GetTable()
local UIElements = TSM.Include("UI.UIElements")
local private = { currentOperationName = nil }
-- ============================================================================
-- Module Functions
-- ============================================================================
function Warehousing.OnInitialize()
TSM.MainUI.Operations.RegisterModule("Warehousing", private.GetWarehousingOperationSettings)
end
-- ============================================================================
-- Warehousing Operation Settings UI
-- ============================================================================
function private.GetWarehousingOperationSettings(operationName)
TSM.UI.AnalyticsRecordPathChange("main", "operations", "warehousing")
private.currentOperationName = operationName
return UIElements.New("ScrollFrame", "settings")
:SetPadding(8, 8, 8, 0)
:AddChild(TSM.MainUI.Operations.CreateExpandableSection("Warehousing", "moveSettings", L["Move Quantity Options"], L["Set how items are moved out of the bank."])
:AddChild(private.CreateEnabledSettingLine("moveQuantity", L["Set move quantity"], L["Quantity to move"], 0, 50000, true))
:AddChild(private.CreateEnabledSettingLine("stackSize", L["Set stack size"], L["Stack size multiple"], 0, 200, true))
:AddChild(private.CreateEnabledSettingLine("keepBagQuantity", L["Set keep in bags quantity"], L["Keep in bags quantity"], 0, 50000, true))
:AddChild(private.CreateEnabledSettingLine("keepBankQuantity", L["Set keep in bank quantity"], L["Keep in bank quantity"], 0, 50000))
)
:AddChild(TSM.MainUI.Operations.CreateExpandableSection("Warehousing", "restockSettings", L["Restock Options"], L["Set how items are restocked from the bank."])
:AddChild(private.CreateEnabledSettingLine("restockQuantity", L["Enable restock"], L["Restock quantity"], 0, 50000, true))
:AddChild(private.CreateEnabledSettingLine("restockStackSize", L["Set stack size for restock"], L["Stack size multiple"], 0, 200, true))
:AddChild(private.CreateEnabledSettingLine("restockKeepBankQuantity", L["Set keep in bank quantity"], L["Keep in bank quantity"], 0, 50000))
)
:AddChild(TSM.MainUI.Operations.GetOperationManagementElements("Warehousing", private.currentOperationName))
end
function private.CreateEnabledSettingLine(key, enableText, text, minValue, maxValue, margin)
local operation = TSM.Operations.GetSettings("Warehousing", private.currentOperationName)
local hasRelationship = TSM.Operations.HasRelationship("Warehousing", private.currentOperationName, key)
return UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
:AddChild(TSM.MainUI.Operations.CreateLinkedSettingLine(key, text)
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("ToggleOnOff", "toggle")
:SetHeight(18)
:SetValue(operation[key] ~= 0)
:SetDisabled(hasRelationship)
:SetContext(key)
:SetScript("OnValueChanged", private.EnabledSettingEnableOnValueChanged)
)
)
:AddChild(TSM.MainUI.Operations.CreateSettingLine("content", text, hasRelationship or operation[key] == 0)
:SetLayout("VERTICAL")
:SetHeight(48)
:SetMargin(0, 0, 0, margin and 12 or 4)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("Input", "input")
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG")
:SetValidateFunc("NUMBER", minValue..":"..maxValue)
:SetSettingInfo(operation, key)
:SetDisabled(hasRelationship or operation[key] == 0)
)
:AddChild(UIElements.New("Text", "label")
:SetWidth("AUTO")
:SetFont("BODY_BODY3")
:SetTextColor((hasRelationship or operation[key] == 0) and "TEXT_DISABLED" or "TEXT")
:SetFormattedText(L["Enter a value from %d - %d"], minValue, maxValue)
)
)
)
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.EnabledSettingEnableOnValueChanged(toggle, value)
local key = toggle:GetContext()
local operation = TSM.Operations.GetSettings("Warehousing", private.currentOperationName)
operation[key] = value and 1 or 0
local settingFrame = toggle:GetElement("__parent.__parent.content")
settingFrame:GetElement("label")
:SetTextColor(value and "TEXT" or "TEXT_DISABLED")
settingFrame:GetElement("content.input")
:SetDisabled(not value)
:SetValue(operation[key])
settingFrame:GetElement("content.label")
:SetTextColor(value and "TEXT" or "TEXT_DISABLED")
settingFrame:Draw()
end

View File

@@ -0,0 +1,105 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Accounting = TSM.MainUI.Settings:NewPackage("Accounting")
local L = TSM.Include("Locale").GetTable()
local Log = TSM.Include("Util.Log")
local UIElements = TSM.Include("UI.UIElements")
local private = {}
local DAYS_OLD_OPTIONS = { 0, 15, 30, 45, 60, 75, 90, 180, 360 }
-- ============================================================================
-- Module Functions
-- ============================================================================
function Accounting.OnInitialize()
TSM.MainUI.Settings.RegisterSettingPage(L["Accounting"], "middle", private.GetAccountingSettingsFrame)
end
-- ============================================================================
-- Accounting Settings UI
-- ============================================================================
function private.GetAccountingSettingsFrame()
TSM.UI.AnalyticsRecordPathChange("main", "settings", "accounting")
return UIElements.New("ScrollFrame", "accountingSettings")
:SetPadding(8, 8, 8, 0)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Accounting", "accounting", L["General Options"], L["Some general Accounting options are below."])
:AddChild(UIElements.New("Frame", "check1")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "tradeCheckbox")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Track Sales / Purchases via trade"])
:SetSettingInfo(TSM.db.global.accountingOptions, "trackTrades")
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("Frame", "check2")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Checkbox", "tradePromptCheckbox")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Don't prompt to record trades"])
:SetSettingInfo(TSM.db.global.accountingOptions, "autoTrackTrades")
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Accounting", "accounting", L["Clear Old Data"], L["You can clear old Accounting data below to keep things running smoothly."])
:AddChild(UIElements.New("Text", "daysOldLabel")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Remove Data Older Than (Days)"])
)
:AddChild(UIElements.New("Frame", "daysOld")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("SelectionDropdown", "dropdown")
:SetMargin(0, 8, 0, 0)
:SetHintText(L["None Selected"])
:SetItems(DAYS_OLD_OPTIONS)
:SetScript("OnSelectionChanged", private.DaysOldDropdownOnSelectionChanged)
)
:AddChild(UIElements.New("ActionButton", "clearBtn")
:SetWidth(107)
:SetDisabled(true)
:SetText(L["Clear Data"])
:SetScript("OnClick", private.ClearBtnOnClick)
)
)
)
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.DaysOldDropdownOnSelectionChanged(dropdown)
dropdown:GetElement("__parent.clearBtn")
:SetDisabled(false)
:Draw()
end
function private.ClearBtnOnClick(button)
local days = button:GetElement("__parent.dropdown"):GetSelectedItem()
button:GetBaseElement():ShowConfirmationDialog(L["Clear Old Data?"], L["Are you sure you want to clear old accounting data?"], private.ClearDataConfirmed, days)
end
function private.ClearDataConfirmed(days)
Log.PrintfUser(L["Removed a total of %s old records."], TSM.Accounting.Transactions.RemoveOldData(days) + TSM.Accounting.Money.RemoveOldData(days) + TSM.Accounting.Auctions.RemoveOldData(days))
end

View File

@@ -0,0 +1,182 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Appearance = TSM.MainUI.Settings:NewPackage("Appearance")
local L = TSM.Include("Locale").GetTable()
local Theme = TSM.Include("Util.Theme")
local LibDBIcon = LibStub("LibDBIcon-1.0")
local UIElements = TSM.Include("UI.UIElements")
local private = {
colorSetKeys = {},
colorSetNames = {},
}
-- ============================================================================
-- Module Functions
-- ============================================================================
function Appearance.OnInitialize()
for _, key, name in TSM.UI.Util.ColorSetIterator() do
tinsert(private.colorSetKeys, key)
tinsert(private.colorSetNames, name)
end
TSM.MainUI.Settings.RegisterSettingPage(L["Appearance"], "middle", private.GetSettingsFrame)
end
-- ============================================================================
-- Appearance Settings UI
-- ============================================================================
function private.GetSettingsFrame()
TSM.UI.AnalyticsRecordPathChange("main", "settings", "appearance")
return UIElements.New("ScrollFrame", "generalSettings")
:SetPadding(8, 8, 8, 0)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Appearance", "appearance", L["General Options"], L["Some general appearance options are below."])
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "minimapCheckbox")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Hide minimap icon"])
:SetSettingInfo(TSM.db.global.coreOptions.minimapIcon, "hide")
:SetScript("OnValueChanged", private.MinimapOnValueChanged)
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "taskListLockCheckbox")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Lock task list's background"])
:SetSettingInfo(TSM.db.global.appearanceOptions, "taskListBackgroundLock")
:SetScript("OnValueChanged", private.TaskListLockOnValueChanged)
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Checkbox", "showTotalMoneyCheckbox")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Show total gold in header"])
:SetSettingInfo(TSM.db.global.appearanceOptions, "showTotalMoney")
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
)
:AddChild(UIElements.New("Text", "label")
:SetHeight(24)
:SetMargin(12, 0, 4, 12)
:SetFont("BODY_BODY1_BOLD")
:SetText(L["Themes"])
)
:AddChild(UIElements.New("Frame", "theme")
:SetLayout("FLOW")
:AddChildrenWithFunction(private.AddTheme)
)
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.MinimapOnValueChanged(_, value)
if value then
LibDBIcon:Hide("TradeSkillMaster")
else
LibDBIcon:Show("TradeSkillMaster")
end
end
function private.TaskListLockOnValueChanged(_, value)
TSM.db.global.appearanceOptions.taskListBackgroundLock = value
if TSM.UI.TaskListUI.IsVisible() then
TSM.UI.TaskListUI.UpdateFrame()
end
end
function private.AddTheme(frame)
for _, key, name in TSM.UI.Util.ColorSetIterator() do
frame:AddChild(UIElements.New("Frame", name)
:SetLayout("VERTICAL")
:SetSize(198, 140)
:SetPadding(0, 0, 12, 8)
:SetMargin(0, 12, 0, 8)
:SetBackgroundColor(Theme.GetColor("FRAME_BG", key), true)
:SetBorderColor(Theme.GetColor("ACTIVE_BG_ALT", key))
:SetContext(key)
:AddChild(UIElements.New("Frame", "top")
:SetLayout("HORIZONTAL")
:SetHeight(36)
:SetMargin(8, 8, 0, 12)
:AddChild(UIElements.New("Frame", "left")
:SetSize(36, 36)
:SetMargin(0, 12, 0, 0)
:SetBackgroundColor(Theme.GetColor("ACTIVE_BG_ALT", key), true)
)
:AddChild(UIElements.New("Frame", "right")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Frame", "line1")
:SetHeight(12)
:SetMargin(0, 0, 0, 12)
:SetBackgroundColor(Theme.GetColor("ACTIVE_BG", key), true)
)
:AddChild(UIElements.New("Frame", "line2")
:SetHeight(12)
:SetBackgroundColor(Theme.GetColor("PRIMARY_BG_ALT", key), true)
)
)
)
:AddChild(UIElements.New("Frame", "line3")
:SetMargin(8, 8, 0, 12)
:SetBackgroundColor(Theme.GetColor("PRIMARY_BG", key), true)
)
:AddChild(UIElements.New("Texture", "divider")
:SetHeight(1)
:SetTexture(Theme.GetColor("ACTIVE_BG_ALT", key))
)
:AddChild(UIElements.New("Toggle", "toggle")
:SetHeight(20)
:SetMargin(8, 0, 8, 0)
:SetFont("BODY_BODY2_MEDIUM")
:AddOption(Theme.GetThemeName(key), TSM.db.global.appearanceOptions.colorSet == key)
:SetScript("OnValueChanged", private.ThemeButtonOnClick)
)
:AddChildNoLayout(UIElements.New("Button", "btn")
:AddAnchor("TOPLEFT")
:AddAnchor("BOTTOMRIGHT")
:SetScript("OnClick", private.ThemeButtonOnClick)
)
)
end
end
function private.ThemeButtonOnClick(buttonToggle)
local selectedKey = buttonToggle:GetParentElement():GetContext()
for _, key, name in TSM.UI.Util.ColorSetIterator() do
local toggle = buttonToggle:GetElement("__parent.__parent."..name..".toggle")
if key == selectedKey then
toggle:SetOption(name, true)
else
toggle:ClearOption(true)
end
end
TSM.db.global.appearanceOptions.colorSet = selectedKey
Theme.SetActiveColorSet(selectedKey)
end

View File

@@ -0,0 +1,225 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Auctioning = TSM.MainUI.Settings:NewPackage("Auctioning")
local L = TSM.Include("Locale").GetTable()
local Sound = TSM.Include("Util.Sound")
local String = TSM.Include("Util.String")
local Log = TSM.Include("Util.Log")
local UIElements = TSM.Include("UI.UIElements")
local private = {
sounds = {},
soundkeys = {},
}
-- ============================================================================
-- Module Functions
-- ============================================================================
function Auctioning.OnInitialize()
TSM.MainUI.Settings.RegisterSettingPage(L["Auctioning"], "middle", private.GetAuctioningSettingsFrame)
for key, name in pairs(Sound.GetSounds()) do
tinsert(private.sounds, name)
tinsert(private.soundkeys, key)
end
end
-- ============================================================================
-- Auctioning Settings UI
-- ============================================================================
function private.GetAuctioningSettingsFrame()
TSM.UI.AnalyticsRecordPathChange("main", "settings", "auctioning")
return UIElements.New("ScrollFrame", "auctioningSettings")
:SetPadding(8, 8, 8, 0)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Auctioning", "auctioning", L["General Options"], L["Some general Auctioning options are below."])
:AddChild(UIElements.New("Frame", "check1")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "cancelBids")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Cancel auctions with bids"])
:SetSettingInfo(TSM.db.global.auctioningOptions, "cancelWithBid")
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("Frame", "check2")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Checkbox", "invalidPrice")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Disable invalid price warnings"])
:SetSettingInfo(TSM.db.global.auctioningOptions, "disableInvalidMsg")
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Auctioning", "sounds", L["Auction House Sounds"], L["Setup various sounds that play when doing Auctioning scans."])
:AddChild(UIElements.New("Frame", "labelLine1")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:AddChild(UIElements.New("Text", "scan")
:SetMargin(0, 12, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Scan complete sound"])
)
:AddChild(UIElements.New("Text", "confirm")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Confirm complete sound"])
)
)
:AddChild(UIElements.New("Frame", "dropdownLine1")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("SelectionDropdown", "scanComplete")
:SetMargin(0, 12, 0, 0)
:SetItems(private.sounds, private.soundkeys)
:SetSettingInfo(TSM.db.global.auctioningOptions, "scanCompleteSound")
:SetScript("OnSelectionChanged", private.SoundOnSelectionChanged)
)
:AddChild(UIElements.New("SelectionDropdown", "confirmComplete")
:SetItems(private.sounds, private.soundkeys)
:SetSettingInfo(TSM.db.global.auctioningOptions, "confirmCompleteSound")
:SetScript("OnSelectionChanged", private.SoundOnSelectionChanged)
)
)
:AddChild(UIElements.New("Text", "saleLabel")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Auction sale sound"])
)
:AddChild(UIElements.New("SelectionDropdown", "saleDropdown")
:SetHeight(24)
:SetItems(private.sounds, private.soundkeys)
:SetSettingInfo(TSM.db.global.coreOptions, "auctionSaleSound")
:SetScript("OnSelectionChanged", private.SoundOnSelectionChanged)
)
)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Auctioning", "whitelist", L["Whitelist"], L["TSM will not undercut any players you add to your whitelist."])
:AddChild(UIElements.New("Text", "matchLabel")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Match whitelisted players"])
)
:AddChild(UIElements.New("ToggleOnOff", "matchToggle")
:SetHeight(24)
:SetMargin(0, 0, 0, 12)
:SetSettingInfo(TSM.db.global.auctioningOptions, "matchWhitelist")
)
:AddChild(UIElements.New("Text", "addLabel")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Whitelisted characters"])
)
:AddChild(UIElements.New("Input", "newPlayerInput")
:SetHeight(24)
:SetMargin(0, 0, 0, 4)
:SetBackgroundColor("ACTIVE_BG")
:SetHintText(L["Enter player name"])
:SetScript("OnEnterPressed", private.NewPlayerOnEnterPressed)
)
:AddChild(UIElements.New("Frame", "whitelistFrame")
:SetLayout("FLOW")
:SetHeight(60)
:AddChildrenWithFunction(private.AddWhitelistRows)
)
)
end
function private.AddWhitelistRows(containerFrame)
for player in pairs(TSM.db.factionrealm.auctioningOptions.whitelist) do
private.AddWhitelistRow(containerFrame, player)
end
end
function private.AddWhitelistRow(frame, player)
frame:AddChild(UIElements.New("Frame", "whitelist_"..player)
:SetLayout("HORIZONTAL")
:SetSize(100, 20)
:SetMargin(0, 12, 0, 0)
:AddChild(UIElements.New("Text", "text")
:SetWidth("AUTO")
:SetMargin(0, 2, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(player)
)
:AddChild(UIElements.New("Button", "removeBtn")
:SetBackgroundAndSize("iconPack.14x14/Close/Circle")
:SetContext(player)
:SetScript("OnClick", private.RemoveWhitelistOnClick)
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.SoundOnSelectionChanged(self)
Sound.PlaySound(self:GetSelectedItemKey())
end
function private.NewPlayerOnEnterPressed(input)
local newPlayer = strlower(input:GetValue())
input:SetValue("")
input:Draw()
if newPlayer == "" or strfind(newPlayer, ",") or newPlayer ~= String.Escape(newPlayer) then
Log.PrintfUser(L["Invalid player name."])
return
elseif TSM.db.factionrealm.auctioningOptions.whitelist[newPlayer] then
Log.PrintfUser(L["The player \"%s\" is already on your whitelist."], TSM.db.factionrealm.auctioningOptions.whitelist[newPlayer])
return
end
local isAlt = false
for factionrealm in TSM.db:GetConnectedRealmIterator("factionrealm") do
for _, character in TSM.db:FactionrealmCharacterIterator(factionrealm) do
if strlower(newPlayer) == strlower(character) then
Log.PrintfUser(L["You do not need to add \"%s\", alts are whitelisted automatically."], newPlayer)
isAlt = true
end
end
end
if isAlt then
return
end
TSM.db.factionrealm.auctioningOptions.whitelist[newPlayer] = newPlayer
-- add a new row to the UI
local frame = input:GetElement("__parent.whitelistFrame")
private.AddWhitelistRow(frame, newPlayer)
frame:Draw()
end
function private.RemoveWhitelistOnClick(self)
local player = self:GetContext()
TSM.db.factionrealm.auctioningOptions.whitelist[player] = nil
-- remove this row
local row = self:GetParentElement()
local frame = row:GetParentElement()
frame:RemoveChild(row)
row:Release()
frame:Draw()
end

View File

@@ -0,0 +1,287 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Settings = TSM.MainUI:NewPackage("Settings")
local L = TSM.Include("Locale").GetTable()
local Wow = TSM.Include("Util.Wow")
local UIElements = TSM.Include("UI.UIElements")
local private = {
settingPages = {
top = {},
middle = {},
bottom = {},
},
callback = {},
childSettingsPages = {},
sectionCollapsed = {},
}
local SECTIONS = { "top", "middle" }
local SETTING_PATH_SEP = "`"
local SETTING_LABEL_WIDTH = 400
-- ============================================================================
-- Module Functions
-- ============================================================================
function Settings.OnInitialize()
TSM.MainUI.RegisterTopLevelPage(L["Settings"], private.GetSettingsFrame)
end
function Settings.RegisterSettingPage(name, section, callback)
assert(tContains(SECTIONS, section))
tinsert(private.settingPages[section], name)
private.callback[name] = callback
end
function Settings.RegisterChildSettingPage(parentName, childName, callback)
local path = parentName..SETTING_PATH_SEP..childName
private.childSettingsPages[parentName] = private.childSettingsPages[parentName] or {}
tinsert(private.childSettingsPages[parentName], childName)
private.callback[path] = callback
end
function Settings.CreateSettingLine(id, labelText, width)
width = width or SETTING_LABEL_WIDTH
return UIElements.New("Frame", id)
:SetLayout("HORIZONTAL")
:SetHeight(26)
:SetMargin(0, 0, 0, 16)
:AddChild(UIElements.New("Text", "label")
:SetWidth(width)
:SetFont("BODY_BODY2_MEDIUM")
:SetTextColor("TEXT_ALT")
:SetText(labelText)
)
end
function Settings.CreateHeading(id, text)
return UIElements.New("Text", id)
:SetHeight(19)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY1_BOLD")
:SetText(text)
end
function Settings.CreateInputWithReset(id, label, context, validate)
local scope, namespace, key = strsplit(".", context)
local validateFunc, validateContext = nil, nil
if type(validate) == "table" then
validateFunc = "CUSTOM_PRICE"
validateContext = validate
elseif type(validate) == "function" then
validateFunc = validate
elseif validate == nil then
validateFunc = "CUSTOM_PRICE"
else
error("Invalid validate: "..tostring(validate))
end
return UIElements.New("Frame", id)
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Text", "label")
:SetHeight(18)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetTextColor("TEXT_ALT")
:SetText(label)
)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("Input", "input")
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG")
:SetValidateFunc(validateFunc, validateContext)
:SetSettingInfo(TSM.db[scope][namespace], key)
:SetScript("OnValueChanged", private.InputOnValueChanged)
)
:AddChild(UIElements.New("ActionButton", "resetButton")
:SetWidth(108)
:SetText(L["Reset"])
:SetDisabled(TSM.db[scope][namespace][key] == TSM.db:GetDefault(scope, namespace, key))
:SetScript("OnClick", private.ResetBtnOnClick)
:SetContext(context)
)
)
end
function Settings.CreateExpandableSection(pageName, id, text, description, descriptionHeight)
return UIElements.New("CollapsibleContainer", id)
:SetLayout("VERTICAL")
:SetMargin(0, 0, 0, 8)
:SetContextTable(private.sectionCollapsed, pageName..text)
:SetHeadingText(text)
:AddChild(UIElements.New("Text", "description")
:SetHeight(descriptionHeight or 20)
:SetMargin(0, 0, 0, 12)
:SetFont("BODY_BODY3")
:SetText(description)
)
end
function Settings.PromptToReload()
StaticPopupDialogs["TSMReloadPrompt"] = StaticPopupDialogs["TSMReloadPrompt"] or {
text = L["You must reload your UI for these settings to take effect. Reload now?"],
button1 = YES,
button2 = NO,
timeout = 0,
OnAccept = ReloadUI,
}
Wow.ShowStaticPopupDialog("TSMReloadPrompt")
end
-- ============================================================================
-- Settings UI
-- ============================================================================
function private.GetSettingsFrame()
TSM.UI.AnalyticsRecordPathChange("main", "settings")
local defaultPage = private.settingPages.top[1]
local frame = UIElements.New("Frame", "settings")
:SetLayout("HORIZONTAL")
:SetBackgroundColor("PRIMARY_BG_ALT")
:AddChild(UIElements.New("Frame", "settingNavigation")
:SetLayout("VERTICAL")
:SetWidth(160)
:SetPadding(12, 12, 1, 9)
:AddChild(UIElements.New("Frame", "top")
:SetLayout("VERTICAL")
)
:AddChild(UIElements.New("Texture", "vline")
:SetHeight(1)
:SetMargin(0, 0, 8, 8)
:SetTexture("ACTIVE_BG_ALT")
)
:AddChild(UIElements.New("Frame", "middle")
:SetLayout("VERTICAL")
)
:AddChild(UIElements.New("Spacer", "spacer")
-- make all the navigation align to the top
)
)
:AddChild(UIElements.New("Texture", "divider")
:SetWidth(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Frame", "contentFrame")
:SetLayout("VERTICAL")
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("ViewContainer", "content")
:SetNavCallback(private.ContentNavCallback)
)
)
local content = frame:GetElement("contentFrame.content")
local settingNav = frame:GetElement("settingNavigation")
for _, location in ipairs(SECTIONS) do
local navFrame = settingNav:GetElement(location)
for _, settingName in ipairs(private.settingPages[location]) do
navFrame:AddChild(UIElements.New("Button", settingName)
:SetHeight(20)
:SetMargin(0, 0, 8, 0)
:SetFont("BODY_BODY2_BOLD")
:SetJustifyH("LEFT")
:SetContext(settingName)
:SetText(settingName)
:SetScript("OnClick", private.NavButtonOnClick)
)
content:AddPath(settingName, settingName == defaultPage)
if private.childSettingsPages[settingName] then
for _, childSettingName in ipairs(private.childSettingsPages[settingName]) do
local path = settingName..SETTING_PATH_SEP..childSettingName
navFrame:AddChild(UIElements.New("Button", path)
:SetHeight(20)
:SetMargin(9, 0, 8, 0)
:SetFont("BODY_BODY3_MEDIUM")
:SetJustifyH("LEFT")
:SetContext(path)
:SetText(strupper(childSettingName))
:SetScript("OnClick", private.NavButtonOnClick)
)
content:AddPath(path, path == defaultPage)
end
end
end
end
private.UpdateNavFrame(settingNav, defaultPage)
return frame
end
function private.ContentNavCallback(content, path)
return private.callback[path]()
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.NavButtonOnClick(button)
local path = button:GetContext()
if private.childSettingsPages[path] then
-- select the first child
path = path..SETTING_PATH_SEP..private.childSettingsPages[path][1]
end
local contentFrame = button:GetElement("__parent.__parent.__parent.contentFrame")
local navFrame = contentFrame:GetElement("__parent.settingNavigation")
private.UpdateNavFrame(navFrame, path)
navFrame:Draw()
contentFrame:GetElement("content"):SetPath(path, true)
end
function private.InputOnValueChanged(input)
local button = input:GetElement("__parent.resetButton")
local scope, namespace, key = strsplit(".", button:GetContext())
button:SetDisabled(TSM.db[scope][namespace][key] == TSM.db:GetDefault(scope, namespace, key))
:Draw()
end
function private.ResetBtnOnClick(button)
local scope, namespace, key = strsplit(".", button:GetContext())
local defaultValue = TSM.db:GetDefault(scope, namespace, key)
TSM.db:Set(scope, nil, namespace, key, defaultValue)
button:GetElement("__parent.input")
:SetValue(defaultValue)
:Draw()
button:SetDisabled(true)
:Draw()
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.UpdateNavFrame(navFrame, selectedPath)
local selectedSetting = strsplit(SETTING_PATH_SEP, selectedPath)
for _, location in ipairs(SECTIONS) do
for _, settingName in ipairs(private.settingPages[location]) do
navFrame:GetElement(location ..".".. settingName)
:SetTextColor(settingName == selectedSetting and "TEXT" or "ACTIVE_BG_ALT")
if private.childSettingsPages[settingName] then
for _, childSettingName in ipairs(private.childSettingsPages[settingName]) do
local path = settingName..SETTING_PATH_SEP..childSettingName
if settingName == selectedSetting then
navFrame:GetElement(location ..".".. path)
:SetTextColor(path == selectedPath and "INDICATOR" or "TEXT")
:Show()
else
navFrame:GetElement(location ..".".. path):Hide()
end
end
end
end
end
end

View File

@@ -0,0 +1,142 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Crafting = TSM.MainUI.Settings:NewPackage("Crafting")
local L = TSM.Include("Locale").GetTable()
local PlayerInfo = TSM.Include("Service.PlayerInfo")
local UIElements = TSM.Include("UI.UIElements")
local private = {
altCharacters = {},
altGuilds = {},
}
local BAD_MAT_PRICE_SOURCES = {
matprice = true,
}
local BAD_CRAFT_VALUE_PRICE_SOURCES = {
crafting = true,
}
-- ============================================================================
-- Module Functions
-- ============================================================================
function Crafting.OnInitialize()
TSM.MainUI.Settings.RegisterSettingPage(L["Crafting"], "middle", private.GetCraftingSettingsFrame)
end
-- ============================================================================
-- Crafting Settings UI
-- ============================================================================
function private.GetCraftingSettingsFrame()
TSM.UI.AnalyticsRecordPathChange("main", "settings", "crafting")
wipe(private.altCharacters)
wipe(private.altGuilds)
for _, character in PlayerInfo.CharacterIterator(true) do
tinsert(private.altCharacters, character)
end
for name in PlayerInfo.GuildIterator() do
tinsert(private.altGuilds, name)
end
return UIElements.New("ScrollFrame", "craftingSettings")
:SetPadding(8, 8, 8, 0)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Crafting", "inventory", L["Inventory Options"], "")
:AddChild(UIElements.New("Frame", "inventoryOptionsLabels")
:SetLayout("HORIZONTAL")
:SetMargin(0, 0, 0, 4)
:SetHeight(20)
:AddChild(UIElements.New("Text", "label")
:SetMargin(0, 12, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Ignore Characters"])
)
:AddChild(UIElements.New("Text", "label")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Ignore Guilds"])
)
)
:AddChild(UIElements.New("Frame", "inventoryOptionsDropdowns")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("MultiselectionDropdown", "charDropdown")
:SetMargin(0, 12, 0, 0)
:SetItems(private.altCharacters, private.altCharacters)
:SetSettingInfo(TSM.db.global.craftingOptions, "ignoreCharacters")
:SetSelectionText(L["No Characters"], L["%d Characters"], L["All Characters"])
)
:AddChild(UIElements.New("MultiselectionDropdown", "guildDropdown")
:SetItems(private.altGuilds, private.altGuilds)
:SetSettingInfo(TSM.db.global.craftingOptions, "ignoreGuilds")
:SetSelectionText(L["No Guilds"], L["%d Guilds"], L["All Guilds"])
)
)
)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Crafting", "price", L["Default price configuration"], "")
:AddChild(UIElements.New("Text", "matCostLabel")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetTextColor("TEXT_ALT")
:SetText(L["Default material cost method"])
)
:AddChild(UIElements.New("MultiLineInput", "matCostInput")
:SetHeight(70)
:SetMargin(0, 0, 0, 12)
:SetValidateFunc("CUSTOM_PRICE", BAD_MAT_PRICE_SOURCES)
:SetSettingInfo(TSM.db.global.craftingOptions, "defaultMatCostMethod")
)
:AddChild(UIElements.New("Text", "craftValueLabel")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetTextColor("TEXT_ALT")
:SetText(L["Default craft value method"])
)
:AddChild(UIElements.New("MultiLineInput", "matCostInput")
:SetHeight(70)
:SetValidateFunc("CUSTOM_PRICE", BAD_CRAFT_VALUE_PRICE_SOURCES)
:SetSettingInfo(TSM.db.global.craftingOptions, "defaultCraftPriceMethod")
)
)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Crafting", "cooldowns", L["Ignored Cooldowns"], L["Use this list to manage what cooldowns you'd like TSM to ignore from crafting."])
:AddChild(UIElements.New("QueryScrollingTable", "items")
:SetHeight(126)
:GetScrollingTableInfo()
:NewColumn("item")
:SetTitle(L["Cooldown"])
:SetFont("BODY_BODY3")
:SetJustifyH("LEFT")
:SetTextInfo(nil, private.CooldownGetText)
:DisableHiding()
:Commit()
:Commit()
:SetQuery(TSM.Crafting.CreateIgnoredCooldownQuery())
:SetAutoReleaseQuery(true)
:SetSelectionDisabled(true)
:SetScript("OnRowClick", private.IgnoredCooldownOnRowClick)
)
)
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.CooldownGetText(row)
return row:GetField("characterKey").." - "..TSM.Crafting.GetName(row:GetField("spellId"))
end
function private.IgnoredCooldownOnRowClick(_, row)
TSM.Crafting.RemoveIgnoredCooldown(row:GetFields("characterKey", "spellId"))
end

View File

@@ -0,0 +1,297 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local CustomSources = TSM.MainUI.Settings:NewPackage("CustomSources")
local L = TSM.Include("Locale").GetTable()
local TempTable = TSM.Include("Util.TempTable")
local Theme = TSM.Include("Util.Theme")
local CustomPrice = TSM.Include("Service.CustomPrice")
local UIElements = TSM.Include("UI.UIElements")
local private = {}
-- ============================================================================
-- Module Functions
-- ============================================================================
function CustomSources.OnInitialize()
TSM.MainUI.Settings.RegisterSettingPage(L["Custom Sources"], "middle", private.GetCustomSourcesSettingsFrame)
end
-- ============================================================================
-- Custom Sources Settings UI
-- ============================================================================
function private.GetCustomSourcesSettingsFrame()
TSM.UI.AnalyticsRecordPathChange("main", "settings", "custom_sources")
return UIElements.New("ScrollFrame", "content")
:SetPadding(8, 8, 8, 0)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Custom Price", "general", L["Custom Sources"], format(L["Custom sources allow you to create more advanced prices for use throughout the addon. You'll be able to use these new variables in the same way you can use the built-in price sources such as %s and %s."], Theme.GetColor("INDICATOR"):ColorText("vendorsell"), Theme.GetColor("INDICATOR"):ColorText("vendorbuy")), 60)
:AddChild(UIElements.New("Frame", "tableHeading")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Text", "col1")
:SetWidth(162)
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["Name"])
)
:AddChild(UIElements.New("Text", "col2")
:SetFont("BODY_BODY3_MEDIUM")
:SetText(L["String"])
)
)
:AddChild(UIElements.New("Texture", "line1")
:SetHeight(1)
:SetTexture("ACTIVE_BG")
)
:AddChildrenWithFunction(private.AddCustomPriceRows)
:AddChild(UIElements.New("ActionButton", "addNewBtn")
:SetHeight(24)
:SetMargin(0, 0, 32, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Add a new custom source"])
:SetScript("OnClick", private.AddNewButtonOnClick)
)
)
end
function private.CreateCustomPriceRow(name)
local priceString = TSM.db.global.userData.customPriceSources[name]
local row = UIElements.New("Frame", "row_"..name)
:SetLayout("HORIZONTAL")
:SetHeight(28)
:SetMargin(-12, -12, 0, 0)
:SetPadding(12, 12, 0, 0)
:SetBackgroundColor("PRIMARY_BG_ALT")
:SetContext(name)
:SetScript("OnEnter", private.CustomPriceRowOnEnter)
:SetScript("OnLeave", private.CustomPriceRowOnLeave)
:AddChild(UIElements.New("Text", "nameText")
:SetWidth(162)
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY3_MEDIUM")
:SetText(name)
)
:AddChild(UIElements.New("Text", "valueText")
:SetFont("BODY_BODY3")
:SetText(priceString)
)
:AddChild(UIElements.New("Button", "editBtn")
:SetMargin(4, 0, 0, 0)
:SetBackgroundAndSize("iconPack.18x18/Edit")
:SetScript("OnClick", private.EditCustomPriceOnClick)
:PropagateScript("OnEnter")
:PropagateScript("OnLeave")
)
:AddChild(UIElements.New("Button", "deleteBtn")
:SetMargin(4, 0, 0, 0)
:SetBackgroundAndSize("iconPack.18x18/Delete")
:SetScript("OnClick", private.DeleteCustomPriceOnClick)
:PropagateScript("OnEnter")
:PropagateScript("OnLeave")
)
row:GetElement("editBtn"):Hide()
row:GetElement("deleteBtn"):Hide()
return row
end
function private.AddCustomPriceRows(frame)
local names = TempTable.Acquire()
for name in pairs(TSM.db.global.userData.customPriceSources) do
tinsert(names, name)
end
sort(names)
for _, name in ipairs(names) do
frame:AddChild(private.CreateCustomPriceRow(name))
end
TempTable.Release(names)
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.CustomPriceRowOnEnter(frame)
frame:SetBackgroundColor("FRAME_BG")
frame:GetElement("editBtn"):Show()
frame:GetElement("deleteBtn"):Show()
frame:Draw()
end
function private.CustomPriceRowOnLeave(frame)
frame:SetBackgroundColor("PRIMARY_BG_ALT")
frame:GetElement("editBtn"):Hide()
frame:GetElement("deleteBtn"):Hide()
frame:Draw()
end
function private.EditCustomPriceOnClick(button)
private.ShowEditDialog(button)
end
function private.ShowEditDialog(editBtn)
local dialogFrame = UIElements.New("Frame", "frame")
:SetLayout("VERTICAL")
:SetSize(478, 314)
:SetPadding(12)
:AddAnchor("CENTER")
:SetMouseEnabled(true)
:SetBackgroundColor("FRAME_BG", true)
:SetContext(editBtn)
:AddChild(UIElements.New("Frame", "header")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, -4, 14)
:AddChild(UIElements.New("Spacer", "spacer")
:SetWidth(20)
)
:AddChild(UIElements.New("Text", "title")
:SetJustifyH("CENTER")
:SetFont("BODY_BODY1_BOLD")
:SetText(L["Edit Custom Source"])
)
:AddChild(UIElements.New("Button", "closeBtn")
:SetMargin(0, -4, 0, 0)
:SetBackgroundAndSize("iconPack.24x24/Close/Default")
:SetScript("OnClick", private.EditPriceCloseBtnOnClick)
)
)
:AddChild(UIElements.New("Text", "name")
:SetHeight(20)
:SetFont("BODY_BODY2_MEDIUM")
:SetJustifyH("LEFT")
:SetText(L["Name"])
)
:AddChild(UIElements.New("Input", "nameInput")
:SetHeight(24)
:SetBackgroundColor("PRIMARY_BG_ALT")
:SetValue(editBtn:GetElement("__parent.nameText"):GetText())
:SetTabPaths("__parent.valueInput", "__parent.valueInput")
:SetValidateFunc(private.NameValidateFunc)
:SetScript("OnValidationChanged", private.ConfirmOnValidationChanged)
)
:AddChild(UIElements.New("Text", "string")
:SetHeight(20)
:SetMargin(0, 0, 6, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetJustifyH("LEFT")
:SetText(L["String"])
)
:AddChild(UIElements.New("MultiLineInput", "valueInput")
:SetBackgroundColor("PRIMARY_BG_ALT")
:SetValue(editBtn:GetElement("__parent.valueText"):GetText())
:SetTabPaths("__parent.nameInput", "__parent.nameInput")
:SetValidateFunc(private.ValueValidateFunc)
:SetScript("OnValidationChanged", private.ConfirmOnValidationChanged)
)
:AddChild(UIElements.New("ActionButton", "confirm")
:SetHeight(24)
:SetMargin(0, 0, 12, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Confirm"])
:SetContext(editBtn:GetElement("__parent.__parent"))
:SetScript("OnClick", private.ConfirmOnClick)
)
editBtn:GetBaseElement():ShowDialogFrame(dialogFrame)
return dialogFrame
end
function private.EditPriceCloseBtnOnClick(button)
button:GetBaseElement():HideDialog()
end
function private.NameValidateFunc(input, value)
if value == "" then
return false
elseif gsub(value, "([a-z]+)", "") ~= "" then
return false, L["Custom price names can only contain lowercase letters."]
elseif value ~= input:GetParentElement():GetContext():GetParentElement():GetContext() then
return CustomPrice.ValidateName(value)
end
return true
end
function private.ConfirmOnValidationChanged(input)
input:GetElement("__parent.confirm")
:SetDisabled(not input:IsValid())
:Draw()
end
function private.ValueValidateFunc(input, value)
value = strlower(strtrim(value))
local isValid, errMsg = CustomPrice.Validate(value)
if not isValid and value ~= "" then
return false, errMsg
end
return true
end
function private.ConfirmOnClick(button)
local baseElement = button:GetBaseElement()
local oldName = button:GetParentElement():GetContext():GetParentElement():GetContext()
local newName = button:GetElement("__parent.nameInput"):GetValue()
if oldName ~= newName then
CustomPrice.RenameCustomPriceSource(oldName, newName)
CustomPrice.SetCustomPriceSource(newName, button:GetElement("__parent.valueInput"):GetValue())
local generalContainer = button:GetParentElement():GetContext():GetParentElement():GetParentElement()
local rowFrame = button:GetParentElement():GetContext():GetParentElement()
generalContainer:AddChildBeforeById("addNewBtn", private.CreateCustomPriceRow(newName))
generalContainer:RemoveChild(rowFrame)
rowFrame:Release()
generalContainer:GetElement("__parent.__parent")
:Draw()
else
CustomPrice.SetCustomPriceSource(newName, button:GetElement("__parent.valueInput"):GetValue())
button:GetParentElement():GetContext():GetElement("__parent.nameText")
:SetText(newName)
:Draw()
button:GetParentElement():GetContext():GetElement("__parent.valueText")
:SetText(button:GetElement("__parent.valueInput"):GetValue())
:Draw()
end
baseElement:HideDialog()
end
function private.DeleteCustomPriceOnClick(button)
CustomPrice.DeleteCustomPriceSource(button:GetParentElement():GetContext())
local rowFrame = button:GetParentElement()
local parentFrame = rowFrame:GetParentElement()
parentFrame:RemoveChild(rowFrame)
rowFrame:Release()
parentFrame:GetElement("__parent.__parent")
:Draw()
end
function private.AddNewButtonOnClick(button)
-- generate a placeholder name
local newName = nil
local suffix = ""
while not newName do
for i = strbyte("a"), strbyte("z") do
newName = "customprice"..suffix..strchar(i)
if not TSM.db.global.userData.customPriceSources[newName] then
break
end
newName = nil
end
suffix = suffix..strchar(random(strbyte("a"), strbyte("z")))
end
CustomPrice.CreateCustomPriceSource(newName, "")
button:GetParentElement()
:AddChildBeforeById("addNewBtn", private.CreateCustomPriceRow(newName))
button:GetElement("__parent.__parent.__parent")
:Draw()
local dialogFrame = private.ShowEditDialog(button:GetElement("__parent.row_"..newName..".editBtn"))
dialogFrame:GetElement("valueInput"):SetFocused(true)
end

View File

@@ -0,0 +1,122 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Destroying = TSM.MainUI.Settings:NewPackage("Destroying")
local L = TSM.Include("Locale").GetTable()
local UIElements = TSM.Include("UI.UIElements")
local private = {}
local ITEM_QUALITY_DESCS = { ITEM_QUALITY2_DESC, ITEM_QUALITY3_DESC, ITEM_QUALITY4_DESC }
local ITEM_QUALITY_KEYS = { 2, 3, 4 }
-- ============================================================================
-- Module Functions
-- ============================================================================
function Destroying.OnInitialize()
TSM.MainUI.Settings.RegisterSettingPage("Destroying", "middle", private.GetDestroyingSettingsFrame)
end
-- ============================================================================
-- Destroying Settings UI
-- ============================================================================
function private.GetDestroyingSettingsFrame()
TSM.UI.AnalyticsRecordPathChange("main", "settings", "destroying")
return UIElements.New("ScrollFrame", "destroyingSettings")
:SetPadding(8, 8, 8, 0)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Destroying", "general", L["General Options"], "")
:AddChild(UIElements.New("Frame", "check1")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "autoStackCheckbox")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Enable automatic stack combination"])
:SetSettingInfo(TSM.db.global.destroyingOptions, "autoStack")
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("Frame", "check2")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "autoShowCheckbox")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Show destroying frame automatically"])
:SetSettingInfo(TSM.db.global.destroyingOptions, "autoShow")
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("Frame", "check3")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Checkbox", "includeSoulboundCheckbox")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Include soulbound items"])
:SetSettingInfo(TSM.db.global.destroyingOptions, "includeSoulbound")
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Destroying", "disenchanting", L["Disenchanting Options"], "")
:AddChild(UIElements.New("Text", "label")
:SetHeight(18)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Maximum disenchant quality"])
)
:AddChild(UIElements.New("SelectionDropdown", "maxQualityDropDown")
:SetHeight(26)
:SetMargin(0, 0, 0, 12)
:SetItems(ITEM_QUALITY_DESCS, ITEM_QUALITY_KEYS)
:SetSettingInfo(TSM.db.global.destroyingOptions, "deMaxQuality")
)
:AddChild(TSM.MainUI.Settings.CreateInputWithReset("deDisenchantPriceField", L["Only show items with disenchant values above this price"], "global.destroyingOptions.deAbovePrice"))
)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Destroying", "ignore", L["Ignored Items"], L["Use this list to manage what items you'd like TSM to ignore from destroying."])
:AddChild(UIElements.New("QueryScrollingTable", "items")
:SetHeight(136)
:GetScrollingTableInfo()
:NewColumn("item")
:SetTitle(L["Item"])
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetIconSize(12)
:SetTextInfo("itemString", TSM.UI.GetColoredItemName)
:SetIconInfo("texture")
:SetTooltipInfo("itemString")
:SetSortInfo("name")
:DisableHiding()
:Commit()
:Commit()
:SetQuery(TSM.Destroying.CreateIgnoreQuery())
:SetAutoReleaseQuery(true)
:SetSelectionDisabled(true)
:SetScript("OnRowClick", private.IgnoredItemsOnRowClick)
)
)
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.IgnoredItemsOnRowClick(_, record, mouseButton)
if mouseButton ~= "LeftButton" then
return
end
TSM.Destroying.ForgetIgnoreItemPermanent(record:GetField("itemString"))
end

View File

@@ -0,0 +1,672 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local General = TSM.MainUI.Settings:NewPackage("General")
local L = TSM.Include("Locale").GetTable()
local Log = TSM.Include("Util.Log")
local TempTable = TSM.Include("Util.TempTable")
local Table = TSM.Include("Util.Table")
local Theme = TSM.Include("Util.Theme")
local Settings = TSM.Include("Service.Settings")
local Sync = TSM.Include("Service.Sync")
local PlayerInfo = TSM.Include("Service.PlayerInfo")
local Tooltip = TSM.Include("UI.Tooltip")
local UIElements = TSM.Include("UI.UIElements")
local private = {
frame = nil,
characterList = {},
guildList = {},
chatFrameList = {},
}
-- ============================================================================
-- Module Functions
-- ============================================================================
function General.OnInitialize()
TSM.MainUI.Settings.RegisterSettingPage(L["General Settings"], "top", private.GetGeneralSettingsFrame)
Sync.RegisterConnectionChangedCallback(private.SyncConnectionChangedCallback)
end
-- ============================================================================
-- General Settings UI
-- ============================================================================
function private.GetGeneralSettingsFrame()
TSM.UI.AnalyticsRecordPathChange("main", "settings", "general")
wipe(private.chatFrameList)
local defaultChatFrame = nil
for i = 1, NUM_CHAT_WINDOWS do
local name = strlower(GetChatWindowInfo(i) or "")
if DEFAULT_CHAT_FRAME == _G["ChatFrame"..i] then
defaultChatFrame = name
end
if name ~= "" and _G["ChatFrame"..i.."Tab"]:IsVisible() then
tinsert(private.chatFrameList, name)
end
end
if not tContains(private.chatFrameList, TSM.db.global.coreOptions.chatFrame) then
if tContains(private.chatFrameList, defaultChatFrame) then
TSM.db.global.coreOptions.chatFrame = defaultChatFrame
Log.SetChatFrame(defaultChatFrame)
else
-- all chat frames are hidden, so just disable the setting
wipe(private.chatFrameList)
end
end
wipe(private.characterList)
for _, character in PlayerInfo.CharacterIterator(true) do
if character ~= UnitName("player") then
tinsert(private.characterList, character)
end
end
wipe(private.guildList)
for guild in PlayerInfo.GuildIterator(true) do
tinsert(private.guildList, guild)
end
return UIElements.New("ScrollFrame", "generalSettings")
:SetPadding(8, 8, 8, 0)
:SetScript("OnUpdate", private.FrameOnUpdate)
:SetScript("OnHide", private.FrameOnHide)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("General", "general", L["General Options"], L["Some general TSM options are below."])
:AddChild(UIElements.New("Frame", "check1")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "globalOperations")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Store operations globally"])
:SetChecked(TSM.Operations.IsStoredGlobally())
:SetScript("OnValueChanged", private.GlobalOperationsOnValueChanged)
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("Frame", "check2")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "protectAuctionHouse")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Prevent closing the Auction House with the esc key"])
:SetSettingInfo(TSM.db.global.coreOptions, "protectAuctionHouse")
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(TSM.MainUI.Settings.CreateInputWithReset("generalGroupPriceField", L["Filter group item lists based on the following price source"], "global.coreOptions.groupPriceSource"))
:AddChild(UIElements.New("Frame", "dropdownLabelLine")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 12, 4)
:AddChild(UIElements.New("Text", "chatTabLabel")
:SetMargin(0, 12, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Chat Tab"])
)
:AddChild(UIElements.New("Text", "forgetLabel")
:SetMargin(0, 12, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Forget Character"])
)
:AddChild(UIElements.New("Text", "ignoreLabel")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Ignore Guilds"])
)
)
:AddChild(UIElements.New("Frame", "dropdownLabelLine")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("SelectionDropdown", "chatTabDropdown")
:SetMargin(0, 16, 0, 0)
:SetItems(private.chatFrameList, private.chatFrameList)
:SetSettingInfo(next(private.chatFrameList) and TSM.db.global.coreOptions or nil, "chatFrame")
:SetScript("OnSelectionChanged", private.ChatTabOnSelectionChanged)
)
:AddChild(UIElements.New("SelectionDropdown", "forgetDropdown")
:SetMargin(0, 16, 0, 0)
:SetItems(private.characterList, private.characterList)
:SetScript("OnSelectionChanged", private.ForgetCharacterOnSelectionChanged)
)
:AddChild(UIElements.New("MultiselectionDropdown", "ignoreDropdown")
:SetItems(private.guildList, private.guildList)
:SetSettingInfo(TSM.db.factionrealm.coreOptions, "ignoreGuilds")
:SetSelectionText(L["No Guilds"], L["%d Guilds"], L["All Guilds"])
)
)
)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("General", "profiles", L["Profiles"], L["Set your active profile or create a new one."])
:AddChildrenWithFunction(private.AddProfileRows)
:AddChild(UIElements.New("Text", "profileLabel")
:SetHeight(20)
:SetMargin(0, 0, 4, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Create new profile"])
)
:AddChild(UIElements.New("Input", "newProfileInput")
:SetHeight(24)
:SetBackgroundColor("ACTIVE_BG")
:SetHintText(L["Enter profile name"])
:SetScript("OnEnterPressed", private.NewProfileInputOnEnterPressed)
)
)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("General", "accountSync", L["Account Syncing"], L["TSM can automatically sync data between multiple WoW accounts."])
:AddChildrenWithFunction(private.AddAccountSyncRows)
:AddChild(UIElements.New("Text", "profileLabel")
:SetHeight(20)
:SetMargin(0, 0, 4, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Add account"])
)
:AddChild(UIElements.New("Input", "newProfileInput")
:SetHeight(24)
:SetBackgroundColor("ACTIVE_BG")
:SetHintText(L["Enter name of logged-in character on other account"])
:SetScript("OnEnterPressed", private.NewAccountSyncInputOnEnterPressed)
)
)
end
function private.AddProfileRows(frame)
for index, profileName in TSM.db:ProfileIterator() do
local isCurrentProfile = profileName == TSM.db:GetCurrentProfile()
local row = UIElements.New("Frame", "profileRow_"..index)
:SetLayout("HORIZONTAL")
:SetHeight(28)
:SetMargin(0, 0, 0, 8)
:SetPadding(8, 8, 4, 4)
:SetBackgroundColor(isCurrentProfile and "ACTIVE_BG" or "PRIMARY_BG_ALT", true)
:SetContext(profileName)
:SetScript("OnEnter", private.ProfileRowOnEnter)
:SetScript("OnLeave", private.ProfileRowOnLeave)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Checkbox", "checkbox")
:SetWidth("AUTO")
:SetCheckboxPosition("LEFT")
:SetText(profileName)
:SetFont("BODY_BODY2")
:SetChecked(isCurrentProfile)
:SetScript("OnValueChanged", private.ProfileCheckboxOnValueChanged)
:PropagateScript("OnEnter")
:PropagateScript("OnLeave")
)
:PropagateScript("OnEnter")
:PropagateScript("OnLeave")
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("Button", "resetBtn")
:SetBackgroundAndSize("iconPack.18x18/Reset")
:SetMargin(4, 0, 0, 0)
:SetScript("OnClick", private.ResetProfileOnClick)
:SetScript("OnEnter", private.ResetProfileOnEnter)
:SetScript("OnLeave", private.ResetProfileOnLeave)
)
:AddChild(UIElements.New("Button", "renameBtn")
:SetBackgroundAndSize("iconPack.18x18/Edit")
:SetMargin(4, 0, 0, 0)
:SetScript("OnClick", private.RenameProfileOnClick)
:SetScript("OnEnter", private.RenameProfileOnEnter)
:SetScript("OnLeave", private.RenameProfileOnLeave)
)
:AddChild(UIElements.New("Button", "duplicateBtn")
:SetBackgroundAndSize("iconPack.18x18/Duplicate")
:SetMargin(4, 0, 0, 0)
:SetScript("OnClick", private.DuplicateProfileOnClick)
:SetScript("OnEnter", private.DuplicateProfileOnEnter)
:SetScript("OnLeave", private.DuplicateProfileOnLeave)
)
:AddChild(UIElements.New("Button", "deleteBtn")
:SetBackgroundAndSize("iconPack.18x18/Delete")
:SetMargin(4, 0, 0, 0)
:SetScript("OnClick", private.DeleteProfileOnClick)
:SetScript("OnEnter", private.DeleteProfileOnEnter)
:SetScript("OnLeave", private.DeleteProfileOnLeave)
)
row:GetElement("deleteBtn"):Hide()
if not isCurrentProfile then
row:GetElement("resetBtn"):Hide()
row:GetElement("renameBtn"):Hide()
row:GetElement("duplicateBtn"):Hide()
end
frame:AddChild(row)
end
end
function private.AddAccountSyncRows(frame)
local newAccountStatusText = Sync.GetNewAccountStatus()
if newAccountStatusText then
local row = private.CreateAccountSyncRow("new", newAccountStatusText)
row:GetElement("sendProfileBtn"):Hide()
row:GetElement("removeBtn"):Hide()
frame:AddChild(row)
end
for _, account in TSM.db:SyncAccountIterator() do
local characters = TempTable.Acquire()
for _, character in Settings.CharacterByAccountFactionrealmIterator(account) do
tinsert(characters, character)
end
sort(characters)
local isConnected, connectedCharacter = Sync.GetConnectionStatus(account)
local statusText = nil
if isConnected then
statusText = Theme.GetFeedbackColor("GREEN"):ColorText(format(L["Connected to %s"], connectedCharacter))
else
statusText = Theme.GetFeedbackColor("RED"):ColorText(L["Offline"])
end
statusText = statusText.." | "..table.concat(characters, ", ")
TempTable.Release(characters)
local row = private.CreateAccountSyncRow("accountSyncRow_"..account, statusText)
row:SetContext(account)
row:GetElement("sendProfileBtn"):Hide()
row:GetElement("removeBtn"):Hide()
frame:AddChild(row)
end
end
function private.CreateAccountSyncRow(id, statusText)
local row = UIElements.New("Frame", id)
:SetLayout("HORIZONTAL")
:SetHeight(28)
:SetMargin(0, 0, 0, 8)
:SetPadding(8, 8, 4, 4)
:SetBackgroundColor("PRIMARY_BG_ALT", true)
:SetScript("OnEnter", private.AccountSyncRowOnEnter)
:SetScript("OnLeave", private.AccountSyncRowOnLeave)
:AddChild(UIElements.New("Text", "status")
:SetFont("BODY_BODY2")
:SetText(statusText)
:SetScript("OnEnter", private.AccountSyncTextOnEnter)
:SetScript("OnLeave", private.AccountSyncTextOnLeave)
)
:AddChild(UIElements.New("Button", "sendProfileBtn")
:SetBackgroundAndSize("iconPack.18x18/Operation")
:SetMargin(4, 0, 0, 0)
:SetScript("OnClick", private.SendProfileOnClick)
:SetScript("OnEnter", private.SendProfileOnEnter)
:SetScript("OnLeave", private.SendProfileOnLeave)
)
:AddChild(UIElements.New("Button", "removeBtn")
:SetBackgroundAndSize("iconPack.18x18/Delete")
:SetMargin(4, 0, 0, 0)
:SetScript("OnClick", private.RemoveAccountSyncOnClick)
:SetScript("OnEnter", private.RemoveAccountOnEnter)
:SetScript("OnLeave", private.RemoveAccountOnLeave)
)
return row
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.SyncConnectionChangedCallback()
if private.frame then
private.frame:GetParentElement():ReloadContent()
end
end
function private.FrameOnUpdate(frame)
frame:SetScript("OnUpdate", nil)
private.frame = frame
end
function private.FrameOnHide(frame)
private.frame = nil
end
function private.GlobalOperationsOnValueChanged(checkbox, value)
-- restore the previous value until it's confirmed
checkbox:SetChecked(not value, true)
local desc = L["If you have multiple profiles set up with operations, enabling this will cause all but the current profile's operations to be irreversibly lost."]
checkbox:GetBaseElement():ShowConfirmationDialog(L["Make Operations Global?"], desc, private.GlobalOperationsConfirmed, checkbox, value)
end
function private.GlobalOperationsConfirmed(checkbox, newValue)
checkbox:SetChecked(newValue, true)
:Draw()
TSM.Operations.SetStoredGlobally(newValue)
end
function private.ChatTabOnSelectionChanged(dropdown)
Log.SetChatFrame(dropdown:GetSelectedItem())
end
function private.ForgetCharacterOnSelectionChanged(self)
local character = self:GetSelectedItem()
if not character then return end
TSM.db:RemoveSyncCharacter(character)
TSM.db.factionrealm.internalData.pendingMail[character] = nil
TSM.db.factionrealm.internalData.characterGuilds[character] = nil
Log.PrintfUser(L["%s removed."], character)
assert(Table.RemoveByValue(private.characterList, character) == 1)
self:SetSelectedItem(nil)
:SetItems(private.characterList)
:Draw()
end
function private.ProfileRowOnEnter(frame)
local isCurrentProfile = frame:GetContext() == TSM.db:GetCurrentProfile()
frame:SetBackgroundColor("ACTIVE_BG", true)
if not isCurrentProfile then
frame:GetElement("resetBtn"):Show()
frame:GetElement("renameBtn"):Show()
frame:GetElement("duplicateBtn"):Show()
frame:GetElement("deleteBtn"):Show()
end
frame:Draw()
end
function private.ProfileRowOnLeave(frame)
local isCurrentProfile = frame:GetContext() == TSM.db:GetCurrentProfile()
frame:SetBackgroundColor(isCurrentProfile and "ACTIVE_BG" or "PRIMARY_BG_ALT", true)
if not isCurrentProfile then
frame:GetElement("resetBtn"):Hide()
frame:GetElement("renameBtn"):Hide()
frame:GetElement("duplicateBtn"):Hide()
frame:GetElement("deleteBtn"):Hide()
end
frame:Draw()
end
function private.ProfileCheckboxOnValueChanged(checkbox, value)
if not value then
-- can't uncheck profile checkboxes
checkbox:SetChecked(true, true)
checkbox:Draw()
return
end
-- uncheck the current profile row
local currentProfileIndex = nil
for index, profileName in TSM.db:ProfileIterator() do
if profileName == TSM.db:GetCurrentProfile() then
assert(not currentProfileIndex)
currentProfileIndex = index
end
end
local prevRow = checkbox:GetElement("__parent.__parent.__parent.profileRow_"..currentProfileIndex)
prevRow:GetElement("content.checkbox")
:SetChecked(false, true)
prevRow:GetElement("resetBtn"):Hide()
prevRow:GetElement("renameBtn"):Hide()
prevRow:GetElement("duplicateBtn"):Hide()
prevRow:GetElement("deleteBtn"):Hide()
prevRow:SetBackgroundColor("PRIMARY_BG_ALT", true)
prevRow:Draw()
-- set the profile
TSM.db:SetProfile(checkbox:GetText())
-- set this row as the current one
local newRow = checkbox:GetElement("__parent.__parent")
newRow:SetBackgroundColor("ACTIVE_BG", true)
newRow:GetElement("resetBtn"):Show()
newRow:GetElement("renameBtn"):Show()
newRow:GetElement("duplicateBtn"):Show()
newRow:GetElement("deleteBtn"):Hide()
newRow:Draw()
end
function private.RenameProfileOnClick(button)
local profileName = button:GetParentElement():GetContext()
local dialogFrame = UIElements.New("Frame", "frame")
:SetLayout("VERTICAL")
:SetSize(600, 187)
:AddAnchor("CENTER")
:SetBackgroundColor("FRAME_BG")
:SetBorderColor("ACTIVE_BG")
:AddChild(UIElements.New("Text", "title")
:SetHeight(44)
:SetMargin(16, 16, 24, 16)
:SetFont("BODY_BODY2_BOLD")
:SetJustifyH("CENTER")
:SetText(L["Rename Profile"])
)
:AddChild(UIElements.New("Input", "nameInput")
:SetHeight(26)
:SetMargin(16, 16, 0, 25)
:SetBackgroundColor("PRIMARY_BG_ALT")
:SetContext(profileName)
:SetValue(profileName)
:SetScript("OnEnterPressed", private.RenameProfileInputOnEnterPressed)
)
:AddChild(UIElements.New("Frame", "buttons")
:SetLayout("HORIZONTAL")
:SetMargin(16, 16, 0, 16)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("ActionButton", "closeBtn")
:SetSize(126, 26)
:SetText(CLOSE)
:SetScript("OnClick", private.DialogCloseBtnOnClick)
)
)
button:GetBaseElement():ShowDialogFrame(dialogFrame)
dialogFrame:GetElement("nameInput"):SetFocused(true)
end
function private.DialogCloseBtnOnClick(button)
private.RenameProfileInputOnEnterPressed(button:GetElement("__parent.__parent.nameInput"))
end
function private.RenameProfileInputOnEnterPressed(input)
local profileName = input:GetValue()
local prevProfileName = input:GetContext()
if not TSM.db:IsValidProfileName(profileName) then
Log.PrintUser(L["This is not a valid profile name. Profile names must be at least one character long and may not contain '@' characters."])
return
elseif TSM.db:ProfileExists(profileName) then
Log.PrintUser(L["A profile with this name already exists."])
return
end
-- create a new profile, copy over the settings, then delete the old one
local currentProfileName = TSM.db:GetCurrentProfile()
TSM.db:SetProfile(profileName)
TSM.db:CopyProfile(prevProfileName)
TSM.db:DeleteProfile(prevProfileName, profileName)
if currentProfileName ~= prevProfileName then
TSM.db:SetProfile(currentProfileName)
end
-- hide the dialog and refresh the settings content
local baseElement = input:GetBaseElement()
baseElement:HideDialog()
baseElement:GetElement("content.settings.contentFrame.content"):ReloadContent()
end
function private.RenameProfileOnEnter(button)
button:ShowTooltip(L["Rename the profile"])
private.ProfileRowOnEnter(button:GetParentElement())
end
function private.RenameProfileOnLeave(button)
Tooltip.Hide()
private.ProfileRowOnLeave(button:GetParentElement())
end
function private.DuplicateProfileOnClick(button)
local profileName = button:GetParentElement():GetContext()
local newName = profileName
while TSM.db:ProfileExists(newName) do
newName = newName.." Copy"
end
local activeProfile = TSM.db:GetCurrentProfile()
TSM.db:SetProfile(newName)
TSM.db:CopyProfile(profileName)
TSM.db:SetProfile(activeProfile)
button:GetBaseElement():GetElement("content.settings.contentFrame.content"):ReloadContent()
end
function private.DuplicateProfileOnEnter(button)
button:ShowTooltip(L["Duplicate the profile"])
private.ProfileRowOnEnter(button:GetParentElement())
end
function private.DuplicateProfileOnLeave(button)
Tooltip.Hide()
private.ProfileRowOnLeave(button:GetParentElement())
end
function private.ResetProfileOnClick(button)
local profileName = button:GetParentElement():GetContext()
local desc = format(L["This will reset all groups and operations (if not stored globally) to be wiped from '%s'."], profileName)
button:GetBaseElement():ShowConfirmationDialog(L["Reset Profile?"], desc, private.ResetProfileConfirmed, profileName)
end
function private.ResetProfileConfirmed(profileName)
local activeProfile = TSM.db:GetCurrentProfile()
TSM.db:SetProfile(profileName)
TSM.db:ResetProfile()
TSM.db:SetProfile(activeProfile)
end
function private.ResetProfileOnEnter(button)
button:ShowTooltip(L["Reset the current profile to default settings"])
private.ProfileRowOnEnter(button:GetParentElement())
end
function private.ResetProfileOnLeave(button)
Tooltip.Hide()
private.ProfileRowOnLeave(button:GetParentElement())
end
function private.DeleteProfileOnClick(button)
local profileName = button:GetParentElement():GetContext()
local desc = format(L["This will permanently delete the '%s' profile."], profileName)
button:GetBaseElement():ShowConfirmationDialog(L["Delete Profile?"], desc, private.DeleteProfileConfirmed, button, profileName)
end
function private.DeleteProfileConfirmed(button, profileName)
TSM.db:DeleteProfile(profileName)
button:GetBaseElement():GetElement("content.settings.contentFrame.content"):ReloadContent()
end
function private.DeleteProfileOnEnter(button)
button:ShowTooltip(L["Delete the profile"])
private.ProfileRowOnEnter(button:GetParentElement())
end
function private.DeleteProfileOnLeave(button)
Tooltip.Hide()
private.ProfileRowOnLeave(button:GetParentElement())
end
function private.NewProfileInputOnEnterPressed(input)
local profileName = input:GetValue()
if not TSM.db:IsValidProfileName(profileName) then
Log.PrintUser(L["This is not a valid profile name. Profile names must be at least one character long and may not contain '@' characters."])
return
elseif TSM.db:ProfileExists(profileName) then
Log.PrintUser(L["A profile with this name already exists."])
return
end
TSM.db:SetProfile(profileName)
input:GetBaseElement():GetElement("content.settings.contentFrame.content"):ReloadContent()
end
function private.AccountSyncRowOnEnter(frame)
local account = frame:GetContext()
if account then
frame:GetElement("sendProfileBtn"):Show()
frame:GetElement("removeBtn"):Show()
end
frame:SetBackgroundColor("ACTIVE_BG", true)
frame:Draw()
end
function private.AccountSyncRowOnLeave(frame)
frame:SetBackgroundColor("PRIMARY_BG_ALT", true)
frame:GetElement("sendProfileBtn"):Hide()
frame:GetElement("removeBtn"):Hide()
frame:Draw()
end
function private.AccountSyncTextOnEnter(text)
local account = text:GetParentElement():GetContext()
local tooltipLines = TempTable.Acquire()
if account then
tinsert(tooltipLines, Theme.GetColor("INDICATOR"):ColorText(L["Sync Status"]))
local mirrorConnected, mirrorSynced = Sync.GetMirrorStatus(account)
local mirrorStatus = nil
if not mirrorConnected then
mirrorStatus = Theme.GetFeedbackColor("RED"):ColorText(L["Not Connected"])
elseif not mirrorSynced then
mirrorStatus = Theme.GetFeedbackColor("YELLOW"):ColorText(L["Updating"])
else
mirrorStatus = Theme.GetFeedbackColor("GREEN"):ColorText(L["Up to date"])
end
tinsert(tooltipLines, L["Inventory / Gold Graph"]..TSM.CONST.TOOLTIP_SEP..mirrorStatus)
tinsert(tooltipLines, L["Profession Info"]..TSM.CONST.TOOLTIP_SEP..TSM.Crafting.Sync.GetStatus(account))
tinsert(tooltipLines, L["Purchase / Sale Info"]..TSM.CONST.TOOLTIP_SEP..TSM.Accounting.Sync.GetStatus(account))
else
tinsert(tooltipLines, L["Establishing connection..."])
end
text:ShowTooltip(table.concat(tooltipLines, "\n"), nil, 52)
TempTable.Release(tooltipLines)
private.AccountSyncRowOnEnter(text:GetParentElement())
end
function private.AccountSyncTextOnLeave(text)
Tooltip.Hide()
private.AccountSyncRowOnLeave(text:GetParentElement())
end
function private.SendProfileOnClick(button)
local player = Sync.GetConnectedCharacterByAccount(button:GetParentElement():GetContext())
if not player then
return
end
TSM.Groups.Sync.SendCurrentProfile(player)
end
function private.SendProfileOnEnter(button)
button:ShowTooltip(L["Send your active profile to this synced account"])
private.AccountSyncRowOnEnter(button:GetParentElement())
end
function private.SendProfileOnLeave(button)
Tooltip.Hide()
private.AccountSyncRowOnLeave(button:GetParentElement())
end
function private.RemoveAccountSyncOnClick(button)
Sync.RemoveAccount(button:GetParentElement():GetContext())
button:GetBaseElement():GetElement("content.settings.contentFrame.content"):ReloadContent()
Tooltip.Hide()
Log.PrintUser(L["Account sync removed. Please delete the account sync from the other account as well."])
end
function private.RemoveAccountOnEnter(button)
button:ShowTooltip(L["Remove this account sync and all synced data from this account"])
private.AccountSyncRowOnEnter(button:GetParentElement())
end
function private.RemoveAccountOnLeave(button)
Tooltip.Hide()
private.AccountSyncRowOnLeave(button:GetParentElement())
end
function private.NewAccountSyncInputOnEnterPressed(input)
local character = Ambiguate(input:GetValue(), "none")
if Sync.EstablishConnection(character) then
Log.PrintfUser(L["Establishing connection to %s. Make sure that you've entered this character's name on the other account."], character)
private.SyncConnectionChangedCallback()
else
input:SetValue("")
input:Draw()
end
end

View File

@@ -0,0 +1,270 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Macros = TSM.MainUI.Settings:NewPackage("Macros")
local L = TSM.Include("Locale").GetTable()
local TempTable = TSM.Include("Util.TempTable")
local Vararg = TSM.Include("Util.Vararg")
local Log = TSM.Include("Util.Log")
local Theme = TSM.Include("Util.Theme")
local UIElements = TSM.Include("UI.UIElements")
local private = {}
local MACRO_NAME = "TSMMacro"
local MACRO_ICON = TSM.IsWowClassic() and "INV_Misc_Flower_01" or "Achievement_Faction_GoldenLotus"
local BINDING_NAME = "MACRO "..MACRO_NAME
local BUTTON_MAPPING = {
["row1.myauctionsCheckbox"] = "TSMCancelAuctionBtn",
["row1.auctioningCheckbox"] = "TSMAuctioningBtn",
["row2.shoppingCheckbox"] = "TSMShoppingBuyoutBtn",
["row2.bidBuyConfirmBtn"] = "TSMBidBuyConfirmBtn",
["row3.sniperCheckbox"] = "TSMSniperBtn",
["row3.craftingCheckbox"] = "TSMCraftingBtn",
["row4.destroyingCheckbox"] = "TSMDestroyBtn",
["row4.vendoringCheckbox"] = "TSMVendoringSellAllButton",
}
local CHARACTER_BINDING_SET = 2
local MAX_MACRO_LENGTH = 255
-- ============================================================================
-- Module Functions
-- ============================================================================
function Macros.OnInitialize()
TSM.MainUI.Settings.RegisterSettingPage(L["Macros"], "middle", private.GetMacrosSettingsFrame)
end
-- ============================================================================
-- Macros Settings UI
-- ============================================================================
function private.GetMacrosSettingsFrame()
TSM.UI.AnalyticsRecordPathChange("main", "settings", "macros")
local body = GetMacroBody(MACRO_NAME) or ""
local upEnabled, downEnabled, altEnabled, ctrlEnabled, shiftEnabled = false, false, false, false, false
for _, binding in Vararg.Iterator(GetBindingKey(BINDING_NAME)) do
upEnabled = upEnabled or (strfind(binding, "MOUSEWHEELUP") and true)
downEnabled = upEnabled or (strfind(binding, "MOUSEWHEELDOWN") and true)
altEnabled = altEnabled or (strfind(binding, "ALT-") and true)
ctrlEnabled = ctrlEnabled or (strfind(binding, "CTRL-") and true)
shiftEnabled = shiftEnabled or (strfind(binding, "SHIFT-") and true)
end
local frame = UIElements.New("ScrollFrame", "macroSettings")
:SetPadding(8, 8, 8, 0)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Macro", "setup", L["Macro Setup"], L["Many commonly-used actions in TSM can be added to a macro and bound to your scroll wheel. Use the options below to setup this macro and scroll wheel binding."], 40)
:AddChild(UIElements.New("Text", "actionsSubHeading")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:SetFont("BODY_BODY2_BOLD")
:SetText(L["Bound Actions"])
)
:AddChild(UIElements.New("Frame", "row1")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "myauctionsCheckbox")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(format(L["My Auctions %s button"], Theme.GetColor("INDICATOR"):ColorText(L["Cancel"])))
)
:AddChild(UIElements.New("Checkbox", "auctioningCheckbox")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(format(L["Auctioning %s button"], Theme.GetColor("INDICATOR"):ColorText(L["Post / Cancel"])))
)
)
:AddChild(UIElements.New("Frame", "row2")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "shoppingCheckbox")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(format(L["Shopping %s button"], Theme.GetColor("INDICATOR"):ColorText(L["Buyout"])))
)
:AddChild(UIElements.New("Checkbox", "bidBuyConfirmBtn")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(format(L["Confirmation %s button"], Theme.GetColor("INDICATOR"):ColorText(L["Bid / Buyout"])))
)
)
:AddChild(UIElements.New("Frame", "row3")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "sniperCheckbox")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(format(L["Sniper %s button"], Theme.GetColor("INDICATOR"):ColorText(L["Buyout"])))
)
:AddChild(UIElements.New("Checkbox", "craftingCheckbox")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(format(L["Crafting %s button"], Theme.GetColor("INDICATOR"):ColorText(L["Craft Next"])))
)
)
:AddChild(UIElements.New("Frame", "row4")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 16)
:AddChild(UIElements.New("Checkbox", "destroyingCheckbox")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(format(L["Destroying %s button"], Theme.GetColor("INDICATOR"):ColorText(L["Destroy Next"])))
)
:AddChild(UIElements.New("Checkbox", "vendoringCheckbox")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(format(L["Vendoring %s button"], Theme.GetColor("INDICATOR"):ColorText(L["Sell All"])))
)
)
:AddChild(UIElements.New("Text", "scrollWheelSubHeading")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:SetFont("BODY_BODY2_BOLD")
:SetText(L["Scroll Wheel Options"])
)
:AddChild(UIElements.New("Frame", "direction")
:SetLayout("VERTICAL")
:SetMargin(0, 0, 0, 14)
:AddChild(UIElements.New("Text", "label")
:SetHeight(20)
:SetMargin(0, 0, 0, 6)
:SetFont("BODY_BODY2")
:SetText(L["Scroll wheel direction"])
)
:AddChild(UIElements.New("Frame", "check")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Checkbox", "up")
:SetWidth("AUTO")
:SetMargin(0, 16, 0, 0)
:SetFont("BODY_BODY2")
:SetText(L["Up"])
:SetChecked(upEnabled)
)
:AddChild(UIElements.New("Checkbox", "down")
:SetWidth("AUTO")
:SetFont("BODY_BODY2")
:SetText(L["Down"])
:SetChecked(downEnabled)
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
)
:AddChild(UIElements.New("Frame", "modifiers")
:SetLayout("VERTICAL")
:SetMargin(0, 0, 0, 18)
:AddChild(UIElements.New("Text", "label")
:SetHeight(20)
:SetMargin(0, 0, 0, 6)
:SetFont("BODY_BODY2")
:SetText(L["Modifiers"])
)
:AddChild(UIElements.New("Frame", "check")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Checkbox", "alt")
:SetWidth("AUTO")
:SetMargin(0, 16, 0, 0)
:SetFont("BODY_BODY2")
:SetText(L["ALT"])
:SetChecked(altEnabled)
)
:AddChild(UIElements.New("Checkbox", "ctrl")
:SetWidth("AUTO")
:SetMargin(0, 16, 0, 0)
:SetFont("BODY_BODY2")
:SetText(L["CTRL"])
:SetChecked(ctrlEnabled)
)
:AddChild(UIElements.New("Checkbox", "shift")
:SetWidth("AUTO")
:SetFont("BODY_BODY2")
:SetText(L["SHIFT"])
:SetChecked(shiftEnabled)
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
)
:AddChild(UIElements.New("ActionButton", "createBtn")
:SetHeight(24)
:SetText(GetMacroInfo(MACRO_NAME) and L["Update existing macro"] or L["Create macro"])
:SetScript("OnClick", private.CreateButtonOnClick)
)
)
for path, buttonName in pairs(BUTTON_MAPPING) do
frame:GetElement("setup.content."..path)
:SetChecked(strfind(body, buttonName) and true or false)
end
return frame
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.CreateButtonOnClick(button)
-- remove the old bindings and macros
for _, binding in Vararg.Iterator(GetBindingKey(BINDING_NAME)) do
SetBinding(binding)
end
DeleteMacro(MACRO_NAME)
if GetNumMacros() >= MAX_ACCOUNT_MACROS then
Log.PrintUser(L["Could not create macro as you already have too many. Delete one of your existing macros and try again."])
return
end
-- create the new macro
local scrollFrame = button:GetParentElement():GetParentElement():GetParentElement()
local lines = TempTable.Acquire()
for elementPath, buttonName in pairs(BUTTON_MAPPING) do
if scrollFrame:GetElement("setup.content."..elementPath):IsChecked() then
tinsert(lines, "/click "..buttonName)
end
end
local macroText = table.concat(lines, "\n")
CreateMacro(MACRO_NAME, MACRO_ICON, macroText)
TempTable.Release(lines)
-- create the binding
local modifierStr = ""
if scrollFrame:GetElement("setup.content.modifiers.check.ctrl"):IsChecked() then
modifierStr = modifierStr.."CTRL-"
end
if scrollFrame:GetElement("setup.content.modifiers.check.alt"):IsChecked() then
modifierStr = modifierStr.."ALT-"
end
if scrollFrame:GetElement("setup.content.modifiers.check.shift"):IsChecked() then
modifierStr = modifierStr.."SHIFT-"
end
-- we want to save these bindings to be per-character, so the mode should be 1 / 2 if we're currently on
-- per-character bindings or not respectively
local bindingMode = (GetCurrentBindingSet() == CHARACTER_BINDING_SET) and 1 or 2
if scrollFrame:GetElement("setup.content.direction.check.up") then
SetBinding(modifierStr.."MOUSEWHEELUP", nil, bindingMode)
SetBinding(modifierStr.."MOUSEWHEELUP", BINDING_NAME, bindingMode)
end
if scrollFrame:GetElement("setup.content.direction.check.down") then
SetBinding(modifierStr.."MOUSEWHEELDOWN", nil, bindingMode)
SetBinding(modifierStr.."MOUSEWHEELDOWN", BINDING_NAME, bindingMode)
end
if TSM.IsWowClassic() then
AttemptToSaveBindings(CHARACTER_BINDING_SET)
else
SaveBindings(CHARACTER_BINDING_SET)
end
button:SetText(GetMacroInfo(MACRO_NAME) and L["Update existing macro"] or L["Create macro"])
:Draw()
Log.PrintUser(L["Macro created and scroll wheel bound!"])
if #macroText > MAX_MACRO_LENGTH then
Log.PrintUser(L["WARNING: The macro was too long, so was truncated to fit by WoW."])
end
end

View File

@@ -0,0 +1,167 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Mailing = TSM.MainUI.Settings:NewPackage("Mailing")
local L = TSM.Include("Locale").GetTable()
local Sound = TSM.Include("Util.Sound")
local Math = TSM.Include("Util.Math")
local UIElements = TSM.Include("UI.UIElements")
local private = {
sounds = {},
soundkeys = {},
}
local ITEM_QUALITY_DESCS = { ITEM_QUALITY2_DESC, ITEM_QUALITY3_DESC, ITEM_QUALITY4_DESC }
local ITEM_QUALITY_KEYS = { 2, 3, 4 }
-- ============================================================================
-- Module Functions
-- ============================================================================
function Mailing.OnInitialize()
TSM.MainUI.Settings.RegisterSettingPage(L["Mailing"], "middle", private.GetMailingSettingsFrame)
for key, name in pairs(Sound.GetSounds()) do
tinsert(private.sounds, name)
tinsert(private.soundkeys, key)
end
end
-- ============================================================================
-- Mailing Settings UI
-- ============================================================================
function private.GetMailingSettingsFrame()
TSM.UI.AnalyticsRecordPathChange("main", "settings", "mailing")
return UIElements.New("ScrollFrame", "mailingSettings")
:SetPadding(8, 8, 8, 0)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Mailing", "inbox", L["Inbox Settings"], "")
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "inboxMessagesCheckbox")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Enable inbox chat messages"])
:SetSettingInfo(TSM.db.global.mailingOptions, "inboxMessages")
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("Text", "label")
:SetHeight(18)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Amount of bag space to keep free"])
)
:AddChild(UIElements.New("Frame", "freeSpaceFrame")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, 0, 8)
:AddChild(UIElements.New("Input", "keepMailInput")
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG")
:SetValidateFunc("NUMBER", "0:20")
:SetSettingInfo(TSM.db.global.mailingOptions, "keepMailSpace")
)
:AddChild(UIElements.New("Text", "label")
:SetSize("AUTO", 16)
:SetFont("BODY_BODY3")
:SetText(L["Min 0 - Max 20"])
)
)
:AddChild(UIElements.New("Text", "label")
:SetHeight(18)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Open mail complete sound"])
)
:AddChild(UIElements.New("SelectionDropdown", "soundDropdown")
:SetHeight(24)
:SetItems(private.sounds, private.soundkeys)
:SetSettingInfo(TSM.db.global.mailingOptions, "openMailSound")
:SetScript("OnSelectionChanged", private.SoundOnSelectionChanged)
)
)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Mailing", "send", L["Sending Settings"], "")
:AddChild(UIElements.New("Frame", "check1")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "sendMessagesCheckbox")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Enable sending chat messages"])
:SetSettingInfo(TSM.db.global.mailingOptions, "sendMessages")
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("Frame", "check2")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 22)
:AddChild(UIElements.New("Checkbox", "sendItemsCheckbox")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Send grouped items individually"])
:SetSettingInfo(TSM.db.global.mailingOptions, "sendItemsIndividually")
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("Text", "label")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Restart delay (minutes)"])
)
:AddChild(UIElements.New("Frame", "restartDelayFrame")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Input", "restartDelay")
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG")
:SetValidateFunc("NUMBER", "0.5:10")
:SetValue(TSM.db.global.mailingOptions.resendDelay)
:SetScript("OnValueChanged", private.RestartDelayOnValueChanged)
)
:AddChild(UIElements.New("Text", "label")
:SetSize("AUTO", 16)
:SetFont("BODY_BODY3")
:SetText(L["Min 0.5 - Max 10"])
)
)
:AddChild(UIElements.New("Text", "label")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Mail disenchantables max quality"])
)
:AddChild(UIElements.New("SelectionDropdown", "mailPageDropdown")
:SetHeight(26)
:SetItems(ITEM_QUALITY_DESCS, ITEM_QUALITY_KEYS)
:SetSettingInfo(TSM.db.global.mailingOptions, "deMaxQuality")
)
)
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.SoundOnSelectionChanged(self, selection)
Sound.PlaySound(TSM.db.global.mailingOptions.openMailSound)
end
function private.RestartDelayOnValueChanged(input)
local value = Math.Round(tonumber(input:GetValue()), 0.5)
TSM.db.global.mailingOptions.resendDelay = value
end

View File

@@ -0,0 +1,168 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Shopping = TSM.MainUI.Settings:NewPackage("Shopping")
local L = TSM.Include("Locale").GetTable()
local Sound = TSM.Include("Util.Sound")
local UIElements = TSM.Include("UI.UIElements")
local private = {
sounds = {},
soundkeys = {},
}
local MAX_ITEM_LEVEL = 500
-- ============================================================================
-- Module Functions
-- ============================================================================
function Shopping.OnInitialize()
TSM.MainUI.Settings.RegisterSettingPage(L["Browse / Sniper"], "middle", private.GetShoppingSettingsFrame)
for key, name in pairs(Sound.GetSounds()) do
tinsert(private.sounds, name)
tinsert(private.soundkeys, key)
end
end
-- ============================================================================
-- Shopping Settings UI
-- ============================================================================
function private.GetShoppingSettingsFrame()
TSM.UI.AnalyticsRecordPathChange("main", "settings", "shopping")
return UIElements.New("ScrollFrame", "shoppingSettings")
:SetPadding(8, 8, 8, 0)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Shopping", "general", L["General Options"], L["Some general Browse/Sniper options are below."])
:AddChild(UIElements.New("Frame", "focusFrame")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "checkbox")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Auto-focus browse search input"])
:SetSettingInfo(TSM.db.global.shoppingOptions, "searchAutoFocus")
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(TSM.MainUI.Settings.CreateInputWithReset("marketValueSourceField", L["Market value price source"], "global.shoppingOptions.pctSource")
:SetMargin(0, 0, 0, 12)
)
:AddChild(TSM.MainUI.Settings.CreateInputWithReset("buyoutConfirmationAlert", L["Buyout confirmation alert"], "global.shoppingOptions.buyoutAlertSource")
:SetMargin(0, 0, 0, 12)
)
:AddChild(UIElements.New("Frame", "showConfirmFrame")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Checkbox", "showConfirm")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetCheckboxPosition("LEFT")
:SetSettingInfo(TSM.db.global.shoppingOptions, "buyoutConfirm")
:SetText(L["Show confirmation alert if buyout is above the alert price"])
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Shopping", "disenchant", L["Disenchant Search Options"], L["Some options for the Disenchant Search are below."])
:AddChild(UIElements.New("Text", "minLevelLabel")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Minimum disenchant level"])
)
:AddChild(UIElements.New("Frame", "minLevelInput")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Input", "input")
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG")
:SetFont("BODY_BODY2_MEDIUM")
:SetValidateFunc("NUMBER", "0:"..MAX_ITEM_LEVEL)
:SetSettingInfo(TSM.db.global.shoppingOptions, "minDeSearchLvl")
)
:AddChild(UIElements.New("Text", "rangeText")
:SetWidth("AUTO")
:SetFont("BODY_BODY3")
:SetText(format(L["(minimum 0 - maximum %d)"], MAX_ITEM_LEVEL))
)
)
:AddChild(UIElements.New("Text", "maxLevelLabel")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Maximum disenchant level"])
)
:AddChild(UIElements.New("Frame", "maxLevelInput")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Input", "input")
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG")
:SetFont("BODY_BODY2_MEDIUM")
:SetValidateFunc("NUMBER", "0:"..MAX_ITEM_LEVEL)
:SetSettingInfo(TSM.db.global.shoppingOptions, "maxDeSearchLvl")
)
:AddChild(UIElements.New("Text", "rangeText")
:SetWidth("AUTO")
:SetFont("BODY_BODY3")
:SetText(format(L["(minimum 0 - maximum %d)"], MAX_ITEM_LEVEL))
)
)
:AddChild(UIElements.New("Text", "pctLabel")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Maximum disenchant search percent"])
)
:AddChild(UIElements.New("Frame", "pctInput")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("Input", "input")
:SetMargin(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG")
:SetFont("BODY_BODY2_MEDIUM")
:SetValidateFunc("NUMBER", "0:100")
:SetSettingInfo(TSM.db.global.shoppingOptions, "maxDeSearchPercent")
)
:AddChild(UIElements.New("Text", "rangeText")
:SetWidth("AUTO")
:SetFont("BODY_BODY3")
:SetText(format(L["(minimum 0 - maximum %d)"], 100))
)
)
)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Shopping", "sniper", L["Sniper Options"], L["Options specific to Sniper are below."])
:AddChild(UIElements.New("Text", "soundLabel")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Found auction sound"])
)
:AddChild(UIElements.New("SelectionDropdown", "soundDrodown")
:SetHeight(24)
:SetItems(private.sounds, private.soundkeys)
:SetSettingInfo(TSM.db.global.sniperOptions, "sniperSound")
:SetScript("OnSelectionChanged", private.SoundOnSelectionChanged)
)
)
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.SoundOnSelectionChanged(self)
Sound.PlaySound(self:GetSelectedItemKey())
end

View File

@@ -0,0 +1,395 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Tooltip = TSM.MainUI.Settings:NewPackage("Tooltip")
local L = TSM.Include("Locale").GetTable()
local Money = TSM.Include("Util.Money")
local Table = TSM.Include("Util.Table")
local TempTable = TSM.Include("Util.TempTable")
local CustomPrice = TSM.Include("Service.CustomPrice")
local UIElements = TSM.Include("UI.UIElements")
local private = {
operationModules = {},
operationModuleNames = {},
destroySources = {},
destroySourceKeys = {},
}
local INVALID_DESTROY_PRICE_SOURCES = {
crafting = true,
vendorbuy = true,
vendorsell = true,
destroy = true,
itemquality = true,
itemlevel = true,
requiredlevel = true,
numinventory = true,
numexpires = true,
salerate = true,
dbregionsalerate = true,
dbregionsoldperday = true,
auctioningopmin = true,
auctioningopmax = true,
auctioningopnormal = true,
shoppingopmax = true,
sniperopmax = true,
}
local GROUPS_OPS_SETTINGS_INFO = {
{ label = L["Group name"], settingKey = "groupNameTooltip" },
{ label = L["Auctioning operation"], settingTbl = "operationTooltips", settingKey = "Auctioning" },
{ label = L["Crafting operation"], settingTbl = "operationTooltips", settingKey = "Crafting" },
{ label = L["Mailing operation"], settingTbl = "operationTooltips", settingKey = "Mailing" },
{ label = L["Shopping operation"], settingTbl = "operationTooltips", settingKey = "Shopping" },
{ label = L["Sniper operation"], settingTbl = "operationTooltips", settingKey = "Sniper" },
{ label = L["Vendoring operation"], settingTbl = "operationTooltips", settingKey = "Vendoring" },
{ label = L["Warehousing operation"], settingTbl = "operationTooltips", settingKey = "Warehousing" },
}
local VALUES_SETTINGS_INFO = {
{ label = L["Disenchant value"], settingKey = "deTooltip" },
{ label = L["Mill value"], settingKey = "millTooltip" },
{ label = L["Prospect value"], settingKey = "prospectTooltip" },
{ label = L["Transform value"], settingKey = "transformTooltip" },
{ label = L["Detailed destroy information"], settingKey = "detailedDestroyTooltip" },
{ label = L["Vendor buy price"], settingKey = "vendorBuyTooltip" },
{ label = L["Vendor sell price"], settingKey = "vendorSellTooltip" },
}
local INVENTORY_SETTINGS_INFO = {
{ label = L["Full inventory"], settingKey = "inventoryTooltipFormat", setValue = "full", clearValue = "none" },
{ label = L["Simple inventory"], settingKey = "inventoryTooltipFormat", setValue = "simple", clearValue = "none" },
}
local ACCOUNTING_SETTINGS_INFO = {
{ label = L["Purchase information"], settingModule = "Accounting", settingKey = "purchase" },
{ label = L["Sale information"], settingModule = "Accounting", settingKey = "sale" },
{ label = L["Sale rate"], settingModule = "Accounting", settingKey = "saleRate" },
{ label = L["Expired information"], settingModule = "Accounting", settingKey = "expiredAuctions" },
{ label = L["Canceled information"], settingModule = "Accounting", settingKey = "cancelledAuctions" },
}
local AUCTIONDB_SETTINGS_INFO = {
{ label = L["Min buyout"], settingModule = "AuctionDB", settingKey = "minBuyout" },
{ label = L["Market value"], settingModule = "AuctionDB", settingKey = "marketValue" },
{ label = L["Historical price"], settingModule = "AuctionDB", settingKey = "historical" },
{ label = L["Region min buyout avg"], settingModule = "AuctionDB", settingKey = "regionMinBuyout" },
{ label = L["Region market value"], settingModule = "AuctionDB", settingKey = "regionMarketValue" },
{ label = L["Region historical price"], settingModule = "AuctionDB", settingKey = "regionHistorical" },
{ label = L["Region sale avg"], settingModule = "AuctionDB", settingKey = "regionSale" },
{ label = L["Region sale rate"], settingModule = "AuctionDB", settingKey = "regionSalePercent" },
{ label = L["Region avg daily sold"], settingModule = "AuctionDB", settingKey = "regionSoldPerDay" },
}
local AUCTIONING_SETTINGS_INFO = {
{ label = L["Post Quantity"], settingModule = "Auctioning", settingKey = "postQuantity" },
{ label = L["Min/Normal/Max price"], settingModule = "Auctioning", settingKey = "operationPrices" },
}
local CRAFTING_SETTINGS_INFO = {
{ label = L["Crafting cost"], settingModule = "Crafting", settingKey = "craftingCost" },
{ label = L["Detailed crafting cost"], settingModule = "Crafting", settingKey = "detailedMats" },
{ label = L["Mat cost"], settingModule = "Crafting", settingKey = "matPrice" },
}
local SHOPPING_SETTINGS_INFO = {
{ label = L["Max shopping price"], settingModule = "Shopping", settingKey = "maxPrice" },
}
local SNIPER_SETTINGS_INFO = {
{ label = L["Max sniper price"], settingModule = "Sniper", settingKey = "belowPrice" },
}
-- ============================================================================
-- Module Functions
-- ============================================================================
function Tooltip.OnInitialize()
TSM.MainUI.Settings.RegisterSettingPage(L["Tooltip Settings"], "top", private.GetTooltipSettingsFrame)
end
-- ============================================================================
-- Tooltip Settings UI
-- ============================================================================
function private.GetTooltipSettingsFrame()
TSM.UI.AnalyticsRecordPathChange("main", "settings", "tooltips", "main")
wipe(private.operationModules)
wipe(private.operationModuleNames)
for _, moduleName in TSM.Operations.ModuleIterator() do
tinsert(private.operationModules, moduleName)
tinsert(private.operationModuleNames, TSM.Operations.GetLocalizedName(moduleName))
end
wipe(private.destroySources)
wipe(private.destroySourceKeys)
local foundCurrentSetting = false
for key, _, label in CustomPrice.Iterator() do
key = strlower(key)
if not INVALID_DESTROY_PRICE_SOURCES[key] then
tinsert(private.destroySources, label)
tinsert(private.destroySourceKeys, key)
if TSM.db.global.coreOptions.destroyValueSource == key then
foundCurrentSetting = true
end
end
end
if not foundCurrentSetting then
-- the current setting isn't in the list, so reset it to the default
TSM.db.global.coreOptions.destroyValueSource = strlower(TSM.db:GetDefaultReadOnly("global", "coreOptions", "destroyValueSource"))
end
return UIElements.New("ScrollFrame", "tooltipSettings")
:SetPadding(8, 8, 8, 0)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Tooltip", "general", L["General Options"], L["Some general options for the TSM tooltip information are below."])
:AddChild(UIElements.New("Text", "label")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Enable TSM tooltips"])
)
:AddChild(UIElements.New("ToggleOnOff", "enableToggle")
:SetHeight(24)
:SetMargin(0, 0, 0, 12)
:SetSettingInfo(TSM.db.global.tooltipOptions, "enabled")
)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "embedCheckbox")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Embed TSM tooltip"])
:SetSettingInfo(TSM.db.global.tooltipOptions, "embeddedTooltip")
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("Frame", "labelRow1")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 4)
:AddChild(UIElements.New("Text", "priceFormatLabel")
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Tooltip price format"])
)
:AddChild(UIElements.New("Text", "modifierLabel")
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Show on modifier"])
)
:AddChild(UIElements.New("Text", "destroyLabel")
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Destroy value source"])
)
)
:AddChild(UIElements.New("Frame", "dropdownRow1")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:AddChild(UIElements.New("SelectionDropdown", "priceFormatDropdown")
:SetMargin(0, 8, 0, 0)
:AddItem(format(L["Coins (%s)"], Money.ToString(3451267, nil, "OPT_ICON")), "icon")
:AddItem(format(L["Text (%s)"], Money.ToString(3451267)), "text")
:SetSettingInfo(TSM.db.global.tooltipOptions, "tooltipPriceFormat")
:SetScript("OnSelectionChanged", private.OnSettingChange)
)
:AddChild(UIElements.New("SelectionDropdown", "modifierDropdown")
:SetMargin(0, 8, 0, 0)
:AddItem(L["None (Always Show)"], "none")
:AddItem(ALT_KEY, "alt")
:AddItem(CTRL_KEY, "ctrl")
:SetSettingInfo(TSM.db.global.tooltipOptions, "tooltipShowModifier")
)
:AddChild(UIElements.New("SelectionDropdown", "dropdown")
:SetItems(private.destroySources, private.destroySourceKeys)
:SetSettingInfo(TSM.db.global.coreOptions, "destroyValueSource")
:SetScript("OnSelectionChanged", private.OnSettingChange)
)
)
)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Tooltip", "options", L["Tooltip Options"], L["Use the settings below to control which lines are shown in tooltips."])
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(private.GetSettingsHeight())
:AddChild(UIElements.New("Frame", "settings")
:SetLayout("VERTICAL")
:SetMargin(0, 8, 0, -12)
:AddChildrenWithFunction(private.AddTooltipSettings)
)
:AddChild(UIElements.New("Frame", "example")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Text", "label")
:SetHeight(20)
:SetMargin(0, 0, 0, 6)
:SetFont("BODY_BODY2_BOLD")
:SetText(L["Example Tooltip"])
)
:AddChild(UIElements.New("Frame", "tooltip")
:SetLayout("VERTICAL")
:SetPadding(4)
:SetBackgroundColor("PRIMARY_BG")
:AddChildrenWithFunction(private.AddExampleTooltip)
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
)
)
end
function private.GetSettingsHeight()
-- calculate the height of the settings and use that for the content height since the settings will always be larger than the tooltip
local height = 0
height = height + 32 + #GROUPS_OPS_SETTINGS_INFO * 32
height = height + 32 + #VALUES_SETTINGS_INFO * 32 + Table.Count(TSM.db.global.userData.customPriceSources) * 32
height = height + 32 + #INVENTORY_SETTINGS_INFO * 32
height = height + 32 + #ACCOUNTING_SETTINGS_INFO * 32
height = height + 32 + #AUCTIONDB_SETTINGS_INFO * 32
height = height + 32 + #AUCTIONING_SETTINGS_INFO * 32
height = height + 32 + #CRAFTING_SETTINGS_INFO * 32
height = height + 32 + #SHOPPING_SETTINGS_INFO * 32
height = height + 32 + #SNIPER_SETTINGS_INFO * 32
height = height - 12
return height
end
function private.AddTooltipSettings(frame)
private.AddSettingHeading(frame, "groupsOpsHeading", L["Groups & Operations"])
private.AddSettingsFromInfoTable(frame, GROUPS_OPS_SETTINGS_INFO)
private.AddSettingHeading(frame, "valuesHeading", L["Values"])
private.AddSettingsFromInfoTable(frame, VALUES_SETTINGS_INFO)
local customPriceSources = TempTable.Acquire()
for name in pairs(TSM.db.global.userData.customPriceSources) do
tinsert(customPriceSources, name)
end
sort(customPriceSources)
for _, name in ipairs(customPriceSources) do
frame:AddChild(UIElements.New("Checkbox", "checkbox_"..name)
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:SetFont("BODY_BODY2")
:SetCheckboxPosition("LEFT")
:SetText(format(L["Custom source (%s)"], name))
:SetSettingInfo(TSM.db.global.tooltipOptions.customPriceTooltips, name)
:SetScript("OnValueChanged", private.CustomPriceSourceOnValueChanged)
)
end
TempTable.Release(customPriceSources)
private.AddSettingHeading(frame, "inventoryHeading", L["Inventory"])
private.AddSettingsFromInfoTable(frame, INVENTORY_SETTINGS_INFO)
private.AddSettingHeading(frame, "accountingHeading", L["Accounting"])
private.AddSettingsFromInfoTable(frame, ACCOUNTING_SETTINGS_INFO)
private.AddSettingHeading(frame, "auctiondbHeading", L["AuctionDB"])
private.AddSettingsFromInfoTable(frame, AUCTIONDB_SETTINGS_INFO)
private.AddSettingHeading(frame, "auctioningHeading", L["Auctioning"])
private.AddSettingsFromInfoTable(frame, AUCTIONING_SETTINGS_INFO)
private.AddSettingHeading(frame, "craftingHeading", L["Crafting"])
private.AddSettingsFromInfoTable(frame, CRAFTING_SETTINGS_INFO)
private.AddSettingHeading(frame, "shoppingHeading", L["Shopping"])
private.AddSettingsFromInfoTable(frame, SHOPPING_SETTINGS_INFO)
private.AddSettingHeading(frame, "sniperHeading", L["Sniper"])
private.AddSettingsFromInfoTable(frame, SNIPER_SETTINGS_INFO)
end
function private.AddSettingHeading(frame, id, heading)
frame:AddChild(UIElements.New("Text", id)
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:SetFont("BODY_BODY2_BOLD")
:SetText(heading)
)
end
function private.GetSettingTableFromInfo(info)
local settingTbl = TSM.db.global.tooltipOptions
if info.settingModule then
settingTbl = settingTbl.moduleTooltips[info.settingModule]
end
if info.settingTbl then
settingTbl = settingTbl[info.settingTbl]
end
return settingTbl
end
function private.AddSettingsFromInfoTable(frame, infoTbl)
for i, info in ipairs(infoTbl) do
local settingTbl = private.GetSettingTableFromInfo(info)
frame:AddChild(UIElements.New("Checkbox", "checkbox_"..i)
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:SetFont("BODY_BODY2")
:SetCheckboxPosition("LEFT")
:SetContext(info)
:SetText(info.label)
:SetChecked(settingTbl[info.settingKey] == (info.setValue or true))
:SetScript("OnValueChanged", private.ContentCheckboxOnValueChanged)
)
end
end
function private.AddExampleTooltip(frame)
for i, left, right, lineColor in TSM.Tooltip.SettingsLineIterator() do
frame:AddChild(UIElements.New("Frame", "row_"..i)
:SetLayout("HORIZONTAL")
:SetHeight(20)
:AddChild(UIElements.New("Text", "left_"..i)
:SetWidth("AUTO")
:SetFont("ITEM_BODY3")
:SetTextColor(lineColor)
:SetText(left)
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChildIf(right, UIElements.New("Text", "right_"..i)
:SetWidth("AUTO")
:SetFont("ITEM_BODY3")
:SetTextColor(lineColor)
:SetJustifyH("RIGHT")
:SetText(right or "")
)
)
end
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.OnSettingChange(checkbox)
private.RebuildExampleTooltip(checkbox:GetElement("__parent.__parent.__parent.__parent.options.content.content.example.tooltip"))
end
function private.ContentCheckboxOnValueChanged(checkbox)
local info = checkbox:GetContext()
local settingTbl = private.GetSettingTableFromInfo(info)
if checkbox:IsChecked() then
settingTbl[info.settingKey] = info.setValue or true
else
settingTbl[info.settingKey] = info.clearValue or false
end
local frame = checkbox:GetParentElement()
for _, child in frame:LayoutChildrenIterator() do
local childContext = child:GetContext()
if child ~= checkbox and childContext and childContext.settingTbl == info.settingTbl and childContext.settingKey == info.settingKey then
child:SetChecked(settingTbl[childContext.settingKey] == (childContext.setValue or true), true)
:Draw()
end
end
private.RebuildExampleTooltip(checkbox:GetElement("__parent.__parent.example.tooltip"))
end
function private.CustomPriceSourceOnValueChanged(checkbox)
private.RebuildExampleTooltip(checkbox:GetElement("__parent.__parent.example.tooltip"))
end
function private.RebuildExampleTooltip(tooltipFrame)
tooltipFrame:ReleaseAllChildren()
tooltipFrame:AddChildrenWithFunction(private.AddExampleTooltip)
tooltipFrame:Draw()
end

View File

@@ -0,0 +1,83 @@
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Vendoring = TSM.MainUI.Settings:NewPackage("Vendoring")
local L = TSM.Include("Locale").GetTable()
local ItemInfo = TSM.Include("Service.ItemInfo")
local UIElements = TSM.Include("UI.UIElements")
local private = {}
-- ============================================================================
-- Module Functions
-- ============================================================================
function Vendoring.OnInitialize()
TSM.MainUI.Settings.RegisterSettingPage(L["Vendoring"], "middle", private.GetVendoringSettingsFrame)
end
-- ============================================================================
-- Vendoring Settings UI
-- ============================================================================
function private.GetVendoringSettingsFrame()
TSM.UI.AnalyticsRecordPathChange("main", "settings", "vendoring")
return UIElements.New("ScrollFrame", "vendoringSettings")
:SetPadding(8, 8, 8, 0)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Vendoring", "general", L["General Options"], "")
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "checkbox")
:SetWidth("AUTO")
:SetFont("BODY_BODY2_MEDIUM")
:SetSettingInfo(TSM.db.global.vendoringOptions, "displayMoneyCollected")
:SetText(L["Display total money received in chat"])
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(TSM.MainUI.Settings.CreateInputWithReset("qsMarketValueSourceField", L["Market Value Price Source"], "global.vendoringOptions.qsMarketValue"))
)
:AddChild(TSM.MainUI.Settings.CreateExpandableSection("Vendoring", "ignore", L["Ignored Items"], "Use this list to manage what items you'd like TSM to ignore from vendoring.")
:AddChild(UIElements.New("QueryScrollingTable", "items")
:SetHeight(326)
:GetScrollingTableInfo()
:NewColumn("item")
:SetTitle(L["Item"])
:SetFont("ITEM_BODY3")
:SetJustifyH("LEFT")
:SetIconSize(12)
:SetTextInfo("itemString", TSM.UI.GetColoredItemName)
:SetIconInfo("itemString", ItemInfo.GetTexture)
:SetTooltipInfo("itemString")
:SetSortInfo("name")
:DisableHiding()
:Commit()
:Commit()
:SetQuery(TSM.Vendoring.Sell.CreateIgnoreQuery())
:SetAutoReleaseQuery(true)
:SetSelectionDisabled(true)
:SetScript("OnRowClick", private.IgnoredItemsOnRowClick)
)
)
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.IgnoredItemsOnRowClick(_, row, mouseButton)
if mouseButton ~= "LeftButton" then
return
end
TSM.Vendoring.Sell.ForgetIgnoreItemPermanent(row:GetField("itemString"))
end