From 843170b282501c2557d691db92956fe6aabad8e7 Mon Sep 17 00:00:00 2001 From: NeilClack Date: Sat, 8 Aug 2026 00:54:18 -0500 Subject: [PATCH] Fix Output Device toggle --- internal/page/AudioOptions.go | 37 ++++++++++++++++++------------ internal/page/AudioOptions_test.go | 29 +++++++++++++++++++++++ 2 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 internal/page/AudioOptions_test.go diff --git a/internal/page/AudioOptions.go b/internal/page/AudioOptions.go index de62ba2..12022a5 100644 --- a/internal/page/AudioOptions.go +++ b/internal/page/AudioOptions.go @@ -15,7 +15,10 @@ import ( "rhemawavetech.com/rhemawave/internal/shaderManager" ) -const focusToggle = -1 +// focusToggle is the focus state of the audio on/off toggle, the bottommost +// focusable item. Focus states increase from top to bottom on screen: +// 0 = Audio Track entry, 1 = Output Device entry, focusToggle = toggle. +const focusToggle = 2 const triangleSize = float32(16) @@ -325,6 +328,20 @@ func (p *AudioOptions) ToggleAudio() { p.layout() } +// moveFocus returns the focus state after moving by delta (1 = down, -1 = up) +// on screen. Focus states run 0 (Audio Track) to focusToggle (toggle), so +// navigation never skips the Output Device entry. +func moveFocus(current, delta int) int { + next := current + delta + if next < 0 { + next = 0 + } + if next > focusToggle { + next = focusToggle + } + return next +} + func (p *AudioOptions) HandleEvent(event *sdl.Event) error { e, ok := (*event).(*sdl.KeyboardEvent) if !ok || e.Type != sdl.KEYDOWN { @@ -343,22 +360,12 @@ func (p *AudioOptions) HandleEvent(event *sdl.Event) error { } case sdl.K_DOWN: - if p.focusState == focusToggle { - p.focusState = 0 - p.updateCursorPosition() - } else if p.focusState < 1 { - p.focusState++ - p.updateCursorPosition() - } + p.focusState = moveFocus(p.focusState, 1) + p.updateCursorPosition() case sdl.K_UP: - if p.focusState == 0 { - p.focusState = focusToggle - p.updateCursorPosition() - } else if p.focusState > 0 { - p.focusState-- - p.updateCursorPosition() - } + p.focusState = moveFocus(p.focusState, -1) + p.updateCursorPosition() case sdl.K_RIGHT: p.UpdateVolume(10) diff --git a/internal/page/AudioOptions_test.go b/internal/page/AudioOptions_test.go new file mode 100644 index 0000000..3759f0e --- /dev/null +++ b/internal/page/AudioOptions_test.go @@ -0,0 +1,29 @@ +package page + +import "testing" + +func TestMoveFocus(t *testing.T) { + tests := []struct { + name string + current int + delta int + want int + }{ + {"down from track goes to device", 0, 1, 1}, + {"down from device goes to toggle", 1, 1, focusToggle}, + {"down from toggle stays", focusToggle, 1, focusToggle}, + {"up from toggle goes to device", focusToggle, -1, 1}, + {"up from device goes to track", 1, -1, 0}, + {"up from track stays", 0, -1, 0}, + {"down does not overshoot below toggle", focusToggle, 5, focusToggle}, + {"up does not undershoot above track", 0, -5, 0}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := moveFocus(tt.current, tt.delta); got != tt.want { + t.Errorf("moveFocus(%d, %d) = %d, want %d", tt.current, tt.delta, got, tt.want) + } + }) + } +}