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.

316 lines
12 KiB

--========================================================--
-- Scorpio Secure UI Framework --
-- --
-- Author : kurapica125@outlook.com --
-- Create Date : 2020/06/04 --
--========================================================--
--========================================================--
Scorpio "Scorpio.Secure" "1.0.0"
--========================================================--
__Sealed__() __Final__() interface "Scorpio.Secure" {}
Environment.RegisterGlobalNamespace("Scorpio.Secure")
namespace "Scorpio.Secure"
import "Scorpio.UI"
-- We can't directly change the secure widgets to the Scorpio UI widget,
-- we can only use the wrapper/origin model, so to define the functions that
-- can be called in the secure snippets, we should use __SecureMethod__ attribute
-- to bind the class object method or the obect method to the secure ui objects
-- so the system can keep those functions defined in the wrapper/origin at the same time
_SecureCallMap = {}
--- The interface that provide the basic features for secure widgets
__Sealed__()__ObjFuncAttr__{ Inheritable= true }
interface "ISecureHandler" (function(_ENV)
local GetRawUI = Scorpio.UI.GetRawUI
local GetProxyUI = Scorpio.UI.GetProxyUI
local GetSuperClass = Class.GetSuperClass
local _RegisterAttributeDriver = RegisterAttributeDriver
local _UnregisterAttributeDriver = UnregisterAttributeDriver
local _RegisterStateDriver = RegisterStateDriver
local _UnregisterStateDriver = UnregisterStateDriver
local _RegisterUnitWatch = RegisterUnitWatch
local _UnregisterUnitWatch = UnregisterUnitWatch
local _UnitWatchRegistered = UnitWatchRegistered
------------------------------------------------------
-- Method
------------------------------------------------------
--- Execute a snippet against a header frame
__Arguments__{ String }
function Execute(self, body)
return SecureHandlerExecute(GetRawUI(self), body)
end
--- Wrap the script on a frame to invoke snippets against a header
__Arguments__{ UI, ScriptsType, String/nil, String/nil }
function WrapScript(self, frame, script, preBody, postBody)
return SecureHandlerWrapScript(GetRawUI(frame), script, GetRawUI(self), preBody, postBody)
end
--- Remove previously applied wrapping, returning its details
__Arguments__{ UI, ScriptsType }
function UnwrapScript(self, frame, script)
return SecureHandlerUnwrapScript(GetRawUI(frame), script)
end
--- Create a frame handle reference and store it against a frame
__Arguments__{ String, UI }
function SetFrameRef(self, label, refFrame)
return SecureHandlerSetFrameRef(GetRawUI(self), label, GetRawUI(refFrame))
end
--- Register a frame attribute to be set automatically with changes in game state
__Arguments__{ String, Any }
function RegisterAttributeDriver(self, attribute, values)
return _RegisterAttributeDriver(GetRawUI(self), attribute, values)
end
--- Unregister a frame from the state driver manager
__Arguments__{ String }
function UnregisterAttributeDriver(self, attribute)
return _UnregisterAttributeDriver(GetRawUI(self), attribute)
end
--- Register a frame state to be set automatically with changes in game state
__Arguments__{ String, Any }
function RegisterStateDriver(self, state, values)
return _RegisterStateDriver(GetRawUI(self), state, values)
end
--- Unregister a frame from the state driver manager
__Arguments__{ String }
function UnregisterStateDriver(self, state)
return _UnregisterStateDriver(GetRawUI(self), state)
end
--- Register a frame to be notified when a unit's existence changes
__Arguments__{ Boolean/nil }
function RegisterUnitWatch(self, asState)
return _RegisterUnitWatch(GetRawUI(self), asState)
end
--- Unregister a frame from the unit existence monitor
function UnregisterUnitWatch(self)
return _UnregisterUnitWatch(GetRawUI(self))
end
--- Check to see if a frame is registered
function IsUnitWatchRegistered(self)
return _UnitWatchRegistered(GetRawUI(self))
end
__Arguments__{ (String + struct { String })/nil } __NoCombat__()
function SetAutoHide(self, conds)
if not conds then
self:UnregisterStateDriver("visibility")
self:Show()
elseif type(conds) == "string" then
conds = conds:match("%b[]")
if conds then
self:RegisterStateDriver("visibility", (conds .. "hide;show"))
else
self:UnregisterStateDriver("visibility")
self:Show()
end
else
local str = ""
for _, cond in ipairs(conds) do
cond = cond:match("%b[]")
if cond then
str = str .. cond .. "hide;"
end
end
if str == "" then
self:UnregisterStateDriver("visibility")
self:Show()
else
self:RegisterStateDriver("visibility", str .. "show")
end
end
end
------------------------------------------------------
-- Initializer
------------------------------------------------------
function __init(self)
local cls = getmetatable(self)
self = GetRawUI(self)
while cls do
local map = _SecureCallMap[cls]
if map then
for name, func in pairs(map) do
self[name] = self[name] or func
end
end
cls = GetSuperClass(cls)
end
end
end)
--- The attribute used to bind functions that be be called by the secure environment
__Sealed__() __Final__()
class "__SecureMethod__" (function(_ENV)
extend "IAttachAttribute"
local GetRawUI = Scorpio.UI.GetRawUI
local GetProxyUI = Scorpio.UI.GetProxyUI
-----------------------------------------------------------
-- method --
-----------------------------------------------------------
function AttachAttribute(self, target, targettype, owner, name, stack)
if targettype == AttributeTargets.Method then
if Class.IsSubType(owner, ISecureHandler) then
local map = _SecureCallMap[owner] or {}
_SecureCallMap[owner] = map
map[name] = function(self, ...)
return target(GetProxyUI(self), ...)
end
end
else
if Class.IsObjectType(owner, ISecureHandler) then
GetRawUI(owner)[name] = function(self, ...)
return target(owner, ...)
end
end
end
end
-----------------------------------------------------------
-- property --
-----------------------------------------------------------
--- the attribute target
property "AttributeTarget" { type = AttributeTargets, default = AttributeTargets.Method + AttributeTargets.Function }
--- the attribute's priority
property "Priority" { type = AttributePriority, default = AttributePriority.Lowest }
end)
--- The attribute used to bind secure template for the class objects
__Sealed__() __Final__()
class "__SecureTemplate__" (function(_ENV)
extend "IAttachAttribute"
local _SecureTemplateMap = {}
local _TempList = List()
function _TempList:Distinct()
self:Sort()
for i = #self, 1, -1 do
if self[i] == self[i - 1] then
self:RemoveByIndex(i)
end
end
return self
end
-----------------------------------------------------------
-- method --
-----------------------------------------------------------
function AttachAttribute(self, target, targettype, owner, name, stack)
if Class.IsSubType(target, ISecureHandler) then
_SecureTemplateMap[target] = self.template
end
end
__Static__() function GetTemplate(cls, template)
local default = _SecureTemplateMap[cls]
while cls and default == nil do
cls = Class.GetSuperClass(cls)
default = cls and _SecureTemplateMap[cls]
end
if default then
_TempList:Clear()
_TempList:Extend(default:gmatch("[%w_]+"))
if type(template) == "string" then
_TempList:Extend(template:gmatch("[%w_]+"))
end
return _TempList:Distinct():Join(",")
elseif type(template) == "string" then
return template
end
end
-----------------------------------------------------------
-- property --
-----------------------------------------------------------
--- the attribute target
property "AttributeTarget" { type = AttributeTargets, default = AttributeTargets.Class }
-----------------------------------------------------------
-- constructor --
-----------------------------------------------------------
__Arguments__{ String/nil }
function __ctor(self, template)
self.template = template or false
end
end)
--- SecureFrame is a root widget class for secure frames
__Sealed__() __SecureTemplate__"SecureFrameTemplate"
class "SecureFrame" {
Frame, ISecureHandler,
__new = function(cls, name, parent, inherits)
local ui = CreateFrame("Frame", name, parent, __SecureTemplate__.GetTemplate(cls, inherits))
local self = { [0] = ui[0] }
UI.RegisterProxyUI(self)
UI.RegisterRawUI(ui)
return self
end
}
--- SecureButton is used as the root widget class for secure buttons
__Sealed__() __SecureTemplate__"SecureActionButtonTemplate"
class "SecureButton" {
Button, ISecureHandler,
__new = function(cls, name, parent, inherits)
local ui = CreateFrame("Button", name, parent, __SecureTemplate__.GetTemplate(cls, inherits))
local self = { [0] = ui[0] }
UI.RegisterProxyUI(self)
UI.RegisterRawUI(ui)
return self
end
}
--- SecureCheckButton is used as the root widget class for secure check buttons
__Sealed__() __SecureTemplate__"SecureActionButtonTemplate"
class "SecureCheckButton" {
CheckButton, ISecureHandler,
__new = function(cls, name, parent, inherits)
local ui = CreateFrame("CheckButton", name, parent, __SecureTemplate__.GetTemplate(cls, inherits))
local self = { [0] = ui[0] }
UI.RegisterProxyUI(self)
UI.RegisterRawUI(ui)
return self
end
}
-----------------------------------------------------------
-- Style Property --
-----------------------------------------------------------
UI.Property {
name = "AutoHide",
type = String + struct { String },
require = { SecureFrame, SecureButton, SecureCheckButton },
set = function(self, val) self:SetAutoHide(val) end,
clear = function(self) self:SetAutoHide(nil) end,
}