256 lines
6.6 KiB
Go
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"
|
|
"rhemawavetech.com/rhemawave/internal/colors"
|
|
"rhemawavetech.com/rhemawave/internal/db"
|
|
"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("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
|
|
}
|