tldr; bootpage initial implementation, fixes for page management code

added supporting functions for BootPage
removed init() from classes, it was stupid to begin with
handleButtonInput() and handleKnobInput no longer optional
added callback member to SelfTestField
placement position value fixes
use gfx.Translate instead of explicitly setting off-origin x,y values
added MARGIN and PADDING calculations to fields
removed unnecessary gfx.BeginPath() calls
This commit is contained in:
Hersi 2022-04-15 04:54:30 +02:00
parent 868d5b9798
commit f44ba3743b
22 changed files with 385 additions and 327 deletions

View File

@ -40,8 +40,8 @@ function ReadGameFileLines(path, mode)
end end
---Read a file in the game folder ---Read a file in the game folder
---@param path string ---@param path string # relative path to game file
---@param mode? openmode default "r" ---@param mode? openmode # default "r"
---@return nil|string|integer[] ---@return nil|string|integer[]
function ReadGameFile(path, mode) function ReadGameFile(path, mode)
mode = mode or "r" mode = mode or "r"
@ -63,9 +63,9 @@ function ReadGameFile(path, mode)
end end
---Find patterns in file ---Find patterns in file
---@param path string ---@param path string # relative path to game file
---@param pattern string ---@param pattern string # search pattern
---@return table {{group1, group2, ...}, ...} ---@return table # {{group1, group2, ...}, ...}
function FindPatterns(path, pattern) function FindPatterns(path, pattern)
local matches = {} local matches = {}
for _, line in ipairs(ReadGameFileLines(path, "r")) do for _, line in ipairs(ReadGameFileLines(path, "r")) do
@ -76,3 +76,28 @@ function FindPatterns(path, pattern)
return matches return matches
end end
--- Check if a file or directory exists in this path
---@param file string # relative path to game file
---@return boolean # file exists
---@return string # error message
function IsFileExists(file)
local gamepath, sep = getGamePath()
file = gamepath .. sep .. file
local ok, err, code = os.rename(file, file)
if not ok then
if code == 13 then
-- Permission denied, but it exists
return true
end
end
return ok, err
end
--- Check if a directory exists in this path
---@param path string # relative path to game directory
---@return boolean # directory exists
function IsDir(path)
-- "/" works on both Unix and Windows
return IsFileExists(path .. "/")
end

View File

@ -17,15 +17,11 @@ function ContainerField:new(o)
o.content = o.content or {} o.content = o.content or {}
return Inherit(self, o, Field) local this = Inherit(self, o, Field)
end
---Initialize members this:refreshFields()
---@return ContainerField
function ContainerField:init() return this
Field.init(self)
self:refreshFields()
return self
end end
---Add content to container ---Add content to container
@ -60,7 +56,7 @@ function ContainerField:render(deltaTime)
gfx.Save() gfx.Save()
gfx.Translate(self.posX, self.posY) gfx.Translate(self.posX, self.posY)
gfx.Scissor(self.offX, self.offY, self.aabbW, self.aabbH) gfx.Scissor(0, 0, self.aabbW, self.aabbH)
self:drawBackground(deltaTime) self:drawBackground(deltaTime)
self:drawContent(deltaTime) self:drawContent(deltaTime)

View File

@ -4,18 +4,10 @@ require("common.class")
---@field parent Page|ContainerField ---@field parent Page|ContainerField
---@field posX number ---@field posX number
---@field posY number ---@field posY number
---@field offX number
---@field offY number
---@field aabbW number ---@field aabbW number
---@field aabbH number ---@field aabbH number
local Field = { local Field = {
__tostring = function() return "Field" end, __tostring = function() return "Field" end,
---@type nil|fun(button: integer): boolean
---return true if further button input processing should be stopped, otherwise false
handleButtonInput = nil,
---@type nil|fun(knob: integer, delta: number): boolean
---return true if further knob input processing should be stopped, otherwise false
handleKnobInput = nil,
} }
---Create a new Field instance ---Create a new Field instance
@ -29,20 +21,12 @@ function Field:new(o)
o.parent = o.parent or nil o.parent = o.parent or nil
o.posX = o.posX or 0 o.posX = o.posX or 0
o.posY = o.posY or 0 o.posY = o.posY or 0
o.offX = o.offX or 0
o.offY = o.offY or 0
o.aabbW = o.aabbW or 0 o.aabbW = o.aabbW or 0
o.aabbH = o.aabbH or 0 o.aabbH = o.aabbH or 0
return Base(self, o) return Base(self, o)
end end
---Initialize members
---@return Field
function Field:init()
return self
end
---Get the containing top-level parent page ---Get the containing top-level parent page
---@return Field|Page ---@return Field|Page
function Field:getParentPage() function Field:getParentPage()
@ -62,8 +46,23 @@ function Field:focus(obj) end
---@param obj? any # message object for the field ---@param obj? any # message object for the field
function Field:deactivate(obj) end function Field:deactivate(obj) end
---@param button integer # options are under the `game` table prefixed with `BUTTON`
---@return boolean # true if further button input processing should be stopped, otherwise false
function Field:handleButtonInput(button)
return false
end
---@param knob integer # `0` = Left, `1` = Right
---@param delta number # in radians, `-2*pi` to `0` (turning CCW) and `0` to `2*pi` (turning CW)
---@return boolean # true if further button input processing should be stopped, otherwise false
function Field:handleKnobInput(knob, delta)
return false
end
---@param deltaTime number # frametime in seconds ---@param deltaTime number # frametime in seconds
function Field:drawContent(deltaTime) function Field:drawContent(deltaTime)
-- dummy field content
gfx.ResetScissor() gfx.ResetScissor()
local offX = -50 local offX = -50
@ -104,7 +103,8 @@ function Field:render(deltaTime)
gfx.Save() gfx.Save()
gfx.Translate(self.posX, self.posY) gfx.Translate(self.posX, self.posY)
gfx.Scissor(self.offX, self.offY, self.aabbW, self.aabbH) gfx.Scissor(0, 0, self.aabbW, self.aabbH)
self:drawContent(deltaTime) self:drawContent(deltaTime)
gfx.Restore() gfx.Restore()

View File

@ -5,9 +5,6 @@ require("common.class")
---@field viewHandler nil|PageView ---@field viewHandler nil|PageView
local Page = { local Page = {
__tostring = function() return "Page" end, __tostring = function() return "Page" end,
drawBackground = nil, ---@type nil|fun(deltaTime: number)
drawHeader = nil, ---@type nil|fun(deltaTime: number)
drawFooter = nil, ---@type nil|fun(deltaTime: number)
} }
---Create a new Page instance ---Create a new Page instance
@ -24,12 +21,6 @@ function Page:new(o)
return Base(self, o) return Base(self, o)
end end
---Initialize members
---@return Page
function Page:init()
return self
end
---Add field to page ---Add field to page
---@param field Field ---@param field Field
function Page:addField(field) function Page:addField(field)
@ -58,26 +49,23 @@ end
function Page:handleKnobInput(knob, delta) end function Page:handleKnobInput(knob, delta) end
---@param deltaTime number # frametime in seconds ---@param deltaTime number # frametime in seconds
function Page:render(deltaTime) function Page:drawBackground(deltaTime) end
---background
if self.drawBackground then
self:drawBackground(deltaTime)
end
--render children ---@param deltaTime number # frametime in seconds
function Page:drawContent(deltaTime)
for _, child in ipairs(self.content) do for _, child in ipairs(self.content) do
child:render(deltaTime) child:render(deltaTime)
end end
end
---header ---@param deltaTime number # frametime in seconds
if self.drawHeader then function Page:drawForeground(deltaTime) end
self:drawHeader(deltaTime)
end
---footer ---@param deltaTime number # frametime in seconds
if self.drawFooter then function Page:render(deltaTime)
self:drawFooter(deltaTime) self:drawBackground(deltaTime)
end self:drawContent(deltaTime)
self:drawForeground(deltaTime)
end end
return Page return Page

