diff --git a/scripts/components/pager/page.lua b/scripts/components/pager/page.lua index 43edab4..51001e2 100644 --- a/scripts/components/pager/page.lua +++ b/scripts/components/pager/page.lua @@ -1,3 +1,4 @@ +require("common.globals") require("common.class") ---@class Page diff --git a/scripts/titlescreen/fields/boot/checkupdatefield.lua b/scripts/titlescreen/fields/boot/checkupdatefield.lua index 640c7fb..51c81a9 100644 --- a/scripts/titlescreen/fields/boot/checkupdatefield.lua +++ b/scripts/titlescreen/fields/boot/checkupdatefield.lua @@ -8,7 +8,7 @@ local ServiceField = require("titlescreen.fields.service.servicefield") local CheckUpdateField = { __tostring = function() return "CheckUpdateField" end, PROGRESS_FREQ = 1 / 5, -- 5Hz - CHECK_UPDATE_MOCK_DELAY = 3, -- seconds + CHECK_UPDATE_TIMEOUT = 5, -- seconds } ---Create a new CheckUpdateField instance @@ -24,6 +24,7 @@ function CheckUpdateField:new(o) this._url = nil this._version = nil + this._onUpdateAvailableFired = false return this end @@ -47,12 +48,16 @@ function CheckUpdateField:drawValue(deltaTime) end function CheckUpdateField:tick(deltaTime) - if self._timer > self.CHECK_UPDATE_MOCK_DELAY then - self._url, self._version = game.UpdateAvailable() - if self._url then - self.onUpdateAvailable(self._url, self._version) - else - self:getParentPage().viewHandler:clear() -- Exit out of bootscreen + if not self._onUpdateAvailableFired then + if self._timer > self.CHECK_UPDATE_TIMEOUT then + self._url, self._version = game.UpdateAvailable() + -- self._url = "" -- debug code to force onUpdateAvailable() + if self._url then + self.onUpdateAvailable(self._url, self._version) + self._onUpdateAvailableFired = true + else + self:getParentPage().viewHandler:clear() -- Exit out of bootscreen + end end end self._timer = self._timer + deltaTime diff --git a/scripts/titlescreen/fields/boot/dialogfield.lua b/scripts/titlescreen/fields/boot/dialogfield.lua new file mode 100644 index 0000000..94cc313 --- /dev/null +++ b/scripts/titlescreen/fields/boot/dialogfield.lua @@ -0,0 +1,149 @@ +require("common.class") +local ContainerField = require("components.pager.containerfield") + +---@class DialogField: ContainerField +---@field _symbolMargin number +---@field _symbolSize number +local DialogField = { + __tostring = function() return "ContainerField" end, + BGCOLOR = {0, 0, 0, 255}, --{r, g, b, a} + DEFAULT_WIDTH = 400, + DEFAULT_HEIGHT = 200, + FONT_SIZE = 16, + FONT_FACE = "dfmarugoth.ttf", + FONT_COLOR = {255, 255, 255, 255}, + BORDERCOLOR = {255, 255, 255, 255}, + BORDERRADII = 12, + BORDERWIDTH = 2, + HEADER = { + title = "Title", + code = "0-0000-0000" + }, + TEXT = { + "Top text,", + "Sample text,", + "Bottom text." + }, + LEGEND = { + { + label = "BUTTON", + text = "DESCRIPTION" + }, + }, +} + +---Create a new DialogField instance +--- +---Inherits from ContainerField +---@param o ContainerField +---@return DialogField +function DialogField:new(o) + o = o or {} + + o.aabbW = o.aabbW or self.DEFAULT_WIDTH + o.aabbH = o.aabbH or self.DEFAULT_HEIGHT + + local this = Inherit(self, o, ContainerField) + + this._symbolMargin = 8 + this._symbolSize = 48 + + return this +end + +---Draw the dialog symbol +--- +---Default implementation is a yellow triangle with an exclamation mark +---@param deltaTime number # frametime in seconds +function DialogField:drawSymbol(deltaTime) + local symbolColor = {255, 255, 0, 255} + gfx.Save() + gfx.Translate(self._symbolMargin, self._symbolMargin) + gfx.FillColor(table.unpack(symbolColor)) + gfx.BeginPath() + local symbolBottomY = math.sqrt(3) / 2 * self._symbolSize + gfx.MoveTo(0, symbolBottomY) + gfx.LineTo(self._symbolSize / 2, 0) + gfx.LineTo(self._symbolSize, symbolBottomY) + gfx.Fill() + -- exclamation mark + local excTopMargin = 10 + local excBottomMargin = 4 + local excThickness = 5 + local excColor = {0, 0, 0, 255} + gfx.FillColor(table.unpack(excColor)) + gfx.BeginPath() + gfx.Rect( + self._symbolSize / 2 - excThickness / 2, -- x + excTopMargin, -- y + excThickness, -- w + symbolBottomY - excTopMargin - excBottomMargin - 3 / 2 * excThickness -- h + ) + gfx.Rect( + self._symbolSize / 2 - excThickness / 2, -- x + symbolBottomY - excBottomMargin - excThickness, -- y + excThickness, excThickness -- w, h + ) + gfx.Fill() + gfx.Restore() +end + +---@param deltaTime number # frametime in seconds +function DialogField:drawBackground(deltaTime) + local textMargin = 4 + -- border + local borderH = self.aabbH - #self.LEGEND * self.FONT_SIZE - textMargin + gfx.BeginPath() + gfx.StrokeColor(table.unpack(self.BORDERCOLOR)) + gfx.StrokeWidth(self.BORDERWIDTH) + gfx.FillColor(table.unpack(self.BGCOLOR)) + gfx.RoundedRect(0, 0, self.aabbW, borderH, self.BORDERRADII) + gfx.Fill() + gfx.Stroke() + + gfx.FontSize(self.FONT_SIZE) + gfx.LoadSkinFont(self.FONT_FACE) + + -- draw symbol + self:drawSymbol(deltaTime) + + -- legend + local legendX = 0 + local legendY = borderH + textMargin + gfx.TextAlign(gfx.TEXT_ALIGN_TOP | gfx.TEXT_ALIGN_LEFT) + gfx.FillColor(table.unpack(self.FONT_COLOR)) + for _, legend in ipairs(self.LEGEND) do + gfx.Text(legend.label .. " = " .. legend.text, legendX, legendY) + legendY = legendY + self.FONT_SIZE + end + + -- header + local headerX = self._symbolSize + self._symbolMargin + 16 + local headerY = self._symbolMargin + gfx.Save() + gfx.Translate(headerX, headerY) + gfx.Text(self.HEADER.title, 0, 0) + local separatorY = self.FONT_SIZE + textMargin + local separatorThickness = 1 + gfx.StrokeWidth(separatorThickness) + gfx.BeginPath() + gfx.MoveTo(0, separatorY) + gfx.LineTo(self.aabbW - headerX - self._symbolMargin, separatorY) + gfx.Stroke() + local codeY = separatorY + textMargin + gfx.Text(self.HEADER.code, 0, codeY) + gfx.Restore() +end + +---@param deltaTime number # frametime in seconds +function DialogField:drawForeground(deltaTime) + local textX = 12 + local textY = 64 + local lineHeight = self.FONT_SIZE + 4 + for _, line in ipairs(self.TEXT) do + gfx.Text(line, textX, textY) + textY = textY + lineHeight + end +end + +return DialogField diff --git a/scripts/titlescreen/fields/boot/updatedialogfield.lua b/scripts/titlescreen/fields/boot/updatedialogfield.lua deleted file mode 100644 index a2510eb..0000000 --- a/scripts/titlescreen/fields/boot/updatedialogfield.lua +++ /dev/null @@ -1,32 +0,0 @@ -require("common.class") -local ContainerField = require("components.pager.containerfield") - ----@class UpdateDialogField: ContainerField -local UpdateDialogField = { - __tostring = function() return "ContainerField" end, - BGCOLOR = {0, 0, 0, 255}, --{r, g, b, a} - BORDERCOLOR = {255, 255, 255, 255}, - BORDERRADII = 4, - BORDERWIDTH = 1, -} - ----Create a new UpdateDialogField instance ---- ----Inherits from ContainerField ----@param o ContainerField ----@return UpdateDialogField -function UpdateDialogField:new(o) - o = o or {} - - return Inherit(self, o, ContainerField) -end - -function UpdateDialogField:drawBackground(deltaTime) - -end - -function UpdateDialogField:drawForeground(deltaTime) - -end - -return UpdateDialogField diff --git a/scripts/titlescreen/pages/boot/checkupdatepage.lua b/scripts/titlescreen/pages/boot/checkupdatepage.lua index 13b53ea..fab0680 100644 --- a/scripts/titlescreen/pages/boot/checkupdatepage.lua +++ b/scripts/titlescreen/pages/boot/checkupdatepage.lua @@ -2,8 +2,10 @@ require("common.class") local Dim = require("common.dimensions") local Page = require("components.pager.page") local CheckUpdateField = require("titlescreen.fields.boot.checkupdatefield") +local DialogField = require("titlescreen.fields.boot.dialogfield") ---@class CheckUpdatePage: Page +---@field _focusedField CheckUpdateField local CheckUpdatePage = { __tostring = function() return "CheckUpdatePage" end, } @@ -14,15 +16,76 @@ local CheckUpdatePage = { function CheckUpdatePage:new(o) local this = Inherit(self, 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{ + posX = posX, + posY = posY, + aabbW = width, + aabbH = height, + HEADER = { + title = "Updates found", + code = "0-1000-0000" + }, + TEXT = { + "An update is available to Unnamed SDVX Clone,", + "please update to receive the latest features." + }, + LEGEND = { + { + label = "BACK BUTTON", + text = "ABORT UPDATE/START GAME" + }, + { + label = "START BUTTON", + text = "GO TO SERVICE PAGE" + } + } + } + this._updateDialogField.handleButtonInput = function (self, button) + if not this.viewHandler then + return false + end + + if button == game.BUTTON_BCK then + this.viewHandler:clear() -- Cancel update, close screen + 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()) + return true + end + end + 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 end + this:addField(this._checkUpdateField) + this._focusedField = this._checkUpdateField + return this end +function CheckUpdatePage:handleButtonInput(button) + if self._focusedField and self._focusedField:handleButtonInput(button) then + return -- stop processing input + end + + if button == game.BUTTON_BCK then + self.viewHandler:back() + end +end + ---@param deltaTime number # frametime in seconds function CheckUpdatePage:drawBackground(deltaTime) gfx.BeginPath()