new() doesn't need to be a class method

This commit is contained in:
Hersi 2022-04-27 02:40:22 +02:00
parent 3ea1429eab
commit 9937f56a4d
26 changed files with 111 additions and 104 deletions

View File

@ -1,3 +1,7 @@
---Member lookup helper function
---@param key string
---@param bases any
---@return any
local function search(key, bases)
for _, base in ipairs(bases) do
local v = base[key] -- try `i'-th superclass
@ -5,25 +9,27 @@ local function search(key, bases)
end
end
---Declare table as polimorphic class
---Create polimorphic class
---@generic BaseT, T
---@param cls T # class metatable
---@param o? table # initial parameters
---@param ... BaseT # base class metatables (if any)
---@return T # class instance
function CreateClass(cls, o, ...)
function CreateInstance(cls, o, ...)
o = o or {}
local nargs = select("#", ...)
local vargs = { select(1, ...) }
cls.__index = cls
if nargs == 1 then
-- single inheritance
local base = vargs[1]
setmetatable(cls, {__index = base})
o = base:new(o)
o = base.new(o)
elseif nargs > 1 then
-- multiple inheritance (note: slow(er) member lookup)
setmetatable(cls, {__index = function(t, k) return search(k, vargs) end})
for _, base in ipairs(vargs) do
o = base:new(o)
o = base.new(o)
end
end
setmetatable(o, cls)

View File

@ -10,14 +10,14 @@ local ContainerField = {
---Create a new ContainerField instance
---@param o? table # initial parameters
---@return ContainerField
function ContainerField:new(o)
function ContainerField.new(o)
o = o or {}
--set instance members
o.content = o.content or {}
local this = CreateClass(self, o, Field)
local this = CreateInstance(ContainerField, o, Field)
this:refreshFields()

View File

@ -13,7 +13,7 @@ local Field = {
---Create a new Field instance
---@param o? table # initial parameters
---@return Field
function Field:new(o)
function Field.new(o)
o = o or {}
--set instance members
@ -24,7 +24,7 @@ function Field:new(o)
o.aabbW = o.aabbW or 0
o.aabbH = o.aabbH or 0
return CreateClass(self, o)
return CreateInstance(Field, o)
end
---Get the containing top-level parent page

View File

@ -10,12 +10,12 @@ local LinkField = {
---Create a new LinkField instance
---@param o? table # initial parameters
---@return LinkField
function LinkField:new(o)
function LinkField.new(o)
o = o or {}
o.link = o.link or nil
return CreateClass(self, o, Field)
return CreateInstance(LinkField, o, Field)
end
---@param button integer # options are under the `game` table prefixed with `BUTTON`

View File

@ -11,7 +11,7 @@ local Page = {
---Create a new Page instance
---@param o? table # initial parameters
---@return Page
function Page:new(o)
function Page.new(o)
o = o or {}
--set instance members
@ -19,7 +19,7 @@ function Page:new(o)
o.content = o.content or {}
o.viewHandler = o.viewHandler or nil
return CreateClass(self, o)
return CreateInstance(Page, o)
end
---Add field to page

View File

@ -17,7 +17,7 @@ end
---Create a new PageView instance
---@param rootPage Page
---@return PageView
function PageView:new(rootPage)
function PageView.new(rootPage)
local o = {}
--set viewHandler as this instance for rootPage
@ -29,7 +29,7 @@ function PageView:new(rootPage)
o.pageStack = {}
pushStack(o.pageStack, rootPage)
return CreateClass(self, o)
return CreateInstance(PageView, o)
end
---Get page from pageStack

View File

@ -3,8 +3,8 @@ local Wallpaper = require("components.wallpaper")
local BootPage = require("titlescreen.pages.boot.bootpage")
local PageView = require("components.pager.pageview")
local bootpage = BootPage:new()
local pageview = PageView:new(bootpage)
local bootpage = BootPage.new()
local pageview = PageView.new(bootpage)
local function render(deltaTime)
Dim.updateResolution()

View File

@ -14,13 +14,13 @@ local CheckUpdateField = {
---Create a new CheckUpdateField instance
---@param o? table # initial parameters
---@return CheckUpdateField
function CheckUpdateField:new(o)
function CheckUpdateField.new(o)
o = o or {}
o._timer = o._timer or 0
o.onUpdateAvailable = o.onUpdateAvailable or nil
local this = CreateClass(self, o, ServiceField)
local this = CreateInstance(CheckUpdateField, o, ServiceField)
this._url = nil
this._version = nil

View File

@ -37,13 +37,13 @@ local DialogField = {
---Inherits from ContainerField
---@param o ContainerField
---@return DialogField
function DialogField:new(o)
function DialogField.new(o)
o = o or {}
o.aabbW = o.aabbW or self.DEFAULT_WIDTH
o.aabbH = o.aabbH or self.DEFAULT_HEIGHT
o.aabbW = o.aabbW or DialogField.DEFAULT_WIDTH
o.aabbH = o.aabbH or DialogField.DEFAULT_HEIGHT
local this = CreateClass(self, o, ContainerField)
local this = CreateInstance(DialogField, o, ContainerField)
this._symbolMargin = 8
this._symbolSize = 48

View File

@ -34,7 +34,7 @@ local SelfTestField = {
---Create a new SelfTestField instance
---@param o? table
---@return SelfTestField
function SelfTestField:new(o)
function SelfTestField.new(o)
o = o or {}
o.status = o.status or SelfTestStatusEnum.IDLE
@ -45,7 +45,7 @@ function SelfTestField:new(o)
"Failed to construct SelfTestField, checkTask is mandatory when onStatusChange is defined!\n" .. debug.traceback()
)
return CreateClass(self, o, ServiceField)
return CreateInstance(SelfTestField, o, ServiceField)
end
function SelfTestField:_closeThread()

View File

@ -13,12 +13,12 @@ local ColorGradientField = {
---Create a new ColorGradientField instance
---@param o? table # initial parameters
---@return ColorGradientField
function ColorGradientField:new(o)
function ColorGradientField.new(o)
o = o or {}
o.value = o.value or {0, 0, 0, 255}
return CreateClass(self, o, ServiceField)
return CreateInstance(ColorGradientField, o, ServiceField)
end
---@param obj? any # message object for the field

View File

@ -10,12 +10,12 @@ local InputButtonField = {
---Create a new InputButtonField instance
---@param o? table # initial parameters
---@return InputButtonField
function InputButtonField:new(o)
function InputButtonField.new(o)
o = o or {}
o.button = o.button or nil
return CreateClass(self, o, ServiceField)
return CreateInstance(InputButtonField, o, ServiceField)
end
---@param obj? any # message object for the field

View File

@ -18,12 +18,12 @@ local InputKnobField = {
---Create a new InputKnobField instance
---@param o? table # initial parameters
---@return InputKnobField
function InputKnobField:new(o)
function InputKnobField.new(o)
o = o or {}
o.knob = o.knob or nil
return CreateClass(self, o, ServiceField)
return CreateInstance(InputKnobField, o, ServiceField)
end
---@param obj? any # message object for the field

View File

@ -15,14 +15,14 @@ local ListField = {
---Create a new ListField instance
---@param o? table # initial parameters
---@return ListField
function ListField:new(o)
function ListField.new(o)
o = o or {}
--set instance members
o.selectedIndex = o.selectedIndex or 1
o.locked = o.locked or false
local this = CreateClass(self, o, ContainerField, ServiceField)
local this = CreateInstance(ListField, o, ContainerField, ServiceField)
local minW = this.MARGIN[1] + this.PADDING[1] + this.PADDING[3] + this.MARGIN[3]
local minH = this.MARGIN[2] + this.PADDING[2] + this.PADDING[4] + this.MARGIN[4]

View File

@ -35,10 +35,10 @@ local ServiceField = {
---Create a new ServiceField instance
---@param o? table # initial parameters
---@return ServiceField
function ServiceField:new(o)
function ServiceField.new(o)
o = o or {}
local h = self.FONT_SIZE + self.MARGIN[2] + self.MARGIN[4]
local h = ServiceField.FONT_SIZE + ServiceField.MARGIN[2] + ServiceField.MARGIN[4]
o.aabbH = o.aabbH or h
o.aabbW = o.aabbW or Dim.design.width --:shrug:
@ -49,7 +49,7 @@ function ServiceField:new(o)
o._state = ServiceFieldState.INACTIVE
local this = CreateClass(self, o, Field)
local this = CreateInstance(ServiceField, o, Field)
if this.aabbH < h then
this.aabbH = h

View File

@ -10,10 +10,10 @@ local ServiceLinkField = {
---Create a new ServiceLinkField instance
---@param o? table # initial parameters
---@return ServiceLinkField
function ServiceLinkField:new(o)
function ServiceLinkField.new(o)
o = o or {}
return CreateClass(self, o, ServiceField, LinkField)
return CreateInstance(ServiceLinkField, o, ServiceField, LinkField)
end
---@param deltaTime number # frametime in seconds

View File

@ -15,12 +15,12 @@ local UpdateField = {
---Create a new UpdateField instance
---@param o? table # initial parameters
---@return UpdateField
function UpdateField:new(o)
function UpdateField.new(o)
o = o or {}
o._timer = 0
return CreateClass(self, o, ServiceField)
return CreateInstance(UpdateField, o, ServiceField)
end
---@param obj? any # message object for the field

View File

@ -16,18 +16,18 @@ local BootPage = {
---Create a new BootPage instance
---@param o? table # initial parameters
---@return BootPage
function BootPage:new(o)
function BootPage.new(o)
o = o or {}
local this = CreateClass(self, o, Page)
local this = CreateInstance(BootPage, o, Page)
this._networkResult = {}
this:addField(ServiceField:new{posX = 32, posY = 32, label = Version.getLongVersion(), value = ""})
this:addField(ServiceField:new{posX = 64, posY = 64, label = "UNNAMED SDVX CLONE STARTUP...", value = ""})
this:addField(ServiceField.new{posX = 32, posY = 32, label = Version.getLongVersion(), value = ""})
this:addField(ServiceField.new{posX = 64, posY = 64, label = "UNNAMED SDVX CLONE STARTUP...", value = ""})
local valueOffX = 220
this._mainIoTestField = SelfTestField:new{label = "MAIN I/O", VALUE_OFFSETX = valueOffX}
this._mainIoTestField = SelfTestField.new{label = "MAIN I/O", VALUE_OFFSETX = valueOffX}
this._mainIoTestField.checkTask = function(obj)
return SelfTestStatusEnum.OK
end
@ -37,7 +37,7 @@ function BootPage:new(o)
end
end
this._skinConfigTestField = SelfTestField:new{label = "SKIN CONFIG", VALUE_OFFSETX = valueOffX}
this._skinConfigTestField = SelfTestField.new{label = "SKIN CONFIG", VALUE_OFFSETX = valueOffX}
this._skinConfigTestField.checkTask = function(obj)
local crewpath = "skins/" .. game.GetSkin() .. "/textures/crew/anim/" .. game.GetSkinSetting("single_idol")
if not IsDir(crewpath) then
@ -51,7 +51,7 @@ function BootPage:new(o)
end
end
this._networkTestField = SelfTestField:new{label = "NETWORK", VALUE_OFFSETX = valueOffX}
this._networkTestField = SelfTestField.new{label = "NETWORK", VALUE_OFFSETX = valueOffX}
-- set up async network check
this._networkTestField.checkTask = function(obj)
local status = SelfTestStatusEnum.INPROGRESS
@ -77,12 +77,12 @@ function BootPage:new(o)
IR.Heartbeat(function(res) this._networkResult = res end) -- IR doesn't like being called in a coroutine
elseif status == SelfTestStatusEnum.PASS or status == SelfTestStatusEnum.OK then
if this.viewHandler then
this.viewHandler:navigate(CheckUpdatePage:new())
this.viewHandler:navigate(CheckUpdatePage.new())
end
end
end
local list = ListField:new{posX = 64, posY = 96}
local list = ListField.new{posX = 64, posY = 96}
list:addField(this._mainIoTestField)
list:addField(this._skinConfigTestField)
list:addField(this._networkTestField)

View File

@ -13,14 +13,14 @@ local CheckUpdatePage = {
---Create a new CheckUpdatePage instance
---@param o? table # initial parameters
---@return CheckUpdatePage
function CheckUpdatePage:new(o)
local this = CreateClass(self, o, Page)
function CheckUpdatePage.new(o)
local this = CreateInstance(CheckUpdatePage, o, Page)
local width = DialogField.DEFAULT_WIDTH
local height = DialogField.DEFAULT_HEIGHT
local posX = (Dim.design.width - width) / 2
local posY = (Dim.design.height - height) / 2
this._updateDialogField = DialogField:new{
this._updateDialogField = DialogField.new{
posX = posX,
posY = posY,
aabbW = width,
@ -54,16 +54,17 @@ function CheckUpdatePage:new(o)
return true
elseif button == game.BUTTON_STA then
-- NOTE: this is a huge ass hack, please rethink
local pageview = this.viewHandler
local MainMenuPage = require("titlescreen.pages.service.mainmenupage")
local VersionInfoPage = require("titlescreen.pages.service.versioninfopage")
pageview:replace(MainMenuPage:new())
pageview:navigate(VersionInfoPage:new())
this.viewHandler:replace(MainMenuPage.new())
this.viewHandler:navigate(VersionInfoPage.new())
return true
end
return false
end
this._checkUpdateField = CheckUpdateField:new{posX = 32, posY = 64, label = "update check"}
this._checkUpdateField = CheckUpdateField.new{posX = 32, posY = 64, label = "update check"}
this._checkUpdateField.onUpdateAvailable = function(url, version)
this:addField(this._updateDialogField)
this._focusedField = this._updateDialogField

View File

@ -21,7 +21,7 @@ local ColorCheckPage = {
---Create a new ColorCheckPage instance
---@param o? table # initial parameters
---@return ColorCheckPage
function ColorCheckPage:new(o)
function ColorCheckPage.new(o)
o = o or {}
o.title = o.title or "COLOR CHECK"
@ -30,17 +30,17 @@ function ColorCheckPage:new(o)
"BACK BUTTON = EXIT"
}
local this = CreateClass(self, o, ServicePage)
local this = CreateInstance(ColorCheckPage, o, ServicePage)
local height = self.GRADIENT_SPACING
local list = ListField:new()
list:addField(ColorGradientField:new{label = "RED", value = {255, 0, 0, 255}, aabbH = height})
list:addField(ColorGradientField:new{label = "YELLOW", value = {255, 255, 0, 255}, aabbH = height})
list:addField(ColorGradientField:new{label = "GREEN", value = {0, 255, 0, 255}, aabbH = height})
list:addField(ColorGradientField:new{label = "CYAN", value = {0, 255, 255, 255}, aabbH = height})
list:addField(ColorGradientField:new{label = "BLUE", value = {0, 0, 255, 255}, aabbH = height})
list:addField(ColorGradientField:new{label = "MAGENTA", value = {255, 0, 255, 255}, aabbH = height})
list:addField(ColorGradientField:new{label = "WHITE", value = {255, 255, 255, 255}, aabbH = height})
local height = ColorCheckPage.GRADIENT_SPACING
local list = ListField.new()
list:addField(ColorGradientField.new{label = "RED", value = {255, 0, 0, 255}, aabbH = height})
list:addField(ColorGradientField.new{label = "YELLOW", value = {255, 255, 0, 255}, aabbH = height})
list:addField(ColorGradientField.new{label = "GREEN", value = {0, 255, 0, 255}, aabbH = height})
list:addField(ColorGradientField.new{label = "CYAN", value = {0, 255, 255, 255}, aabbH = height})
list:addField(ColorGradientField.new{label = "BLUE", value = {0, 0, 255, 255}, aabbH = height})
list:addField(ColorGradientField.new{label = "MAGENTA", value = {255, 0, 255, 255}, aabbH = height})
list:addField(ColorGradientField.new{label = "WHITE", value = {255, 255, 255, 255}, aabbH = height})
list:refreshFields()
this:addField(list)

View File

@ -12,24 +12,24 @@ local InputCheckPage = {
---Create a new InputCheckPage instance
---@param o? table # initial parameters
---@return InputCheckPage
function InputCheckPage:new(o)
function InputCheckPage.new(o)
o = o or {}
o.title = o.title or "INPUT CHECK"
o.footer = o.footer or "BACK BUTTON = EXIT"
local this = CreateClass(self, o, ServicePage)
local this = CreateInstance(InputCheckPage, o, ServicePage)
local list = ListField:new()
list:addField(InputButtonField:new{label="START BUTTON", button=game.BUTTON_STA})
list:addField(InputButtonField:new{label="A BUTTON", button=game.BUTTON_BTA})
list:addField(InputButtonField:new{label="B BUTTON", button=game.BUTTON_BTB})
list:addField(InputButtonField:new{label="C BUTTON", button=game.BUTTON_BTC})
list:addField(InputButtonField:new{label="D BUTTON", button=game.BUTTON_BTD})
list:addField(InputButtonField:new{label="FX L BUTTON", button=game.BUTTON_FXL})
list:addField(InputButtonField:new{label="FX R BUTTON", button=game.BUTTON_FXR})
list:addField(InputKnobField:new{label="ANALOG VOLUME L", knob=0})
list:addField(InputKnobField:new{label="ANALOG VOLUME R", knob=1})
local list = ListField.new()
list:addField(InputButtonField.new{label="START BUTTON", button=game.BUTTON_STA})
list:addField(InputButtonField.new{label="A BUTTON", button=game.BUTTON_BTA})
list:addField(InputButtonField.new{label="B BUTTON", button=game.BUTTON_BTB})
list:addField(InputButtonField.new{label="C BUTTON", button=game.BUTTON_BTC})
list:addField(InputButtonField.new{label="D BUTTON", button=game.BUTTON_BTD})
list:addField(InputButtonField.new{label="FX L BUTTON", button=game.BUTTON_FXL})
list:addField(InputButtonField.new{label="FX R BUTTON", button=game.BUTTON_FXR})
list:addField(InputKnobField.new{label="ANALOG VOLUME L", knob=0})
list:addField(InputKnobField.new{label="ANALOG VOLUME R", knob=1})
list:refreshFields()
this:addField(list)

View File

@ -15,18 +15,18 @@ local MainMenuPage = {
---Create a new MainMenuPage instance
---@param o? table # initial parameters
---@return MainMenuPage
function MainMenuPage:new(o)
function MainMenuPage.new(o)
o = o or {}
o.title = o.title or "MAIN MENU"
local this = CreateClass(self, o, ServicePage)
local this = CreateInstance(MainMenuPage, o, ServicePage)
local list = ListField:new()
list:addField(ServiceLinkField:new{label = "INPUT CHECK", link = InputCheckPage:new()})
list:addField(ServiceLinkField:new{label = "SCREEN CHECK", link = ScreenCheckPage:new()})
list:addField(ServiceLinkField:new{label = "COLOR CHECK", link = ColorCheckPage:new()})
list:addField(ServiceLinkField:new{label = "VERSION INFORMATION", link = VersionInfoPage:new()})
local list = ListField.new()
list:addField(ServiceLinkField.new{label = "INPUT CHECK", link = InputCheckPage.new()})
list:addField(ServiceLinkField.new{label = "SCREEN CHECK", link = ScreenCheckPage.new()})
list:addField(ServiceLinkField.new{label = "COLOR CHECK", link = ColorCheckPage.new()})
list:addField(ServiceLinkField.new{label = "VERSION INFORMATION", link = VersionInfoPage.new()})
list:refreshFields()
this:addField(list)

View File

@ -19,7 +19,7 @@ local ScreenCheckPage = {
---Create a new ScreenCheckPage instance
---@param o? table # initial parameters
---@return ScreenCheckPage
function ScreenCheckPage:new(o)
function ScreenCheckPage.new(o)
o = o or {}
o.title = o.title or "SCREEN CHECK"
@ -28,7 +28,7 @@ function ScreenCheckPage:new(o)
"BACK BUTTON = EXIT"
}
return CreateClass(self, o, ServicePage)
return CreateInstance(ScreenCheckPage, o, ServicePage)
end
---@param button integer # options are under the `game` table prefixed with `BUTTON`

View File

@ -36,14 +36,14 @@ local ServicePage = {
---Create a new ServicePage instance
---@param o? table # initial parameters
---@return ServicePage
function ServicePage:new(o)
function ServicePage.new(o)
o = o or {}
o.title = o.title or ""
o.selectedIndex = o.selectedIndex or 1
o.footer = o.footer or self.FOOTER
o.footer = o.footer or ServicePage.FOOTER
return CreateClass(self, o, Page)
return CreateInstance(ServicePage, o, Page)
end
---Refresh content values

View File

@ -20,7 +20,7 @@ local VersionInfoPage = {
---Create a new VersionInfoPage instance
---@param o? table # initial parameters
---@return VersionInfoPage
function VersionInfoPage:new(o)
function VersionInfoPage.new(o)
o = o or {}
o.title = o.title or "SYSTEM INFORMATION"
@ -30,19 +30,19 @@ function VersionInfoPage:new(o)
}
o.selectedIndex = o.selectedIndex or 1
local this = CreateClass(self, o, ServicePage)
local this = CreateInstance(VersionInfoPage, o, ServicePage)
local logStr = ReadGameFile("log_usc-game.exe.txt") or ReadGameFile("log_usc-game.txt")
local list = ListField:new{selectedIndex = 2, locked = true}
list:addField(ServiceField:new{label = "SKIN ID CODE", value = Version.getLongVersion(), MARGIN = {0, 0, 0, 24}})
list:addField(UpdateField:new{label = "USC VERSION", value = getGameLogValue("Version", logStr)})
list:addField(ServiceField:new{label = "USC BRANCH", value = GameConfig["UpdateChannel"]})
list:addField(ServiceField:new{label = "USC GIT COMMIT", value = getGameLogValue("Git commit", logStr), MARGIN = {0, 0, 0, 24}})
list:addField(ServiceField:new{label = "GL VERSION", value = getGameLogValue("OpenGL Version", logStr)})
list:addField(ServiceField:new{label = "GLSL VERSION", value = getGameLogValue("OpenGL Shading Language Version", logStr)})
list:addField(ServiceField:new{label = "GL RENDERER", value = getGameLogValue("OpenGL Renderer", logStr)})
list:addField(ServiceField:new{label = "GL VENDOR", value = getGameLogValue("OpenGL Vendor", logStr)})
local list = ListField.new{selectedIndex = 2, locked = true}
list:addField(ServiceField.new{label = "SKIN ID CODE", value = Version.getLongVersion(), MARGIN = {0, 0, 0, 24}})
list:addField(UpdateField.new{label = "USC VERSION", value = getGameLogValue("Version", logStr)})
list:addField(ServiceField.new{label = "USC BRANCH", value = GameConfig["UpdateChannel"]})
list:addField(ServiceField.new{label = "USC GIT COMMIT", value = getGameLogValue("Git commit", logStr), MARGIN = {0, 0, 0, 24}})
list:addField(ServiceField.new{label = "GL VERSION", value = getGameLogValue("OpenGL Version", logStr)})
list:addField(ServiceField.new{label = "GLSL VERSION", value = getGameLogValue("OpenGL Shading Language Version", logStr)})
list:addField(ServiceField.new{label = "GL RENDERER", value = getGameLogValue("OpenGL Renderer", logStr)})
list:addField(ServiceField.new{label = "GL VENDOR", value = getGameLogValue("OpenGL Vendor", logStr)})
list:refreshFields()
this:addField(list)

View File

@ -30,12 +30,12 @@ local rootMenu = {
]]
local currentpage = MainMenuPage:new()
local currentpage = MainMenuPage.new()
local pageview = PageView:new(currentpage)
local pageview = PageView.new(currentpage)
local function reset()
pageview = PageView:new(currentpage)
pageview = PageView.new(currentpage)
end
local function render(deltaTime)