--========================================================-- -- Scorpio UI Basic Widgets -- -- -- -- Author : kurapica125@outlook.com -- -- Create Date : 2019/01/09 -- --========================================================-- --========================================================-- Scorpio "Scorpio.UI.Widget" "1.0.0" --========================================================-- do local UI_PROTOTYPE = {} local function onEventHandlerChanged(delegate, self, name) if not delegate.Hooked and self:HasScript(name) then delegate.Hooked = true self:HookScript(name, function(_, ...) return delegate(self, ...) end) end end ---------------------------------------------- -- Static Methods -- ---------------------------------------------- function Release() for name, ele in pairs(UI_PROTOTYPE) do pcall(ele.SetParent, ele, nil) end wipe(UI_PROTOTYPE) UI_PROTOTYPE = nil InstallPrototype = nil Release = nil collectgarbage() end function InstallPrototype(_ENV, par, ui) local target = Environment.GetNamespace(_ENV) local super = Class.GetSuperClass(target) local frmtype = Namespace.GetNamespaceName(target, true) local new = Class.GetMetaMethod(target, "__new") or function(_, name, parent, ...) return CreateFrame(frmtype, nil, parent, ...) end if not (ui and type(ui) == "table" and ui.GetObjectType and ui:GetObjectType() == frmtype) then ui = nil end if not ui then ui = new(target, nil, frmtype ~= "Frame" and UI_PROTOTYPE[par or UI.Frame] or nil) UI_PROTOTYPE[target]= ui if Class.IsSubType(target, LayoutFrame) then ui:Hide() end end -- Install Events if type(ui.HasScript) == "function" then for _, evt in Enum.GetEnumValues(ScriptsType) do if ui:HasScript(evt) and not Class.GetFeature(super, evt, true) then __EventChangeHandler__(onEventHandlerChanged) _ENV.event(evt) end end end -- Install Methods for name, func in pairs(getmetatable(ui).__index) do _ENV[name] = func end -- Install Constructor _ENV.__new = new end end --- LayoutFrame is the basic type for anything that can occupy an area of the screen __Sealed__()__Abstract__()class"LayoutFrame"(function(_ENV) inherit "UIObject" local _GetPoint = getRealMethodCache("GetPoint") ---------------------------------------------- -- Helpers -- ---------------------------------------------- local function GetPos(self, point, e) local x, y = self:GetCenter() return (strfind(point, "LEFT") and self:GetLeft() or strfind(point, "RIGHT") and self:GetRight() or x) * e, (strfind(point, "TOP") and self:GetTop() or strfind(point, "BOTTOM") and self:GetBottom() or y) * e end ---------------------------------------------- -- Methods -- ---------------------------------------------- --- Gets the anchor point of the given index __Final__() function GetPoint(self, index) local p, f, r, x, y = _GetPoint[getmetatable(self)](self, index) return p, f and GetProxyUI(f), r, x, y end --- Get the region object's location(Type: Anchors), the data is serializable, can be saved directly. -- You can also apply a data of Anchors to get a location based on the data's point, relativeTo and relativePoint settings. __Final__() __Arguments__{}:Throwable() function GetLocation(self) local loc = {} for i = 1, self:GetNumPoints() do local p, f, r, x, y = self:GetPoint(i) if f then f = UIObject.GetRelativeUIName(self, f) if f == false then throw("Usage: LayoutFrame:GetLocation() - The System can't identify the relativeTo frame's name") end end if r == p then r = nil end if x == 0 then x = nil end if y == 0 then y = nil end loc[i] = Anchor(p, x, y, f, r) end return loc end __Final__() __Arguments__{ Anchors }:Throwable() function GetLocation(self, oLoc) local loc = {} local parent = self:GetParent() for i, anchor in ipairs(oLoc) do local relativeTo = anchor.relativeTo local relativeFrame = UIObject.GetRelativeUI(self, relativeTo) if not relativeFrame then local sname = self:GetName(true) if sname then throw("Usage: LayoutFrame:GetLocation(accordingLoc) - The System can't identify the relativeTo frame of " .. sname) else throw("Usage: LayoutFrame:GetLocation(accordingLoc) - The System can't identify the relativeTo frame") end else local e = self:GetEffectiveScale()/UIParent:GetScale() local x, y = GetPos(self, anchor.point, e) local rx, ry = GetPos(relativeFrame, anchor.relativePoint or anchor.point, relativeFrame:GetEffectiveScale()/UIParent:GetScale()) tinsert(loc, Anchor(anchor.point, (x-rx)/e, (y-ry)/e, relativeTo, anchor.relativePoint or anchor.point)) end end return loc end --- Set the region object's location __Final__() __Arguments__{ Anchors }:Throwable() function SetLocation(self, loc) if #loc > 0 then self:ClearAllPoints() for _, anchor in ipairs(loc) do local relativeTo= UIObject.GetRelativeUI(self, anchor.relativeTo) if not relativeTo then local sname = self:GetName(true) if sname then throw("Usage: LayoutFrame:SetLocation(" .. Toolset.tostring(loc) .. ") - The System can't identify the relativeTo frame of " .. sname) else throw("Usage: LayoutFrame:SetLocation(" .. Toolset.tostring(loc) .. ") - The System can't identify the relativeTo frame") end else self:SetPoint(anchor.point, relativeTo, anchor.relativePoint or anchor.point, anchor.x or 0, anchor.y or 0) end end end end ---------------------------------------------- -- Dispose -- ---------------------------------------------- function Dispose(self) self:ClearAllPoints() self:Hide() end end) --- Frame is in many ways the most fundamental widget object. Other types of widget derivatives such as FontStrings, Textures and Animations can only be created attached to a Frame or other derivative of a Frame. __Sealed__() class "Frame" (function(_ENV) inherit(LayoutFrame) InstallPrototype(_ENV) function Dispose(self) self:UnregisterAllEvents() end end) --- FontStrings are one of the two types of LayoutFrame that is visible on the screen. It draws a block of text on the screen using the characteristics in an associated FontObject. __Sealed__() class "FontString" (function(_ENV) inherit(LayoutFrame)__new = function (_, name, parent, layer, inherits, ...) return parent:CreateFontString(nil, layer or "OVERLAY", inherits or "GameFontNormal", ...) end InstallPrototype(_ENV, nil, _G.ZoneTextString) end) --- Textures are visible areas descended from LayoutFrame, that display either a color block, a gradient, or a graphic raster taken from a .tga or .blp file __Sealed__() class "Texture" (function(_ENV) inherit(LayoutFrame)__new = function (_, name, parent, layer, inherits, sublevel) return parent:CreateTexture(nil, layer or "ARTWORK", inherits, sublevel or 0) end InstallPrototype(_ENV, nil, _G.WorldStateScoreFrameSeparator) end) --- MaskTextures are used to mask other textures __Sealed__() class "MaskTexture" (function(_ENV) inherit(Texture) -- Since the mask texture is applied to the texture, but created on texture's owner -- We need expand the SetParent/GetParent to support that local _OriginalParent = {} function __new(_, name, parent, layer, inherits, sublevel) local originalParent = parent while parent and not parent.CreateMaskTexture do parent = parent:GetParent() end local self = parent and parent:CreateMaskTexture(nil, layer or "ARTWORK", inherits, sublevel or 0) if self and parent ~= originalParent then _OriginalParent[self] = originalParent end return self end InstallPrototype(_ENV) local oldGetParent = _ENV.GetParent local oldSetParent = _ENV.SetParent function GetParent(self) return _OriginalParent[self] or oldGetParent(self) end function SetParent(self, parent) local originalParent = parent while parent and not parent.CreateMaskTexture do parent = parent:GetParent() end if originalParent ~= parent then _OriginalParent[self] = originalParent else _OriginalParent[self] = nil end return oldSetParent(self, parent) end end) --- Lines are used to link two anchor points. __Sealed__() class "Line" (function(_ENV) inherit(UIObject) __new = function (_, name, parent, ...) return parent:CreateLine(nil, ...) end InstallPrototype(_ENV) end) ------------------------------------------------------------ -- Animation -- ------------------------------------------------------------ --- An AnimationGroup is how various animations are actually applied to a region; this is how different behaviors can be run in sequence or in parallel with each other, automatically. When you pause an AnimationGroup, it tracks which of its child animations were playing and how far advanced they were, and resumes them from that point. -- An Animation in a group has an order from 1 to 100, which determines when it plays; once all animations with order 1 have completed, including any delays, the AnimationGroup starts all animations with order 2. -- An AnimationGroup can also be set to loop, either repeating from the beginning or playing backward back to the beginning. An AnimationGroup has an OnLoop handler that allows you to call your own code back whenever a loop completes. The :Finish() method stops the animation after the current loop has completed, rather than immediately. __Sealed__() class "AnimationGroup" (function(_ENV) inherit(UIObject) __new = function (_, name, parent, ...) return parent:CreateAnimationGroup(nil, ...) end InstallPrototype(_ENV) end) --- Animations are used to change presentations or other characteristics of a frame or other region over time. The Animation object will take over the work of calling code over time, or when it is done, and tracks how close the animation is to completion. -- The Animation type doesn't create any visual effects by itself, but it does provide an OnUpdate handler that you can use to support specialized time-sensitive behaviors that aren't provided by the transformations descended from Animations. In addition to tracking the passage of time through an elapsed argument, you can query the animation's progress as a 0-1 fraction to determine how you should set your behavior. -- You can also change how the elapsed time corresponds to the progress by changing the smoothing, which creates acceleration or deceleration, or by adding a delay to the beginning or end of the animation. -- You can also use an Animation as a timer, by setting the Animation's OnFinished script to trigger a callback and setting the duration to the desired time. __Sealed__() class "Animation" (function(_ENV) inherit(UIObject) __new = function (_, name, parent, ...) return parent:CreateAnimation("Animation", nil, ...) end InstallPrototype(_ENV, AnimationGroup) end) --- Alpha is a type of animation that automatically changes the transparency level of its attached region as it progresses. You can set the degree by which it will change the alpha as a fraction; for instance, a change of -1 will fade out a region completely __Sealed__() class "Alpha" (function(_ENV) inherit(Animation) __new = function (_, name, parent, ...) return parent:CreateAnimation("Alpha", nil, ...) end InstallPrototype(_ENV, AnimationGroup) end) --- Path is an Animation type that combines multiple transitions into a single control path with multiple ControlPoints. __Sealed__() class "Path" (function(_ENV) inherit(Animation) __new = function (_, name, parent, ...) return parent:CreateAnimation("Path", nil, ...) end InstallPrototype(_ENV, AnimationGroup) end) --- A special type that represent a point in a Path Animation. __Sealed__() class "ControlPoint" (function(_ENV) inherit(UIObject) __new = function (_, name, parent, ...) return parent:CreateControlPoint(nil, ...) end InstallPrototype(_ENV, Path) end) --- Rotation is an Animation that automatically applies an affine rotation to the region being animated. You can set the origin around which the rotation is being done, and the angle of rotation in either degrees or radians. __Sealed__() class "Rotation" (function(_ENV) inherit(Animation) __new = function (_, name, parent, ...) return parent:CreateAnimation("Rotation", nil, ...) end InstallPrototype(_ENV, AnimationGroup) end) --- Scale is an Animation type that automatically applies an affine scalar transformation to the region being animated as it progresses. You can set both the multiplier by which it scales, and the point from which it is scaled. __Sealed__() class "Scale" (function(_ENV) inherit(Animation) __new = function (_, name, parent, ...) return parent:CreateAnimation("Scale", nil, ...) end InstallPrototype(_ENV, AnimationGroup) end) --- LineScale is an Animation type inherit Scale. __Sealed__() class "LineScale" (function(_ENV) inherit(Scale) __new = function (_, name, parent, ...) return parent:CreateAnimation("LineScale", nil, ...) end InstallPrototype(_ENV, AnimationGroup) end) --- Translation is an Animation type that applies an affine translation to its affected region automatically as it progresses. __Sealed__() class "Translation" (function(_ENV) inherit(Animation) __new = function (_, name, parent, ...) return parent:CreateAnimation("Translation", nil, ...) end InstallPrototype(_ENV, AnimationGroup) end) --- LineTranslation is an Animation type that applies an affine translation to its affected Line __Sealed__() class "LineTranslation" (function(_ENV) inherit(Translation)__new = function (_, name, parent, ...) return parent:CreateAnimation("LineTranslation", nil, ...) end InstallPrototype(_ENV, AnimationGroup) end) ------------------------------------------------------------ -- Frame Widgets -- ------------------------------------------------------------ -- ABANDON: ArchaeologyDigSiteFrame, Browser, Checkout, FogOfWarFrame, MovieFrame, QuestPOIFrame, ScenarioPOIFrame, UnitPositionFrame, GameTooltip --- Button is the primary means for users to control the game and their characters. __Sealed__() class "Button" (function(_ENV) inherit(Frame) InstallPrototype(_ENV, nil, _G.SpellBookFrameTabButton1) end) --- CheckButtons are a specialized form of Button; they maintain an on/off state, which toggles automatically when they are clicked, and additional textures for when they are checked, or checked while disabled. __Sealed__() class "CheckButton" (function(_ENV) inherit(Button) InstallPrototype(_ENV, nil, _G.SpellBookSkillLineTab1) end) __Sealed__() class "ColorSelect" (function(_ENV) inherit(Frame) InstallPrototype(_ENV, nil, _G.ColorPickerFrame) end) --- Cooldown is a specialized variety of Frame that displays the little "clock" effect over abilities and buffs. It can be set with its running time, whether it should appear to "fill up" or "empty out", and whether or not there should be a bright edge where it's changing between dim and bright. __ChildProperty__(Frame, "Cooldown") __Sealed__() class "Cooldown" (function(_ENV) inherit(Frame) __new = function(_, name, parent, template, ...) return CreateFrame("Cooldown", nil, parent, template or "CooldownFrameTemplate", ...) end InstallPrototype(_ENV, nil, _G.ActionButton1Cooldown) end) --- EditBoxes are used to allow the player to type text into a UI component. __Sealed__() class "EditBox" (function(_ENV) inherit(Frame) InstallPrototype(_ENV, nil, _G.BagItemSearchBox) end) --- MessageFrames are used to present series of messages or other lines of text, usually stacked on top of each other. __Sealed__() class "MessageFrame" (function(_ENV) inherit(Frame) InstallPrototype(_ENV, nil, _G.UIErrorsFrame) end) --- ScrollFrame is used to show a large body of content through a small window. The ScrollFrame is the size of the "window" through which you want to see the larger content, and it has another frame set as a "ScrollChild" containing the full content. __Sealed__() class "ScrollFrame" (function(_ENV) inherit(Frame) InstallPrototype(_ENV, nil, _G.ReputationListScrollFrame) end) --- The most sophisticated control over text display is offered by SimpleHTML widgets. When its text is set to a string containing valid HTML markup, a SimpleHTML widget will parse the content into its various blocks and sections, and lay the text out. While it supports most common text commands, a SimpleHTML widget accepts an additional argument to most of these; if provided, the element argument will specify the HTML elements to which the new style information should apply, such as formattedText:SetTextColor("h2", 1, 0.3, 0.1) which will cause all level 2 headers to display in red. If no element name is specified, the settings apply to the SimpleHTML widget's default font. __Sealed__() class "SimpleHTML" (function(_ENV) inherit(Frame) InstallPrototype(_ENV, nil, _G.OpenMailBodyText) end) --- Sliders are elements intended to display or allow the user to choose a value in a range. __Sealed__() class "Slider" (function(_ENV) inherit(Frame) InstallPrototype(_ENV, nil, _G.OpacitySliderFrame) end) --- StatusBars are similar to Sliders, but they are generally used for display as they don't offer any tools to receive user input. __Sealed__() class "StatusBar" (function(_ENV) inherit(Frame) InstallPrototype(_ENV, nil, _G.PlayerFrameHealthBar) end) ------------------------------------------------------------ -- Model -- ------------------------------------------------------------ --- Model provide a rendering environment which is drawn into the backdrop of their frame, allowing you to display the contents of an .m2 file and set facing, scale, light and fog information, or run motions associated __Sealed__() class "Model" (function(_ENV) inherit(Frame) InstallPrototype(_ENV) end) --- ModelScene __Sealed__() class "ModelScene" (function(_ENV) inherit(Frame) InstallPrototype(_ENV, nil, _G.AzeriteLevelUpToast and _G.AzeriteLevelUpToast.IconEffect) end) --- PlayerModels are the most commonly used subtype of Model frame. They expand on the Model type by adding functions to quickly set the model to represent a particular player or creature, by unitID or creature ID. __Sealed__() class "PlayerModel" (function(_ENV) inherit(Model) InstallPrototype(_ENV, nil, _G.CharacterModelFrame) end) __Sealed__() class "CinematicModel" (function(_ENV) inherit(PlayerModel) InstallPrototype(_ENV) end) __Sealed__() class "DressUpModel" (function(_ENV) inherit(PlayerModel) InstallPrototype(_ENV, nil, _G.DressUpModel) end) __Sealed__() class "TabardModel" (function(_ENV) inherit(PlayerModel) InstallPrototype(_ENV, nil, _G.TabardModel) end) ------------------------------------------------------------ -- Release -- ------------------------------------------------------------ Release()