diff --git a/docs/superpowers/specs/2026-04-05-sounds-tab-design.md b/docs/superpowers/specs/2026-04-05-sounds-tab-design.md new file mode 100644 index 0000000..f30dac1 --- /dev/null +++ b/docs/superpowers/specs/2026-04-05-sounds-tab-design.md @@ -0,0 +1,171 @@ +# Sounds Tab Design + +Date: 2026-04-05 + +## Context + +Cthulhu currently stores several non-speech sound settings in the general settings file, but the preferences dialog does not present them coherently: + +- The General tab contains an inline Sound section for backend, theme, and role-sound presentation. +- The progress-bar beep checkbox lives in the General tab's progress-bar section. +- `soundVolume` exists in settings and the user's active profile, but there is no UI control for it. +- `enableSound`, `playSoundForRole`, `playSoundForState`, `playSoundForPositionInSet`, and `playSoundForValue` exist as persisted settings but are not currently exposed in the dialog. +- `progressBarBeepInterval` exists in runtime defaults but is not part of the normal persisted general-settings key list. + +The result is that sound-related behavior is split across the dialog and some active settings cannot be inspected or changed from the UI. + +## Goals + +- Add a dedicated `Sounds` preferences tab. +- Move currently exposed sound-related controls out of `General` and into `Sounds`. +- Move the progress-bar beep option into `Sounds` while leaving the rest of the progress-bar section in `General`. +- Expose currently hidden sound-related settings in the UI. +- Add a UI control for `soundVolume`. +- Expose and persist `progressBarBeepInterval`. +- Preserve the existing settings model and save format. +- Avoid clobbering unrelated settings when saving preferences. + +## Non-Goals + +- No refactor of the broader preferences architecture. +- No changes to sound playback implementation outside what is needed to load and save settings correctly. +- No new settings schema beyond persisting the existing hidden `progressBarBeepInterval`. +- No dynamic enable/disable logic for sound controls in this pass. + +## Design Summary + +Add a new notebook page labeled `Sounds` and make it the single home for non-speech sound configuration. Remove the inline Sound frame from `General`. Keep the existing progress-bar speech/braille controls and shared progress-bar behavior controls in `General`, but move beep-specific controls into `Sounds`. + +The new tab will use existing settings keys wherever possible and will save through the existing `prefsDict` and settings-manager flow. + +## Sounds Tab Layout + +The `Sounds` tab will contain three sections. + +### Output + +- `enableSound` checkbox +- `soundVolume` slider +- `soundSink` combo box + +`soundVolume` should be represented by a native `GtkScale` and persisted back to the existing floating-point `soundVolume` setting. The control should initialize from `prefsDict.get("soundVolume", settings.soundVolume)`. + +For this implementation, the slider should match the stored setting directly rather than introducing a new percentage representation. That keeps the implementation small and avoids conversion-only complexity in a settings path that already exists. + +### Presentation + +- `soundTheme` combo box +- `roleSoundPresentation` combo box +- `playSoundForRole` checkbox +- `playSoundForState` checkbox +- `playSoundForPositionInSet` checkbox +- `playSoundForValue` checkbox + +These controls will expose already-existing settings and use the same `prefsDict` update pattern already used by the current dialog. + +### Alerts + +- `beepProgressBarUpdates` checkbox +- `progressBarBeepInterval` spin button + +This section controls only beep-based progress-bar alerts. The label should make it clear that the interval is beep-specific, not the general progress-bar announcement interval. + +## General Tab Changes + +Keep these controls in `General`: + +- `speakProgressBarUpdates` +- `brailleProgressBarUpdates` +- `progressBarUpdateInterval` +- `progressBarVerbosity` +- `ignoreStatusBarProgressBars` + +Remove these from `General`: + +- the inline Sound frame +- `beepProgressBarUpdates` + +This preserves the current organization for general progress-bar announcement behavior while moving sound-only concerns into the new tab. + +## Settings and Persistence + +### Existing Keys Reused + +The new UI will continue to use the existing settings keys: + +- `enableSound` +- `soundVolume` +- `soundSink` +- `soundTheme` +- `roleSoundPresentation` +- `playSoundForRole` +- `playSoundForState` +- `playSoundForPositionInSet` +- `playSoundForValue` +- `beepProgressBarUpdates` + +### Persisted Hidden Key + +Add `progressBarBeepInterval` to the persisted general-settings key list so it round-trips through: + +- defaults in `settings.py` +- settings-manager general settings +- TOML backend save/load +- `prefsDict` in the preferences dialog + +This avoids the current mismatch where beep interval exists as a runtime default but is not part of the normal persisted general-settings path. + +### Save Behavior + +The implementation should continue to update individual keys in `prefsDict` and then rely on the existing general-settings save flow. No bulk replacement of the whole settings structure should be introduced. + +This is specifically intended to avoid accidental overwrites of unrelated settings already present in `user-settings.toml`. + +## Default Values + +- Keep `progressBarUpdateInterval = 10` as the default for speech and braille progress-bar updates. +- Keep `progressBarBeepInterval = 0` as the default for beep-based progress-bar updates. +- Keep `soundVolume = 0.5` as the existing default unless the user explicitly changes it. + +The new UI should reflect these values accurately on load. + +## Accessibility + +Use native GTK controls and follow the existing preferences-dialog patterns: + +- every label must be associated with its control via `mnemonic_widget` +- checkboxes should use the existing `checkButtonToggled` convention when possible +- combo boxes should keep proper `label-for` / `labelled-by` relationships +- no custom-drawn controls +- no keyboard traps + +The new tab should be fully reachable with standard tab navigation. + +## Implementation Notes + +Expected files to change: + +- `src/cthulhu/cthulhu-setup.ui` +- `src/cthulhu/cthulhu_gui_prefs.py` +- `src/cthulhu/settings.py` + +Implementation should: + +- add the new notebook page and move or recreate the relevant widgets there +- initialize and save the new sound controls using existing dialog patterns +- add explicit handling for `soundVolume` +- add explicit handling for `progressBarBeepInterval` +- keep all unrelated preference behavior unchanged + +## Verification + +The implementation should be considered complete only after all of the following are checked: + +1. The preferences dialog opens and the new `Sounds` tab is present. +2. Existing sound settings load into the correct controls. +3. Changing sound settings updates `prefsDict` without breaking unrelated settings. +4. Saving preferences preserves unrelated keys in `user-settings.toml`. +5. `progressBarBeepInterval` is written and reloaded correctly. +6. The General tab still handles speech/braille progress-bar settings correctly. +7. Touched Python files pass compile checks. +8. Manual verification confirms keyboard navigation and label association remain intact.