You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

465 lines
17 KiB

--========================================================--
-- Scorpio Secure Element Panel --
-- --
-- Author : kurapica125@outlook.com --
-- Create Date : 2020/11/12 --
--========================================================--
--========================================================--
Scorpio "Scorpio.Secure.SecurePanel" "1.0.0"
--========================================================--
-----------------------------------------------------------
-- Secure Element Panel Widget --
-----------------------------------------------------------
__Sealed__()
class "SecurePanel" (function(_ENV)
inherit "SecureFrame" extend "ICountable"
-------------------------------------
-- Secure Manager
-------------------------------------
-- Manager Frame
_ManagerFrame = SecureFrame("Scorpio_SecurePanel_LayoutMananger", UIParent, "SecureHandlerStateTemplate")
_ManagerFrame:Hide()
_ManagerFrame:Execute[[
Manager = self
_Panels = newtable()
_Cache = newtable()
_Map = newtable()
_Queue = newtable()
QueueUpdatePanel = [=[
local panel = _Map[self] or self
local noForce= ...
if not noForce then
_Queue[panel] = false
elseif _Queue[panel] == nil then
_Queue[panel] = true
end
-- Reset the timer
Manager:SetAttribute("state-timer", "reset")
]=]
UnQueueUpdatePanel = [=[
local panel = _Map[self] or self
_Queue[panel] = nil
]=]
UpdatePanelSize = [=[
local noForce = ...
local panel = _Map[self] or self
local elements = _Panels[panel]
local count = 0
local row
local column
local columnCount = panel:GetAttribute("IFSecurePanel_ColumnCount") or 5
local rowCount = panel:GetAttribute("IFSecurePanel_RowCount") or 5
local elementWidth = panel:GetAttribute("IFSecurePanel_ElementWidth") or 16
local elementHeight = panel:GetAttribute("IFSecurePanel_ElementHeight") or 16
local hSpacing = panel:GetAttribute("IFSecurePanel_HSpacing") or 0
local vSpacing = panel:GetAttribute("IFSecurePanel_VSpacing") or 0
local marginTop = panel:GetAttribute("IFSecurePanel_MarginTop") or 0
local marginBottom = panel:GetAttribute("IFSecurePanel_MarginBottom") or 0
local marginLeft = panel:GetAttribute("IFSecurePanel_MarginLeft") or 0
local marginRight = panel:GetAttribute("IFSecurePanel_MarginRight") or 0
local orientation = panel:GetAttribute("IFSecurePanel_Orientation") or "HORIZONTAL"
local leftToRight = panel:GetAttribute("IFSecurePanel_LeftToRight")
local topToBottom = panel:GetAttribute("IFSecurePanel_TopToBottom")
local autoPos = panel:GetAttribute("IFSecurePanel_AutoPosition")
local autoSize = panel:GetAttribute("IFSecurePanel_AutoSize")
if leftToRight == nil then leftToRight = true end
if topToBottom == nil then topToBottom = true end
if autoPos == nil then autoPos = true end
if autoSize== nil then autoSize = true end
if elements then
for i = 1, #elements do
local frm = elements[i]
frm:SetWidth(elementWidth)
frm:SetHeight(elementHeight)
if not autoPos or frm:IsShown() then
local posX = (orientation == "HORIZONTAL" and count % columnCount or floor(count / rowCount)) * (elementWidth + hSpacing)
local posY = (orientation == "HORIZONTAL" and floor(count / columnCount) or count % rowCount) * (elementHeight + vSpacing)
frm:ClearAllPoints()
if topToBottom then
frm:SetPoint("TOP", panel, "TOP", 0, - posY - marginTop)
else
frm:SetPoint("BOTTOM", panel, "BOTTOM", 0, posY + marginBottom)
end
if leftToRight then
frm:SetPoint("LEFT", panel, "LEFT", posX + marginLeft, 0)
else
frm:SetPoint("RIGHT", panel, "RIGHT", - posX - marginRight, 0)
end
count = count + 1
end
end
end
if not panel:GetAttribute("IFSecurePanel_KeepMaxSize") then
if not noForce or autoSize then
if count ~= _Cache[panel] then
_Cache[panel] = count
if orientation == "HORIZONTAL" then
row = ceil(count / columnCount)
column = row == 1 and count or columnCount
else
column = ceil(count / rowCount)
row = column == 1 and count or rowCount
end
if panel:GetAttribute("IFSecurePanel_KeepColumnSize") then
column = columnCount
if row == 0 then row = 1 end
end
if panel:GetAttribute("IFSecurePanel_KeepRowSize") then
row = rowCount
if column == 0 then column = 1 end
end
if row > 0 and column > 0 then
panel:SetWidth(column * elementWidth + (column - 1) * hSpacing + marginLeft + marginRight)
panel:SetHeight(row * elementHeight + (row - 1) * vSpacing + marginTop + marginBottom)
else
panel:SetWidth(1)
panel:SetHeight(1)
end
end
end
else
panel:SetWidth(columnCount * elementWidth + (columnCount - 1) * hSpacing + marginLeft + marginRight)
panel:SetHeight(rowCount * elementHeight + (rowCount - 1) * vSpacing + marginTop + marginBottom)
end
]=]
]]
-- The condition has no real use, just a timer ticker
_ManagerFrame:SetAttribute("_onstate-timer", [=[
if newstate ~= "reset" then
for obj, noForce in pairs(_Queue) do
Manager:RunFor(obj, UpdatePanelSize, noForce)
end
wipe(_Queue)
end
]=])
_ManagerFrame:RegisterStateDriver("timer", "[pet]pet;nopet;")
_RegisterPanel = [=[
local panel = Manager:GetFrameRef("SecurePanel")
if panel and not _Panels[panel] then
_Panels[panel] = newtable()
end
]=]
_UnregisterPanel = [=[
local panel = Manager:GetFrameRef("SecurePanel")
if panel then
_Panels[panel] = nil
_Cache[panel] = nil
end
]=]
_RegisterFrame = [=[
local panel = Manager:GetFrameRef("SecurePanel")
local frame = Manager:GetFrameRef("SecureElement")
if panel and frame then
_Panels[panel] = _Panels[panel] or newtable()
tinsert(_Panels[panel], frame)
_Map[frame] = panel
end
]=]
_UnregisterFrame = [=[
local panel = Manager:GetFrameRef("SecurePanel")
local frame = Manager:GetFrameRef("SecureElement")
_Map[frame] = nil
if panel and frame and _Panels[panel] then
for k, v in ipairs(_Panels[panel]) do
if v == frame then
return tremove(_Panels[panel], k)
end
end
end
]=]
_WrapShow = [[
Manager:RunFor(self, QueueUpdatePanel, true)
]]
_WrapHide = [[
Manager:RunFor(self, QueueUpdatePanel, true)
]]
_UpdatePanelSize = [=[
local panel = Manager:GetFrameRef("SecurePanel")
_Cache[panel] = nil
Manager:RunFor(panel, QueueUpdatePanel)
]=]
_ForceUpdatePanel = [=[
local panel = Manager:GetFrameRef("SecurePanel")
_Cache[panel] = nil
Manager:RunFor(panel, UnQueueUpdatePanel)
Manager:RunFor(panel, UpdatePanelSize)
]=]
local function registerPanel(self)
_ManagerFrame:SetFrameRef("SecurePanel", self)
_ManagerFrame:Execute(_RegisterPanel)
end
local function unregisterPanel(self)
_ManagerFrame:SetFrameRef("SecurePanel", self)
_ManagerFrame:Execute(_UnregisterPanel)
end
local function registerFrame(self, frame)
_ManagerFrame:SetFrameRef("SecurePanel", self)
_ManagerFrame:SetFrameRef("SecureElement", frame)
_ManagerFrame:Execute(_RegisterFrame)
_ManagerFrame:WrapScript(frame, "OnShow", _WrapShow)
_ManagerFrame:WrapScript(frame, "OnHide", _WrapHide)
end
local function unregisterFrame(self, frame)
_ManagerFrame:UnwrapScript(frame, "OnShow")
_ManagerFrame:UnwrapScript(frame, "OnHide")
_ManagerFrame:SetFrameRef("SecurePanel", self)
_ManagerFrame:SetFrameRef("SecureElement", frame)
_ManagerFrame:Execute(_UnregisterFrame)
end
local function secureUpdatePanelSize(self)
_ManagerFrame:SetFrameRef("SecurePanel", self)
_ManagerFrame:Execute(_UpdatePanelSize)
end
local function nextItem(self, index)
index = index + 1
local ele = self[index]
if ele then return index, ele end
end
local function reduce(self, index)
index = index or self.RowCount * self.ColumnCount
if index < self.Count then
for i = self.Count, index + 1, -1 do
local ele = self[i]
self[i] = nil
ele:Hide()
OnElementRemove(self, ele)
self.ElementPool(ele)
self:SetAttribute("IFSecurePanel_Count", i - 1)
end
return secureUpdatePanelSize(self)
end
end
local function generate(self, index)
if self.ElementPool and index > self.Count then
for i = self.Count + 1, index do
local ele = self.ElementPool()
self[i] = ele
ele:SetParent(self)
ele:SetID(i)
ele:Show()
OnElementAdd(self, ele)
self:SetAttribute("IFSecurePanel_Count", i)
end
return secureUpdatePanelSize(self)
end
end
local function handlePropertyChange(self, prop, value)
self:SetAttribute("IFSecurePanel_" .. prop, value)
if prop == "RowCount" or prop == "ColumnCount" then reduce(self) end
return secureUpdatePanelSize(self)
end
local function onPropertyChanged(self, value, old, prop)
return NoCombat(handlePropertyChange, self, prop, value)
end
------------------------------------------------------
-- Event
------------------------------------------------------
-- Fired when an element is added
event "OnElementAdd"
-- Fired when an element is removed
event "OnElementRemove"
------------------------------------------------------
-- Method
------------------------------------------------------
function GetIterator(self, key)
return nextItem, self, tonumber(key) or 0
end
__NoCombat__()
RefreshLayout = secureUpdatePanelSize
function ForceRefreshLayout(self)
if not InCombatLockdown() then
_ManagerFrame:SetFrameRef("SecurePanel", self)
_ManagerFrame:Execute(_ForceUpdatePanel)
end
end
------------------------------------------------------
-- Property
------------------------------------------------------
--- The Element Pool
property "ElementPool" { type = Recycle, default = function(self) return self.ElementType and Recycle(self.ElementType, self.ElementPrefix .. "%d", self) end }
-- The element's type
property "ElementType" { type = ClassType }
-- The prefix for the element's name
property "ElementPrefix" { type = String, default = "Element" }
-- The Element accessor, used like obj.Elements[i].
__Indexer__(NaturalNumber)
property "Elements" {
get = function(self, index)
if index >= 1 and index <= self.ColumnCount * self.RowCount then
if self[index] then return self[index] end
if self.ElementPool and not InCombatLockdown() then
generate(self, index)
return self[index]
else
return nil
end
end
end,
}
-- The columns's count
property "ColumnCount" { type = PositiveNumber, default = 5, handler = onPropertyChanged }
-- The row's count
property "RowCount" { type = PositiveNumber, default = 5, handler = onPropertyChanged }
-- The elements's max count
property "MaxCount" { Get = function(self) return self.ColumnCount * self.RowCount end }
-- The element's width
property "ElementWidth" { type = PositiveNumber, default = 16, handler = onPropertyChanged }
-- The element's height
property "ElementHeight" { type = PositiveNumber, default = 16, handler = onPropertyChanged }
-- The element's count
property "Count" {
get = function(self)
return self:GetAttribute("IFSecurePanel_Count") or 0
end,
set = function(self, cnt)
if cnt > self.RowCount * self.ColumnCount then
error("Count can't be more than "..self.RowCount * self.ColumnCount, 2)
end
if cnt > self.Count then
if self.ElementPool then
NoCombat(generate, self, cnt)
else
error("ElementType not set.", 2)
end
elseif cnt < self.Count then
NoCombat(reduce, self, cnt)
end
end,
type = NaturalNumber,
}
-- The orientation for elements
property "Orientation" { type = Orientation, default = Orientation.HORIZONTAL, handler = onPropertyChanged }
-- Whether the elements start from left to right
property "LeftToRight" { type = Boolean, default = true, handler = onPropertyChanged }
-- Whether the elements start from top to bottom
property "TopToBottom" { type = Boolean, default = true, handler = onPropertyChanged }
-- The horizontal spacing
property "HSpacing" { type = Number, handler = onPropertyChanged }
-- The vertical spacing
property "VSpacing" { type = Number, handler = onPropertyChanged }
-- Whether the elementPanel is autosize
property "AutoSize" { type = Boolean, default = true, handler = onPropertyChanged }
-- The top margin
property "MarginTop" { type = Number, handler = onPropertyChanged }
-- The bottom margin
property "MarginBottom" { type = Number, handler = onPropertyChanged }
-- The left margin
property "MarginLeft" { type = Number, handler = onPropertyChanged }
-- The right margin
property "MarginRight" { type = Number, handler = onPropertyChanged }
-- Whether the elementPanel should keep it's max size
property "KeepMaxSize" { type = Boolean, handler = onPropertyChanged }
-- Whether adjust the elements position automatically
property "AutoPosition" { type = Boolean, default = true, handler = onPropertyChanged }
-- Whether keep the max size for columns
property "KeepColumnSize" { type = Boolean, handler = onPropertyChanged }
-- Whether keep the max size for rows
property "KeepRowSize" { type = Boolean, handler = onPropertyChanged }
------------------------------------------------------
-- Constructor
------------------------------------------------------
function __ctor(self)
self.OnElementAdd = self.OnElementAdd + registerFrame
self.OnElementRemove = self.OnElementRemove + unregisterFrame
registerPanel(self)
end
end)