Files
radiantwave-legacy/internal/page/settingsPage.go
T
NeilClack 312f5e2a90
build-prod.yml / build (push) Failing after 2s
build-dev.yml / build (push) Failing after 2s
Rename rhemawave to radiantwave throughout
2026-08-08 01:20:11 -05:00

256 lines
6.6 KiB
Go

package page
import (
"fmt"
"github.com/go-gl/gl/v3.3-core/gl"
"github.com/veandco/go-sdl2/sdl"
"radiantwavetech.com/radiantwave/internal/colors"
"radiantwavetech.com/radiantwave/internal/db"
"radiantwavetech.com/radiantwave/internal/fontManager"
"radiantwavetech.com/radiantwave/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("SpaceMonoNerdFont-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,
})
audioLabel, err := NewStringItem("Audio", 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,
})
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,
})
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,
})
// TODO: Add entry for "Tutorial"
// TODO: Add entry for "About"
// Get base font size from database
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
baseFontSize := config.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 - int32(float32(p.prompt.W)/2)
p.prompt.Y = p.title.Y - p.verticalMargin*2 - p.prompt.H
// If this value starts at 0, nothing is further left than that...
var furthestLeft int32 = p.ScreenWidth // < more to the left, > more to the right, = same
// Position options stacked upward from prompt
for i, option := range p.options {
p.options[i].label.X = p.ScreenCenterX - option.label.W/2 // Calculate horizontal center posision
if p.options[i].label.X < furthestLeft { // If the left most pixel is further left than furthestLeft, indicating a longer line:
// Then update furthestLeft
furthestLeft = p.options[i].label.X
}
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
}
}
// Now, re-iterate over the options and justify everything to furthestLeft
for i := range p.options {
p.options[i].label.X = furthestLeft
}
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
}