Files
radiantwave-legacy/internal/page/settingsPage.go
T
NeilClack 17c088cc2f Update Database
Database is more usable now.
All pages have been updated to use the database, and share an application configuration.
Page Stack has been removed, no more pages hanging around in memory. Replaced with a 'Router' which uses an Enum to determine which page should be displayed, destroys the old page and initializes the new page all in one go. No more push, pop, rollback, etc. No more holding instances of pages.
Logger has been updated with proper timestamps and sorting now works as expected."
2026-03-23 15:02:07 -05:00

245 lines
6.1 KiB
Go

package page
import (
"fmt"
"github.com/go-gl/gl/v3.3-core/gl"
"github.com/veandco/go-sdl2/sdl"
"rhemawavetech.com/rhemawave/internal/colors"
"rhemawavetech.com/rhemawave/internal/fontManager"
"rhemawavetech.com/rhemawave/internal/shaderManager"
)
type Settings struct {
Base
font *fontManager.FontEntry
textShader *shaderManager.Shader
solidShader *shaderManager.Shader
title StringItem
prompt StringItem
options []Option
verticalMargin int32
bgHighlight PageItem
highlightIndex int
}
type Option struct {
target pageType
label StringItem
}
func (p *Settings) Init(ctx *PageCtx) error {
var err error
p.verticalMargin = int32(20)
// Get font
fm := fontManager.Get()
font, ok := fm.GetFont("Roboto-Regular")
if !ok {
return fmt.Errorf("failed to get font: %w", sdl.GetError())
}
p.font = font
// Get shaders
sm := shaderManager.Get()
p.textShader, ok = sm.Get("text")
if !ok {
return fmt.Errorf("failed to get text shader: %w", sdl.GetError())
}
p.solidShader, ok = sm.Get("solid_color")
if !ok {
return fmt.Errorf("failed to get solid_color shader: %w", sdl.GetError())
}
// Initialize base
if err := p.Base.Init(ctx); err != nil {
return fmt.Errorf("failed base page initialization: %w", err)
}
// Create title
p.title, err = NewStringItem("Settings", font, colors.White)
if err != nil {
return fmt.Errorf("creating title: %w", err)
}
// Create prompt
p.prompt, err = NewStringItem("Use Arrow Keys to Navigate, Enter to Select, or F1 to return to the Main Menu", font, colors.White)
if err != nil {
return fmt.Errorf("creating prompt: %w", err)
}
// Create options
proclamationsLabel, err := NewStringItem("Proclamations", font, colors.White)
if err != nil {
return fmt.Errorf("creating proclamations label: %w", err)
}
p.options = append(p.options, Option{
target: PROCLAMATIONS,
label: proclamationsLabel,
})
wifiLabel, err := NewStringItem("WiFi Setup", font, colors.White)
if err != nil {
return fmt.Errorf("creating wifi label: %w", err)
}
p.options = append(p.options, Option{
target: WIFI,
label: wifiLabel,
})
audioLabel, err := NewStringItem("Audio Device", font, colors.White)
if err != nil {
return fmt.Errorf("creating audio label: %w", err)
}
p.options = append(p.options, Option{
target: AUDIO,
label: audioLabel,
})
emailLabel, err := NewStringItem("Email Address", font, colors.White)
if err != nil {
return fmt.Errorf("creating email label: %w", err)
}
p.options = append(p.options, Option{
target: EMAIL_ADDRESS,
label: emailLabel,
})
licenseKeyLabel, err := NewStringItem("License Key", font, colors.White)
if err != nil {
return fmt.Errorf("creating license key label: %w", err)
}
p.options = append(p.options, Option{
target: LICENSE_KEY,
label: licenseKeyLabel,
})
logsLabel, err := NewStringItem("Logs", font, colors.White)
if err != nil {
return fmt.Errorf("creating logs label: %w", err)
}
p.options = append(p.options, Option{
target: LOGS,
label: logsLabel,
})
updateLabel, err := NewStringItem("Check for Updates", font, colors.White)
if err != nil {
return fmt.Errorf("creating update label: %w", err)
}
p.options = append(p.options, Option{
target: CHECK_UPDATES,
label: updateLabel,
})
// Get base font size from database
baseFontSize := p.Context.CfgPtr.StandardFontSize
// Calculate scales
titleScale := float32(64) / float32(baseFontSize)
scale := float32(32) / float32(baseFontSize)
// Apply scales
p.title.Scale(titleScale)
p.prompt.Scale(scale)
for i := range p.options {
p.options[i].label.Scale(scale)
}
// Create background highlight using first option's dimensions
p.bgHighlight = PageItem{
ID: 0,
W: p.options[0].label.W,
H: p.options[0].label.H,
Color: colors.White,
}
p.highlightIndex = 0
// Position title at bottom
p.title.X = p.Base.ScreenCenterX - p.title.W/2
p.title.Y = p.ScreenHeight - p.title.H - p.verticalMargin*2
// Position prompt above title
p.prompt.X = p.ScreenCenterX - p.prompt.W/2
p.prompt.Y = p.title.Y - p.verticalMargin*2 - p.prompt.H
// Position options stacked upward from prompt
for i, option := range p.options {
p.options[i].label.X = p.ScreenCenterX - option.label.W/2
if i == 0 {
p.options[i].label.Y = int32(float32(p.prompt.Y)-(float32(p.verticalMargin)*4)) - option.label.H
} else {
p.options[i].label.Y = p.options[i-1].label.Y - option.label.H - 10
}
}
return nil
}
func (p *Settings) Update(dt float32) error {
return nil
}
func (p *Settings) HandleEvent(event *sdl.Event) error {
switch e := (*event).(type) {
case *sdl.KeyboardEvent:
if e.Type != sdl.KEYDOWN {
return nil
}
switch e.Keysym.Sym {
case sdl.K_UP:
if p.highlightIndex > 0 {
p.highlightIndex--
}
case sdl.K_DOWN:
if p.highlightIndex < len(p.options)-1 {
p.highlightIndex++
}
case sdl.K_RETURN:
if p.highlightIndex >= 0 && p.highlightIndex < len(p.options) {
selectedOption := p.options[p.highlightIndex]
p.Context.NavigateTo(selectedOption.target)
}
case sdl.K_BACKSPACE:
p.Context.NavigateTo(HOME)
}
}
return nil
}
func (p *Settings) Render() error {
// Render title and prompt
p.RenderTexture(p.textShader, p.title.ID, p.title.Position(), p.title.RawDimensions(), p.title.Color)
p.RenderTexture(p.textShader, p.prompt.ID, p.prompt.Position(), p.prompt.RawDimensions(), p.prompt.Color)
// Render highlight behind selected option
p.RenderSolidColorQuad(
p.solidShader,
p.options[p.highlightIndex].label.Position(),
p.options[p.highlightIndex].label.RawDimensions(),
p.bgHighlight.Color,
)
// Render all options with appropriate colors
for i, option := range p.options {
if p.highlightIndex == i {
option.label.Color = colors.Black
} else {
option.label.Color = colors.White
}
p.RenderTexture(p.textShader, option.label.ID, option.label.Position(), option.label.RawDimensions(), option.label.Color)
}
return nil
}
func (p *Settings) Destroy() error {
gl.DeleteTextures(1, &p.title.ID)
gl.DeleteTextures(1, &p.prompt.ID)
for i := range p.options {
gl.DeleteTextures(1, &p.options[i].label.ID)
}
return nil
}