Fix prefs state churn and sound-only role speech

Some settings were being reset when tab changed and a key was pressed, e.g. control.

Radio buttons were still announced even with sound only set.

Controls for AI assistant tab were vanishing after being set.
This commit is contained in:
Storm Dragon
2026-02-18 07:02:31 -05:00
parent 9152455227
commit 95d33047fa
5 changed files with 34 additions and 22 deletions
+11 -13
View File
@@ -2563,22 +2563,20 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
self._updateAIControlsState(enabled)
def _updateAIControlsState(self, enabled):
"""Enable or disable AI controls based on AI enabled state."""
self.aiProviderCombo.set_sensitive(enabled)
self.aiApiKeyEntry.set_sensitive(enabled)
self.aiOllamaModelEntry.set_sensitive(enabled)
self.aiOllamaEndpointEntry.set_sensitive(enabled)
self.aiConfirmationCheckButton.set_sensitive(enabled)
self.aiScreenshotQualityCombo.set_sensitive(enabled)
"""Refresh AI controls while keeping configuration fields editable."""
_ = enabled # kept for signal/call compatibility
# Keep settings editable even when AI assistant is disabled so users
# can configure providers/keys before enabling it.
self.aiProviderCombo.set_sensitive(True)
self.aiConfirmationCheckButton.set_sensitive(True)
self.aiScreenshotQualityCombo.set_sensitive(True)
try:
self.get_widget("aiGetClaudeKeyButton").set_sensitive(enabled)
self.get_widget("aiGetClaudeKeyButton").set_sensitive(True)
except:
pass # Button might not exist in older UI files
# Update provider-specific controls if AI is enabled
if enabled:
current_provider = self.prefsDict.get("aiProvider", settings.aiProvider)
self._updateProviderControls(current_provider)
current_provider = self.prefsDict.get("aiProvider", settings.aiProvider)
self._updateProviderControls(current_provider)
def _initIndentationState(self):
"""Initialize Indentation widgets with current settings."""
+8 -7
View File
@@ -325,7 +325,6 @@ class AIAssistant(Plugin):
if not self._prefs_widgets:
return
enabled = self._prefs_widgets["enable_check"].get_active()
provider_values = self._prefs_widgets.get("provider_values", [])
provider_index = self._prefs_widgets["provider_combo"].get_active()
provider = provider_values[provider_index] if 0 <= provider_index < len(provider_values) else settings.aiProvider
@@ -333,12 +332,14 @@ class AIAssistant(Plugin):
is_gemini = provider == settings.AI_PROVIDER_GEMINI
is_ollama = provider == settings.AI_PROVIDER_OLLAMA
self._prefs_widgets["provider_combo"].set_sensitive(enabled)
self._prefs_widgets["api_key_entry"].set_sensitive(enabled and is_gemini)
self._prefs_widgets["ollama_model_entry"].set_sensitive(enabled and is_ollama)
self._prefs_widgets["ollama_endpoint_entry"].set_sensitive(enabled and is_ollama)
self._prefs_widgets["confirmation_check"].set_sensitive(enabled)
self._prefs_widgets["quality_combo"].set_sensitive(enabled)
# Keep preferences editable even when the feature is disabled so users
# can prepare configuration before turning AI assistant on.
self._prefs_widgets["provider_combo"].set_sensitive(True)
self._prefs_widgets["api_key_entry"].set_sensitive(is_gemini)
self._prefs_widgets["ollama_model_entry"].set_sensitive(is_ollama)
self._prefs_widgets["ollama_endpoint_entry"].set_sensitive(is_ollama)
self._prefs_widgets["confirmation_check"].set_sensitive(True)
self._prefs_widgets["quality_combo"].set_sensitive(True)
def refresh_settings(self):
"""Refresh plugin settings and reinitialize provider. Called when settings change."""
+9
View File
@@ -1967,6 +1967,15 @@ class Script(script.Script):
debug.printMessage(debug.LEVEL_INFO, msg, True)
return
# Some toolkits emit transient window:deactivate/window:activate pairs
# while the same window remains active. Treat those as noise so we do
# not clear state and force a full script/settings reactivation.
AXObject.clear_cache(event.source)
if AXUtilities.is_active(event.source):
msg = "DEFAULT: Ignoring event. Source window still active."
debug.printMessage(debug.LEVEL_INFO, msg, True)
return
if self.flatReviewPresenter.is_active():
self.flatReviewPresenter.quit()
+3 -1
View File
@@ -572,7 +572,9 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
and soundEnabled:
roleSoundIcon = sound_theme_manager.getManager().getRoleSoundIcon(role)
if roleSoundPresentation == settings.ROLE_SOUND_PRESENTATION_SOUND_ONLY \
and soundEnabled and roleSoundIcon:
and soundEnabled:
# Stateful controls present their role via state sounds; suppress
# spoken role names here even if no dedicated role icon exists.
if AXUtilities.is_check_box(obj) \
or AXUtilities.is_check_menu_item(obj) \
or AXUtilities.is_radio_button(obj) \
+3 -1
View File
@@ -678,7 +678,9 @@ class SpeechGenerator(generator.Generator):
and soundEnabled:
roleSoundIcon = sound_theme_manager.getManager().getRoleSoundIcon(role)
if roleSoundPresentation == settings.ROLE_SOUND_PRESENTATION_SOUND_ONLY \
and soundEnabled and roleSoundIcon:
and soundEnabled:
# Stateful controls present their role via state sounds; suppress
# spoken role names here even if no dedicated role icon exists.
if AXUtilities.is_check_box(obj) \
or AXUtilities.is_check_menu_item(obj) \
or AXUtilities.is_radio_button(obj) \