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/logger" "rhemawavetech.com/rhemawave/internal/shaderManager" ) type AudioDevices struct { Base font *fontManager.FontEntry textShader *shaderManager.Shader solidShader *shaderManager.Shader title StringItem prompt StringItem AudioStatusToggle StringItem highlightIndex int selectedIndex int verticalMargin int32 CfgPtr *db.AppConfig } func (p *AudioDevices) 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("base init failed: %w", err) } // Get font size from database baseFontSize := p.Context.CfgPtr.StandardFontSize // Calculate scales titleScale := float32(64) / float32(baseFontSize) itemScale := float32(32) / float32(baseFontSize) // Create title p.title, err = NewStringItem("Select an Audio Output Device", p.font, colors.White) if err != nil { return fmt.Errorf("creating title: %w", err) } p.title.Scale(titleScale) // Create prompt p.prompt, err = NewStringItem("Use Arrow Keys to select, Enter to confirm", p.font, colors.White) if err != nil { return fmt.Errorf("creating prompt: %w", err) } p.prompt.Scale(itemScale) on := p.Context.CfgPtr.AudioEnabled audioStatus := "Turn Audio On" if on { audioStatus = "Turn Audio Off" } audioStatusStringItem, err := NewStringItem(audioStatus, p.font, colors.White) if err != nil { return fmt.Errorf("failed to create Turn Audio Off string item: %w", err) } // Scale the new option audioStatusStringItem.Scale(itemScale) p.layout() return nil } func (p *AudioDevices) CreateAudioStatusItem() error { on := p.Context.CfgPtr.AudioEnabled statusString := "Turn Audio Off" // The audio is ON color := colors.Green if !on { statusString = "Turn Audio on" color = colors.Red } audioStatusStringItem, err := NewStringItem(statusString, p.font, color) if err != nil { return fmt.Errorf("failed to create '%s' string item: %v", statusString, err) } p.AudioStatusToggle = audioStatusStringItem return nil } func (p *AudioDevices) layout() { // Position title at bottom p.title.X = p.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 } func (p *AudioDevices) HandleEvent(event *sdl.Event) error { e, ok := (*event).(*sdl.KeyboardEvent) if !ok || e.Type != sdl.KEYDOWN { return nil } switch e.Keysym.Sym { case sdl.K_RETURN: // Toggle AudioEnabled p.Context.CfgPtr.AudioEnabled = !p.Context.CfgPtr.AudioEnabled // Save the config to the database p.Context.DbPtr.Save(p.Context.CfgPtr) // Refresh the config throughout the application p.Context.RefreshConfig() // Update AudioEnabled UI element case sdl.K_BACKSPACE: p.Context.NavigateTo(SETTINGS) } return nil } func (p *AudioDevices) Render() error { // Always render title and prompt if err := p.RenderTexture(p.textShader, p.title.ID, p.title.Position(), p.title.RawDimensions(), p.title.Color); err != nil { logger.Error("unable to render title texture: %v", err) return fmt.Errorf("unable to render title texture: %w", err) } if err := p.RenderTexture(p.textShader, p.prompt.ID, p.prompt.Position(), p.prompt.RawDimensions(), p.prompt.Color); err != nil { logger.Error("unable to render prompt texture: %v", err) return fmt.Errorf("unable to render prompt texture: %w", err) } if err := p.RenderTexture(p.textShader, p.AudioStatusToggle.ID, p.AudioStatusToggle.Position(), p.AudioStatusToggle.RawDimensions(), p.AudioStatusToggle.Color); err != nil { logger.Error("unable to render audioStatusToggle texture: %v", err) return fmt.Errorf("unable to render audioStatusToggle texture: %w", err) } return nil } func (p *AudioDevices) Destroy() error { gl.DeleteTextures(1, &p.title.ID) gl.DeleteTextures(1, &p.prompt.ID) return nil }