TradeSkillMaster/Core/UI/MainUI/Groups.lua

1871 lines
67 KiB
Lua
Raw Normal View History

2020-11-13 14:13:12 -05:00
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local _, TSM = ...
local Groups = TSM.MainUI:NewPackage("Groups")
local L = TSM.Include("Locale").GetTable()
local Analytics = TSM.Include("Util.Analytics")
local TempTable = TSM.Include("Util.TempTable")
local Table = TSM.Include("Util.Table")
local String = TSM.Include("Util.String")
local Log = TSM.Include("Util.Log")
local Theme = TSM.Include("Util.Theme")
local ItemString = TSM.Include("Util.ItemString")
local Database = TSM.Include("Util.Database")
local ItemInfo = TSM.Include("Service.ItemInfo")
local ItemFilter = TSM.Include("Service.ItemFilter")
local CustomPrice = TSM.Include("Service.CustomPrice")
local BagTracking = TSM.Include("Service.BagTracking")
local Settings = TSM.Include("Service.Settings")
local UIElements = TSM.Include("UI.UIElements")
local private = {
settings = nil,
currentGroupPath = TSM.CONST.ROOT_GROUP_PATH,
moveGroupPath = nil,
itemFilter = ItemFilter.New(),
groupedItemList = {},
ungroupedItemList = { {}, {} },
moduleCollapsed = {},
results = { {}, {} },
resultsRaw = {},
filterText = "",
groupSearch = "",
itemSearch = "",
frame = nil,
operationQuery = nil,
importExportGroupDB = nil,
exportSubGroups = {},
importGroupTreeContext = {},
}
local DRAG_SCROLL_SPEED_FACTOR = 12
local OPERATION_LABELS = {
Auctioning = L["Auctioning operations control posting to and canceling from the AH."],
Crafting = L["Crafting operations control how queuing profession crafts."],
Mailing = L["Mailing operations control mailing to other characters."],
Shopping = L["Shopping operations control buyout from the AH."],
Sniper = L["Sniper operations control sniping from the AH."],
Vendoring = L["Vendoring operations control selling to and buying from a vendor."],
Warehousing = L["Warehousing operations control moving in and out of the bank."],
}
local DEFAULT_IMPORT_GROUP_TREE_CONTEXT = { unselected = {}, collapsed = {} }
-- ============================================================================
-- Module Functions
-- ============================================================================
function Groups.OnInitialize()
private.settings = Settings.NewView()
:AddKey("global", "coreOptions", "groupPriceSource")
:AddKey("global", "mainUIContext", "groupsDividedContainer")
:AddKey("char", "mainUIContext", "groupsManagementGroupTree")
:AddKey("profile", "userData", "groups")
TSM.MainUI.RegisterTopLevelPage(L["Groups"], private.GetGroupsFrame)
private.itemFilter:ParseStr("")
private.importExportGroupDB = Database.NewSchema("IMPORT_EXPORT_GROUPS")
:AddStringField("groupPath")
:AddStringField("orderStr")
:AddIndex("groupPath")
:Commit()
end
function Groups.ShowGroupSettings(baseFrame, groupPath)
baseFrame:SetSelectedNavButton(L["Groups"], true)
baseFrame:GetElement("content.groups.groupSelection.groupTree"):SetSelectedGroup(groupPath, true)
end
-- ============================================================================
-- Groups UI
-- ============================================================================
function private.GetGroupsFrame()
TSM.UI.AnalyticsRecordPathChange("main", "groups")
private.currentGroupPath = TSM.CONST.ROOT_GROUP_PATH
private.moveGroupPath = nil
local frame = UIElements.New("DividedContainer", "groups")
:SetSettingsContext(private.settings, "groupsDividedContainer")
:SetMinWidth(250, 250)
:SetLeftChild(UIElements.New("Frame", "groupSelection")
:SetLayout("VERTICAL")
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Frame", "search")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8)
:AddChild(UIElements.New("Input", "input")
:SetIconTexture("iconPack.18x18/Search")
:SetClearButtonEnabled(true)
:AllowItemInsert(true)
:SetValue(private.groupSearch)
:SetHintText(L["Search Groups"])
:SetScript("OnValueChanged", private.GroupSearchOnValueChanged)
)
:AddChild(UIElements.New("Button", "expandAllBtn")
:SetSize(24, 24)
:SetMargin(8, 0, 0, 0)
:SetBackground("iconPack.18x18/Expand All")
:SetScript("OnClick", private.ExpandAllGroupsOnClick)
:SetTooltip(L["Expand / Collapse All Groups"])
)
:AddChild(UIElements.New("Button", "expandAllBtn")
:SetSize(24, 24)
:SetMargin(8, 0, 0, 0)
:SetBackground("iconPack.18x18/Import")
:SetScript("OnClick", private.ImportGroupBtnOnClick)
:SetTooltip(L["Import group"])
)
)
:AddChild(UIElements.New("Texture", "line")
:SetHeight(2)
:SetTexture("ACTIVE_BG_ALT")
)
:AddChild(UIElements.New("ManagementGroupTree", "groupTree")
:SetSettingsContext(private.settings, "groupsManagementGroupTree")
:SetQuery(TSM.Groups.CreateQuery())
:SetSelectedGroup(private.currentGroupPath)
:SetSearchString(private.groupSearch)
:SetScript("OnGroupSelected", private.GroupTreeOnGroupSelected)
:SetScript("OnNewGroup", private.GroupTreeOnNewGroup)
)
)
:SetRightChild(UIElements.New("ViewContainer", "view")
:SetNavCallback(private.GetViewContainerContent)
:AddPath("content", true)
:AddPath("search")
)
frame:GetElement("view.content.header.title.renameBtn"):Hide()
private.frame = frame
return frame
end
function private.GetViewContainerContent(viewContainer, path)
if path == "content" then
wipe(private.results[1])
wipe(private.results[2])
return private.GetContentFrame()
elseif path == "search" then
return private.GetSearchFrame()
else
error("Unexpected path: "..tostring(path))
end
end
function private.GetContentFrame()
local frame = UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Frame", "header")
:SetLayout("VERTICAL")
:SetSize("EXPAND", 40)
:SetPadding(8)
:AddChild(UIElements.New("Frame", "title")
:SetLayout("HORIZONTAL")
:SetWidth("EXPAND")
:AddChild(UIElements.New("Texture", "icon")
:SetMargin(0, 8, 0, 0)
:SetTextureAndSize(TSM.UI.TexturePacks.GetColoredKey("iconPack.18x18/Folder", "TEXT"))
)
:AddChild(UIElements.New("EditableText", "text")
:SetWidth("AUTO")
:AllowItemInsert(true)
:SetFont("BODY_BODY1_BOLD")
:SetText(L["Base Group"])
:SetScript("OnValueChanged", private.GroupNameChanged)
:SetScript("OnEditingChanged", private.NameOnEditingChanged)
)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Button", "renameBtn")
:SetMargin(8, 0, 0, 0)
:SetBackgroundAndSize("iconPack.18x18/Edit")
:SetScript("OnClick", private.RenameBtnOnClick)
:SetTooltip(L["Rename this group"])
)
:AddChild(UIElements.New("Button", "exportBtn")
:SetMargin(8, 4, 0, 0)
:SetBackgroundAndSize("iconPack.18x18/Export")
:SetScript("OnClick", private.ExportBtnOnClick)
:SetTooltip(L["Export this group"])
)
)
)
:AddChild(UIElements.New("TabGroup", "buttons")
:SetMargin(0, 0, 6, 0)
:SetNavCallback(private.GetGroupsPage)
:AddPath(L["Information"], true)
:AddPath(L["Operations"])
)
frame:GetElement("header.title.renameBtn"):Hide()
frame:GetElement("header.title.exportBtn"):Hide()
return frame
end
function private.GetSearchFrame()
return UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Frame", "header")
:SetLayout("HORIZONTAL")
:SetHeight(40)
:SetPadding(8)
:AddChild(UIElements.New("ActionButton", "button")
:SetWidth(64)
:SetMargin(0, 8, 0, 0)
:SetIcon("iconPack.14x14/Chevron/Right@180")
:SetText(BACK)
:SetScript("OnClick", private.SearchBackButtonOnClick)
)
:AddChild(UIElements.New("Input", "input")
:SetMargin(0, 8, 0, 0)
:SetIconTexture("iconPack.18x18/Search")
:AllowItemInsert()
:SetClearButtonEnabled(true)
:SetValidateFunc(private.ValidateBaseSearchValue)
:SetValue(private.itemSearch)
:SetScript("OnValueChanged", private.BaseSearchOnValueChanged)
)
:AddChild(UIElements.New("Button", "selectAllBtn")
:SetSize(24, 24)
:SetBackground("iconPack.18x18/Select All")
:SetScript("OnClick", private.SelectAllResultsOnClick)
:SetTooltip(L["Select / Deselect All Results"])
)
)
:AddChild(UIElements.New("Frame", "header2")
:SetLayout("HORIZONTAL")
:SetHeight(30)
:SetPadding(8, 8, 5, 5)
:AddChild(UIElements.New("Text", "label")
:SetFont("BODY_BODY3")
:SetText(format(L["%d Results"], 0))
)
:AddChild(UIElements.New("Checkbox", "ignoreItemVariations")
:SetSize("AUTO", 24)
:SetFont("BODY_BODY1")
:SetCheckboxPosition("LEFT")
:SetText(L["Ignore variations"])
:SetSettingInfo(private.settings.groups[private.currentGroupPath], "ignoreItemVariations")
:SetScript("OnValueChanged", private.IgnoreSearchRandomOnValueChanged)
)
)
:AddChild(UIElements.New("Texture", "line")
:SetHeight(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("ItemList", "itemList")
:SetScript("OnSelectionChanged", private.ItemListOnSelectionChanged)
)
:AddChild(UIElements.New("Texture", "line")
:SetHeight(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Frame", "bottom")
:SetLayout("HORIZONTAL")
:SetHeight(40)
:SetPadding(8)
:SetBackgroundColor("PRIMARY_BG_ALT")
:AddChild(UIElements.New("GroupSelector", "group")
:SetMargin(0, 8, 0, 0)
:SetHintText(L["Select Group"])
:SetSingleSelection(true)
:AddCreateNew()
:SetSelection(TSM.Groups.Exists(private.moveGroupPath) and private.moveGroupPath)
:SetScript("OnSelectionChanged", private.BaseGroupOnSelectionChanged)
)
:AddChild(UIElements.New("ActionButton", "move")
:SetWidth(124)
:SetDisabled(true)
:SetText(L["Move Item"])
:SetScript("OnClick", private.BaseMoveItemOnClick)
)
)
end
function private.GetGroupsPage(_, button)
private.itemSearch = ""
private.itemFilter:ParseStr("")
if button == L["Information"] then
TSM.UI.AnalyticsRecordPathChange("main", "groups", "information")
return UIElements.New("Frame", "items")
:SetLayout("VERTICAL")
:SetPadding(0, 0, 9, 0)
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Text", "text")
:SetHeight(42)
:SetMargin(8, 8, 0, 8)
:SetFont("BODY_BODY3")
:SetText(L["The Base Group contains all ungrouped items in the game. Use the search and filter controls to find items to add to other groups."])
)
:AddChild(UIElements.New("Frame", "filter")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8, 8, 0, 8)
:AddChild(UIElements.New("Input", "filter")
:SetMargin(0, 12, 0, 0)
:SetIconTexture("iconPack.18x18/Search")
:AllowItemInsert()
:SetClearButtonEnabled(true)
:SetValidateFunc(private.ValidateBaseSearchValue)
:SetHintText(L["Search items"])
:SetScript("OnValueChanged", private.InformationSearchOnValueChanged)
)
:AddChild(UIElements.New("Checkbox", "ignoreItemVariations")
:SetSize("AUTO", 24)
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY1")
:SetCheckboxPosition("LEFT")
:SetText(L["Ignore variations"])
:SetSettingInfo(private.settings.groups[private.currentGroupPath], "ignoreItemVariations")
:SetScript("OnValueChanged", private.IgnoreBaseRandomOnValueChanged)
)
)
:AddChild(UIElements.New("ItemList", "itemList")
:SetItems(private.GetUngroupedBagItemList())
:SetFilterFunction(private.ItemListItemIsFiltered)
:SetScript("OnSelectionChanged", private.ItemListOnSelectionChanged)
)
:AddChild(UIElements.New("Texture", "line")
:SetHeight(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Frame", "bottom")
:SetLayout("HORIZONTAL")
:SetHeight(40)
:SetPadding(8)
:SetBackgroundColor("PRIMARY_BG_ALT")
:AddChild(UIElements.New("GroupSelector", "group")
:SetMargin(0, 8, 0, 0)
:SetHintText(L["Select Group"])
:SetSingleSelection(true)
:AddCreateNew()
:SetSelection(TSM.Groups.Exists(private.moveGroupPath) and private.moveGroupPath)
:SetScript("OnSelectionChanged", private.GroupOnSelectionChanged)
)
:AddChild(UIElements.New("ActionButton", "move")
:SetWidth(124)
:SetDisabled(true)
:SetText(L["Move Item"])
:SetScript("OnClick", private.MoveItemOnClick)
)
)
elseif button == L["Items"] then
TSM.UI.AnalyticsRecordPathChange("main", "groups", "items")
assert(private.currentGroupPath ~= TSM.CONST.ROOT_GROUP_PATH)
local parentGroup = TSM.Groups.Path.GetParent(private.currentGroupPath)
parentGroup = parentGroup ~= TSM.CONST.ROOT_GROUP_PATH and parentGroup or nil
return UIElements.New("Frame", "items")
:SetLayout("VERTICAL")
:SetPadding(8)
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Frame", "filter")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, 0, 8)
:AddChild(UIElements.New("Input", "filter")
:SetMargin(0, 12, 0, 0)
:SetIconTexture("iconPack.18x18/Search")
:SetClearButtonEnabled(true)
:SetValidateFunc(private.ItemFilterValidateFunc)
:SetHintText(L["Search items in group"])
:SetScript("OnValueChanged", private.ItemFilterOnValueChanged)
)
:AddChild(UIElements.New("Checkbox", "ignoreItemVariations")
:SetSize("AUTO", 24)
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY1")
:SetCheckboxPosition("LEFT")
:SetText(L["Ignore variations"])
:SetSettingInfo(private.settings.groups[private.currentGroupPath], "ignoreItemVariations")
:SetScript("OnValueChanged", private.IgnoreRandomOnValueChanged)
)
)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("HORIZONTAL")
:AddChild(UIElements.New("Frame", "ungrouped")
:SetLayout("VERTICAL")
:SetMargin(0, 8, 0, 0)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
:SetBackgroundColor("PRIMARY_BG_ALT", true)
:AddChild(UIElements.New("Frame", "header")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetBackgroundColor("FRAME_BG", true)
:AddChild(UIElements.New("Text", "text")
:SetMargin(8, 0, 4, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Ungrouped Items"])
)
:AddChild(UIElements.New("Button", "selectAllBtn")
:SetSize(20, 20)
:SetMargin(8, 4, 0, 0)
:SetBackground("iconPack.18x18/Select All")
:SetScript("OnClick", private.ItemListSelectAllOnClick)
:SetTooltip(L["Select / Deselect All Items"])
)
)
-- draw a line along the bottom to hide the rounded corners at the bottom of the header frame
:AddChildNoLayout(UIElements.New("Texture", "line")
:AddAnchor("BOTTOMLEFT", "header")
:AddAnchor("BOTTOMRIGHT", "header")
:SetHeight(4)
:SetTexture("FRAME_BG")
)
:AddChild(UIElements.New("ItemList", "itemList")
:SetMargin(0, 0, 0, 7)
:SetBackgroundColor("PRIMARY_BG_ALT")
:SetItems(private.GetUngroupedItemList())
:SetFilterFunction(private.ItemListItemIsFiltered)
:SetScript("OnSelectionChanged", private.UngroupedItemsOnSelectionChanged)
)
)
:AddChild(UIElements.New("ActionButton", "btn")
:SetHeight(26)
:SetMargin(0, 0, 10, 0)
:SetText(L["Add"])
:SetDisabled(true)
:SetScript("OnClick", private.AddItemsOnClick)
)
)
:AddChild(UIElements.New("Frame", "grouped")
:SetLayout("VERTICAL")
:AddChild(UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
:SetBackgroundColor("PRIMARY_BG_ALT", true)
:AddChild(UIElements.New("Frame", "header")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetBackgroundColor("FRAME_BG", true)
:AddChild(UIElements.New("Text", "text")
:SetMargin(8, 0, 4, 4)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Grouped Items"])
)
:AddChild(UIElements.New("Button", "selectAllBtn")
:SetSize(20, 20)
:SetMargin(8, 4, 0, 0)
:SetBackground("iconPack.18x18/Select All")
:SetScript("OnClick", private.ItemListSelectAllOnClick)
:SetTooltip(L["Select / Deselect All Items"])
)
)
-- draw a line along the bottom to hide the rounded corners at the bottom of the header frame
:AddChildNoLayout(UIElements.New("Texture", "line")
:AddAnchor("BOTTOMLEFT", "header")
:AddAnchor("BOTTOMRIGHT", "header")
:SetHeight(4)
:SetTexture("FRAME_BG")
)
:AddChild(UIElements.New("ItemList", "itemList")
:SetMargin(0, 0, 0, 7)
:SetBackgroundColor("PRIMARY_BG_ALT")
:SetItems(private.GetGroupedItemList())
:SetFilterFunction(private.ItemListItemIsFiltered)
:SetScript("OnSelectionChanged", private.GroupedItemsOnSelectionChanged)
)
)
:AddChildIf(parentGroup, UIElements.New("ActionButton", "btn")
:SetHeight(26)
:SetMargin(0, 0, 10, 0)
:SetText(L["Remove"])
:SetDisabled(true)
:SetModifierText(L["Move to Parent Group"], "SHIFT")
:SetScript("OnClick", private.RemoveItemsOnClick)
:SetTooltip(L["Hold shift to move the items to the parent group instead of removing them."])
)
:AddChildIf(not parentGroup, UIElements.New("ActionButton", "btn")
:SetHeight(26)
:SetMargin(0, 0, 10, 0)
:SetText(L["Remove"])
:SetDisabled(true)
:SetScript("OnClick", private.RemoveItemsOnClick)
)
)
)
elseif button == L["Operations"] then
TSM.UI.AnalyticsRecordPathChange("main", "groups", "operations")
return UIElements.New("ScrollFrame", "operations")
:SetPadding(8)
:SetBackgroundColor("PRIMARY_BG")
:AddChild(private.GetModuleOperationFrame("Auctioning"))
:AddChild(private.GetModuleOperationFrame("Crafting"))
:AddChild(private.GetModuleOperationFrame("Mailing"))
:AddChild(private.GetModuleOperationFrame("Shopping"))
:AddChild(private.GetModuleOperationFrame("Sniper"))
:AddChild(private.GetModuleOperationFrame("Vendoring"))
:AddChild(private.GetModuleOperationFrame("Warehousing"))
else
error("Unknown button!")
end
end
function private.GetModuleOperationFrame(moduleName)
local override = TSM.Groups.HasOperationOverride(private.currentGroupPath, moduleName) or private.currentGroupPath == TSM.CONST.ROOT_GROUP_PATH
local numGroupOperations = 0
for _ in TSM.Groups.OperationIterator(private.currentGroupPath, moduleName) do
numGroupOperations = numGroupOperations + 1
end
return UIElements.New("CollapsibleContainer", "operationInfo"..moduleName)
:SetLayout("VERTICAL")
:SetMargin(0, 0, 0, moduleName == "Warehousing" and 0 or 8)
:SetContext(moduleName)
:SetContextTable(private.moduleCollapsed, moduleName)
:SetHeadingText(format(L["%s Operations"], moduleName))
:AddChild(UIElements.New("Text", "moduleDesc")
:SetSize("AUTO", 20)
:SetFont("BODY_BODY3")
:SetText(OPERATION_LABELS[moduleName])
)
:AddChildIf(private.currentGroupPath ~= TSM.CONST.ROOT_GROUP_PATH, UIElements.New("Checkbox", "overrideCheckbox")
:SetHeight(20)
:SetMargin(0, 0, 6, 0)
:SetFont("BODY_BODY2")
:SetCheckboxPosition("LEFT")
:SetText(L["Override Parent Operations"])
:SetChecked(override)
:SetScript("OnValueChanged", private.OverrideToggleOnValueChanged)
)
:AddChild(UIElements.New("Frame", "container")
:SetLayout("VERTICAL")
:SetContext(moduleName)
:SetHeight(36 * numGroupOperations)
:AddChildrenWithFunction(private.AddOperationRows)
)
:AddChildIf(override and numGroupOperations < TSM.Operations.GetMaxNumber(moduleName), UIElements.New("Frame", "addMore")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, 8, 0)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Button", "button")
:SetWidth("AUTO")
:SetMargin(0, 2, 0, 0)
:SetFont("BODY_BODY2")
:SetTextColor("INDICATOR")
:SetText(L["Add More Operations"])
:SetContext(moduleName)
:SetScript("OnClick", private.AddOperationButtonOnClick)
)
)
end
function private.AddOperationRows(container)
local moduleName = container:GetContext()
local override = TSM.Groups.HasOperationOverride(private.currentGroupPath, moduleName) or private.currentGroupPath == TSM.CONST.ROOT_GROUP_PATH
for i, operationName in TSM.Groups.OperationIterator(private.currentGroupPath, moduleName) do
container:AddChild(UIElements.New("Frame", "operation"..i)
:SetLayout("HORIZONTAL")
:SetHeight(28)
:SetMargin(0, 0, 8, 0)
:SetBackgroundColor("PRIMARY_BG_ALT")
:AddChild(UIElements.New("Text", "operationNum")
:SetWidth(20)
:SetMargin(2, 8, 0, 0)
:SetFont("BODY_BODY1_BOLD")
:SetText(i)
)
:AddChild(UIElements.New("Frame", "title")
:SetLayout("HORIZONTAL")
:SetPadding(0, 8, 0, 0)
:SetBackgroundColor("ACTIVE_BG", true)
:AddChildNoLayout(UIElements.New("Button", "dragFrame")
:SetSize(15, 24)
:AddAnchor("LEFT", 1, 0)
:SetContext(i)
:SetScript("OnMouseDown", override and private.DragButtonOnMouseDown or nil)
:SetScript("OnMouseUp", override and private.DragButtonOnMouseUp or nil)
)
:AddChild(UIElements.New("Frame", "handleBackground")
:SetSize(16, 28)
:SetBackgroundColor("FRAME_BG", true)
-- draw a line along the right to hide the rounded corners at the bottom of the header frame
:AddChildNoLayout(UIElements.New("Texture", "line")
:AddAnchor("TOPRIGHT")
:AddAnchor("BOTTOMRIGHT")
:SetWidth(4)
:SetTexture("FRAME_BG")
)
:AddChildNoLayout(UIElements.New("Texture", "texture")
:AddAnchor("LEFT")
:SetTextureAndSize("iconPack.18x18/Grip")
)
)
:AddChild(UIElements.New("Text", "name")
:SetWidth("AUTO")
:SetMargin(8, 0, 0, 0)
:SetFont("BODY_BODY2")
:SetText(operationName)
)
:AddChild(UIElements.New("Frame", "spacer"))
:AddChild(UIElements.New("Button", "configBtn")
:SetBackgroundAndSize("iconPack.18x18/Popout")
:SetContext(operationName)
:SetScript("OnClick", private.ConfigOperationOnClick)
)
:AddChildIf(override, UIElements.New("Button", "removeBtn")
:SetMargin(4, 0, 0, 0)
:SetBackgroundAndSize("iconPack.18x18/Close/Default")
:SetContext(i)
:SetScript("OnClick", private.RemoveOperationOnClick)
)
)
)
end
end
-- ============================================================================
-- Local Script Handlers
-- ============================================================================
function private.DragButtonOnMouseDown(button)
local frame = button:GetParentElement()
frame:SetRelativeLevel(20)
frame:StartMoving()
button:SetScript("OnUpdate", private.DragFrameOnUpdate)
button:GetElement("__parent.name")
:SetTextColor("INDICATOR")
frame:SetWidth(250)
:Draw()
end
function private.DragButtonOnMouseUp(button)
button:SetScript("OnUpdate", nil)
local frame = button:GetParentElement()
frame:StopMovingOrSizing()
frame:SetRelativeLevel(1)
local container = frame:GetParentElement():GetParentElement()
local moduleName = container:GetParentElement():GetParentElement():GetContext()
local index = button:GetContext()
-- TODO: refactor
for k, v in container:LayoutChildrenIterator() do
if k ~= index and v:IsMouseOver() then
TSM.Groups.SwapOperation(private.currentGroupPath, moduleName, index, k)
end
end
for i, operationName in TSM.Groups.OperationIterator(private.currentGroupPath, moduleName) do
container:GetElement("operation"..i..".title.name"):SetText(operationName)
end
frame:SetWidth(nil)
frame:GetElement("name")
:SetTextColor("TEXT")
frame:GetParentElement():GetParentElement()
:Draw()
end
function private.DragFrameOnUpdate(frame)
local scrollFrame = frame:GetElement("__parent.__parent.__parent.__parent.__parent.__parent")
local uiScale = UIParent:GetEffectiveScale()
local x, y = GetCursorPosition()
x = x / uiScale
y = y / uiScale
-- TODO: refactor
local top = scrollFrame:_GetBaseFrame():GetTop()
local bottom = scrollFrame:_GetBaseFrame():GetBottom()
if y > top then
scrollFrame._scrollAmount = top - y
elseif y < bottom then
scrollFrame._scrollAmount = bottom - y
else
scrollFrame._scrollAmount = 0
end
scrollFrame._scrollbar:SetValue(scrollFrame._scrollbar:GetValue() + scrollFrame._scrollAmount / DRAG_SCROLL_SPEED_FACTOR)
end
function private.GroupSearchOnValueChanged(input)
local groupsContentFrame = input:GetElement("__parent.__parent.__parent.view.content")
-- Copy search filter
local text = strlower(input:GetValue())
if private.groupSearch == text then
return
end
private.groupSearch = text
local searchStr = String.Escape(private.groupSearch)
-- Check if the selection is being filtered out
if strmatch(strlower(private.currentGroupPath), searchStr) then
local titleFrame = groupsContentFrame:GetElement("header.title")
local buttonsFrame = groupsContentFrame:GetElement("buttons")
input:GetElement("__parent.__parent.groupTree"):SetSelectedGroup(private.currentGroupPath)
if private.currentGroupPath == TSM.CONST.ROOT_GROUP_PATH then
titleFrame:GetElement("text")
:SetTextColor("TEXT")
:SetText(L["Base Group"])
else
local groupColor = Theme.GetGroupColor(select('#', strsplit(TSM.CONST.GROUP_SEP, private.currentGroupPath)))
titleFrame:GetElement("text")
:SetTextColor(groupColor)
:SetText(TSM.Groups.Path.GetName(private.currentGroupPath))
end
titleFrame:GetElement("renameBtn"):Show()
titleFrame:GetElement("exportBtn"):Show()
buttonsFrame:Show()
buttonsFrame:Draw()
titleFrame:Draw()
else
local titleFrame = groupsContentFrame:GetElement("header.title")
local buttonsFrame = groupsContentFrame:GetElement("buttons")
input:GetElement("__parent.__parent.groupTree"):SetSelectedGroup(TSM.CONST.ROOT_GROUP_PATH)
titleFrame:GetElement("text")
:SetText(L["No group selected"])
:SetEditing(false)
-- Hide the content
titleFrame:GetElement("renameBtn"):Hide()
titleFrame:GetElement("exportBtn"):Hide()
buttonsFrame:Hide()
buttonsFrame:Draw()
titleFrame:Draw()
end
input:GetElement("__parent.__parent.groupTree")
:SetSearchString(private.groupSearch)
:Draw()
end
function private.ExpandAllGroupsOnClick(button)
button:GetElement("__parent.__parent.groupTree")
:ToggleExpandAll()
end
function private.ImportGroupBtnOnClick(button)
local dialogFrame = UIElements.New("Frame", "frame")
:SetLayout("VERTICAL")
:SetSize(658, 250)
:SetPadding(12)
:AddAnchor("CENTER")
:SetBackgroundColor("FRAME_BG", true)
:SetMouseEnabled(true)
:AddChild(UIElements.New("Frame", "header")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(20, -4, -4, 12)
:AddChild(UIElements.New("Text", "title")
:SetFont("BODY_BODY2_BOLD")
:SetJustifyH("CENTER")
:SetText(L["Import Groups & Operations"])
)
:AddChild(UIElements.New("Button", "closeBtn")
:SetBackgroundAndSize("iconPack.24x24/Close/Default")
:SetScript("OnClick", private.ImportExportCloseBtnOnClick)
)
)
:AddChild(UIElements.New("Text", "desc")
:SetHeight(40)
:SetMargin(0, 0, 0, 12)
:SetFont("BODY_BODY3")
:SetText(L["You can import groups by pasting an import string into the box below. Group import strings can be found at: https://tradeskillmaster.com/group-maker/all"])
)
:AddChild(UIElements.New("Text", "text")
:SetHeight(20)
:SetMargin(0, 0, 0, 8)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Import String"])
)
:AddChild(UIElements.New("MultiLineInput", "input")
:SetMargin(0, 0, 0, 12)
:SetBackgroundColor("PRIMARY_BG_ALT")
:SetFocused(true)
:SetPasteMode()
:SetScript("OnValueChanged", private.ImportInputOnValueChanged)
)
:SetScript("OnHide", private.ImportOnHide)
button:GetBaseElement():ShowDialogFrame(dialogFrame)
dialogFrame:Draw()
end
function private.GetImportSummaryDialog()
wipe(private.importGroupTreeContext)
local dialogFrame = UIElements.New("Frame", "frame")
:SetLayout("VERTICAL")
:SetSize(612, 437)
:SetPadding(8)
:AddAnchor("CENTER")
:SetBackgroundColor("FRAME_BG", true)
:SetMouseEnabled(true)
:AddChild(UIElements.New("Frame", "header")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(20, -4, -4, 16)
:AddChild(UIElements.New("Text", "title")
:SetFont("BODY_BODY2_BOLD")
:SetJustifyH("CENTER")
:SetText(L["Import Summary"])
)
:AddChild(UIElements.New("Button", "closeBtn")
:SetBackgroundAndSize("iconPack.24x24/Close/Default")
:SetScript("OnClick", private.ImportExportCloseBtnOnClick)
)
)
:AddChild(UIElements.New("Frame", "nav")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 16)
:AddChild(UIElements.New("Spacer", "spacer"))
-- TODO: add the other tabs (and OnClick handlers for these buttons)
:AddChild(UIElements.New("Button", "groups")
:SetWidth("AUTO")
:SetMargin(8, 8, 0, 0)
:SetFont("BODY_BODY2_BOLD")
:SetJustifyH("CENTER")
:SetText(format(L["%d Groups"], 0))
)
:AddChild(UIElements.New("Texture", "line")
:SetWidth(2)
:SetTexture("ACTIVE_BG_ALT")
)
:AddChild(UIElements.New("Button", "operations")
:SetWidth("AUTO")
:SetMargin(8, 8, 0, 0)
:SetFont("BODY_BODY2_BOLD")
:SetJustifyH("CENTER")
:SetText(format(L["%d Operations"], 0))
)
:AddChild(UIElements.New("Texture", "line2")
:SetWidth(2)
:SetTexture("ACTIVE_BG_ALT")
)
:AddChild(UIElements.New("Button", "items")
:SetWidth("AUTO")
:SetMargin(8, 8, 0, 0)
:SetFont("BODY_BODY2_BOLD")
:SetJustifyH("CENTER")
:SetText(format(L["%d Items"], 0))
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("Frame", "container")
:SetLayout("VERTICAL")
:SetPadding(2)
:SetMargin(0, 0, 0, 12)
:SetBackgroundColor("PRIMARY_BG")
:SetBorderColor("ACTIVE_BG")
:AddChild(UIElements.New("Frame", "header")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8)
:AddChild(UIElements.New("Input", "input")
:AllowItemInsert(true)
:SetIconTexture("iconPack.18x18/Search")
:SetClearButtonEnabled(true)
:SetHintText(L["Search Groups"])
:SetScript("OnValueChanged", private.ImportFilterOnValueChanged)
)
:AddChild(UIElements.New("Button", "expandAllBtn")
:SetSize(24, 24)
:SetMargin(8, 4, 0, 0)
:SetBackground("iconPack.18x18/Expand All")
:SetScript("OnClick", private.ImportExpandAllOnClick)
:SetTooltip(L["Expand / Collapse All Groups"])
)
:AddChild(UIElements.New("Button", "selectAllBtn")
:SetSize(24, 24)
:SetBackground("iconPack.18x18/Select All")
:SetScript("OnClick", private.ImportSelectAllOnClick)
:SetTooltip(L["Select / Deselect All Groups"])
)
)
:AddChild(UIElements.New("ApplicationGroupTree", "groupTree")
:SetContextTable(private.importGroupTreeContext, DEFAULT_IMPORT_GROUP_TREE_CONTEXT)
:SetQuery(private.CreateImportExportDBQuery())
:SetScript("OnGroupSelectionChanged", private.ImportGroupTreeOnGroupSelectionChanged)
)
)
:AddChild(UIElements.New("Frame", "items")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "moveCheckbox")
:SetWidth("AUTO")
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY3")
:SetCheckboxPosition("LEFT")
:SetChecked(true)
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("Frame", "operations")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("Checkbox", "includeCheckbox")
:SetWidth("AUTO")
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY3")
:SetCheckboxPosition("LEFT")
:SetChecked(true)
:SetText(L["Include operations?"])
:SetScript("OnValueChanged", private.ImportIncludeOperationsCheckboxOnValueChanged)
)
:AddChild(UIElements.New("Checkbox", "replaceCheckbox")
:SetWidth("AUTO")
:SetMargin(0, 8, 0, 0)
:SetFont("BODY_BODY3")
:SetCheckboxPosition("LEFT")
:SetChecked(true)
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("ActionButton", "btn")
:SetHeight(24)
:SetText(L["Import"])
:SetScript("OnClick", private.ImportBtnOnClick)
)
:SetScript("OnHide", private.ImportOnHide)
return dialogFrame
end
function private.ImportInputOnValueChanged(input)
local baseFrame = input:GetBaseElement()
if not TSM.Groups.ImportExport.ProcessImport(input:GetValue()) then
baseFrame:HideDialog()
Log.PrintUser(L["The pasted value was not valid. Ensure you are pasting the entire import string."])
return
end
-- build the import group DB
private.importExportGroupDB:TruncateAndBulkInsertStart()
local importGroupName = TSM.Groups.ImportExport.GetPendingImportGroupName()
for groupPath in TSM.Groups.ImportExport.PendingImportGroupIterator() do
groupPath = groupPath == TSM.CONST.ROOT_GROUP_PATH and importGroupName or TSM.Groups.Path.Join(importGroupName, groupPath)
local orderStr = gsub(groupPath, TSM.CONST.GROUP_SEP, "\001")
orderStr = strlower(orderStr)
private.importExportGroupDB:BulkInsertNewRow(groupPath, orderStr)
end
private.importExportGroupDB:BulkInsertEnd()
-- clear the OnHide handler so we don't reset the import context
input:GetParentElement():SetScript("OnHide", nil)
baseFrame:HideDialog()
local dialogFrame = private.GetImportSummaryDialog()
baseFrame:ShowDialogFrame(dialogFrame)
private.UpdateImportConfirmationDialog(dialogFrame)
end
function private.UpdateImportConfirmationDialog(dialogFrame)
local numItems, numGroups, numExistingItems, numOperations, numExistingOperations, numExistingCustomSources = TSM.Groups.ImportExport.GetImportTotals()
dialogFrame:GetElement("nav.groups")
:SetText(format(L["%d Groups"], numGroups))
dialogFrame:GetElement("nav.operations")
:SetText(format(L["%d Operations"], numOperations))
dialogFrame:GetElement("nav.items")
:SetText(format(L["%d Items"], numItems))
if numExistingItems > 0 then
dialogFrame:GetElement("items.moveCheckbox")
:SetText(format(L["Move %d already grouped items?"], numExistingItems))
:SetChecked(true)
dialogFrame:GetElement("items"):Show()
else
dialogFrame:GetElement("items"):Hide()
end
if numOperations > 0 then
dialogFrame:GetElement("operations.includeCheckbox")
:SetChecked(true)
dialogFrame:GetElement("operations.replaceCheckbox")
:SetChecked(true)
if numExistingOperations > 0 then
if numExistingCustomSources > 0 then
dialogFrame:GetElement("operations.replaceCheckbox")
:SetText(format(L["Replace %d existing operations and %d existing custom sources?"], numExistingOperations, numExistingCustomSources))
else
dialogFrame:GetElement("operations.replaceCheckbox")
:SetText(format(L["Replace %d existing operations?"], numExistingOperations))
end
dialogFrame:GetElement("operations.replaceCheckbox"):Show()
else
dialogFrame:GetElement("operations.replaceCheckbox"):Hide()
end
dialogFrame:GetElement("operations"):Show()
else
dialogFrame:GetElement("operations"):Hide()
end
dialogFrame:Draw()
end
function private.ImportFilterOnValueChanged(input)
input:GetElement("__parent.__parent.groupTree")
:SetSearchString(strlower(input:GetValue()))
:Draw()
end
function private.ImportExpandAllOnClick(button)
button:GetElement("__parent.__parent.groupTree")
:ToggleExpandAll()
end
function private.ImportSelectAllOnClick(button)
local importGroupName = TSM.Groups.ImportExport.GetPendingImportGroupName()
local groupTree = button:GetElement("__parent.__parent.groupTree")
groupTree:SetGroupSelected(importGroupName, false)
groupTree:ToggleSelectAll()
end
function private.ImportGroupTreeOnGroupSelectionChanged(groupTree)
local importGroupName = TSM.Groups.ImportExport.GetPendingImportGroupName()
groupTree:SetGroupSelected(importGroupName, true)
-- make sure the parent of any selected groups are also selected
for relativeGroupPath in TSM.Groups.ImportExport.PendingImportGroupIterator() do
local groupPath = relativeGroupPath == TSM.CONST.ROOT_GROUP_PATH and importGroupName or TSM.Groups.Path.Join(importGroupName, relativeGroupPath)
local isSelected = groupTree:IsGroupSelected(groupPath)
TSM.Groups.ImportExport.SetGroupFiltered(relativeGroupPath, not isSelected)
if isSelected then
local tempGroupPath = TSM.Groups.Path.Split(groupPath)
while tempGroupPath do
groupTree:SetGroupSelected(tempGroupPath, true)
tempGroupPath = TSM.Groups.Path.Split(tempGroupPath)
end
end
end
for relativeGroupPath in TSM.Groups.ImportExport.PendingImportGroupIterator() do
local groupPath = relativeGroupPath == TSM.CONST.ROOT_GROUP_PATH and importGroupName or TSM.Groups.Path.Join(importGroupName, relativeGroupPath)
local isSelected = groupTree:IsGroupSelected(groupPath)
TSM.Groups.ImportExport.SetGroupFiltered(relativeGroupPath, not isSelected)
end
private.UpdateImportConfirmationDialog(groupTree:GetParentElement():GetParentElement())
end
function private.ImportIncludeOperationsCheckboxOnValueChanged(checkbox)
if checkbox:IsChecked() then
checkbox:GetElement("__parent.replaceCheckbox"):Show()
else
checkbox:GetElement("__parent.replaceCheckbox"):Hide()
end
end
function private.ImportBtnOnClick(button)
local moveExistingItems = button:GetElement("__parent.items.moveCheckbox"):IsChecked()
local includeOperations = button:GetElement("__parent.operations.includeCheckbox"):IsChecked()
local replaceOperations = button:GetElement("__parent.operations.replaceCheckbox"):IsChecked()
TSM.Groups.ImportExport.CommitImport(moveExistingItems, includeOperations, replaceOperations)
button:GetBaseElement():HideDialog()
end
function private.ImportOnHide()
TSM.Groups.ImportExport.ClearImportContext()
end
function private.GroupTreeOnGroupSelected(groupTree, path)
local view = groupTree:GetElement("__parent.__parent.view")
if view ~= "content" then
view:SetPath("content", true)
end
private.currentGroupPath = path
local contentFrame = view:GetElement("content")
local titleFrame = contentFrame:GetElement("header.title")
local buttonsFrame = contentFrame:GetElement("buttons")
if path == TSM.CONST.ROOT_GROUP_PATH then
titleFrame:GetElement("icon")
:SetTextureAndSize(TSM.UI.TexturePacks.GetColoredKey("iconPack.18x18/Folder", "TEXT"))
titleFrame:GetElement("text")
:SetTextColor("TEXT")
:SetText(L["Base Group"])
:SetEditing(false)
titleFrame:GetElement("renameBtn"):Hide()
titleFrame:GetElement("exportBtn"):Hide()
buttonsFrame:RenamePath(L["Information"], 1)
else
local groupColor = Theme.GetGroupColor(select('#', strsplit(TSM.CONST.GROUP_SEP, path)))
titleFrame:GetElement("icon")
:SetTextureAndSize(TSM.UI.TexturePacks.GetColoredKey("iconPack.18x18/Folder", groupColor))
titleFrame:GetElement("text")
:SetTextColor(groupColor)
:SetText(TSM.Groups.Path.GetName(path))
:SetEditing(false)
titleFrame:GetElement("renameBtn"):Show()
titleFrame:GetElement("exportBtn"):Show()
buttonsFrame:RenamePath(L["Items"], 1)
end
-- Show the frame in case it is hidden by filter
buttonsFrame:Show()
buttonsFrame:Draw()
titleFrame:Draw()
contentFrame:GetElement("buttons"):ReloadContent()
end
function private.GroupTreeOnNewGroup(groupTree)
groupTree:GetElement("__parent.__parent.view.content.header.title.text"):SetEditing(true)
end
function private.GroupNameChanged(text, newValue)
newValue = strtrim(newValue)
local parent = TSM.Groups.Path.GetParent(private.currentGroupPath)
local newPath = parent and parent ~= TSM.CONST.ROOT_GROUP_PATH and (parent..TSM.CONST.GROUP_SEP..newValue) or newValue
if newPath == private.currentGroupPath then
-- didn't change
text:Draw()
elseif strfind(newValue, TSM.CONST.GROUP_SEP) or newValue == "" then
Log.PrintUser(L["Invalid group name."])
text:Draw()
elseif TSM.Groups.Exists(newPath) then
Log.PrintUser(L["Group already exists."])
text:Draw()
else
TSM.Groups.Move(private.currentGroupPath, newPath)
Analytics.Action("MOVED_GROUP", private.currentGroupPath, newPath)
text:GetElement("__parent.__parent.__parent.__parent.__parent.groupSelection.groupTree"):SetSelectedGroup(newPath, true)
end
end
function private.NameOnEditingChanged(text, editing)
if editing then
text:GetElement("__parent.renameBtn"):Hide()
text:GetElement("__parent.exportBtn"):Hide()
else
text:GetElement("__parent.renameBtn"):Show()
text:GetElement("__parent.exportBtn"):Show()
end
end
function private.RenameBtnOnClick(button)
button:GetElement("__parent.text"):SetEditing(true)
end
function private.ExportBtnOnClick(button)
-- build the export DB
wipe(private.exportSubGroups)
private.importExportGroupDB:TruncateAndBulkInsertStart()
for _, groupPath in TSM.Groups.GroupIterator() do
local relGroupPath = nil
if TSM.Groups.Path.IsChild(groupPath, private.currentGroupPath) then
relGroupPath = TSM.Groups.Path.GetRelative(groupPath, private.currentGroupPath)
end
if relGroupPath then
private.exportSubGroups[relGroupPath] = true
local orderStr = gsub(relGroupPath, TSM.CONST.GROUP_SEP, "\001")
orderStr = strlower(orderStr)
private.importExportGroupDB:BulkInsertNewRow(relGroupPath, orderStr)
end
end
private.importExportGroupDB:BulkInsertEnd()
local str, numItems, numSubGroups, numOperations, numCustomSources = TSM.Groups.ImportExport.GenerateExport(private.currentGroupPath, private.exportSubGroups, false, false)
local groupColor = Theme.GetGroupColor(select('#', strsplit(TSM.CONST.GROUP_SEP, private.currentGroupPath)))
button:GetBaseElement():ShowDialogFrame(UIElements.New("Frame", "frame")
:SetLayout("VERTICAL")
:SetSize(658, 408)
:SetPadding(12)
:AddAnchor("CENTER")
:SetBackgroundColor("FRAME_BG", true)
:SetMouseEnabled(true)
:AddChild(UIElements.New("Frame", "header")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(20, -4, -4, 12)
:AddChild(UIElements.New("Text", "title")
:SetFont("BODY_BODY2_BOLD")
:SetJustifyH("CENTER")
:SetText(L["Export"]..": "..groupColor:ColorText(TSM.Groups.Path.GetName(private.currentGroupPath)))
)
:AddChild(UIElements.New("Button", "closeBtn")
:SetBackgroundAndSize("iconPack.24x24/Close/Default")
:SetScript("OnClick", private.ImportExportCloseBtnOnClick)
)
)
:AddChild(UIElements.New("Text", "desc")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:SetFont("BODY_BODY3")
:SetText(L["You can use the export string below to share this group with others."])
)
:AddChild(UIElements.New("Frame", "options")
:SetLayout("HORIZONTAL")
:SetHeight(20)
:SetMargin(0, 0, 0, 12)
:AddChild(UIElements.New("GroupSelector", "subGroups")
:SetWidth(240)
:SetMargin(0, 12, 0, 0)
:SetSelectedText(L["%d subgroups included"])
:SetCustomQueryFunc(private.CreateImportExportDBQuery)
:SetSelection(private.exportSubGroups)
:SetHintText(L["Select included subgroups"])
:SetScript("OnSelectionChanged", private.ExportOptionOnValueChanged)
)
:AddChild(UIElements.New("Checkbox", "excludeOperations")
:SetWidth("AUTO")
:SetMargin(0, 12, 0, 0)
:SetFont("BODY_BODY3")
:SetCheckboxPosition("LEFT")
:SetText(L["Exclude operations?"])
:SetScript("OnValueChanged", private.ExportOptionOnValueChanged)
)
:AddChild(UIElements.New("Checkbox", "excludeCustomSources")
:SetWidth("AUTO")
:SetMargin(0, 12, 0, 0)
:SetFont("BODY_BODY3")
:SetCheckboxPosition("LEFT")
:SetText(L["Exclude custom sources?"])
:SetScript("OnValueChanged", private.ExportOptionOnValueChanged)
)
:AddChild(UIElements.New("Spacer", "spacer"))
)
:AddChild(UIElements.New("Text", "heading")
:SetMargin(0, 0, 0, 8)
:SetHeight(20)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(L["Export String"])
)
:AddChild(UIElements.New("Frame", "content")
:SetLayout("VERTICAL")
:SetBackgroundColor("PRIMARY_BG_ALT", true)
:AddChild(UIElements.New("MultiLineInput", "input")
:SetBackgroundColor("PRIMARY_BG_ALT")
:SetValue(str)
)
:AddChild(UIElements.New("Texture", "line")
:SetHeight(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Frame", "footer")
:SetLayout("HORIZONTAL")
:SetHeight(28)
:SetPadding(8, 8, 4, 4)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Text", "items")
:SetWidth("AUTO")
:SetMargin(8, 8, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(format(L["%d Items"], numItems))
)
:AddChild(UIElements.New("Texture", "line1")
:SetWidth(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Text", "subGroups")
:SetWidth("AUTO")
:SetMargin(8, 8, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(format(L["%d Sub-Groups"], numSubGroups))
)
:AddChild(UIElements.New("Texture", "line2")
:SetWidth(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Text", "operations")
:SetWidth("AUTO")
:SetMargin(8, 8, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(format(L["%d Operations"], numOperations))
)
:AddChild(UIElements.New("Texture", "line3")
:SetWidth(2)
:SetTexture("ACTIVE_BG")
)
:AddChild(UIElements.New("Text", "customSources")
:SetWidth("AUTO")
:SetMargin(8, 0, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetText(format(L["%d Custom Sources"], numCustomSources))
)
)
)
)
end
function private.CreateImportExportDBQuery()
return private.importExportGroupDB:NewQuery()
:OrderBy("orderStr", true)
end
function private.ImportExportCloseBtnOnClick(button)
button:GetBaseElement():HideDialog()
end
function private.ExportOptionOnValueChanged(element)
wipe(private.exportSubGroups)
for groupPath in element:GetElement("__parent.subGroups"):SelectedGroupIterator() do
private.exportSubGroups[groupPath] = true
end
local excludeOperations = element:GetElement("__parent.excludeOperations"):IsChecked()
local excludeCustomSources = element:GetElement("__parent.excludeCustomSources"):IsChecked()
local str, numItems, numSubGroups, numOperations, numCustomSources = TSM.Groups.ImportExport.GenerateExport(private.currentGroupPath, private.exportSubGroups, excludeOperations, excludeCustomSources)
element:GetElement("__parent.excludeCustomSources")
:SetDisabled(excludeOperations)
:SetChecked(excludeCustomSources and not excludeOperations, true)
:Draw()
local content = element:GetElement("__parent.__parent.content")
content:GetElement("input"):SetValue(str)
content:GetElement("footer.items"):SetText(format(L["%d Items"], numItems))
content:GetElement("footer.subGroups"):SetText(format(L["%d Sub-Groups"], numSubGroups))
content:GetElement("footer.operations"):SetText(format(L["%d Operations"], numOperations))
content:GetElement("footer.customSources"):SetText(format(L["%d Custom Sources"], numCustomSources))
content:Draw()
end
function private.ItemFilterValidateFunc(_, value)
return private.itemFilter:ParseStr(value)
end
function private.ItemFilterOnValueChanged(input)
local text = input:GetValue()
if private.itemSearch == text then
return
end
private.itemSearch = text
input:GetElement("__parent.__parent.content.ungrouped.content.itemList")
:SetFilterFunction(private.ItemListItemIsFiltered)
:Draw()
input:GetElement("__parent.__parent.content.grouped.content.itemList")
:SetFilterFunction(private.ItemListItemIsFiltered)
:Draw()
end
function private.UpdateBaseItemList()
wipe(private.results[1])
wipe(private.results[2])
local addedItems = TempTable.Acquire()
for _, itemString in ipairs(private.resultsRaw) do
if private.settings.groups[private.currentGroupPath].ignoreItemVariations then
itemString = ItemString.GetBase(itemString)
else
if ItemString.IsPet(itemString) and itemString == ItemString.GetBase(itemString) then
addedItems[itemString] = true
end
end
if not TSM.Groups.IsItemInGroup(itemString) and not addedItems[itemString] then
tinsert(private.results[1], itemString)
addedItems[itemString] = true
end
end
TempTable.Release(addedItems)
private.results[1].header = Theme.GetColor("INDICATOR"):ColorText(L["Search Results"].."|r")
end
function private.ValidateBaseSearchValue(_, value)
if value == "" then
return true
elseif #value < 3 then
return false, L["The search term must be at least 3 characters."]
elseif not private.itemFilter:ParseStr(value) then
return false, L["Invalid search term."]
elseif private.itemFilter:GetStr() and #private.itemFilter:GetStr() < 3 then
return false, L["The name portion of the search term must be at least 3 characters if present."]
elseif private.itemFilter:GetMinPrice() or private.itemFilter:GetMaxPrice() then
return false, L["Invalid search term. Cannot filter by price here."]
end
return true
end
function private.InformationSearchOnValueChanged(input)
local value = input:GetValue()
if private.itemSearch == value or value == "" then
return
end
private.BaseSearchOnValueChanged(input)
private.frame:GetBaseElement():GetElement("content.groups.view.content.header.input")
:SetFocused(true)
:ClearHighlight()
end
function private.BaseSearchOnValueChanged(input)
local value = input:GetValue()
if private.itemSearch == value or value == "" then
return
end
assert(private.itemFilter:ParseStr(value))
private.itemSearch = value
ItemInfo.MatchItemFilter(private.itemFilter, wipe(private.resultsRaw))
private.UpdateBaseItemList()
private.frame:GetBaseElement():GetElement("content.groups.view"):SetPath("search", true)
private.frame:GetBaseElement():GetElement("content.groups.view.content.itemList"):SetItems(private.results, true)
private.frame:GetBaseElement():GetElement("content.groups.view.content.header2.label")
:SetText(format(L["%d Results"], #private.results[1]))
:Draw()
end
function private.SelectAllResultsOnClick(button)
button:GetElement("__parent.__parent.itemList"):ToggleSelectAll()
end
function private.IgnoreSearchRandomOnValueChanged(checkbox, checked)
private.UpdateBaseItemList()
checkbox:GetElement("__parent.__parent.itemList"):SetItems(private.results, true)
checkbox:GetElement("__parent.label")
:SetText(format(L["%d Results"], #private.results[1]))
:Draw()
end
function private.SearchBackButtonOnClick(button)
button:GetBaseElement():GetElement("content.groups.view"):SetPath("content", true)
end
function private.IgnoreBaseRandomOnValueChanged(checkbox, checked)
-- update the base item list
checkbox:GetElement("__parent.__parent.itemList"):SetItems(private.GetUngroupedBagItemList(), true)
end
function private.ItemListOnSelectionChanged(itemList)
local selection = itemList:GetElement("__parent.bottom.group"):GetSelection()
local button = itemList:GetElement("__parent.bottom.move")
local numSelected = itemList:GetNumSelected()
button:SetDisabled(not selection or numSelected == 0)
:SetText(numSelected == 0 and L["Move Item"] or format(L["Move %d |4Item:Items"], numSelected))
:Draw()
end
function private.BaseMoveItemOnClick(button)
assert(private.moveGroupPath)
local itemList = button:GetElement("__parent.__parent.itemList")
local numAdded = 0
for _, itemLink in ipairs(private.results[1]) do
if itemList:IsItemSelected(itemLink) then
local itemString = ItemString.Get(itemLink)
TSM.Groups.SetItemGroup(itemString, private.moveGroupPath)
numAdded = numAdded + 1
end
end
Analytics.Action("ADDED_GROUP_ITEMS", private.moveGroupPath, numAdded)
private.UpdateBaseItemList()
itemList:SetItems(private.results, true)
itemList:GetElement("__parent.header2.label")
:SetText(format(L["%d Results"], #private.results[1]))
:Draw()
end
function private.MoveItemOnClick(button)
assert(private.moveGroupPath)
local itemList = button:GetElement("__parent.__parent.itemList")
local numAdded = 0
for _, items in ipairs(private.GetUngroupedBagItemList()) do
for _, itemLink in ipairs(items) do
if itemList:IsItemSelected(itemLink) then
local itemString = ItemString.Get(itemLink)
TSM.Groups.SetItemGroup(itemString, private.moveGroupPath)
numAdded = numAdded + 1
end
end
end
Analytics.Action("ADDED_GROUP_ITEMS", private.moveGroupPath, numAdded)
itemList:SetItems(private.GetUngroupedBagItemList(), true)
end
function private.BaseGroupOnSelectionChanged(self)
local selection = self:GetSelection()
private.moveGroupPath = selection
local numSelected = self:GetBaseElement():GetElement("content.groups.view.content.itemList"):GetNumSelected()
self:GetBaseElement():GetElement("content.groups.view.content.bottom.move")
:SetDisabled(not selection or numSelected == 0)
:SetText(numSelected == 0 and L["Move Item"] or format(L["Move %d |4Item:Items"], numSelected))
:Draw()
end
function private.GroupOnSelectionChanged(self)
local selection = self:GetSelection()
private.moveGroupPath = selection
local numSelected = self:GetBaseElement():GetElement("content.groups.view.content.buttons.items.itemList"):GetNumSelected()
self:GetBaseElement():GetElement("content.groups.view.content.buttons.items.bottom.move")
:SetDisabled(not selection or numSelected == 0)
:SetText(numSelected == 0 and L["Move Item"] or format(L["Move %d |4Item:Items"], numSelected))
:Draw()
end
function private.IgnoreRandomOnValueChanged(checkbox, checked)
-- update the ungrouped item list
checkbox:GetElement("__parent.__parent.content.ungrouped.content.itemList"):SetItems(private.GetUngroupedItemList(), true)
end
function private.AddItemsOnClick(button)
local itemList = button:GetElement("__parent.content.itemList")
local numAdded = 0
for _, items in ipairs(private.GetUngroupedItemList()) do
for _, itemLink in ipairs(items) do
if itemList:IsItemSelected(itemLink) then
local itemString = ItemString.Get(itemLink)
TSM.Groups.SetItemGroup(itemString, private.currentGroupPath)
numAdded = numAdded + 1
end
end
end
Analytics.Action("ADDED_GROUP_ITEMS", private.currentGroupPath, numAdded)
-- update the item lists
itemList:SetItems(private.GetUngroupedItemList(), true)
local otherItemList = button:GetElement("__parent.__parent.grouped.content.itemList")
otherItemList:SetItems(private.GetGroupedItemList(), true)
end
function private.ItemListSelectAllOnClick(button)
button:GetElement("__parent.__parent.itemList"):ToggleSelectAll()
end
function private.UngroupedItemsOnSelectionChanged(itemList)
local button = itemList:GetElement("__parent.__parent.btn")
local numSelected = itemList:GetNumSelected()
button:SetDisabled(numSelected == 0)
:SetText(numSelected == 0 and L["Add"] or format(L["Add %d |4Item:Items"], numSelected))
:Draw()
end
function private.GroupedItemsOnSelectionChanged(itemList)
local button = itemList:GetElement("__parent.__parent.btn")
local numSelected = itemList:GetNumSelected()
local parentGroup = TSM.Groups.Path.GetParent(private.currentGroupPath)
parentGroup = parentGroup ~= TSM.CONST.ROOT_GROUP_PATH and parentGroup or nil
if parentGroup then
button:SetModifierText(numSelected == 0 and L["Move to Parent Group"] or format(L["Move %d |4Item:Items"], numSelected), "SHIFT")
end
button:SetDisabled(numSelected == 0)
:SetText(numSelected == 0 and L["Remove"] or format(L["Remove %d |4Item:Items"], numSelected))
:Draw()
end
function private.RebuildModuleOperations(moduleOperationFrame)
local moduleName = moduleOperationFrame:GetContext()
local override = TSM.Groups.HasOperationOverride(private.currentGroupPath, moduleName) or private.currentGroupPath == TSM.CONST.ROOT_GROUP_PATH
-- remove the existing operations container and add more row
local content = moduleOperationFrame:GetElement("content")
local container = content:GetElement("container")
content:RemoveChild(container)
container:Release()
if content:HasChildById("addMore") then
local addMore = content:GetElement("addMore")
content:RemoveChild(addMore)
addMore:Release()
end
local numGroupOperations = 0
for _ in TSM.Groups.OperationIterator(private.currentGroupPath, moduleName) do
numGroupOperations = numGroupOperations + 1
end
moduleOperationFrame:AddChild(UIElements.New("Frame", "container")
:SetLayout("VERTICAL")
:SetContext(moduleName)
:SetHeight(36 * numGroupOperations)
:AddChildrenWithFunction(private.AddOperationRows)
)
moduleOperationFrame:AddChildIf(override and numGroupOperations < TSM.Operations.GetMaxNumber(moduleName), UIElements.New("Frame", "addMore")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, 8, 0)
:AddChild(UIElements.New("Spacer", "spacer"))
:AddChild(UIElements.New("Button", "button")
:SetWidth("AUTO")
:SetMargin(0, 2, 0, 0)
:SetFont("BODY_BODY2")
:SetTextColor("INDICATOR")
:SetText(L["Add More Operations"])
:SetContext(moduleName)
:SetScript("OnClick", private.AddOperationButtonOnClick)
)
)
moduleOperationFrame:GetParentElement():Draw()
end
function private.RemoveItemsOnClick(button)
local itemList = button:GetElement("__parent.content.itemList")
local numRemoved = 0
local parentGroup = TSM.Groups.Path.GetParent(private.currentGroupPath)
parentGroup = parentGroup ~= TSM.CONST.ROOT_GROUP_PATH and parentGroup or nil
local targetGroup = IsShiftKeyDown() and parentGroup or nil
for _, itemLink in ipairs(private.GetGroupedItemList()) do
if itemList:IsItemSelected(itemLink) then
TSM.Groups.SetItemGroup(ItemString.Get(itemLink), targetGroup)
numRemoved = numRemoved + 1
end
end
Analytics.Action("REMOVED_GROUP_ITEMS", private.currentGroupPath, numRemoved, targetGroup or "")
-- update the item lists
itemList:SetItems(private.GetGroupedItemList(), true)
local otherItemList = button:GetElement("__parent.__parent.ungrouped.content.itemList")
otherItemList:SetItems(private.GetUngroupedItemList(), true)
end
function private.OverrideToggleOnValueChanged(checkbox, value)
assert(private.currentGroupPath ~= TSM.CONST.ROOT_GROUP_PATH)
local moduleOperationFrame = checkbox:GetParentElement():GetParentElement()
local moduleName = moduleOperationFrame:GetContext()
TSM.Groups.SetOperationOverride(private.currentGroupPath, moduleName, value)
Analytics.Action("CHANGED_GROUP_OVERRIDE", private.currentGroupPath, moduleName, value)
private.RebuildModuleOperations(moduleOperationFrame)
end
function private.ConfigOperationOnClick(button)
local moduleName = button:GetParentElement():GetParentElement():GetParentElement():GetParentElement():GetParentElement():GetContext()
local operationName = button:GetContext()
local baseFrame = button:GetBaseElement()
TSM.MainUI.Operations.ShowOperationSettings(baseFrame, moduleName, operationName)
end
function private.AddOperationButtonOnClick(button)
local moduleName = button:GetContext()
private.operationQuery = private.operationQuery or TSM.Operations.CreateQuery()
private.operationQuery:Reset()
private.operationQuery
:Contains("operationName", private.filterText)
:Equal("moduleName", moduleName)
:OrderBy("operationName", true)
button:GetBaseElement():ShowDialogFrame(UIElements.New("Frame", "frame")
:SetLayout("VERTICAL")
:SetSize(464, 318)
:SetPadding(12)
:AddAnchor("CENTER")
:SetBackgroundColor("FRAME_BG")
:SetBorderColor("ACTIVE_BG")
:SetMouseEnabled(true)
:AddChild(UIElements.New("Frame", "header")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(0, 0, -4, 10)
:AddChild(UIElements.New("Spacer", "spacer")
:SetWidth(24)
)
:AddChild(UIElements.New("Text", "title")
:SetFont("BODY_BODY2_MEDIUM")
:SetJustifyH("CENTER")
:SetText(format(L["Add %s Operation"], moduleName))
)
:AddChild(UIElements.New("Button", "closeBtn")
:SetMargin(0, -4, 0, 0)
:SetBackgroundAndSize("iconPack.24x24/Close/Default")
:SetScript("OnClick", private.AddOperationCloseBtnOnClick)
)
)
:AddChild(UIElements.New("Frame", "container")
:SetLayout("VERTICAL")
:SetPadding(1)
:SetBackgroundColor("PRIMARY_BG")
:AddChild(UIElements.New("Frame", "search")
:SetLayout("HORIZONTAL")
:SetHeight(24)
:SetMargin(8, 8, 8, 12)
:AddChild(UIElements.New("Input", "input")
:SetContext(moduleName)
:SetIconTexture("iconPack.18x18/Search")
:SetClearButtonEnabled(true)
:AllowItemInsert(true)
:SetHintText(format(L["Search %s operations"], strlower(moduleName)))
:SetValue(private.filterText)
:SetScript("OnValueChanged", private.OperationSearchOnValueChanged)
)
)
:AddChild(UIElements.New("Button", "createOperation")
:SetHeight(24)
:SetPadding(8, 0, 0, 0)
:SetFont("BODY_BODY2_MEDIUM")
:SetContext(button)
:SetTextColor("INDICATOR")
:SetJustifyH("LEFT")
:SetText(L["Create New Operation"])
:SetScript("OnEnter", private.AddOperationCreateBtnOnEnter)
:SetScript("OnLeave", private.AddOperationCreateBtnOnLeave)
:SetScript("OnClick", private.AddOperationCreateBtnOnClick)
)
:AddChild(UIElements.New("QueryScrollingTable", "list")
:SetContext(moduleName)
:SetHeaderHidden(true)
:SetQuery(private.operationQuery)
:GetScrollingTableInfo()
:NewColumn("name")
:SetTitle("")
:SetFont("BODY_BODY2_MEDIUM")
:SetJustifyH("LEFT")
:SetTextInfo("operationName")
:Commit()
:Commit()
:SetScript("OnSelectionChanged", private.AddOperationSelectionChanged)
)
)
:AddChild(UIElements.New("ActionButton", "addBtn")
:SetHeight(24)
:SetMargin(0, 0, 8, 0)
:SetDisabled(true)
:SetContext(button)
:SetText(L["Add Operation"])
:SetScript("OnClick", private.AddOperationBtnOnClick)
)
)
end
function private.AddOperationCloseBtnOnClick(button)
button:GetBaseElement():HideDialog()
end
function private.AddOperationCreateBtnOnEnter(button)
button:SetTextColor("TEXT")
:Draw()
end
function private.AddOperationCreateBtnOnLeave(button)
button:SetTextColor(Theme.GetGroupColor(1))
:Draw()
end
function private.AddOperationCreateBtnOnClick(button)
local scrollingTable = button:GetElement("__parent.list")
local moduleName = scrollingTable:GetContext()
local operationName = L["New Operation"]
local extra = ""
local num = 0
while TSM.Operations.Exists(moduleName, operationName..extra) do
num = num + 1
extra = " "..num
end
operationName = operationName..extra
TSM.Operations.Create(moduleName, operationName)
TSM.Groups.AppendOperation(private.currentGroupPath, moduleName, operationName)
Analytics.Action("ADDED_GROUP_OPERATION", private.currentGroupPath, moduleName, operationName)
TSM.MainUI.Operations.ShowOperationSettings(button:GetBaseElement(), moduleName, operationName)
end
function private.OperationSearchOnValueChanged(input)
local text = strlower(input:GetValue())
if text == private.filterText then
return
end
private.filterText = text
private.operationQuery:SetUpdatesPaused(true)
private.operationQuery:ResetFilters()
:Contains("operationName", private.filterText)
:Equal("moduleName", input:GetContext())
private.operationQuery:SetUpdatesPaused(false)
input:GetElement("__parent.__parent.list"):UpdateData(true)
end
function private.AddOperationBtnOnClick(button)
local scrollingTable = button:GetElement("__parent.container.list")
local moduleName = scrollingTable:GetContext()
local operationName = scrollingTable:GetSelection():GetField("operationName")
TSM.Groups.AppendOperation(private.currentGroupPath, scrollingTable:GetContext(), operationName)
Analytics.Action("ADDED_GROUP_OPERATION", private.currentGroupPath, moduleName, operationName)
local moduleOperationFrame = button:GetContext():GetElement("__parent.__parent.__parent")
private.RebuildModuleOperations(moduleOperationFrame)
moduleOperationFrame:GetBaseElement():HideDialog()
end
function private.AddOperationSelectionChanged(scrollingTable)
if scrollingTable:GetSelection() then
scrollingTable:GetElement("__parent.__parent.addBtn")
:SetDisabled(false)
:Draw()
end
end
function private.RemoveOperationOnClick(button)
local moduleOperationFrame = button:GetElement("__parent.__parent.__parent.__parent.__parent")
local moduleName = moduleOperationFrame:GetContext()
local operationIndex = button:GetContext()
local operationName = nil
for index, name in TSM.Groups.OperationIterator(private.currentGroupPath, moduleName) do
if index == operationIndex then
operationName = name
end
end
assert(operationName)
TSM.Groups.RemoveOperation(private.currentGroupPath, moduleName, operationIndex)
Analytics.Action("REMOVED_GROUP_OPERATION", private.currentGroupPath, moduleName, operationName)
private.RebuildModuleOperations(moduleOperationFrame)
end
-- ============================================================================
-- Helper Functions
-- ============================================================================
function private.ItemSortHelper(a, b)
return (ItemInfo.GetName(a) or "") < (ItemInfo.GetName(b) or "")
end
function private.GetUngroupedBagItemList()
wipe(private.ungroupedItemList[1])
wipe(private.ungroupedItemList[2])
-- items in bags
local addedItems = TempTable.Acquire()
local query = BagTracking.CreateQueryBags()
:OrderBy("slotId", true)
:Select("itemString")
:Equal("isBoP", false)
for _, itemString in query:Iterator() do
if private.settings.groups[private.currentGroupPath].ignoreItemVariations then
itemString = ItemString.GetBase(itemString)
end
if not TSM.Groups.IsItemInGroup(itemString) and not addedItems[itemString] then
local itemLink = ItemInfo.GetLink(itemString)
tinsert(private.ungroupedItemList[1], itemLink)
addedItems[itemString] = true
end
end
query:Release()
TempTable.Release(addedItems)
private.ungroupedItemList[1].header = Theme.GetColor("INDICATOR"):ColorText(L["Ungrouped Items in Bags"])
sort(private.ungroupedItemList[1], private.ItemSortHelper)
return private.ungroupedItemList
end
function private.GetUngroupedItemList()
wipe(private.ungroupedItemList[1])
wipe(private.ungroupedItemList[2])
-- items in bags
local addedItems = TempTable.Acquire()
local query = BagTracking.CreateQueryBags()
:OrderBy("slotId", true)
:Select("itemString")
:Equal("isBoP", false)
for _, itemString in query:Iterator() do
if private.settings.groups[private.currentGroupPath].ignoreItemVariations then
itemString = ItemString.GetBase(itemString)
end
if not TSM.Groups.IsItemInGroup(itemString) and not addedItems[itemString] then
local itemLink = ItemInfo.GetLink(itemString)
tinsert(private.ungroupedItemList[1], itemLink)
addedItems[itemString] = true
end
end
query:Release()
TempTable.Release(addedItems)
private.ungroupedItemList[1].header = Theme.GetColor("INDICATOR"):ColorText(L["Ungrouped Items in Bags"])
-- items in the parent group
local parentGroupPath = TSM.Groups.Path.GetParent(private.currentGroupPath)
if parentGroupPath ~= TSM.CONST.ROOT_GROUP_PATH then
for _, itemString in TSM.Groups.ItemIterator(parentGroupPath) do
local itemLink = ItemInfo.GetLink(itemString)
tinsert(private.ungroupedItemList[2], itemLink)
end
end
private.ungroupedItemList[2].header = Theme.GetColor("INDICATOR"):ColorText(L["Parent Items"])
sort(private.ungroupedItemList[1], private.ItemSortHelper)
sort(private.ungroupedItemList[2], private.ItemSortHelper)
return private.ungroupedItemList
end
function private.GetGroupedItemList()
wipe(private.groupedItemList)
-- items in this group or a subgroup
local itemNames = TempTable.Acquire()
for _, itemString in TSM.Groups.ItemIterator(private.currentGroupPath, true) do
local link = ItemInfo.GetLink(itemString)
tinsert(private.groupedItemList, link)
itemNames[link] = ItemInfo.GetName(itemString) or ""
end
Table.SortWithValueLookup(private.groupedItemList, itemNames)
TempTable.Release(itemNames)
return private.groupedItemList
end
function private.ItemListItemIsFiltered(itemLink)
local basePrice = CustomPrice.GetValue(private.settings.groupPriceSource, itemLink)
return not private.itemFilter:Matches(itemLink, basePrice)
end