View File

@ -24,7 +24,7 @@ local screens = {
} }
} }
local currentScreen = game.GetSkinSetting("animations_skipIntro") and screens.title or screens.service -- show boot screen if skipIntro is not set local currentScreen = game.GetSkinSetting("animations_skipIntro") and screens.title or screens.boot -- show boot screen if skipIntro is not set
local function deltaKnob(delta) local function deltaKnob(delta)
if math.abs(delta) > 1.5 * math.pi then if math.abs(delta) > 1.5 * math.pi then

View File

@ -14,8 +14,15 @@ local function render(deltaTime)
Dim.transformToScreenSpace() Dim.transformToScreenSpace()
pageview:render(deltaTime) pageview:render(deltaTime)
--pageview will be empty when you `back()` out of the root page
if not pageview:get() then
return {eventType = "switch", toScreen = "splash"}
end
end end
return { local function onButtonPressed(button)
render = render pageview:get():handleButtonInput(button)
} end
return {render = render, onButtonPressed = onButtonPressed}

View File

@ -13,35 +13,45 @@ SelfTestStatusEnum = {
---@class SelfTestField: ServiceField ---@class SelfTestField: ServiceField
---@field status SelfTestStatusEnum ---@field status SelfTestStatusEnum
---@field callback nil|fun(obj: any): SelfTestStatusEnum
---@field _timer number ---@field _timer number
local SelfTestField = { local SelfTestField = {
SELFTEST_COLOR_INPROGRESS = {255, 255, 255, 255}, SELFTEST_COLOR_INPROGRESS = {255, 255, 255, 255},
SELFTEST_COLOR_OK = {0, 255, 0, 255}, SELFTEST_COLOR_OK = {0, 255, 0, 255},
SELFTEST_COLOR_PASS = {255, 255, 0, 255}, SELFTEST_COLOR_PASS = {255, 255, 0, 255},
SELFTEST_COLOR_ERROR = {255, 0, 0, 255}, SELFTEST_COLOR_ERROR = {255, 0, 0, 255},
SELFTEST_INPROGRESS_FREQ = 1 / 20 --20Hz SELFTEST_INPROGRESS_FREQ = 1 / 20, --20Hz
} }
---Create a new SelfTestField instance ---Create a new SelfTestField instance
---@param o ServiceField ---@param o? table
---@return SelfTestField ---@return SelfTestField
function SelfTestField:new(o) function SelfTestField:new(o)
o = o or {} o = o or {}
o.status = o.status or SelfTestStatusEnum.IDLE o.status = o.status or SelfTestStatusEnum.IDLE
o.callback = o.callback or nil
o._timer = 0 o._timer = 0
return Inherit(self, o, ServiceField) return Inherit(self, o, ServiceField)
end end
function SelfTestField:activate(obj)
if self.callback then
self.status = self.callback(obj) or SelfTestStatusEnum.INPROGRESS
end
end
function SelfTestField:drawValue(deltaTime) function SelfTestField:drawValue(deltaTime)
gfx.Translate(self.VALUE_OFFSETX, 0)
gfx.TextAlign(gfx.TEXT_ALIGN_RIGHT | gfx.TEXT_ALIGN_TOP) gfx.TextAlign(gfx.TEXT_ALIGN_RIGHT | gfx.TEXT_ALIGN_TOP)
gfx.FillColor(table.unpack(self.SERVICE_DEFAULT_FONT_COLOR)) gfx.FillColor(table.unpack(self.FONT_COLOR))
gfx.Text(":", self.valueOffX, 0) gfx.Text(": ", 0, 0)
local color, text local color, text
if self.status == SelfTestStatusEnum.IDLE then if self.status == SelfTestStatusEnum.IDLE then
color = self.SERVICE_DEFAULT_FONT_COLOR color = self.FONT_COLOR
text = "" text = ""
elseif self.status == SelfTestStatusEnum.INPROGRESS then elseif self.status == SelfTestStatusEnum.INPROGRESS then
self._timer = self._timer + deltaTime self._timer = self._timer + deltaTime
@ -58,9 +68,10 @@ function SelfTestField:drawValue(deltaTime)
color = self.SELFTEST_COLOR_ERROR color = self.SELFTEST_COLOR_ERROR
text = "ERROR" text = "ERROR"
end end
gfx.TextAlign(gfx.TEXT_ALIGN_LEFT | gfx.TEXT_ALIGN_TOP) gfx.TextAlign(gfx.TEXT_ALIGN_LEFT | gfx.TEXT_ALIGN_TOP)
gfx.FillColor(table.unpack(color)) gfx.FillColor(table.unpack(color))
gfx.Text(text, self.valueOffX, 0) gfx.Text(text, 0, 0)
end end
return SelfTestField return SelfTestField

View File

@ -6,7 +6,7 @@ local ServiceField = require("titlescreen.fields.service.servicefield")
local ColorGradientField = { local ColorGradientField = {
__tostring = function() return "ColorGradientField" end, __tostring = function() return "ColorGradientField" end,
GRADIENT_X_OFFSET = 128, GRADIENT_X_OFFSET = 128,
GRADIENT_WIDTH = 512, GRADIENT_WIDTH = 576,
GRADIENT_STEPS = 32 GRADIENT_STEPS = 32
} }
@ -17,7 +17,6 @@ function ColorGradientField:new(o)
o = o or {} o = o or {}
o.value = o.value or {0, 0, 0, 255} o.value = o.value or {0, 0, 0, 255}
o.aabbH = o.aabbH or self.FONT_SIZE
return Inherit(self, o, ServiceField) return Inherit(self, o, ServiceField)
end end

View File

@ -29,13 +29,15 @@ function InputButtonField:deactivate(obj) end
---@param deltaTime number # frametime in seconds ---@param deltaTime number # frametime in seconds
function InputButtonField:drawValue(deltaTime) function InputButtonField:drawValue(deltaTime)
gfx.Translate(self.VALUE_OFFSETX, 0)
if not self.button then if not self.button then
gfx.Text("<BUTTON NOT SET>", self.valueOffX, 0) gfx.Text("<BUTTON NOT SET>", 0, 0)
return return
end end
self.value = game.GetButton(self.button) and "ON" or "OFF" self.value = game.GetButton(self.button) and "ON" or "OFF"
gfx.Text(self.value, self.valueOffX, 0) gfx.Text(self.value, 0, 0)
end end
return InputButtonField return InputButtonField

View File

@ -6,7 +6,7 @@ local ServiceField = require("titlescreen.fields.service.servicefield")
---@field knob integer ---@field knob integer
local InputKnobField = { local InputKnobField = {
__tostring = function() return "InputKnobField" end, __tostring = function() return "InputKnobField" end,
SLIDER_SIZE = {256, ServiceField.FONT_SIZE}, --{w, h} SLIDER_SIZE = {200, 16}, --{w, h}
SLIDER_BGCOLOR = {255, 0, 0, 255}, SLIDER_BGCOLOR = {255, 0, 0, 255},
SLIDER_FRAME_COLOR = ServiceField.FONT_COLOR, SLIDER_FRAME_COLOR = ServiceField.FONT_COLOR,
SLIDER_FRAME_WIDTH = 1, SLIDER_FRAME_WIDTH = 1,
@ -37,13 +37,14 @@ function InputKnobField:deactivate(obj) end
---@param deltaTime number # frametime in seconds ---@param deltaTime number # frametime in seconds
function InputKnobField:drawValue(deltaTime) function InputKnobField:drawValue(deltaTime)
gfx.Translate(self.VALUE_OFFSETX, 0)
if not self.knob then if not self.knob then
gfx.Text("<KNOB NOT SET>", self.valueOffX, 0) gfx.Text("<KNOB NOT SET>", 0, 0)
return return
end end
local knobAngle = game.GetKnob(self.knob) local knobAngle = game.GetKnob(self.knob)
local sliderPosX = self.valueOffX + self.SLIDER_OFFSETX
local sliderWidth = self.SLIDER_SIZE[1] local sliderWidth = self.SLIDER_SIZE[1]
local sliderHeight = self.SLIDER_SIZE[2] local sliderHeight = self.SLIDER_SIZE[2]
local sliderBgColor = self.SLIDER_BGCOLOR local sliderBgColor = self.SLIDER_BGCOLOR
@ -54,19 +55,19 @@ function InputKnobField:drawValue(deltaTime)
self.value = math.floor(Util.lerp(knobAngle,0, 0, 2 * math.pi, maxValue)) % maxValue self.value = math.floor(Util.lerp(knobAngle,0, 0, 2 * math.pi, maxValue)) % maxValue
--draw value --draw value
gfx.BeginPath() gfx.Text(self.value, 0, 0)
gfx.Text(self.value, self.valueOffX, 0)
--draw slider --draw slider
gfx.Translate(self.SLIDER_OFFSETX, 0)
gfx.BeginPath() gfx.BeginPath()
gfx.Rect(sliderPosX, 0, sliderWidth, sliderHeight) gfx.Rect(0, 0, sliderWidth, sliderHeight)
gfx.FillColor(table.unpack(sliderBgColor)) gfx.FillColor(table.unpack(sliderBgColor))
gfx.StrokeColor(table.unpack(sliderFrameColor)) gfx.StrokeColor(table.unpack(sliderFrameColor))
gfx.StrokeWidth(sliderFrameWidth) gfx.StrokeWidth(sliderFrameWidth)
gfx.Fill() gfx.Fill()
gfx.Stroke() gfx.Stroke()
local sliderIndicatorX = Util.lerp(self.value, 0, sliderPosX, maxValue, sliderWidth) local sliderIndicatorX = Util.lerp(self.value, 0, 0, maxValue, sliderWidth)
local sliderIndicatorWidth = self.SLIDER_INDICATOR_WIDTH local sliderIndicatorWidth = self.SLIDER_INDICATOR_WIDTH
local sliderIndicatorColor = self.SLIDER_INDICATOR_COLOR local sliderIndicatorColor = self.SLIDER_INDICATOR_COLOR
--draw indicator --draw indicator
@ -74,7 +75,6 @@ function InputKnobField:drawValue(deltaTime)
gfx.Rect(sliderIndicatorX, sliderFrameWidth, sliderIndicatorWidth, sliderHeight - 2 * sliderFrameWidth) gfx.Rect(sliderIndicatorX, sliderFrameWidth, sliderIndicatorWidth, sliderHeight - 2 * sliderFrameWidth)
gfx.FillColor(table.unpack(sliderIndicatorColor)) gfx.FillColor(table.unpack(sliderIndicatorColor))
gfx.Fill() gfx.Fill()
end end
return InputKnobField return InputKnobField

View File

@ -4,8 +4,11 @@ local ServiceField = require("titlescreen.fields.service.servicefield")
---@class ListField: ContainerField, ServiceField ---@class ListField: ContainerField, ServiceField
---@field selectedIndex integer ---@field selectedIndex integer
---@field locked boolean
---@field PADDING number[]
local ListField = { local ListField = {
__tostring = function() return "ListField" end, __tostring = function() return "ListField" end,
MARGIN = {0, 0, 0, 0}, --{left, top, right, bottom}
PADDING = {0, 0, 0, 0}, --{left, top, right, bottom} PADDING = {0, 0, 0, 0}, --{left, top, right, bottom}
} }
@ -17,20 +20,16 @@ function ListField:new(o)
--set instance members --set instance members
o.selectedIndex = o.selectedIndex or 1 o.selectedIndex = o.selectedIndex or 1
o.locked = o.locked or false
return Inherit(self, o, ContainerField, ServiceField) local this = Inherit(self, o, ContainerField, ServiceField)
end
---Initialize members local minW = this.MARGIN[1] + this.PADDING[1] + this.PADDING[3] + this.MARGIN[3]
---@return ListField local minH = this.MARGIN[2] + this.PADDING[2] + this.PADDING[4] + this.MARGIN[4]
function ListField:init() this.aabbW = math.max(this.aabbW, minW)
ServiceField.init(self) this.aabbH = math.max(this.aabbH, minH)
ContainerField.init(self)
local minW = self.MARGIN[1] + self.PADDING[1] + self.PADDING[3] + self.MARGIN[3] return this
local minH = self.MARGIN[2] + self.PADDING[2] + self.PADDING[4] + self.MARGIN[4]
self.aabbW = math.max(self.aabbW, minW)
self.aabbH = math.max(self.aabbH, minH)
return self
end end
---@param obj? any # message object for the field ---@param obj? any # message object for the field
@ -66,10 +65,6 @@ end
---Add field to list container ---Add field to list container
---@param field Field ---@param field Field
function ListField:addField(field) function ListField:addField(field)
--place field to correct position
field.posX = self.PADDING[1]
field.posY = self.aabbH - self.PADDING[4]
--update size --update size
self.aabbH = self.aabbH + field.aabbH self.aabbH = self.aabbH + field.aabbH
local fieldAabbW = self.PADDING[1] + field.aabbW + self.PADDING[3] local fieldAabbW = self.PADDING[1] + field.aabbW + self.PADDING[3]
@ -83,14 +78,8 @@ end
---Refresh content parameters ---Refresh content parameters
function ListField:refreshFields() function ListField:refreshFields()
local posY = self.PADDING[1]
local aabbH = self.MARGIN[2] + self.PADDING[2] + self.PADDING[4] + self.MARGIN[4] local aabbH = self.MARGIN[2] + self.PADDING[2] + self.PADDING[4] + self.MARGIN[4]
for _, child in ipairs(self.content) do for _, child in ipairs(self.content) do
--place field to correct position
child.posX = self.PADDING[1]
child.posY = posY
posY = posY + child.aabbH
--update size --update size
aabbH = aabbH + child.aabbH aabbH = aabbH + child.aabbH
local fieldAabbW = self.PADDING[1] + child.aabbW + self.PADDING[3] local fieldAabbW = self.PADDING[1] + child.aabbW + self.PADDING[3]
@ -107,20 +96,25 @@ end
---@return boolean # true if further button input processing should be stopped, otherwise false ---@return boolean # true if further button input processing should be stopped, otherwise false
function ListField:handleButtonInput(button) function ListField:handleButtonInput(button)
local field = self.content[self.selectedIndex] local field = self.content[self.selectedIndex]
if field and field.handleButtonInput then
if field:handleButtonInput(button) then if field:handleButtonInput(button) then
return true return true
end end
end
local direction = 0
if button == game.BUTTON_BCK then if button == game.BUTTON_BCK then
local viewHandler = self:getParentPage().viewHandler local viewHandler = self:getParentPage().viewHandler
if viewHandler then if viewHandler then
viewHandler:back() viewHandler:back()
end end
elseif button == game.BUTTON_BTA then return true
end
if self.locked then
return true
end
local direction = 0
if button == game.BUTTON_BTA then
direction = -1 direction = -1
elseif button == game.BUTTON_BTB then elseif button == game.BUTTON_BTB then
direction = 1 direction = 1
@ -142,4 +136,13 @@ function ListField:handleButtonInput(button)
return true return true
end end
---@param deltaTime number # frametime in seconds
function ListField:drawContent(deltaTime)
gfx.Translate(self.PADDING[1] + self.MARGIN[1], self.PADDING[2] + self.MARGIN[2])
for _, child in ipairs(self.content) do
child:render(deltaTime)
gfx.Translate(0, child.aabbH)
end
end
return ListField return ListField

View File

@ -12,17 +12,24 @@ ServiceFieldState = {
---@class ServiceField: Field ---@class ServiceField: Field
---@field label string ---@field label string
---@field value any ---@field value any
---@field valueOffX number
---@field footer string|string[] ---@field footer string|string[]
---@field _state ServiceFieldState ---@field _state ServiceFieldState
---@field FONT_SIZE number
---@field FONT_FACE string
---@field FONT_COLOR integer[] # {r, g, b, a}
---@field FONT_ACTIVE_COLOR integer[] # {r, g, b, a}
---@field FONT_FOCUSED_COLOR integer[] # {r, g, b, a}
---@field MARGIN number[] # {left, top, right, bottom}
---@field VALUE_OFFSETX number
local ServiceField = { local ServiceField = {
__tostring = function() return "ServiceField" end, __tostring = function() return "ServiceField" end,
FONT_SIZE = 24, FONT_SIZE = 24,
FONT_FACE = "dfmarugoth.ttf", FONT_FACE = "dfmarugoth.ttf",
FONT_COLOR = {255, 255, 255, 255}, --{r, g, b, a} FONT_COLOR = {255, 255, 255, 255},
FONT_ACTIVE_COLOR = {0, 255, 0, 255}, FONT_ACTIVE_COLOR = {0, 255, 0, 255},
FONT_FOCUSED_COLOR = {255, 0, 0, 255}, FONT_FOCUSED_COLOR = {255, 0, 0, 255},
MARGIN = {0, 0, 0, 4}, --{left, top, right, bottom} MARGIN = {0, 0, 0, 0},
VALUE_OFFSETX = 500
} }
---Create a new ServiceField instance ---Create a new ServiceField instance
@ -31,14 +38,10 @@ local ServiceField = {
function ServiceField:new(o) function ServiceField:new(o)
o = o or {} o = o or {}
local h = self.FONT_SIZE + local h = self.FONT_SIZE + self.MARGIN[2] + self.MARGIN[4]
self.MARGIN[2] +
self.MARGIN[4]
o.aabbH = o.aabbH or h o.aabbH = o.aabbH or h
o.aabbW = o.aabbW or Dim.design.width - 128 --:shrug: o.aabbW = o.aabbW or Dim.design.width --:shrug:
o.valueOffX = o.valueOffX or Dim.design.width / 2
o.label = o.label or "<UNDEFINED>" o.label = o.label or "<UNDEFINED>"
o.value = o.value or nil o.value = o.value or nil
@ -46,25 +49,31 @@ function ServiceField:new(o)
o._state = ServiceFieldState.INACTIVE o._state = ServiceFieldState.INACTIVE
return Inherit(self, o, Field) local this = Inherit(self, o, Field)
if this.aabbH < h then
this.aabbH = h
end
return this
end end
---@param obj? any message object for the field ---@param obj? any # message object for the field
function ServiceField:activate(obj) function ServiceField:activate(obj)
self._state = ServiceFieldState.ACTIVE self._state = ServiceFieldState.ACTIVE
end end
---@param obj? any message object for the field ---@param obj? any # message object for the field
function ServiceField:focus(obj) function ServiceField:focus(obj)
self._state = ServiceFieldState.FOCUSED self._state = ServiceFieldState.FOCUSED
end end
---@param obj? any message object for the field ---@param obj? any # message object for the field
function ServiceField:deactivate(obj) function ServiceField:deactivate(obj)
self._state = ServiceFieldState.INACTIVE self._state = ServiceFieldState.INACTIVE
end end
---@param deltaTime number frametime in seconds ---@param deltaTime number # frametime in seconds
function ServiceField:drawLabel(deltaTime) function ServiceField:drawLabel(deltaTime)
local color local color
if self._state == ServiceFieldState.FOCUSED then if self._state == ServiceFieldState.FOCUSED then
@ -80,7 +89,7 @@ function ServiceField:drawLabel(deltaTime)
gfx.Text(self.label, 0, 0) gfx.Text(self.label, 0, 0)
end end
---@param deltaTime number frametime in seconds ---@param deltaTime number # frametime in seconds
function ServiceField:drawValue(deltaTime) function ServiceField:drawValue(deltaTime)
local text local text
if type(self.value) == "string" then if type(self.value) == "string" then
@ -89,15 +98,18 @@ function ServiceField:drawValue(deltaTime)
text = "N/A" text = "N/A"
end end
gfx.Translate(self.VALUE_OFFSETX, 0)
gfx.FontSize(self.FONT_SIZE) gfx.FontSize(self.FONT_SIZE)
gfx.LoadSkinFont(self.FONT_FACE) gfx.LoadSkinFont(self.FONT_FACE)
gfx.TextAlign(gfx.TEXT_ALIGN_LEFT | gfx.TEXT_ALIGN_TOP) gfx.TextAlign(gfx.TEXT_ALIGN_LEFT | gfx.TEXT_ALIGN_TOP)
gfx.FillColor(table.unpack(self.FONT_COLOR)) gfx.FillColor(table.unpack(self.FONT_COLOR))
gfx.Text(text, self.valueOffX, 0) gfx.Text(text, 0, 0)
end end
---@param deltaTime number frametime in seconds ---@param deltaTime number # frametime in seconds
function ServiceField:drawContent(deltaTime) function ServiceField:drawContent(deltaTime)
gfx.Translate(self.MARGIN[1], self.MARGIN[2])
self:drawLabel(deltaTime) self:drawLabel(deltaTime)
self:drawValue(deltaTime) self:drawValue(deltaTime)
end end

View File

@ -19,4 +19,8 @@ end
---@param deltaTime number # frametime in seconds ---@param deltaTime number # frametime in seconds
function ServiceLinkField:drawValue(deltaTime) end function ServiceLinkField:drawValue(deltaTime) end
function ServiceLinkField:handleButtonInput(button)
return LinkField.handleButtonInput(self, button)
end
return ServiceLinkField return ServiceLinkField

View File

@ -1,19 +0,0 @@
require("common.class")
local ServiceField = require("titlescreen.fields.service.servicefield")
---@class SpacerField: ServiceField
local SpacerField = {}
---Create a new ServiceField instance
---@param o? table # initial parameters
---@return SpacerField
function SpacerField:new(o)
return Inherit(self, o, ServiceField)
end
---@param deltaTime number # frametime in seconds
function SpacerField:drawContent(deltaTime)
--empty, what did you think would be here?
end
return SpacerField

View File

@ -23,6 +23,15 @@ function UpdateField:new(o)
return Inherit(self, o, ServiceField) return Inherit(self, o, ServiceField)
end end
---@param obj? any # message object for the field
function UpdateField:activate(obj) end
---@param obj? any # message object for the field
function UpdateField:focus(obj) end
---@param obj? any # message object for the field
function UpdateField:deactivate(obj) end
---@param button integer # options are under the `game` table prefixed with `BUTTON` ---@param button integer # options are under the `game` table prefixed with `BUTTON`
---@return boolean # true if further button input processing should be stopped, otherwise false ---@return boolean # true if further button input processing should be stopped, otherwise false
function UpdateField:handleButtonInput(button) function UpdateField:handleButtonInput(button)
@ -41,7 +50,8 @@ function UpdateField:drawValue(deltaTime)
self._timer = self._timer + deltaTime self._timer = self._timer + deltaTime
local url, version = game.UpdateAvailable() local url, version = game.UpdateAvailable()
gfx.BeginPath() gfx.Translate(self.VALUE_OFFSETX, 0)
gfx.FontSize(self.FONT_SIZE) gfx.FontSize(self.FONT_SIZE)
gfx.LoadSkinFont(self.FONT_FACE) gfx.LoadSkinFont(self.FONT_FACE)
gfx.TextAlign(gfx.TEXT_ALIGN_LEFT | gfx.TEXT_ALIGN_TOP) gfx.TextAlign(gfx.TEXT_ALIGN_LEFT | gfx.TEXT_ALIGN_TOP)
@ -51,12 +61,11 @@ function UpdateField:drawValue(deltaTime)
else else
gfx.FillColor(table.unpack(self.UPDATE_FLICKER_COLORS[2])) gfx.FillColor(table.unpack(self.UPDATE_FLICKER_COLORS[2]))
end end
gfx.Text("*UPDATE AVAILABLE (" .. version .. ")*", self.valueOffX, 0) gfx.Text("*UPDATE AVAILABLE (" .. version .. ")*", 0, 0)
else else
gfx.FillColor(table.unpack(self.FONT_COLOR)) gfx.FillColor(table.unpack(self.FONT_COLOR))
gfx.Text(self.value or "<VERSION STRING NOT AVAILABLE>", self.valueOffX, 0) gfx.Text(self.value or "<VERSION STRING NOT AVAILABLE>", 0, 0)
end end
end end
return UpdateField return UpdateField

View File

@ -1,9 +1,35 @@
require("common.class") require("common.class")
require("common.filereader")
local Dim = require("common.dimensions") local Dim = require("common.dimensions")
local Version = require("common.version") local Version = require("common.version")
local Page = require("components.pager.page") local Page = require("components.pager.page")
local ServiceField = require("titlescreen.fields.service.servicefield") local ServiceField = require("titlescreen.fields.service.servicefield")
local LinkField = require("components.pager.linkfield") local ListField = require("titlescreen.fields.service.listfield")
local SelfTestField = require("titlescreen.fields.boot.selftestfield")
local function checkSkinConfig(obj)
local crewpath = "textures/crew/anim/" .. game.GetSkinSetting("single_idol")
if not IsDir(crewpath) then
return SelfTestStatusEnum.ERROR
end
end
local networkStatus = SelfTestStatusEnum.IDLE
local function irHeardbeat(res)
if res.statusCode == IRData.States.Success then
networkStatus = SelfTestStatusEnum.OK
else
networkStatus = SelfTestStatusEnum.ERROR
end
end
local function checkNetwork(obj)
if not IRData.Active then
return SelfTestStatusEnum.PASS
end
IR.Heartbeat(irHeardbeat)
end
---@class BootPage: Page ---@class BootPage: Page
local BootPage = { local BootPage = {
@ -16,27 +42,19 @@ local BootPage = {
function BootPage:new(o) function BootPage:new(o)
o = o or {} o = o or {}
return Inherit(self, o, Page) local this = Inherit(self, o, Page)
end
---Initialize members this:addField(ServiceField:new{posX = 32, posY = 32, label = Version.getLongVersion(), value = ""})
---@return BootPage this:addField(ServiceField:new{posX = 64, posY = 64, label = "UNNAMED SDVX CLONE STARTUP...", value = ""})
function BootPage:init()
self:addField(ServiceField:new{
label = Version.getLongVersion(),
value = "",
posX = 32,
posY = 32
})
self:addField(ServiceField:new{ local valueOffX = 220
label = "UNNAMED SDVX CLONE STARTUP...", local list = ListField:new{posX = 64, posY = 96}
value = "", list:addField(SelfTestField:new{label = "MAIN I/O", VALUE_OFFSETX = valueOffX, status = SelfTestStatusEnum.OK})
posX = 64, list:addField(SelfTestField:new{label = "SKIN CONFIG", VALUE_OFFSETX = valueOffX, status = SelfTestStatusEnum.OK, callback = checkSkinConfig})
posY = 64 list:addField(SelfTestField:new{label = "IR NETWORK", VALUE_OFFSETX = valueOffX, status = SelfTestStatusEnum.ERROR, callback = checkNetwork})
}) this:addField(list)
return self return this
end end
---@param deltaTime number # frametime in seconds ---@param deltaTime number # frametime in seconds
@ -47,4 +65,12 @@ function BootPage:drawBackground(deltaTime)
gfx.Fill() gfx.Fill()
end end
function BootPage:render(deltaTime)
Page.render(self, deltaTime)
local skinconfig = self.content[3].content[2] --this is hacktastic
local network = self.content[3].content[3] --this is also hacktastic
end
return BootPage return BootPage

View File

@ -1,5 +1,4 @@
require("common.class") require("common.class")
local ServiceField = require("titlescreen.fields.service.servicefield")
local ServicePage = require("titlescreen.pages.service.servicepage") local ServicePage = require("titlescreen.pages.service.servicepage")
local ListField = require("titlescreen.fields.service.listfield") local ListField = require("titlescreen.fields.service.listfield")
local ColorGradientField = require("titlescreen.fields.service.colorgradientfield") local ColorGradientField = require("titlescreen.fields.service.colorgradientfield")
@ -8,7 +7,9 @@ local ColorGradientField = require("titlescreen.fields.service.colorgradientfiel
local ColorCheckPage = { local ColorCheckPage = {
__tostring = function() return "ColorCheckPage" end, __tostring = function() return "ColorCheckPage" end,
GRADIENT_SPACING = ServiceField.FONT_SIZE + 8, PADDING = {56, 120, 0, 56}, --{left, top, right, bottom}
GRADIENT_SPACING = 32,
SEPARATOR_LINE_COLOR = {255, 255, 255, 255}, SEPARATOR_LINE_COLOR = {255, 255, 255, 255},
SEPARATOR_LINE_WIDTH = 4, SEPARATOR_LINE_WIDTH = 4,
@ -29,25 +30,23 @@ function ColorCheckPage:new(o)
"BACK BUTTON = EXIT" "BACK BUTTON = EXIT"
} }
return Inherit(self, o, ServicePage) local this = Inherit(self, o, ServicePage)
end
---Initialize members
---@return ColorCheckPage
function ColorCheckPage:init()
ServicePage.init(self)
local height = self.GRADIENT_SPACING 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})
list:refreshFields()
self:addField(ColorGradientField:new{label = "RED", value = {255, 0, 0, 255}, aabbH = height}) this:addField(list)
self:addField(ColorGradientField:new{label = "YELLOW", value = {255, 255, 0, 255}, aabbH = height}) this:refreshFields()
self:addField(ColorGradientField:new{label = "GREEN", value = {0, 255, 0, 255}, aabbH = height})
self:addField(ColorGradientField:new{label = "CYAN", value = {0, 255, 255, 255}, aabbH = height})
self:addField(ColorGradientField:new{label = "BLUE", value = {0, 0, 255, 255}, aabbH = height})
self:addField(ColorGradientField:new{label = "MAGENTA", value = {255, 0, 255, 255}, aabbH = height})
self:addField(ColorGradientField:new{label = "WHITE", value = {255, 255, 255, 255}, aabbH = height})
return self return this
end end
---@param button integer # options are under the `game` table prefixed with `BUTTON` ---@param button integer # options are under the `game` table prefixed with `BUTTON`
@ -73,7 +72,7 @@ function ColorCheckPage:_drawArrows(deltaTime)
local stepW = ColorGradientField.GRADIENT_WIDTH / ColorGradientField.GRADIENT_STEPS local stepW = ColorGradientField.GRADIENT_WIDTH / ColorGradientField.GRADIENT_STEPS
gfx.BeginPath() gfx.BeginPath()
for i = 0, 3 do for i = 0, 3 do
local posX = i * stepW local posX = ColorGradientField.GRADIENT_X_OFFSET + i * stepW
gfx.MoveTo(posX + self.SEPARATOR_ARROW_MARGIN, self.SEPARATOR_ARROW_SIZE - self.SEPARATOR_ARROW_MARGIN) gfx.MoveTo(posX + self.SEPARATOR_ARROW_MARGIN, self.SEPARATOR_ARROW_SIZE - self.SEPARATOR_ARROW_MARGIN)
gfx.LineTo(posX + stepW / 2, self.SEPARATOR_ARROW_MARGIN) gfx.LineTo(posX + stepW / 2, self.SEPARATOR_ARROW_MARGIN)
gfx.LineTo(posX + stepW - self.SEPARATOR_ARROW_MARGIN, self.SEPARATOR_ARROW_SIZE - self.SEPARATOR_ARROW_MARGIN) gfx.LineTo(posX + stepW - self.SEPARATOR_ARROW_MARGIN, self.SEPARATOR_ARROW_SIZE - self.SEPARATOR_ARROW_MARGIN)
@ -97,14 +96,17 @@ end
---@param deltaTime number # frametime in seconds ---@param deltaTime number # frametime in seconds
function ColorCheckPage:drawBackground(deltaTime) function ColorCheckPage:drawBackground(deltaTime)
ServicePage.drawBackground(self, deltaTime)
gfx.Save() gfx.Save()
gfx.Translate(self.PADDING[1], self.PADDING[2])
gfx.Translate(ServicePage.PADDING[1], self.PADDING[2] + #self.content * self.GRADIENT_SPACING) local list = self.content[1]
local posX = list.posX
local posY = list.posY + list.aabbH
gfx.Translate(posX, posY)
self:_drawSeparator(deltaTime) self:_drawSeparator(deltaTime)
gfx.Translate(0, self.SEPARATOR_LINE_WIDTH) gfx.Translate(0, self.SEPARATOR_LINE_WIDTH)
self:_drawArrows(deltaTime) self:_drawArrows(deltaTime)
gfx.Translate(0, self.SEPARATOR_ARROW_SIZE) gfx.Translate(0, self.SEPARATOR_ARROW_SIZE)
self:_drawArrowText(deltaTime) self:_drawArrowText(deltaTime)

View File

@ -2,6 +2,7 @@ require("common.class")
local ServicePage = require("titlescreen.pages.service.servicepage") local ServicePage = require("titlescreen.pages.service.servicepage")
local InputButtonField = require("titlescreen.fields.service.inputbuttonfield") local InputButtonField = require("titlescreen.fields.service.inputbuttonfield")
local InputKnobField = require("titlescreen.fields.service.inputknobfield") local InputKnobField = require("titlescreen.fields.service.inputknobfield")
local ListField = require("titlescreen.fields.service.listfield")
---@class InputCheckPage: ServicePage ---@class InputCheckPage: ServicePage
local InputCheckPage = { local InputCheckPage = {
@ -17,23 +18,24 @@ function InputCheckPage:new(o)
o.title = o.title or "INPUT CHECK" o.title = o.title or "INPUT CHECK"
o.footer = o.footer or "BACK BUTTON = EXIT" o.footer = o.footer or "BACK BUTTON = EXIT"
return Inherit(self, o, ServicePage) local this = Inherit(self, o, ServicePage)
end
---Initialize members local list = ListField:new()
---@return InputCheckPage list:addField(InputButtonField:new{label="START BUTTON", button=game.BUTTON_STA})
function InputCheckPage:init() list:addField(InputButtonField:new{label="A BUTTON", button=game.BUTTON_BTA})
ServicePage.init(self) list:addField(InputButtonField:new{label="B BUTTON", button=game.BUTTON_BTB})
self:addField(InputButtonField:new{label="START BUTTON", button=game.BUTTON_STA}) list:addField(InputButtonField:new{label="C BUTTON", button=game.BUTTON_BTC})
self:addField(InputButtonField:new{label="A BUTTON", button=game.BUTTON_BTA}) list:addField(InputButtonField:new{label="D BUTTON", button=game.BUTTON_BTD})
self:addField(InputButtonField:new{label="B BUTTON", button=game.BUTTON_BTB}) list:addField(InputButtonField:new{label="FX L BUTTON", button=game.BUTTON_FXL})
self:addField(InputButtonField:new{label="C BUTTON", button=game.BUTTON_BTC}) list:addField(InputButtonField:new{label="FX R BUTTON", button=game.BUTTON_FXR})
self:addField(InputButtonField:new{label="D BUTTON", button=game.BUTTON_BTD}) list:addField(InputKnobField:new{label="ANALOG VOLUME L", knob=0})
self:addField(InputButtonField:new{label="FX L BUTTON", button=game.BUTTON_FXL}) list:addField(InputKnobField:new{label="ANALOG VOLUME R", knob=1})
self:addField(InputButtonField:new{label="FX R BUTTON", button=game.BUTTON_FXR}) list:refreshFields()
self:addField(InputKnobField:new{label="ANALOG VOLUME L", knob=0})
self:addField(InputKnobField:new{label="ANALOG VOLUME R", knob=1}) this:addField(list)
return self this:refreshFields()
return this
end end
---@param button integer # options are under the `game` table prefixed with `BUTTON` ---@param button integer # options are under the `game` table prefixed with `BUTTON`

View File

@ -20,44 +20,19 @@ function MainMenuPage:new(o)
o.title = o.title or "MAIN MENU" o.title = o.title or "MAIN MENU"
return Inherit(self, o, ServicePage) local this = Inherit(self, o, ServicePage)
end
---Initialize members local list = ListField:new()
---@return MainMenuPage list:addField(ServiceLinkField:new{label = "INPUT CHECK", link = InputCheckPage:new()})
function MainMenuPage:init() list:addField(ServiceLinkField:new{label = "SCREEN CHECK", link = ScreenCheckPage:new()})
ServicePage.init(self) list:addField(ServiceLinkField:new{label = "COLOR CHECK", link = ColorCheckPage:new()})
list:addField(ServiceLinkField:new{label = "VERSION INFORMATION", link = VersionInfoPage:new()})
list:refreshFields()
local posX = self.PADDING[1] this:addField(list)
local posY = self.PADDING[2] this:refreshFields()
local list = ListField:new{ return this
posX = posX,
posY = posY,
}:init()
list:addField(ServiceLinkField:new{
label = "INPUT CHECK",
link = InputCheckPage:new():init(),
})
list:addField(ServiceLinkField:new{
label = "SCREEN CHECK",
link = ScreenCheckPage:new():init(),
})
list:addField(ServiceLinkField:new{
label = "COLOR CHECK",
link = ColorCheckPage:new():init(),
})
list:addField(ServiceLinkField:new{
label = "VERSION INFORMATION",
link = VersionInfoPage:new():init(),
})
self:addField(list)
self:refreshFields()
return self
end end
return MainMenuPage return MainMenuPage

View File

@ -9,12 +9,19 @@ local ServiceField = require("titlescreen.fields.service.servicefield")
---@field selectedIndex integer ---@field selectedIndex integer
---@field footer string[] ---@field footer string[]
---@field content ServiceField[] ---@field content ServiceField[]
---@field FONT_SIZE number
---@field FONT_FACE string
---@field FONT_COLOR integer[] # {r, g, b, a}
---@field PADDING number[] # {left, top, right, bottom}
---@field PAGE_PADDING number[] # {left, top, right, bottom}
---@field FOOTER string|string[]
---@field FOOTER_SPACING number
local ServicePage = { local ServicePage = {
__tostring = function() return "ServicePage" end, __tostring = function() return "ServicePage" end,
FONT_SIZE = ServiceField.FONT_SIZE, FONT_SIZE = ServiceField.FONT_SIZE,
FONT_FACE = ServiceField.FONT_FACE, FONT_FACE = ServiceField.FONT_FACE,
FONT_COLOR = ServiceField.FONT_COLOR, --{r, g, b, a} FONT_COLOR = ServiceField.FONT_COLOR, --{r, g, b, a}
PADDING = {92, 128, 0, 56}, --{left, top, right, bottom} PADDING = {100, 128, 0, 56}, --{left, top, right, bottom}
PAGE_PADDING = {16, 16, 16, 16}, --{left, top, right, bottom} PAGE_PADDING = {16, 16, 16, 16}, --{left, top, right, bottom}
FOOTER = { FOOTER = {
"A/B BUTTON = SELECT ITEM", "A/B BUTTON = SELECT ITEM",
@ -51,69 +58,16 @@ function ServicePage:refreshFields()
Page.refreshFields(self) Page.refreshFields(self)
end end
---@param deltaTime number # frametime in seconds
function ServicePage:drawBackground(deltaTime)
gfx.BeginPath()
gfx.FillColor(0, 0, 0)
gfx.Rect(0, 0, Dim.design.width, Dim.design.height)
gfx.Fill()
end
---@param deltaTime number # frametime in seconds
function ServicePage:drawHeader(deltaTime)
local pageTitleTopPadding = self.PAGE_PADDING[2]
local lineHeight = self.FOOTER_SPACING
gfx.BeginPath()
gfx.FontSize(self.FONT_SIZE)
gfx.LoadSkinFont(self.FONT_FACE)
gfx.FillColor(table.unpack(self.FONT_COLOR))
gfx.TextAlign(gfx.TEXT_ALIGN_CENTER | gfx.TEXT_ALIGN_TOP)
if type(self.title) == "table" then
for index, line in ipairs(self.title) do
gfx.Text(line, Dim.design.width / 2, pageTitleTopPadding + (index-1) * lineHeight)
end
elseif type(self.title) == "string" then
gfx.Text(self.title, Dim.design.width / 2, pageTitleTopPadding)
end
end
---@param deltaTime number # frametime in seconds
function ServicePage:drawFooter(deltaTime)
local footer = self.content[self.selectedIndex] and self.content[self.selectedIndex].footer or self.footer
local pageFooterBottomPadding = self.PADDING[4]
local lineHeight = self.FOOTER_SPACING
gfx.BeginPath()
gfx.FontSize(self.FONT_SIZE)
gfx.LoadSkinFont(self.FONT_FACE)
gfx.FillColor(table.unpack(self.FONT_COLOR))
gfx.TextAlign(gfx.TEXT_ALIGN_CENTER | gfx.TEXT_ALIGN_BOTTOM)
local yFooterBase
if type(footer) == "table" then
yFooterBase = Dim.design.height - pageFooterBottomPadding - #footer * lineHeight
for index, line in ipairs(footer) do
gfx.Text(line, Dim.design.width / 2, yFooterBase + (index-1) * lineHeight)
end
elseif type(footer) == "string" then
yFooterBase = Dim.design.height - pageFooterBottomPadding
gfx.Text(footer, Dim.design.width / 2, yFooterBase)
end
end
---@param button integer # options are under the `game` table prefixed with `BUTTON` ---@param button integer # options are under the `game` table prefixed with `BUTTON`
function ServicePage:handleButtonInput(button) function ServicePage:handleButtonInput(button)
local field = self.content[self.selectedIndex] local field = self.content[self.selectedIndex]
if field and field.handleButtonInput then
-- if the field indicates that the button input has been handled in a -- if the field indicates that the button input has been handled in a
-- way that requires no further processing, return from this function -- way that requires no further processing, return from this function
if field:handleButtonInput(button) then if field:handleButtonInput(button) then
return return
end end
end
-- default behaviour -- default behaviour:
field:deactivate()
local direction = 0 local direction = 0
@ -122,18 +76,20 @@ function ServicePage:handleButtonInput(button)
self.viewHandler:back() self.viewHandler:back()
end end
return return
end elseif button == game.BUTTON_BTA then
if button == game.BUTTON_BTA then
direction = -1 direction = -1
elseif button == game.BUTTON_BTB then elseif button == game.BUTTON_BTB then
direction = 1 direction = 1
end end
if direction ~= 0 then
field:deactivate()
self.selectedIndex = Util.modIndex(self.selectedIndex + direction, #self.content) self.selectedIndex = Util.modIndex(self.selectedIndex + direction, #self.content)
field = self.content[self.selectedIndex] field = self.content[self.selectedIndex]
field:focus({direction = direction}) -- send direction as the message field:focus({direction = direction}) -- send direction as the message
end
end end
---@param knob integer # `0` = Left, `1` = Right ---@param knob integer # `0` = Left, `1` = Right
@ -144,4 +100,73 @@ function ServicePage:handleKnobInput(knob, delta)
end end
end end
---@param deltaTime number # frametime in seconds
function ServicePage:drawBackground(deltaTime)
gfx.BeginPath()
gfx.FillColor(0, 0, 0)
gfx.Rect(0, 0, Dim.design.width, Dim.design.height)
gfx.Fill()
end
---@param deltaTime number # frametime in seconds
function ServicePage:drawContent(deltaTime)
gfx.Save()
gfx.Translate(self.PADDING[1], self.PADDING[2])
local contentW = Dim.design.width - self.PADDING[1] - self.PADDING[3]
local contentH = Dim.design.height - self.PADDING[2] - self.PADDING[4]
gfx.Scissor(0, 0, contentW, contentH)
Page.drawContent(self, deltaTime)
gfx.Restore()
end
---@param deltaTime number # frametime in seconds
function ServicePage:drawHeader(deltaTime)
local lineHeight = self.FOOTER_SPACING
gfx.BeginPath()
gfx.FontSize(self.FONT_SIZE)
gfx.LoadSkinFont(self.FONT_FACE)
gfx.FillColor(table.unpack(self.FONT_COLOR))
gfx.TextAlign(gfx.TEXT_ALIGN_CENTER | gfx.TEXT_ALIGN_TOP)
if type(self.title) == "table" then
for index, line in ipairs(self.title) do
gfx.Text(line, Dim.design.width / 2, (index-1) * lineHeight)
end
elseif type(self.title) == "string" then
gfx.Text(self.title, Dim.design.width / 2, 0)
end
end
---@param deltaTime number # frametime in seconds
function ServicePage:drawFooter(deltaTime)
local footer = self.content[self.selectedIndex] and self.content[self.selectedIndex].footer or self.footer
local lineHeight = self.FOOTER_SPACING
gfx.BeginPath()
gfx.FontSize(self.FONT_SIZE)
gfx.LoadSkinFont(self.FONT_FACE)
gfx.FillColor(table.unpack(self.FONT_COLOR))
gfx.TextAlign(gfx.TEXT_ALIGN_CENTER | gfx.TEXT_ALIGN_BOTTOM)
if type(footer) == "table" then
local yFooterBase = -#footer * lineHeight
for index, line in ipairs(footer) do
gfx.Text(line, Dim.design.width / 2, yFooterBase + (index-1) * lineHeight)
end
elseif type(footer) == "string" then
gfx.Text(footer, Dim.design.width / 2, 0)
end
end
---@param deltaTime number # frametime in seconds
function ServicePage:drawForeground(deltaTime)
gfx.Save()
gfx.Translate(0, self.PAGE_PADDING[2])
self:drawHeader(deltaTime)
gfx.Restore()
gfx.Save()
gfx.Translate(0, Dim.design.height - self.PAGE_PADDING[4])
self:drawFooter(deltaTime)
gfx.Restore()
end
return ServicePage return ServicePage

View File

@ -5,7 +5,7 @@ local Version = require("common.version")
local ServicePage = require("titlescreen.pages.service.servicepage") local ServicePage = require("titlescreen.pages.service.servicepage")
local ServiceField = require("titlescreen.fields.service.servicefield") local ServiceField = require("titlescreen.fields.service.servicefield")
local UpdateField = require("titlescreen.fields.service.updatefield") local UpdateField = require("titlescreen.fields.service.updatefield")
local SpacerField = require("titlescreen.fields.service.spacerfield") local ListField = require("titlescreen.fields.service.listfield")
local function getGameLogValue(prefix, str) local function getGameLogValue(prefix, str)
local pattern = prefix .. ":%s*([^\r\n]*)" local pattern = prefix .. ":%s*([^\r\n]*)"
@ -28,36 +28,27 @@ function VersionInfoPage:new(o)
"START BUTTON = UPDATE", "START BUTTON = UPDATE",
"BACK BUTTON = EXIT" "BACK BUTTON = EXIT"
} }
o.selectedIndex = o.selectedIndex or 3 o.selectedIndex = o.selectedIndex or 1
return Inherit(self, o, ServicePage) local this = Inherit(self, o, ServicePage)
end
---Initialize members
---@return VersionInfoPage
function VersionInfoPage:init()
ServicePage.init(self)
local logStr = ReadGameFile("log_usc-game.exe.txt") local logStr = ReadGameFile("log_usc-game.exe.txt")
self:addField(ServiceField:new{label = "SKIN ID CODE", value = Version.getLongVersion()}) 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()
self:addField(SpacerField:new()) this:addField(list)
this:refreshFields()
self:addField(UpdateField:new{label = "USC VERSION", value = getGameLogValue("Version", logStr)}) return this
self:addField(ServiceField:new{label = "USC BRANCH", value = GameConfig["UpdateChannel"]})
self:addField(ServiceField:new{label = "USC GIT COMMIT", value = getGameLogValue("Git commit", logStr)})
self:addField(SpacerField:new())
self:addField(ServiceField:new{label = "GL VERSION", value = getGameLogValue("OpenGL Version", logStr)})
self:addField(ServiceField:new{label = "GLSL VERSION", value = getGameLogValue("OpenGL Shading Language Version", logStr)})
self:addField(ServiceField:new{label = "GL RENDERER", value = getGameLogValue("OpenGL Renderer", logStr)})
self:addField(ServiceField:new{label = "GL VENDOR", value = getGameLogValue("OpenGL Vendor", logStr)})
self.content[self.selectedIndex]:focus()
return self
end end
---@param button integer # options are under the `game` table prefixed with `BUTTON` ---@param button integer # options are under the `game` table prefixed with `BUTTON`

View File

@ -30,7 +30,7 @@ local rootMenu = {
]] ]]
local currentpage = MainMenuPage:new():init() local currentpage = MainMenuPage:new()
local pageview = PageView:new(currentpage) local pageview = PageView:new(currentpage)