289 lines
9.9 KiB
Lua
289 lines
9.9 KiB
Lua
|
-- ------------------------------------------------------------------------------ --
|
||
|
-- TradeSkillMaster --
|
||
|
-- https://tradeskillmaster.com --
|
||
|
-- All Rights Reserved - Detailed license information included with addon. --
|
||
|
-- ------------------------------------------------------------------------------ --
|
||
|
|
||
|
--- OperationTree UI Element Class.
|
||
|
-- The operation tree is used to display operations grouped by module and allows for adding, duplicating, and deleting
|
||
|
-- them. Only one module is allowed to be expanded at a time. It is a subclass of the @{ScrollingTable} class.
|
||
|
-- @classmod OperationTree
|
||
|
|
||
|
local _, TSM = ...
|
||
|
local OperationTree = TSM.Include("LibTSMClass").DefineClass("OperationTree", TSM.UI.ScrollingTable)
|
||
|
local L = TSM.Include("Locale").GetTable()
|
||
|
local Theme = TSM.Include("Util.Theme")
|
||
|
local ScriptWrapper = TSM.Include("Util.ScriptWrapper")
|
||
|
local UIElements = TSM.Include("UI.UIElements")
|
||
|
UIElements.Register(OperationTree)
|
||
|
TSM.UI.OperationTree = OperationTree
|
||
|
local private = {}
|
||
|
local DATA_SEP = "\001"
|
||
|
|
||
|
|
||
|
-- ============================================================================
|
||
|
-- Public Class Methods
|
||
|
-- ============================================================================
|
||
|
|
||
|
function OperationTree.__init(self)
|
||
|
self.__super:__init()
|
||
|
self:SetRowHeight(28)
|
||
|
|
||
|
self._operationNameFilter = ""
|
||
|
self._selected = nil
|
||
|
self._expandedModule = nil
|
||
|
self._selectedOperation = nil
|
||
|
self._prevSelectedOperation = nil
|
||
|
self._onOperationSelectedHandler = nil
|
||
|
self._onOperationAddedHandler = nil
|
||
|
self._onOperationDeletedHandler = nil
|
||
|
end
|
||
|
|
||
|
function OperationTree.Acquire(self)
|
||
|
self._backgroundColor = "PRIMARY_BG_ALT"
|
||
|
self._headerHidden = true
|
||
|
self.__super:Acquire()
|
||
|
self:GetScrollingTableInfo()
|
||
|
:NewColumn("text")
|
||
|
:SetFont("BODY_BODY2_MEDIUM")
|
||
|
:SetJustifyH("LEFT")
|
||
|
:SetTextFunction(private.GetText)
|
||
|
:SetExpanderStateFunction(private.GetExpanderState)
|
||
|
:SetActionIconInfo(2, 14, private.GetActionIcon)
|
||
|
:SetActionIconClickHandler(private.OnActionIconClick)
|
||
|
:DisableHiding()
|
||
|
:Commit()
|
||
|
:Commit()
|
||
|
self:UpdateData()
|
||
|
end
|
||
|
|
||
|
function OperationTree.Release(self)
|
||
|
for _, row in ipairs(self._rows) do
|
||
|
ScriptWrapper.Clear(row._frame, "OnDoubleClick")
|
||
|
end
|
||
|
self._selected = nil
|
||
|
self._operationNameFilter = ""
|
||
|
self._expandedModule = nil
|
||
|
self._selectedOperation = nil
|
||
|
self._prevSelectedOperation = nil
|
||
|
self._onOperationSelectedHandler = nil
|
||
|
self._onOperationAddedHandler = nil
|
||
|
self._onOperationDeletedHandler = nil
|
||
|
self.__super:Release()
|
||
|
self:SetRowHeight(28)
|
||
|
end
|
||
|
|
||
|
--- Sets the operation name filter.
|
||
|
-- @tparam OperationTree self The operation tree object
|
||
|
-- @tparam string filter The filter string (any operations which don't match this are hidden)
|
||
|
function OperationTree.SetOperationNameFilter(self, filter)
|
||
|
self._operationNameFilter = filter
|
||
|
if filter == "" and self._prevSelectedOperation and not self._selectedOperation then
|
||
|
-- restore any previous selection if we don't have something selected
|
||
|
self:SetSelectedOperation(self:_SplitOperationKey(self._prevSelectedOperation))
|
||
|
self._prevSelectedOperation = nil
|
||
|
elseif filter ~= "" and self._selectedOperation then
|
||
|
local _, operationName = self:_SplitOperationKey(self._selectedOperation)
|
||
|
if not operationName or not strmatch(strlower(operationName), filter) then
|
||
|
-- save the current selection to restore after the filter is cleared and then clear the current selection
|
||
|
self._prevSelectedOperation = self._selectedOperation
|
||
|
self:SetSelectedOperation()
|
||
|
end
|
||
|
end
|
||
|
self:UpdateData(true)
|
||
|
end
|
||
|
|
||
|
--- Registers a script handler.
|
||
|
-- @tparam OperationTree self The operation tree object
|
||
|
-- @tparam string script The script to register for (supported scripts: `OnOperationSelected`, `OnOperationAdded`,
|
||
|
-- `OnOperationDeleted`)
|
||
|
-- @tparam function handler The script handler which will be called with the operation tree object followed by any
|
||
|
-- arguments to the script
|
||
|
-- @treturn OperationTree The operation tree object
|
||
|
function OperationTree.SetScript(self, script, handler)
|
||
|
if script == "OnOperationSelected" then
|
||
|
self._onOperationSelectedHandler = handler
|
||
|
elseif script == "OnOperationAdded" then
|
||
|
self._onOperationAddedHandler = handler
|
||
|
elseif script == "OnOperationDeleted" then
|
||
|
self._onOperationDeletedHandler = handler
|
||
|
else
|
||
|
error("Unknown OperationTree script: "..tostring(script))
|
||
|
end
|
||
|
return self
|
||
|
end
|
||
|
|
||
|
--- Sets the selected operation.
|
||
|
-- @tparam OperationTree self The operation tree object
|
||
|
-- @tparam string moduleName The name of the module which the operation belongs to
|
||
|
-- @tparam string operationName The name of the operation
|
||
|
-- @treturn OperationTree The operation tree object
|
||
|
function OperationTree.SetSelectedOperation(self, moduleName, operationName)
|
||
|
if moduleName and operationName then
|
||
|
self._selectedOperation = moduleName..DATA_SEP..operationName
|
||
|
self._expandedModule = moduleName
|
||
|
elseif moduleName then
|
||
|
self._selectedOperation = moduleName
|
||
|
self._expandedModule = moduleName
|
||
|
else
|
||
|
self._selectedOperation = nil
|
||
|
self._expandedModule = nil
|
||
|
end
|
||
|
self:UpdateData()
|
||
|
self.__super:SetSelection(self._selectedOperation, true)
|
||
|
if self._onOperationSelectedHandler then
|
||
|
self:_onOperationSelectedHandler(moduleName, operationName)
|
||
|
end
|
||
|
self:_ForceLastDataUpdate()
|
||
|
self:UpdateData(true)
|
||
|
return self
|
||
|
end
|
||
|
|
||
|
function OperationTree.SetSelection(self, data)
|
||
|
self:SetSelectedOperation(self:_SplitOperationKey(data))
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
-- ============================================================================
|
||
|
-- Private Class Methods
|
||
|
-- ============================================================================
|
||
|
|
||
|
function OperationTree._GetTableRow(self, isHeader)
|
||
|
local row = self.__super:_GetTableRow(isHeader)
|
||
|
if not isHeader then
|
||
|
ScriptWrapper.Set(row._frame, "OnDoubleClick", private.RowOnDoubleClick, row)
|
||
|
end
|
||
|
return row
|
||
|
end
|
||
|
|
||
|
function OperationTree._IsDataHidden(self, data)
|
||
|
local moduleName, operationName = self:_SplitOperationKey(data)
|
||
|
if operationName and not strmatch(strlower(operationName), self._operationNameFilter) then
|
||
|
return true
|
||
|
elseif operationName and moduleName ~= self._expandedModule then
|
||
|
return true
|
||
|
end
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
function OperationTree._SplitOperationKey(self, data)
|
||
|
local moduleName, operationName = strmatch(data, "([^"..DATA_SEP.."]+)"..DATA_SEP.."?(.*)")
|
||
|
operationName = operationName ~= "" and operationName or nil
|
||
|
return moduleName, operationName
|
||
|
end
|
||
|
|
||
|
function OperationTree._UpdateData(self)
|
||
|
wipe(self._data)
|
||
|
for _, moduleName in TSM.Operations.ModuleIterator() do
|
||
|
if not self:_IsDataHidden(moduleName) then
|
||
|
tinsert(self._data, moduleName)
|
||
|
end
|
||
|
for _, operationName in TSM.Operations.OperationIterator(moduleName) do
|
||
|
local data = moduleName..DATA_SEP..operationName
|
||
|
if not self:_IsDataHidden(data) then
|
||
|
tinsert(self._data, data)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function OperationTree._HandleRowClick(self)
|
||
|
self:Draw()
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
-- ============================================================================
|
||
|
-- Local Script Handlers
|
||
|
-- ============================================================================
|
||
|
|
||
|
function private.GetText(self, data)
|
||
|
local moduleName, operationName = self:_SplitOperationKey(data)
|
||
|
local color = Theme.GetColor(operationName and "TEXT" or "INDICATOR")
|
||
|
return color:ColorText(operationName or moduleName.." "..L["Operations"])
|
||
|
end
|
||
|
|
||
|
function private.GetExpanderState(self, data)
|
||
|
local moduleName, operationName = self:_SplitOperationKey(data)
|
||
|
return not operationName, self._expandedModule == moduleName, operationName and 1 or 0
|
||
|
end
|
||
|
|
||
|
function private.GetActionIcon(self, data, iconIndex, isMouseOver)
|
||
|
local _, operationName = self:_SplitOperationKey(data)
|
||
|
if iconIndex == 1 then
|
||
|
if operationName and data == self._selectedOperation then
|
||
|
local texturePack = "iconPack.14x14/Duplicate"
|
||
|
return true, isMouseOver and TSM.UI.TexturePacks.GetColoredKey(texturePack, Theme.GetColor("INDICATOR")) or texturePack
|
||
|
elseif operationName then
|
||
|
return false, nil
|
||
|
else
|
||
|
local texturePack = "iconPack.14x14/Add/Circle"
|
||
|
return true, isMouseOver and TSM.UI.TexturePacks.GetColoredKey(texturePack, Theme.GetColor("INDICATOR")) or texturePack
|
||
|
end
|
||
|
elseif iconIndex == 2 then
|
||
|
if operationName and data == self._selectedOperation then
|
||
|
local texturePack = "iconPack.14x14/Delete"
|
||
|
return true, isMouseOver and TSM.UI.TexturePacks.GetColoredKey(texturePack, Theme.GetColor("INDICATOR")) or texturePack
|
||
|
else
|
||
|
return false, nil
|
||
|
end
|
||
|
else
|
||
|
error("Invalid index: "..tostring(iconIndex))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function private.OnActionIconClick(self, data, iconIndex)
|
||
|
local moduleName, operationName = self:_SplitOperationKey(data)
|
||
|
if iconIndex == 1 then
|
||
|
if operationName then
|
||
|
-- duplicate
|
||
|
local num = 1
|
||
|
while TSM.Operations.Exists(moduleName, operationName.." "..num) do
|
||
|
num = num + 1
|
||
|
end
|
||
|
local newOperationName = operationName.." "..num
|
||
|
self:_onOperationAddedHandler(moduleName, newOperationName, operationName)
|
||
|
self:UpdateData()
|
||
|
self:SetSelectedOperation(moduleName, newOperationName)
|
||
|
else
|
||
|
-- add
|
||
|
operationName = "New Operation"
|
||
|
local num = 1
|
||
|
while TSM.Operations.Exists(moduleName, operationName.." "..num) do
|
||
|
num = num + 1
|
||
|
end
|
||
|
operationName = operationName .. " " .. num
|
||
|
self._expandedModule = moduleName
|
||
|
self:_onOperationAddedHandler(moduleName, operationName)
|
||
|
self:UpdateData()
|
||
|
self:SetSelectedOperation(moduleName, operationName)
|
||
|
end
|
||
|
self:Draw()
|
||
|
elseif iconIndex == 2 then
|
||
|
assert(operationName)
|
||
|
-- delete
|
||
|
self:_onOperationDeletedHandler(moduleName, operationName)
|
||
|
self:UpdateData(true)
|
||
|
else
|
||
|
error("Invalid index: "..tostring(iconIndex))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function private.RowOnDoubleClick(row, mouseButton)
|
||
|
if mouseButton ~= "LeftButton" then
|
||
|
return
|
||
|
end
|
||
|
local self = row._scrollingTable
|
||
|
local data = row:GetData()
|
||
|
local moduleName, operationName = self:_SplitOperationKey(data)
|
||
|
if operationName then
|
||
|
return
|
||
|
end
|
||
|
if moduleName == self._selectedOperation then
|
||
|
self:SetSelectedOperation()
|
||
|
else
|
||
|
self:SetSelectedOperation(moduleName, operationName)
|
||
|
end
|
||
|
end
|