361 lines
12 KiB
Lua
361 lines
12 KiB
Lua
-- ------------------------------------------------------------------------------ --
|
|
-- TradeSkillMaster --
|
|
-- https://tradeskillmaster.com --
|
|
-- All Rights Reserved - Detailed license information included with addon. --
|
|
-- ------------------------------------------------------------------------------ --
|
|
|
|
--- Group Selector UI Element Class.
|
|
-- A group selector is an element which can be used to prompt the user to select a list of groups, usually for
|
|
-- filtering. It is a subclass of the @{Element} class.
|
|
-- @classmod GroupSelector
|
|
|
|
local _, TSM = ...
|
|
local L = TSM.Include("Locale").GetTable()
|
|
local Table = TSM.Include("Util.Table")
|
|
local Analytics = TSM.Include("Util.Analytics")
|
|
local Theme = TSM.Include("Util.Theme")
|
|
local NineSlice = TSM.Include("Util.NineSlice")
|
|
local ScriptWrapper = TSM.Include("Util.ScriptWrapper")
|
|
local UIElements = TSM.Include("UI.UIElements")
|
|
local GroupSelector = TSM.Include("LibTSMClass").DefineClass("GroupSelector", TSM.UI.Element)
|
|
UIElements.Register(GroupSelector)
|
|
TSM.UI.GroupSelector = GroupSelector
|
|
local private = {}
|
|
local TEXT_MARGIN = 8
|
|
local ICON_MARGIN = 8
|
|
local DEFAULT_CONTEXT = { selected = {}, collapsed = {} }
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Public Class Methods
|
|
-- ============================================================================
|
|
|
|
function GroupSelector.__init(self)
|
|
local frame = UIElements.CreateFrame(self, "Button")
|
|
ScriptWrapper.Set(frame, "OnClick", private.OnClick, self)
|
|
self.__super:__init(frame)
|
|
|
|
frame.text = UIElements.CreateFontString(self, frame)
|
|
frame.text:SetPoint("TOPLEFT", TEXT_MARGIN, 0)
|
|
frame.text:SetPoint("BOTTOMRIGHT", -ICON_MARGIN - TSM.UI.TexturePacks.GetWidth("iconPack.18x18/Add/Default") - TEXT_MARGIN, 0)
|
|
frame.text:SetJustifyH("LEFT")
|
|
frame.text:SetJustifyV("MIDDLE")
|
|
|
|
frame.icon = frame:CreateTexture(nil, "ARTWORK")
|
|
frame.icon:SetPoint("RIGHT", -ICON_MARGIN, 0)
|
|
|
|
frame.iconBtn = CreateFrame("Button", nil, frame)
|
|
frame.iconBtn:SetAllPoints(frame.icon)
|
|
ScriptWrapper.Set(frame.iconBtn, "OnClick", private.OnIconClick, self)
|
|
|
|
self._nineSlice = NineSlice.New(frame)
|
|
|
|
self._groupTreeContext = CopyTable(DEFAULT_CONTEXT)
|
|
self._hintText = ""
|
|
self._selectedText = L["%d groups"]
|
|
self._singleSelection = nil
|
|
self._onSelectionChanged = nil
|
|
self._customQueryFunc = nil
|
|
self._showCreateNew = false
|
|
end
|
|
|
|
function GroupSelector.Release(self)
|
|
wipe(self._groupTreeContext.collapsed)
|
|
wipe(self._groupTreeContext.selected)
|
|
self._hintText = ""
|
|
self._selectedText = L["%d groups"]
|
|
self._singleSelection = nil
|
|
self._onSelectionChanged = nil
|
|
self._customQueryFunc = nil
|
|
self._showCreateNew = false
|
|
self.__super:Release()
|
|
end
|
|
|
|
--- Sets the hint text.
|
|
-- @tparam GroupSelector self The group selector object
|
|
-- @tparam string text The hint text
|
|
-- @treturn GroupSelector The group selector object
|
|
function GroupSelector.SetHintText(self, text)
|
|
assert(type(text) == "string")
|
|
self._hintText = text
|
|
return self
|
|
end
|
|
|
|
--- Sets the selected text.
|
|
-- @tparam GroupSelector self The group selector object
|
|
-- @tparam string text The selected text (with a %d formatter for the number of groups)
|
|
-- @treturn GroupSelector The group selector object
|
|
function GroupSelector.SetSelectedText(self, text)
|
|
assert(type(text) == "string" and strmatch(text, "%%d"))
|
|
self._selectedText = text
|
|
return self
|
|
end
|
|
|
|
--- Registers a script handler.
|
|
-- @tparam GroupSelector self The group selector object
|
|
-- @tparam string script The script to register for (supported scripts: `OnSelectionChanged`)
|
|
-- @tparam function handler The script handler which will be called with the group selector object followed by any
|
|
-- arguments to the script
|
|
-- @treturn GroupSelector The group selector object
|
|
function GroupSelector.SetScript(self, script, handler)
|
|
if script == "OnSelectionChanged" then
|
|
self._onSelectionChanged = handler
|
|
else
|
|
error("Unknown GroupSelector script: "..tostring(script))
|
|
end
|
|
return self
|
|
end
|
|
|
|
--- Sets a function to generate a custom query to use for the group tree
|
|
-- @tparam GroupSelector self The group selector object
|
|
-- @tparam function func A function to call to create the custom query (gets auto-released by the GroupTree)
|
|
-- @treturn GroupSelector The group selector object
|
|
function GroupSelector.SetCustomQueryFunc(self, func)
|
|
self._customQueryFunc = func
|
|
return self
|
|
end
|
|
|
|
--- Adds the "Create New Group" option to the group tree
|
|
-- @tparam GroupSelector self The group selector object
|
|
-- @treturn GroupSelector The group selector object
|
|
function GroupSelector.AddCreateNew(self)
|
|
self._showCreateNew = true
|
|
return self
|
|
end
|
|
|
|
--- Sets the selection to only handle single selection.
|
|
-- @tparam GroupSelector self The group selector object
|
|
-- @tparam boolean enabled The state of the single selection
|
|
-- @treturn GroupSelector The group selector object
|
|
function GroupSelector.SetSingleSelection(self, enabled)
|
|
self._singleSelection = enabled
|
|
return self
|
|
end
|
|
|
|
--- Returns the single selected group path.
|
|
-- @tparam GroupSelector self The group selector object
|
|
function GroupSelector.GetSelection(self)
|
|
assert(self._singleSelection)
|
|
return next(self._groupTreeContext.selected)
|
|
end
|
|
|
|
--- Sets the single selected group path.
|
|
-- @tparam GroupSelector self The group selector object
|
|
-- @tparam string|table selection The selected group(s) or nil if nothing should be selected
|
|
-- @treturn GroupSelector The group selector object
|
|
function GroupSelector.SetSelection(self, selection)
|
|
wipe(self._groupTreeContext.selected)
|
|
if not selection then
|
|
return self
|
|
end
|
|
if self._singleSelection then
|
|
self._groupTreeContext.selected[selection] = true
|
|
else
|
|
for groupPath in pairs(selection) do
|
|
self._groupTreeContext.selected[groupPath] = true
|
|
end
|
|
end
|
|
return self
|
|
end
|
|
|
|
--- Returns an iterator for all selected groups.
|
|
-- @tparam GroupSelector self The group selector object
|
|
-- @return An iterator which iterates over the selected groups and has the following values: `groupPath`
|
|
function GroupSelector.SelectedGroupIterator(self)
|
|
return pairs(self._groupTreeContext.selected)
|
|
end
|
|
|
|
--- Clears all selected groups.
|
|
-- @tparam GroupSelector self The group selector object
|
|
-- @tparam boolean silent Don't call the selection changed callback
|
|
-- @treturn GroupSelector The group selector object
|
|
function GroupSelector.ClearSelectedGroups(self, silent)
|
|
wipe(self._groupTreeContext.selected)
|
|
if not silent and self._onSelectionChanged then
|
|
self:_onSelectionChanged()
|
|
end
|
|
return self
|
|
end
|
|
|
|
function GroupSelector.Draw(self)
|
|
self.__super:Draw()
|
|
local frame = self:_GetBaseFrame()
|
|
|
|
frame.text:SetFont(Theme.GetFont("BODY_BODY2"):GetWowFont())
|
|
local numGroups = Table.Count(self._groupTreeContext.selected)
|
|
frame.text:SetText(numGroups == 0 and self._hintText or (self._singleSelection and TSM.Groups.Path.Format(next(self._groupTreeContext.selected)) or format(self._selectedText, numGroups)))
|
|
|
|
TSM.UI.TexturePacks.SetTextureAndSize(frame.icon, numGroups == 0 and "iconPack.18x18/Add/Default" or "iconPack.18x18/Close/Default")
|
|
|
|
self._nineSlice:SetStyle("rounded")
|
|
self._nineSlice:SetVertexColor(Theme.GetColor("ACTIVE_BG"):GetFractionalRGBA())
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Private Class Methods
|
|
-- ============================================================================
|
|
|
|
function GroupSelector._CreateQuery(self)
|
|
local query = nil
|
|
if self._customQueryFunc then
|
|
query = self._customQueryFunc()
|
|
else
|
|
query = TSM.Groups.CreateQuery()
|
|
end
|
|
if self._singleSelection then
|
|
query:NotEqual("groupPath", TSM.CONST.ROOT_GROUP_PATH)
|
|
end
|
|
return query
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Private Helper Functions
|
|
-- ============================================================================
|
|
|
|
function private.OnClick(self)
|
|
self:GetBaseElement():ShowDialogFrame(UIElements.New("Frame", "frame", "DIALOG")
|
|
:SetLayout("VERTICAL")
|
|
:SetSize(464, 500)
|
|
:SetPadding(8)
|
|
:AddAnchor("CENTER")
|
|
:SetBackgroundColor("FRAME_BG", true)
|
|
:SetMouseEnabled(true)
|
|
:AddChild(UIElements.New("Frame", "header")
|
|
:SetLayout("HORIZONTAL")
|
|
:SetHeight(24)
|
|
:SetMargin(0, 0, 0, 8)
|
|
:AddChild(UIElements.New("Text", "title")
|
|
:SetMargin(32, 8, 0, 0)
|
|
:SetFont("BODY_BODY2_MEDIUM")
|
|
:SetJustifyH("CENTER")
|
|
:SetText(L["Select Group"])
|
|
)
|
|
:AddChild(UIElements.New("Button", "closeBtn")
|
|
:SetBackgroundAndSize("iconPack.24x24/Close/Default")
|
|
:SetScript("OnClick", private.DialogCloseBtnOnClick)
|
|
)
|
|
)
|
|
:AddChild(UIElements.New("Frame", "container")
|
|
:SetLayout("VERTICAL")
|
|
:SetPadding(2)
|
|
: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.DialogFilterOnValueChanged)
|
|
)
|
|
: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"])
|
|
)
|
|
:AddChildIf(not self._singleSelection, UIElements.New("Button", "selectAllBtn")
|
|
:SetSize(24, 24)
|
|
:SetMargin(8, 0, 0, 0)
|
|
:SetBackground("iconPack.18x18/Select All")
|
|
:SetScript("OnClick", private.SelectAllGroupsOnClick)
|
|
:SetTooltip(L["Select / Deselect All Groups"])
|
|
)
|
|
)
|
|
:AddChildIf(self._showCreateNew, UIElements.New("Button", "createGroup")
|
|
:SetHeight(24)
|
|
:SetMargin(8, 8, 0, 0)
|
|
:SetFont("BODY_BODY2_MEDIUM")
|
|
:SetJustifyH("LEFT")
|
|
:SetIcon("iconPack.14x14/Add/Circle", "LEFT")
|
|
:SetText(L["Create New Group"])
|
|
:SetScript("OnClick", private.CreateGroupOnClick)
|
|
)
|
|
:AddChild(UIElements.New(self._singleSelection and "SelectionGroupTree" or "ApplicationGroupTree", "groupTree")
|
|
:SetContext(self)
|
|
:SetContextTable(self._groupTreeContext, DEFAULT_CONTEXT)
|
|
:SetQuery(self:_CreateQuery())
|
|
)
|
|
)
|
|
:AddChild(UIElements.New("ActionButton", "groupBtn")
|
|
:SetHeight(24)
|
|
:SetMargin(0, 0, 8, 0)
|
|
:SetContext(self)
|
|
:SetText(L["Select Group"])
|
|
:SetScript("OnClick", private.DialogSelectOnClick)
|
|
)
|
|
)
|
|
end
|
|
|
|
function private.OnIconClick(self)
|
|
if Table.Count(self._groupTreeContext.selected) > 0 then
|
|
self:ClearSelectedGroups()
|
|
self:Draw()
|
|
if self._onSelectionChanged then
|
|
self:_onSelectionChanged()
|
|
end
|
|
else
|
|
private.OnClick(self)
|
|
end
|
|
end
|
|
|
|
function private.DialogCloseBtnOnClick(button)
|
|
local self = button:GetElement("__parent.__parent.groupBtn"):GetContext()
|
|
button:GetBaseElement():HideDialog()
|
|
self:Draw()
|
|
if self._onSelectionChanged then
|
|
self:_onSelectionChanged()
|
|
end
|
|
end
|
|
|
|
function private.DialogFilterOnValueChanged(input)
|
|
input:GetElement("__parent.__parent.groupTree")
|
|
:SetSearchString(strlower(input:GetValue()))
|
|
:Draw()
|
|
end
|
|
|
|
function private.ExpandAllGroupsOnClick(button)
|
|
button:GetElement("__parent.__parent.groupTree")
|
|
:ToggleExpandAll()
|
|
end
|
|
|
|
function private.SelectAllGroupsOnClick(button)
|
|
button:GetElement("__parent.__parent.groupTree")
|
|
:ToggleSelectAll()
|
|
end
|
|
|
|
function private.DialogSelectOnClick(button)
|
|
local self = button:GetContext()
|
|
button:GetBaseElement():HideDialog()
|
|
self:Draw()
|
|
if self._onSelectionChanged then
|
|
self:_onSelectionChanged()
|
|
end
|
|
end
|
|
|
|
function private.CreateGroupOnClick(button)
|
|
local newGroupPath = L["New Group"]
|
|
if TSM.Groups.Exists(newGroupPath) then
|
|
local num = 1
|
|
while TSM.Groups.Exists(newGroupPath.." "..num) do
|
|
num = num + 1
|
|
end
|
|
newGroupPath = newGroupPath.." "..num
|
|
end
|
|
TSM.Groups.Create(newGroupPath)
|
|
Analytics.Action("CREATED_GROUP", newGroupPath)
|
|
button:GetElement("__parent.groupTree")
|
|
:UpdateData()
|
|
:SetSelection(newGroupPath)
|
|
:Draw()
|
|
end
|