initial commit
This commit is contained in:
281
Core/UI/Elements/DividedContainer.lua
Normal file
281
Core/UI/Elements/DividedContainer.lua
Normal file
@@ -0,0 +1,281 @@
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
-- TradeSkillMaster --
|
||||
-- https://tradeskillmaster.com --
|
||||
-- All Rights Reserved - Detailed license information included with addon. --
|
||||
-- ------------------------------------------------------------------------------ --
|
||||
|
||||
--- Divided Container UI Element Class.
|
||||
-- A divided container is a container with two children with a divider between them. It is a subclass of the @{Frame} class.
|
||||
-- @classmod DividedContainer
|
||||
|
||||
local _, TSM = ...
|
||||
local UIElements = TSM.Include("UI.UIElements")
|
||||
local DividedContainer = TSM.Include("LibTSMClass").DefineClass("DividedContainer", TSM.UI.Frame)
|
||||
UIElements.Register(DividedContainer)
|
||||
TSM.UI.DividedContainer = DividedContainer
|
||||
local private = {}
|
||||
local DIVIDER_SIZE = 2
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Public Class Methods
|
||||
-- ============================================================================
|
||||
|
||||
function DividedContainer.__init(self)
|
||||
self.__super:__init()
|
||||
self._leftChild = nil
|
||||
self._rightChild = nil
|
||||
self._resizeStartX = nil
|
||||
self._resizeOffset = 0
|
||||
self._contextTable = nil
|
||||
self._defaultContextTable = nil
|
||||
self._minLeftWidth = nil
|
||||
self._minRightWidth = nil
|
||||
end
|
||||
|
||||
function DividedContainer.Acquire(self)
|
||||
self.__super:AddChildNoLayout(UIElements.New("Frame", "leftEmpty")
|
||||
:AddAnchor("TOPLEFT")
|
||||
:AddAnchor("BOTTOMRIGHT", "divider", "BOTTOMLEFT")
|
||||
)
|
||||
self.__super:AddChild(UIElements.New("Button", "divider")
|
||||
:SetSize(DIVIDER_SIZE, nil)
|
||||
:SetHitRectInsets(-2, -2, 0, 0)
|
||||
:SetRelativeLevel(2)
|
||||
:EnableRightClick()
|
||||
:SetScript("OnMouseDown", private.HandleOnMouseDown)
|
||||
:SetScript("OnMouseUp", private.HandleOnMouseUp)
|
||||
:SetScript("OnClick", private.HandleOnClick)
|
||||
:SetScript("OnUpdate", private.HandleOnUpdate)
|
||||
)
|
||||
self.__super:AddChildNoLayout(UIElements.New("Frame", "rightEmpty")
|
||||
:AddAnchor("TOPLEFT", "divider", "TOPRIGHT")
|
||||
:AddAnchor("BOTTOMRIGHT")
|
||||
)
|
||||
self.__super:Acquire()
|
||||
self.__super:SetLayout("HORIZONTAL")
|
||||
end
|
||||
|
||||
function DividedContainer.Release(self)
|
||||
self._isVertical = false
|
||||
self._leftChild = nil
|
||||
self._rightChild = nil
|
||||
self._resizeStartX = nil
|
||||
self._resizeOffset = 0
|
||||
self._contextTable = nil
|
||||
self._defaultContextTable = nil
|
||||
self._minLeftWidth = nil
|
||||
self._minRightWidth = nil
|
||||
self.__super:Release()
|
||||
end
|
||||
|
||||
function DividedContainer.SetVertical(self)
|
||||
assert(not self._leftChild and not self._rightChild and not self._isVertical)
|
||||
self._isVertical = true
|
||||
self:GetElement("leftEmpty")
|
||||
:WipeAnchors()
|
||||
:AddAnchor("TOPLEFT")
|
||||
:AddAnchor("BOTTOMRIGHT", "divider", "TOPRIGHT")
|
||||
self:GetElement("divider")
|
||||
:SetSize(nil, DIVIDER_SIZE)
|
||||
:SetHitRectInsets(0, 0, -2, -2)
|
||||
self:GetElement("rightEmpty")
|
||||
:WipeAnchors()
|
||||
:AddAnchor("TOPLEFT", "divider", "BOTTOMLEFT")
|
||||
:AddAnchor("BOTTOMRIGHT")
|
||||
self.__super:SetLayout("VERTICAL")
|
||||
return self
|
||||
end
|
||||
|
||||
function DividedContainer.SetLayout(self, layout)
|
||||
error("DividedContainer doesn't support this method")
|
||||
end
|
||||
|
||||
function DividedContainer.AddChild(self, child)
|
||||
error("DividedContainer doesn't support this method")
|
||||
end
|
||||
|
||||
function DividedContainer.AddChildBeforeById(self, beforeId, child)
|
||||
error("DividedContainer doesn't support this method")
|
||||
end
|
||||
|
||||
--- Sets the context table.
|
||||
-- This table can be used to preserve the divider position across lifecycles of the divided container and even WoW
|
||||
-- sessions if it's within the settings DB. The position is stored as the width of the left child element.
|
||||
-- @tparam DividedContainer self The divided container object
|
||||
-- @tparam table tbl The context table
|
||||
-- @tparam table defaultTbl The default table (required fields: `leftWidth`)
|
||||
-- @treturn DividedContainer The divided container object
|
||||
function DividedContainer.SetContextTable(self, tbl, defaultTbl)
|
||||
assert(defaultTbl.leftWidth > 0)
|
||||
tbl.leftWidth = tbl.leftWidth or defaultTbl.leftWidth
|
||||
self._contextTable = tbl
|
||||
self._defaultContextTable = defaultTbl
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the context table from a settings object.
|
||||
-- @tparam DividedContainer self The divided container object
|
||||
-- @tparam Settings settings The settings object
|
||||
-- @tparam string key The setting key
|
||||
-- @treturn DividedContainer The divided container object
|
||||
function DividedContainer.SetSettingsContext(self, settings, key)
|
||||
return self:SetContextTable(settings[key], settings:GetDefaultReadOnly(key))
|
||||
end
|
||||
|
||||
--- Sets the minimum width of the child element.
|
||||
-- @tparam DividedContainer self The divided container object
|
||||
-- @tparam number minLeftWidth The minimum width of the left child element
|
||||
-- @tparam number minRightWidth The minimum width of the right child element
|
||||
-- @treturn DividedContainer The divided container object
|
||||
function DividedContainer.SetMinWidth(self, minLeftWidth, minRightWidth)
|
||||
self._minLeftWidth = minLeftWidth
|
||||
self._minRightWidth = minRightWidth
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the left child element.
|
||||
-- @tparam DividedContainer self The divided container object
|
||||
-- @tparam Element child The left child element
|
||||
-- @treturn DividedContainer The divided container object
|
||||
function DividedContainer.SetLeftChild(self, child)
|
||||
assert(not self._isVertical and not self._leftChild and child)
|
||||
self._leftChild = child
|
||||
self.__super:AddChildBeforeById("divider", child)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the right child element.
|
||||
-- @tparam DividedContainer self The divided container object
|
||||
-- @tparam Element child The right child element
|
||||
-- @treturn DividedContainer The divided container object
|
||||
function DividedContainer.SetRightChild(self, child)
|
||||
assert(not self._isVertical and not self._rightChild and child)
|
||||
self._rightChild = child
|
||||
self.__super:AddChild(child)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the top child element in vertical mode.
|
||||
-- @tparam DividedContainer self The divided container object
|
||||
-- @tparam Element child The top child element
|
||||
-- @treturn DividedContainer The divided container object
|
||||
function DividedContainer.SetTopChild(self, child)
|
||||
assert(self._isVertical and not self._leftChild and child)
|
||||
self._leftChild = child
|
||||
self.__super:AddChildBeforeById("divider", child)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the bottom child element in vertical mode.
|
||||
-- @tparam DividedContainer self The divided container object
|
||||
-- @tparam Element child The bottom child element
|
||||
-- @treturn DividedContainer The divided container object
|
||||
function DividedContainer.SetBottomChild(self, child)
|
||||
assert(self._isVertical and not self._rightChild and child)
|
||||
self._rightChild = child
|
||||
self.__super:AddChild(child)
|
||||
return self
|
||||
end
|
||||
|
||||
function DividedContainer.Draw(self)
|
||||
assert(self._contextTable and self._minLeftWidth and self._minRightWidth)
|
||||
self.__super.__super.__super:Draw()
|
||||
self:GetElement("divider")
|
||||
:SetBackground("ACTIVE_BG")
|
||||
:SetHighlightEnabled(true)
|
||||
|
||||
local width = self:_GetDimension(self._isVertical and "HEIGHT" or "WIDTH") - DIVIDER_SIZE
|
||||
local leftWidth = self._contextTable.leftWidth + self._resizeOffset
|
||||
local rightWidth = width - leftWidth
|
||||
if rightWidth < self._minRightWidth then
|
||||
leftWidth = width - self._minRightWidth
|
||||
assert(leftWidth >= self._minLeftWidth)
|
||||
elseif leftWidth < self._minLeftWidth then
|
||||
leftWidth = self._minLeftWidth
|
||||
end
|
||||
self._contextTable.leftWidth = leftWidth - self._resizeOffset
|
||||
|
||||
local leftChild = self._leftChild
|
||||
local rightChild = self._rightChild
|
||||
local leftEmpty = self:GetElement("leftEmpty")
|
||||
local rightEmpty = self:GetElement("rightEmpty")
|
||||
if self._isVertical then
|
||||
leftEmpty:SetHeight(leftWidth)
|
||||
leftChild:SetHeight(leftWidth)
|
||||
else
|
||||
leftEmpty:SetWidth(leftWidth)
|
||||
leftChild:SetWidth(leftWidth)
|
||||
end
|
||||
if self._resizeStartX then
|
||||
leftChild:_GetBaseFrame():SetAlpha(0)
|
||||
leftChild:_GetBaseFrame():SetFrameStrata("LOW")
|
||||
rightChild:_GetBaseFrame():SetAlpha(0)
|
||||
rightChild:_GetBaseFrame():SetFrameStrata("LOW")
|
||||
leftEmpty:Show()
|
||||
rightEmpty:Show()
|
||||
else
|
||||
leftChild:_GetBaseFrame():SetAlpha(1)
|
||||
leftChild:_GetBaseFrame():SetFrameStrata(self:_GetBaseFrame():GetFrameStrata())
|
||||
rightChild:_GetBaseFrame():SetAlpha(1)
|
||||
rightChild:_GetBaseFrame():SetFrameStrata(self:_GetBaseFrame():GetFrameStrata())
|
||||
leftEmpty:Hide()
|
||||
rightEmpty:Hide()
|
||||
end
|
||||
|
||||
self.__super:Draw()
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- Private Helper Functions
|
||||
-- ============================================================================
|
||||
|
||||
function private.HandleOnUpdate(handle)
|
||||
local self = handle:GetParentElement()
|
||||
if self._resizeStartX then
|
||||
if self._isVertical then
|
||||
local currY = select(2, GetCursorPosition()) / self:_GetBaseFrame():GetEffectiveScale()
|
||||
self._resizeOffset = self._resizeStartX - currY
|
||||
else
|
||||
local currX = GetCursorPosition() / self:_GetBaseFrame():GetEffectiveScale()
|
||||
self._resizeOffset = currX - self._resizeStartX
|
||||
end
|
||||
self:Draw()
|
||||
end
|
||||
end
|
||||
|
||||
function private.HandleOnMouseDown(handle, mouseButton)
|
||||
if mouseButton ~= "LeftButton" then
|
||||
return
|
||||
end
|
||||
local self = handle:GetParentElement()
|
||||
if self._isVertical then
|
||||
self._resizeStartX = select(2, GetCursorPosition()) / self:_GetBaseFrame():GetEffectiveScale()
|
||||
else
|
||||
self._resizeStartX = GetCursorPosition() / self:_GetBaseFrame():GetEffectiveScale()
|
||||
end
|
||||
self._resizeOffset = 0
|
||||
end
|
||||
|
||||
function private.HandleOnMouseUp(handle, mouseButton)
|
||||
if mouseButton ~= "LeftButton" then
|
||||
return
|
||||
end
|
||||
local self = handle:GetParentElement()
|
||||
self._contextTable.leftWidth = max(self._contextTable.leftWidth + self._resizeOffset, self._minLeftWidth)
|
||||
self._resizeOffset = 0
|
||||
self._resizeStartX = nil
|
||||
self:Draw()
|
||||
end
|
||||
|
||||
function private.HandleOnClick(handle, mouseButton)
|
||||
if mouseButton ~= "RightButton" then
|
||||
return
|
||||
end
|
||||
local self = handle:GetParentElement()
|
||||
self._contextTable.leftWidth = self._defaultContextTable.leftWidth
|
||||
self:Draw()
|
||||
end
|
||||
Reference in New Issue
Block a user