After spending two years on web project with Openresty, finally I got time and the new ideas for the Scorpio lib's UI part. This is not an officially introduction, so I'm sorry I can't explain all the details. It's only a preview of my new design.
i. As the first example, I'll show the popup dialog using the Scorpio lib:
Lua Code:
-- The addon is load on demand
LoadAddOn("Scorpio.Widget")
-- from this line, I can use features from Scorpio
Scorpio "Test" ""
-- Declare an async function that will be running in a coroutine
__Async__()
function TestPopup()
print("Hello " .. Input("Please input your name"))
end
TestPopup()
Works like:
ScorpioInput.jpg
So we can use the input result directly, the system also provide
Confirm and
Alert APIs like this. Since the function processed in a coroutine, the Input API can yield the coroutine, and resume it when the user finished his input, this is a trick I used many years in my IGAS lib.
ii. The new idea for the Scorpio UI is come from the HTML+CSS. The HTML only provide the elements and their relationship, we can give different css file to show a very different view with the same HTML.
We can change an element's style based on its type, its class, or the custom settings of itself. Also we can change the element's style from the element's parent(the parent type, class or the parent itself) and the parent's parent, and so on.
With this design pattern, we can split the functionality and the view styles.
Take the Input Popup dialog as an example, its template is a class defined like:
Lua Code:
class "InputDialog" (function(_ENV) -- don't mind the _ENV, it's for Lua 5.2
-- inherit another template class
inherit "Dialog"
-- Bind the child element's script event to the input dialog's new event
-- so press the confirm button of press enter in the inputbox will trigger
-- the input dialog's OnConfirm event
__Bubbling__{ ConfirmButton = "OnClick", InputBox = "OnEnterPressed" }
event "OnConfirm"
-- The close button is defined in the Dialog template class
__Bubbling__{ CancelButton = "OnClick", InputBox = "OnEscapePressed", CloseButton = "OnClick" }
event "OnCancel"
-- __ctor is the constructor of the class, normall used to bind the
-- default event handlers for the elements, but here no use, we
-- need define it so __Template__ have something to bind
--
-- The __Template__ is used to declare the child elements with
-- their types. The key is the child name, the value is the template
-- class.
--
__Template__{
-- The fontstring used to display the message
Message = FontString,
-- The inputbox used to get the user's input
InputBox = InputBox,
-- The confirm button
ConfirmButton = UIPanelButton,
-- The cancel button
CancelButton = UIPanelButton,
}
function __ctor(self) end
end)
There is no texture, font and location settings in the template, so the template only provide the functionality.
Now we can declare the default skin for the template :
Lua Code:
Style.UpdateSkin("Default", {
[InputDialog] = {
Size = Size(360, 130),
Resizable = false,
FrameStrata = "FULLSCREEN_DIALOG",
Location = { Anchor("CENTER") },
-- Childs
Message = {
Location = { Anchor("TOP", 0, -16) },
Width = 290,
DrawLayer = "ARTWORK",
FontObject = GameFontHighlight,
},
InputBox = {
Location = { Anchor("TOP", 0, -50) },
Size = Size(240, 32),
AutoFocus = true,
},
ConfirmButton = {
Text = "Okay",
Location = { Anchor("BOTTOMRIGHT", -4, 16, nil, "BOTTOM") },
Size = Size(90, 20),
},
CancelButton = {
Text = "Cancel",
Location = { Anchor("BOTTOMLEFT", 4, 16, nil, "BOTTOM") },
Size = Size(90, 20),
}
},
})
The skin settings is a little like the xml, we have plenty properties(case ignored) to be set, we don't need set all the properties, like the ConfirmButtons' normal texture, since it's already done in the default skin of the UIPanelButton.
Now, we'll see how to give a new skin for the InputDialog:
Lua Code:
Scorpio "Test" ""
-- Skin must be register first, case ignored
Style.RegisterSkin("Custom", {
[InputDialog] = {
-- inherit the default skin so we don't need to override all
inherit = "Default",
-- Change the backdrop settings
Backdrop = {
edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]],
tile = true, tileSize = 16, edgeSize = 16,
insets = { left = 5, right = 5, top = 5, bottom = 5 }
},
BackdropBorderColor = { r = 0.6, g = 0.6, b = 0.6 },
}
})
-- active the skin for the InputDialog
Style.ActiveSkin("Custom", InputDialog)
When active the custom skin, all InputDialog objects will receive the skin updating:
RegisterSkin.jpg
The updating process is processed in the Scorpio's task schedule system, so it won't freeze the game even if you have thousand ui elements to be updated.
It's a little comple for the class definition, but if we don't need bind those events, we can create a class template very simple:
Lua Code:
-- declare the base template class within the __Template__
-- then declare the elements in the table
__Template__(EditBox)
class "InputBox" {
LeftBG = Texture,
RightBG = Texture,
MiddleBG = Texture,
}
-- The skin part
-- the same of the xml that define the InputBoxTemplate
Style.UpdateSkin("Default", {
[InputBox] = {
FontObject = ChatFontNormal,
LeftBG = {
Atlas = {
atlas = [[common-search-border-left]],
useAtlasSize = false,
},
Location = {
Anchor("TOPLEFT", -5, 0),
Anchor("BOTTOMLEFT", -5, 0),
},
Width = 8,
},
RightBG = {
Atlas = {
atlas = [[common-search-border-right]],
useAtlasSize = false,
},
Location = {
Anchor("TOPRIGHT", 0, 0),
Anchor("BOTTOMRIGHT", 0, 0),
},
Width = 8,
},
MiddleBG = {
Atlas = {
atlas = [[common-search-border-middle]],
useAtlasSize = false,
},
Location = {
Anchor("TOPLEFT", 0, 0, "LeftBG", "TOPRIGHT"),
Anchor("BOTTOMRIGHT", 0, 0, "RightBG", "BOTTOMLEFT"),
}
},
},
})
iii. You can find all the skin properties in
Scorpio.UI.Property.lua, besided the same properties from the UI.xsd like alpha, altas, size. We also can define other useful properties like
Fadeout, it works like
Lua Code:
Scorpio "Test" ""
local dialog = Dialog("Test")
Style[dialog] = {
-- The dialog header settings
Header = {
Text = "Test Fadeout",
},
-- the fade out settings
Fadeout = {
duration = 2, -- the fade out duration
delay = 1, -- the delay when move mouse away from the dialog
stop = 0.2, -- the final alpha
}
}
fadeout.jpg
We can use the Style[obj] to change the object's custom styles. It's not a skin for the class, so only affect the object.
Since there would be too many template classes and properties, a developer tool will be provided like how we inspect the css styles in the Chrome.
For now, it's still under development, the code won't be released to curseforge until most useful template classes are added. So this is only a preview.
[2021-03-24]For now, the first version introduction for the ui style and the unit frame are all done:
003.ui.md
006.unitframe.md