Completely redesigned the indentation plugin. Now adds a tab to preferences with complete customization for how indentation is presented.
This commit is contained in:
+670
-21
@@ -21,6 +21,55 @@
|
|||||||
<property name="step_increment">10</property>
|
<property name="step_increment">10</property>
|
||||||
<property name="page_increment">50</property>
|
<property name="page_increment">50</property>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="GtkAdjustment" id="indentationSpacesPerLevelAdjustment">
|
||||||
|
<property name="lower">1</property>
|
||||||
|
<property name="upper">16</property>
|
||||||
|
<property name="value">4</property>
|
||||||
|
<property name="step_increment">1</property>
|
||||||
|
<property name="page_increment">1</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkAdjustment" id="indentationTabWidthAdjustment">
|
||||||
|
<property name="lower">1</property>
|
||||||
|
<property name="upper">16</property>
|
||||||
|
<property name="value">4</property>
|
||||||
|
<property name="step_increment">1</property>
|
||||||
|
<property name="page_increment">1</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkAdjustment" id="indentationAudioBaseFrequencyAdjustment">
|
||||||
|
<property name="lower">50</property>
|
||||||
|
<property name="upper">2000</property>
|
||||||
|
<property name="value">200</property>
|
||||||
|
<property name="step_increment">10</property>
|
||||||
|
<property name="page_increment">50</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkAdjustment" id="indentationAudioStepFrequencyAdjustment">
|
||||||
|
<property name="lower">1</property>
|
||||||
|
<property name="upper">500</property>
|
||||||
|
<property name="value">80</property>
|
||||||
|
<property name="step_increment">5</property>
|
||||||
|
<property name="page_increment">20</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkAdjustment" id="indentationAudioMaxFrequencyAdjustment">
|
||||||
|
<property name="lower">200</property>
|
||||||
|
<property name="upper">5000</property>
|
||||||
|
<property name="value">1200</property>
|
||||||
|
<property name="step_increment">50</property>
|
||||||
|
<property name="page_increment">100</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkAdjustment" id="indentationAudioDurationAdjustment">
|
||||||
|
<property name="lower">0.01</property>
|
||||||
|
<property name="upper">2</property>
|
||||||
|
<property name="value">0.15</property>
|
||||||
|
<property name="step_increment">0.01</property>
|
||||||
|
<property name="page_increment">0.1</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkAdjustment" id="indentationAudioVolumeAdjustment">
|
||||||
|
<property name="lower">0</property>
|
||||||
|
<property name="upper">1</property>
|
||||||
|
<property name="value">0.7</property>
|
||||||
|
<property name="step_increment">0.05</property>
|
||||||
|
<property name="page_increment">0.1</property>
|
||||||
|
</object>
|
||||||
<object class="GtkListStore" id="liststore1">
|
<object class="GtkListStore" id="liststore1">
|
||||||
<columns>
|
<columns>
|
||||||
<!-- column-name gchararray1 -->
|
<!-- column-name gchararray1 -->
|
||||||
@@ -1830,21 +1879,6 @@
|
|||||||
<property name="top_attach">0</property>
|
<property name="top_attach">0</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
|
||||||
<object class="GtkCheckButton" id="enableSpeechIndentationCheckButton">
|
|
||||||
<property name="label" translatable="yes">Speak _indentation and justification</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="receives_default">False</property>
|
|
||||||
<property name="use_underline">True</property>
|
|
||||||
<property name="draw_indicator">True</property>
|
|
||||||
<signal name="toggled" handler="checkButtonToggled" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left_attach">0</property>
|
|
||||||
<property name="top_attach">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkCheckButton" id="enableMnemonicSpeakingCheckButton">
|
<object class="GtkCheckButton" id="enableMnemonicSpeakingCheckButton">
|
||||||
<property name="label" translatable="yes">Spea_k object mnemonics</property>
|
<property name="label" translatable="yes">Spea_k object mnemonics</property>
|
||||||
@@ -3331,8 +3365,8 @@
|
|||||||
<property name="top_attach">0</property>
|
<property name="top_attach">0</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkGrid" id="textAttributesConfigGrid">
|
<object class="GtkGrid" id="textAttributesConfigGrid">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<child>
|
<child>
|
||||||
@@ -3553,6 +3587,621 @@
|
|||||||
<property name="tab_fill">False</property>
|
<property name="tab_fill">False</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="indentationGrid">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="border_width">12</property>
|
||||||
|
<property name="row_spacing">10</property>
|
||||||
|
<property name="column_spacing">10</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkFrame" id="indentationPresentationFrame">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="shadow_type">none</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment" id="indentationPresentationAlignment">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="left_padding">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="indentationPresentationGrid">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="row_spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="indentationPresentationOffButton">
|
||||||
|
<property name="label" translatable="yes">_Off</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<signal name="toggled" handler="indentationPresentationModeToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="indentationPresentationSpeechButton">
|
||||||
|
<property name="label" translatable="yes">_Speech</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">indentationPresentationOffButton</property>
|
||||||
|
<signal name="toggled" handler="indentationPresentationModeToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="indentationPresentationBeepsButton">
|
||||||
|
<property name="label" translatable="yes">_Beeps</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">indentationPresentationOffButton</property>
|
||||||
|
<signal name="toggled" handler="indentationPresentationModeToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="indentationPresentationSpeechAndBeepsButton">
|
||||||
|
<property name="label" translatable="yes">Speech _and beeps</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">indentationPresentationOffButton</property>
|
||||||
|
<signal name="toggled" handler="indentationPresentationModeToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="label">
|
||||||
|
<object class="GtkLabel" id="indentationPresentationLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Presentation Mode</property>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="weight" value="bold"/>
|
||||||
|
</attributes>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkFrame" id="indentationChangeFrame">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="shadow_type">none</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment" id="indentationChangeAlignment">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="left_padding">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="indentationChangeGrid">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="row_spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="indentationChangeAlwaysButton">
|
||||||
|
<property name="label" translatable="yes">Always present indentation</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<signal name="toggled" handler="indentationChangeModeToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="indentationChangeAnyButton">
|
||||||
|
<property name="label" translatable="yes">Present any indentation changes</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">indentationChangeAlwaysButton</property>
|
||||||
|
<signal name="toggled" handler="indentationChangeModeToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="indentationChangeLevelButton">
|
||||||
|
<property name="label" translatable="yes">Present only when indentation level changes</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">indentationChangeAlwaysButton</property>
|
||||||
|
<signal name="toggled" handler="indentationChangeModeToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="label">
|
||||||
|
<object class="GtkLabel" id="indentationChangeLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">When to Present</property>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="weight" value="bold"/>
|
||||||
|
</attributes>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkFrame" id="indentationSpeechFrame">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="shadow_type">none</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment" id="indentationSpeechAlignment">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="left_padding">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="indentationSpeechGrid">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="row_spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="indentationSpeechSpacesTabsButton">
|
||||||
|
<property name="label" translatable="yes">Spaces and tabs</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<signal name="toggled" handler="indentationSpeechStyleToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="indentationSpeechLevelsButton">
|
||||||
|
<property name="label" translatable="yes">Indentation level</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">indentationSpeechSpacesTabsButton</property>
|
||||||
|
<signal name="toggled" handler="indentationSpeechStyleToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="indentationSpeechColumnsButton">
|
||||||
|
<property name="label" translatable="yes">Indentation columns</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">indentationSpeechSpacesTabsButton</property>
|
||||||
|
<signal name="toggled" handler="indentationSpeechStyleToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="label">
|
||||||
|
<object class="GtkLabel" id="indentationSpeechLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Speech Format</property>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="weight" value="bold"/>
|
||||||
|
</attributes>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkFrame" id="indentationUnitsFrame">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="shadow_type">none</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment" id="indentationUnitsAlignment">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="left_padding">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="indentationUnitsGrid">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="row_spacing">6</property>
|
||||||
|
<property name="column_spacing">10</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="indentationSpacesPerLevelLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Spaces per level:</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="mnemonic_widget">indentationSpacesPerLevelSpinButton</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSpinButton" id="indentationSpacesPerLevelSpinButton">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="adjustment">indentationSpacesPerLevelAdjustment</property>
|
||||||
|
<property name="climb_rate">1</property>
|
||||||
|
<property name="numeric">True</property>
|
||||||
|
<signal name="value-changed" handler="indentationSpinValueChanged" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="indentationTabWidthLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Tab width:</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="mnemonic_widget">indentationTabWidthSpinButton</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSpinButton" id="indentationTabWidthSpinButton">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="adjustment">indentationTabWidthAdjustment</property>
|
||||||
|
<property name="climb_rate">1</property>
|
||||||
|
<property name="numeric">True</property>
|
||||||
|
<signal name="value-changed" handler="indentationSpinValueChanged" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="indentationAudioUnitLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Audio unit:</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="indentationAudioUnitGrid">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="row_spacing">4</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="indentationAudioUnitLevelsButton">
|
||||||
|
<property name="label" translatable="yes">Levels</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<signal name="toggled" handler="indentationAudioUnitToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="indentationAudioUnitColumnsButton">
|
||||||
|
<property name="label" translatable="yes">Columns</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">indentationAudioUnitLevelsButton</property>
|
||||||
|
<signal name="toggled" handler="indentationAudioUnitToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="label">
|
||||||
|
<object class="GtkLabel" id="indentationUnitsLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Units</property>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="weight" value="bold"/>
|
||||||
|
</attributes>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkFrame" id="indentationAudioFrame">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="shadow_type">none</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment" id="indentationAudioAlignment">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="left_padding">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="indentationAudioGrid">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="row_spacing">6</property>
|
||||||
|
<property name="column_spacing">10</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="indentationAudioBaseFrequencyLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Base frequency (Hz):</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="mnemonic_widget">indentationAudioBaseFrequencySpinButton</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSpinButton" id="indentationAudioBaseFrequencySpinButton">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="adjustment">indentationAudioBaseFrequencyAdjustment</property>
|
||||||
|
<property name="climb_rate">1</property>
|
||||||
|
<property name="numeric">True</property>
|
||||||
|
<signal name="value-changed" handler="indentationSpinValueChanged" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="indentationAudioStepFrequencyLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Step per unit (Hz):</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="mnemonic_widget">indentationAudioStepFrequencySpinButton</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSpinButton" id="indentationAudioStepFrequencySpinButton">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="adjustment">indentationAudioStepFrequencyAdjustment</property>
|
||||||
|
<property name="climb_rate">1</property>
|
||||||
|
<property name="numeric">True</property>
|
||||||
|
<signal name="value-changed" handler="indentationSpinValueChanged" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="indentationAudioMaxFrequencyLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Maximum frequency (Hz):</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="mnemonic_widget">indentationAudioMaxFrequencySpinButton</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSpinButton" id="indentationAudioMaxFrequencySpinButton">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="adjustment">indentationAudioMaxFrequencyAdjustment</property>
|
||||||
|
<property name="climb_rate">1</property>
|
||||||
|
<property name="numeric">True</property>
|
||||||
|
<signal name="value-changed" handler="indentationSpinValueChanged" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="indentationAudioDurationLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Tone duration (sec):</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="mnemonic_widget">indentationAudioDurationSpinButton</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSpinButton" id="indentationAudioDurationSpinButton">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="adjustment">indentationAudioDurationAdjustment</property>
|
||||||
|
<property name="climb_rate">0.01</property>
|
||||||
|
<property name="digits">2</property>
|
||||||
|
<property name="numeric">True</property>
|
||||||
|
<signal name="value-changed" handler="indentationSpinValueChanged" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="indentationAudioVolumeLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Volume multiplier:</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="mnemonic_widget">indentationAudioVolumeSpinButton</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSpinButton" id="indentationAudioVolumeSpinButton">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="adjustment">indentationAudioVolumeAdjustment</property>
|
||||||
|
<property name="climb_rate">0.05</property>
|
||||||
|
<property name="digits">2</property>
|
||||||
|
<property name="numeric">True</property>
|
||||||
|
<signal name="value-changed" handler="indentationSpinValueChanged" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="label">
|
||||||
|
<object class="GtkLabel" id="indentationAudioLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Audio</property>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="weight" value="bold"/>
|
||||||
|
</attributes>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="width">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">8</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child type="tab">
|
||||||
|
<object class="GtkLabel" id="indentationTabLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Indentation</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">8</property>
|
||||||
|
<property name="tab_fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkGrid" id="aiPage">
|
<object class="GtkGrid" id="aiPage">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
@@ -3773,7 +4422,7 @@
|
|||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">8</property>
|
<property name="position">9</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child type="tab">
|
<child type="tab">
|
||||||
@@ -3783,7 +4432,7 @@
|
|||||||
<property name="label" translatable="yes">AI Assistant</property>
|
<property name="label" translatable="yes">AI Assistant</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">8</property>
|
<property name="position">9</property>
|
||||||
<property name="tab_fill">False</property>
|
<property name="tab_fill">False</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
@@ -3959,7 +4608,7 @@
|
|||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">9</property>
|
<property name="position">10</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child type="tab">
|
<child type="tab">
|
||||||
@@ -3969,7 +4618,7 @@
|
|||||||
<property name="label" translatable="yes">OCR</property>
|
<property name="label" translatable="yes">OCR</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">9</property>
|
<property name="position">10</property>
|
||||||
<property name="tab_fill">False</property>
|
<property name="tab_fill">False</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
|||||||
@@ -1482,8 +1482,6 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
self.get_widget("onlySpeakDisplayedTextCheckButton").set_active(
|
self.get_widget("onlySpeakDisplayedTextCheckButton").set_active(
|
||||||
prefs["onlySpeakDisplayedText"])
|
prefs["onlySpeakDisplayedText"])
|
||||||
|
|
||||||
self.get_widget("enableSpeechIndentationCheckButton").set_active(\
|
|
||||||
prefs["enableSpeechIndentation"])
|
|
||||||
|
|
||||||
self.get_widget("speakBlankLinesCheckButton").set_active(\
|
self.get_widget("speakBlankLinesCheckButton").set_active(\
|
||||||
prefs["speakBlankLines"])
|
prefs["speakBlankLines"])
|
||||||
@@ -1825,6 +1823,10 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
# AI Assistant settings
|
# AI Assistant settings
|
||||||
#
|
#
|
||||||
self._initAIState()
|
self._initAIState()
|
||||||
|
|
||||||
|
# Indentation settings
|
||||||
|
#
|
||||||
|
self._initIndentationState()
|
||||||
|
|
||||||
# OCR Plugin settings
|
# OCR Plugin settings
|
||||||
#
|
#
|
||||||
@@ -1929,6 +1931,119 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
if enabled:
|
if enabled:
|
||||||
current_provider = self.prefsDict.get("aiProvider", settings.aiProvider)
|
current_provider = self.prefsDict.get("aiProvider", settings.aiProvider)
|
||||||
self._updateProviderControls(current_provider)
|
self._updateProviderControls(current_provider)
|
||||||
|
|
||||||
|
def _initIndentationState(self):
|
||||||
|
"""Initialize Indentation tab widgets with current settings."""
|
||||||
|
prefs = self.prefsDict
|
||||||
|
|
||||||
|
self.indentationPresentationOffButton = self.get_widget("indentationPresentationOffButton")
|
||||||
|
self.indentationPresentationSpeechButton = self.get_widget("indentationPresentationSpeechButton")
|
||||||
|
self.indentationPresentationBeepsButton = self.get_widget("indentationPresentationBeepsButton")
|
||||||
|
self.indentationPresentationSpeechAndBeepsButton = self.get_widget("indentationPresentationSpeechAndBeepsButton")
|
||||||
|
|
||||||
|
self.indentationChangeAlwaysButton = self.get_widget("indentationChangeAlwaysButton")
|
||||||
|
self.indentationChangeAnyButton = self.get_widget("indentationChangeAnyButton")
|
||||||
|
self.indentationChangeLevelButton = self.get_widget("indentationChangeLevelButton")
|
||||||
|
|
||||||
|
self.indentationSpeechSpacesTabsButton = self.get_widget("indentationSpeechSpacesTabsButton")
|
||||||
|
self.indentationSpeechLevelsButton = self.get_widget("indentationSpeechLevelsButton")
|
||||||
|
self.indentationSpeechColumnsButton = self.get_widget("indentationSpeechColumnsButton")
|
||||||
|
|
||||||
|
self.indentationAudioUnitLevelsButton = self.get_widget("indentationAudioUnitLevelsButton")
|
||||||
|
self.indentationAudioUnitColumnsButton = self.get_widget("indentationAudioUnitColumnsButton")
|
||||||
|
|
||||||
|
self.indentationSpacesPerLevelSpinButton = self.get_widget("indentationSpacesPerLevelSpinButton")
|
||||||
|
self.indentationTabWidthSpinButton = self.get_widget("indentationTabWidthSpinButton")
|
||||||
|
self.indentationAudioBaseFrequencySpinButton = self.get_widget("indentationAudioBaseFrequencySpinButton")
|
||||||
|
self.indentationAudioStepFrequencySpinButton = self.get_widget("indentationAudioStepFrequencySpinButton")
|
||||||
|
self.indentationAudioMaxFrequencySpinButton = self.get_widget("indentationAudioMaxFrequencySpinButton")
|
||||||
|
self.indentationAudioDurationSpinButton = self.get_widget("indentationAudioDurationSpinButton")
|
||||||
|
self.indentationAudioVolumeSpinButton = self.get_widget("indentationAudioVolumeSpinButton")
|
||||||
|
|
||||||
|
mode = prefs.get("indentationPresentationMode", settings.indentationPresentationMode)
|
||||||
|
if mode == settings.INDENTATION_PRESENTATION_SPEECH:
|
||||||
|
self.indentationPresentationSpeechButton.set_active(True)
|
||||||
|
elif mode == settings.INDENTATION_PRESENTATION_BEEPS:
|
||||||
|
self.indentationPresentationBeepsButton.set_active(True)
|
||||||
|
elif mode == settings.INDENTATION_PRESENTATION_SPEECH_AND_BEEPS:
|
||||||
|
self.indentationPresentationSpeechAndBeepsButton.set_active(True)
|
||||||
|
else:
|
||||||
|
self.indentationPresentationOffButton.set_active(True)
|
||||||
|
|
||||||
|
enableSpeechIndentation = mode in (
|
||||||
|
settings.INDENTATION_PRESENTATION_SPEECH,
|
||||||
|
settings.INDENTATION_PRESENTATION_SPEECH_AND_BEEPS,
|
||||||
|
)
|
||||||
|
self.prefsDict["enableSpeechIndentation"] = enableSpeechIndentation
|
||||||
|
|
||||||
|
only_if_changed = prefs.get("speakIndentationOnlyIfChanged", settings.speakIndentationOnlyIfChanged)
|
||||||
|
change_mode = prefs.get("indentationChangeMode", settings.indentationChangeMode)
|
||||||
|
if not only_if_changed or change_mode == settings.INDENTATION_CHANGE_ALWAYS:
|
||||||
|
self.indentationChangeAlwaysButton.set_active(True)
|
||||||
|
elif change_mode == settings.INDENTATION_CHANGE_ANY:
|
||||||
|
self.indentationChangeAnyButton.set_active(True)
|
||||||
|
else:
|
||||||
|
self.indentationChangeLevelButton.set_active(True)
|
||||||
|
|
||||||
|
speech_style = prefs.get("indentationSpeechStyle", settings.indentationSpeechStyle)
|
||||||
|
if speech_style == settings.INDENTATION_SPEECH_STYLE_LEVELS:
|
||||||
|
self.indentationSpeechLevelsButton.set_active(True)
|
||||||
|
elif speech_style == settings.INDENTATION_SPEECH_STYLE_COLUMNS:
|
||||||
|
self.indentationSpeechColumnsButton.set_active(True)
|
||||||
|
else:
|
||||||
|
self.indentationSpeechSpacesTabsButton.set_active(True)
|
||||||
|
|
||||||
|
audio_unit = prefs.get("indentationAudioUnit", settings.indentationAudioUnit)
|
||||||
|
if audio_unit == settings.INDENTATION_UNIT_COLUMNS:
|
||||||
|
self.indentationAudioUnitColumnsButton.set_active(True)
|
||||||
|
else:
|
||||||
|
self.indentationAudioUnitLevelsButton.set_active(True)
|
||||||
|
|
||||||
|
self.indentationSpacesPerLevelSpinButton.set_value(
|
||||||
|
prefs.get("indentationSpacesPerLevel", settings.indentationSpacesPerLevel))
|
||||||
|
self.indentationTabWidthSpinButton.set_value(
|
||||||
|
prefs.get("indentationTabWidth", settings.indentationTabWidth))
|
||||||
|
self.indentationAudioBaseFrequencySpinButton.set_value(
|
||||||
|
prefs.get("indentationAudioBaseFrequency", settings.indentationAudioBaseFrequency))
|
||||||
|
self.indentationAudioStepFrequencySpinButton.set_value(
|
||||||
|
prefs.get("indentationAudioStepFrequency", settings.indentationAudioStepFrequency))
|
||||||
|
self.indentationAudioMaxFrequencySpinButton.set_value(
|
||||||
|
prefs.get("indentationAudioMaxFrequency", settings.indentationAudioMaxFrequency))
|
||||||
|
self.indentationAudioDurationSpinButton.set_value(
|
||||||
|
prefs.get("indentationAudioDuration", settings.indentationAudioDuration))
|
||||||
|
self.indentationAudioVolumeSpinButton.set_value(
|
||||||
|
prefs.get("indentationAudioVolume", settings.indentationAudioVolume))
|
||||||
|
|
||||||
|
self._updateIndentationControlsState(mode)
|
||||||
|
|
||||||
|
def _updateIndentationControlsState(self, mode):
|
||||||
|
"""Enable or disable indentation controls based on presentation mode."""
|
||||||
|
speech_enabled = mode in (
|
||||||
|
settings.INDENTATION_PRESENTATION_SPEECH,
|
||||||
|
settings.INDENTATION_PRESENTATION_SPEECH_AND_BEEPS,
|
||||||
|
)
|
||||||
|
beeps_enabled = mode in (
|
||||||
|
settings.INDENTATION_PRESENTATION_BEEPS,
|
||||||
|
settings.INDENTATION_PRESENTATION_SPEECH_AND_BEEPS,
|
||||||
|
)
|
||||||
|
|
||||||
|
for widget in (
|
||||||
|
self.indentationSpeechSpacesTabsButton,
|
||||||
|
self.indentationSpeechLevelsButton,
|
||||||
|
self.indentationSpeechColumnsButton,
|
||||||
|
):
|
||||||
|
widget.set_sensitive(speech_enabled)
|
||||||
|
|
||||||
|
for widget in (
|
||||||
|
self.indentationAudioUnitLevelsButton,
|
||||||
|
self.indentationAudioUnitColumnsButton,
|
||||||
|
self.indentationAudioBaseFrequencySpinButton,
|
||||||
|
self.indentationAudioStepFrequencySpinButton,
|
||||||
|
self.indentationAudioMaxFrequencySpinButton,
|
||||||
|
self.indentationAudioDurationSpinButton,
|
||||||
|
self.indentationAudioVolumeSpinButton,
|
||||||
|
):
|
||||||
|
widget.set_sensitive(beeps_enabled)
|
||||||
|
|
||||||
def _updateProviderControls(self, provider):
|
def _updateProviderControls(self, provider):
|
||||||
"""Update visibility/sensitivity of provider-specific controls."""
|
"""Update visibility/sensitivity of provider-specific controls."""
|
||||||
@@ -3839,6 +3954,92 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
|
|
||||||
self.__initProfileCombo()
|
self.__initProfileCombo()
|
||||||
|
|
||||||
|
# Indentation signal handlers
|
||||||
|
|
||||||
|
def indentationPresentationModeToggled(self, widget):
|
||||||
|
"""Indentation presentation mode radio toggled handler."""
|
||||||
|
if not widget.get_active():
|
||||||
|
return
|
||||||
|
|
||||||
|
mapping = {
|
||||||
|
"indentationPresentationOffButton": settings.INDENTATION_PRESENTATION_OFF,
|
||||||
|
"indentationPresentationSpeechButton": settings.INDENTATION_PRESENTATION_SPEECH,
|
||||||
|
"indentationPresentationBeepsButton": settings.INDENTATION_PRESENTATION_BEEPS,
|
||||||
|
"indentationPresentationSpeechAndBeepsButton": settings.INDENTATION_PRESENTATION_SPEECH_AND_BEEPS,
|
||||||
|
}
|
||||||
|
widget_name = Gtk.Buildable.get_name(widget)
|
||||||
|
mode = mapping.get(widget_name)
|
||||||
|
if mode is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.prefsDict["indentationPresentationMode"] = mode
|
||||||
|
self.prefsDict["enableSpeechIndentation"] = mode in (
|
||||||
|
settings.INDENTATION_PRESENTATION_SPEECH,
|
||||||
|
settings.INDENTATION_PRESENTATION_SPEECH_AND_BEEPS,
|
||||||
|
)
|
||||||
|
self._updateIndentationControlsState(mode)
|
||||||
|
|
||||||
|
def indentationChangeModeToggled(self, widget):
|
||||||
|
"""Indentation change mode radio toggled handler."""
|
||||||
|
if not widget.get_active():
|
||||||
|
return
|
||||||
|
|
||||||
|
widget_name = Gtk.Buildable.get_name(widget)
|
||||||
|
if widget_name == "indentationChangeAlwaysButton":
|
||||||
|
self.prefsDict["speakIndentationOnlyIfChanged"] = False
|
||||||
|
self.prefsDict["indentationChangeMode"] = settings.INDENTATION_CHANGE_ALWAYS
|
||||||
|
elif widget_name == "indentationChangeAnyButton":
|
||||||
|
self.prefsDict["speakIndentationOnlyIfChanged"] = True
|
||||||
|
self.prefsDict["indentationChangeMode"] = settings.INDENTATION_CHANGE_ANY
|
||||||
|
else:
|
||||||
|
self.prefsDict["speakIndentationOnlyIfChanged"] = True
|
||||||
|
self.prefsDict["indentationChangeMode"] = settings.INDENTATION_CHANGE_LEVEL
|
||||||
|
|
||||||
|
def indentationSpeechStyleToggled(self, widget):
|
||||||
|
"""Indentation speech style radio toggled handler."""
|
||||||
|
if not widget.get_active():
|
||||||
|
return
|
||||||
|
|
||||||
|
mapping = {
|
||||||
|
"indentationSpeechSpacesTabsButton": settings.INDENTATION_SPEECH_STYLE_SPACES_TABS,
|
||||||
|
"indentationSpeechLevelsButton": settings.INDENTATION_SPEECH_STYLE_LEVELS,
|
||||||
|
"indentationSpeechColumnsButton": settings.INDENTATION_SPEECH_STYLE_COLUMNS,
|
||||||
|
}
|
||||||
|
widget_name = Gtk.Buildable.get_name(widget)
|
||||||
|
style = mapping.get(widget_name)
|
||||||
|
if style is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.prefsDict["indentationSpeechStyle"] = style
|
||||||
|
|
||||||
|
def indentationAudioUnitToggled(self, widget):
|
||||||
|
"""Indentation audio unit radio toggled handler."""
|
||||||
|
if not widget.get_active():
|
||||||
|
return
|
||||||
|
|
||||||
|
if Gtk.Buildable.get_name(widget) == "indentationAudioUnitColumnsButton":
|
||||||
|
self.prefsDict["indentationAudioUnit"] = settings.INDENTATION_UNIT_COLUMNS
|
||||||
|
else:
|
||||||
|
self.prefsDict["indentationAudioUnit"] = settings.INDENTATION_UNIT_LEVELS
|
||||||
|
|
||||||
|
def indentationSpinValueChanged(self, widget):
|
||||||
|
"""Indentation spin button value changed handler."""
|
||||||
|
settingName = Gtk.Buildable.get_name(widget)
|
||||||
|
if settingName.endswith("SpinButton"):
|
||||||
|
settingName = settingName[:-10]
|
||||||
|
|
||||||
|
int_settings = {
|
||||||
|
"indentationSpacesPerLevel",
|
||||||
|
"indentationTabWidth",
|
||||||
|
"indentationAudioBaseFrequency",
|
||||||
|
"indentationAudioStepFrequency",
|
||||||
|
"indentationAudioMaxFrequency",
|
||||||
|
}
|
||||||
|
if settingName in int_settings:
|
||||||
|
self.prefsDict[settingName] = int(widget.get_value())
|
||||||
|
else:
|
||||||
|
self.prefsDict[settingName] = float(widget.get_value())
|
||||||
|
|
||||||
# AI Assistant signal handlers
|
# AI Assistant signal handlers
|
||||||
|
|
||||||
def enableAIToggled(self, widget):
|
def enableAIToggled(self, widget):
|
||||||
|
|||||||
@@ -44,6 +44,12 @@ from typing import TYPE_CHECKING, Optional
|
|||||||
import gi
|
import gi
|
||||||
gi.require_version("Atspi", "2.0")
|
gi.require_version("Atspi", "2.0")
|
||||||
from gi.repository import Atspi
|
from gi.repository import Atspi
|
||||||
|
try:
|
||||||
|
gi.require_version("Wnck", "3.0")
|
||||||
|
from gi.repository import Wnck
|
||||||
|
_wnck_available = True
|
||||||
|
except Exception:
|
||||||
|
_wnck_available = False
|
||||||
|
|
||||||
from . import debug
|
from . import debug
|
||||||
from . import focus_manager
|
from . import focus_manager
|
||||||
@@ -53,6 +59,7 @@ from . import settings
|
|||||||
from . import cthulhu_state
|
from . import cthulhu_state
|
||||||
from .ax_object import AXObject
|
from .ax_object import AXObject
|
||||||
from .ax_utilities import AXUtilities
|
from .ax_utilities import AXUtilities
|
||||||
|
from .ax_utilities_application import AXUtilitiesApplication
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from . import keybindings
|
from . import keybindings
|
||||||
@@ -69,6 +76,35 @@ class InputEventManager:
|
|||||||
self._grabbed_bindings: dict[int, keybindings.KeyBinding] = {}
|
self._grabbed_bindings: dict[int, keybindings.KeyBinding] = {}
|
||||||
self._paused: bool = False
|
self._paused: bool = False
|
||||||
|
|
||||||
|
def _active_window_has_accessible_app(self) -> Optional[bool]:
|
||||||
|
"""Returns True if the WM active window maps to an AT-SPI app."""
|
||||||
|
|
||||||
|
if not _wnck_available:
|
||||||
|
return None
|
||||||
|
|
||||||
|
screen = Wnck.Screen.get_default()
|
||||||
|
if not screen:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
screen.force_update()
|
||||||
|
active_window = screen.get_active_window()
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not active_window:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
pid = active_window.get_pid()
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if pid <= 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return AXUtilitiesApplication.get_application_with_pid(pid) is not None
|
||||||
|
|
||||||
def start_key_watcher(self) -> None:
|
def start_key_watcher(self) -> None:
|
||||||
"""Starts the watcher for keyboard input events."""
|
"""Starts the watcher for keyboard input events."""
|
||||||
|
|
||||||
@@ -281,6 +317,12 @@ class InputEventManager:
|
|||||||
|
|
||||||
manager = focus_manager.get_manager()
|
manager = focus_manager.get_manager()
|
||||||
if pressed:
|
if pressed:
|
||||||
|
has_accessible_app = self._active_window_has_accessible_app()
|
||||||
|
if has_accessible_app is False and manager.get_active_window() is not None:
|
||||||
|
msg = "INPUT EVENT MANAGER: Active window has no AT-SPI app. Clearing active window."
|
||||||
|
debug.print_message(debug.LEVEL_INFO, msg, True)
|
||||||
|
manager.set_active_window(None, notify_script=True)
|
||||||
|
|
||||||
window = manager.get_active_window()
|
window = manager.get_active_window()
|
||||||
if not AXUtilities.can_be_active_window(window):
|
if not AXUtilities.can_be_active_window(window):
|
||||||
new_window = AXUtilities.find_active_window()
|
new_window = AXUtilities.find_active_window()
|
||||||
|
|||||||
@@ -2812,6 +2812,16 @@ def tabsCount(count):
|
|||||||
# tab characters in a string.
|
# tab characters in a string.
|
||||||
return ngettext("%d tab", "%d tabs", count) % count
|
return ngettext("%d tab", "%d tabs", count) % count
|
||||||
|
|
||||||
|
def indentationLevelCount(count):
|
||||||
|
# Translators: This message is presented to inform the user of the
|
||||||
|
# indentation level for a line of text.
|
||||||
|
return ngettext("indentation level %d", "indentation level %d", count) % count
|
||||||
|
|
||||||
|
def indentationColumnCount(count):
|
||||||
|
# Translators: This message is presented to inform the user of the number
|
||||||
|
# of indentation columns for a line of text.
|
||||||
|
return ngettext("indentation %d column", "indentation %d columns", count) % count
|
||||||
|
|
||||||
def tableCount(count, onlyIfFound=True):
|
def tableCount(count, onlyIfFound=True):
|
||||||
if not count and onlyIfFound:
|
if not count and onlyIfFound:
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
@@ -10,11 +10,14 @@
|
|||||||
"""IndentationAudio plugin for Cthulhu - Provides audio feedback for indentation level changes."""
|
"""IndentationAudio plugin for Cthulhu - Provides audio feedback for indentation level changes."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import math
|
||||||
import re
|
import re
|
||||||
from gi.repository import GLib
|
from gi.repository import GLib
|
||||||
|
|
||||||
from cthulhu.plugin import Plugin, cthulhu_hookimpl
|
from cthulhu.plugin import Plugin, cthulhu_hookimpl
|
||||||
from cthulhu import debug
|
from cthulhu import debug
|
||||||
|
from cthulhu import settings
|
||||||
|
from cthulhu import settings_manager
|
||||||
from cthulhu.ax_object import AXObject
|
from cthulhu.ax_object import AXObject
|
||||||
from cthulhu.ax_text import AXText
|
from cthulhu.ax_text import AXText
|
||||||
|
|
||||||
@@ -28,6 +31,7 @@ except ImportError as e:
|
|||||||
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: Sound import failed: {e}", True)
|
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: Sound import failed: {e}", True)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
_settingsManager = settings_manager.getManager()
|
||||||
|
|
||||||
|
|
||||||
class IndentationAudio(Plugin):
|
class IndentationAudio(Plugin):
|
||||||
@@ -37,14 +41,18 @@ class IndentationAudio(Plugin):
|
|||||||
"""Initialize the IndentationAudio plugin."""
|
"""Initialize the IndentationAudio plugin."""
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self._enabled = True # Start enabled by default
|
self._enabled = True # Start enabled by default
|
||||||
self._last_indentation_level = {} # Track per-object indentation
|
self._last_indentation_data = {} # Track per-object indentation
|
||||||
self._event_listener_id = None
|
self._event_listener_id = None
|
||||||
self._kb_binding = None
|
self._kb_binding = None
|
||||||
# Audio settings
|
# Audio settings
|
||||||
self._base_frequency = 200 # Base frequency in Hz
|
self._base_frequency = settings.indentationAudioBaseFrequency
|
||||||
self._frequency_step = 80 # Hz per indentation level
|
self._frequency_step = settings.indentationAudioStepFrequency
|
||||||
self._tone_duration = 0.15 # Seconds
|
self._tone_duration = settings.indentationAudioDuration
|
||||||
self._max_frequency = 1200 # Cap frequency to avoid harsh sounds
|
self._max_frequency = settings.indentationAudioMaxFrequency
|
||||||
|
self._volume_multiplier = settings.indentationAudioVolume
|
||||||
|
self._alerts_suspended = False
|
||||||
|
self._saved_presentation_mode = None
|
||||||
|
self._saved_speech_indentation = None
|
||||||
|
|
||||||
self._activated = False
|
self._activated = False
|
||||||
debug.printMessage(debug.LEVEL_INFO, "IndentationAudio: Plugin initialized", True)
|
debug.printMessage(debug.LEVEL_INFO, "IndentationAudio: Plugin initialized", True)
|
||||||
@@ -98,7 +106,7 @@ class IndentationAudio(Plugin):
|
|||||||
self._disconnect_from_events()
|
self._disconnect_from_events()
|
||||||
|
|
||||||
# Clear tracking data
|
# Clear tracking data
|
||||||
self._last_indentation_level.clear()
|
self._last_indentation_data.clear()
|
||||||
|
|
||||||
self._activated = False
|
self._activated = False
|
||||||
debug.printMessage(debug.LEVEL_INFO, "IndentationAudio: Plugin deactivated successfully", True)
|
debug.printMessage(debug.LEVEL_INFO, "IndentationAudio: Plugin deactivated successfully", True)
|
||||||
@@ -117,7 +125,7 @@ class IndentationAudio(Plugin):
|
|||||||
|
|
||||||
# Register Cthulhu+I keybinding using the plugin's registerGestureByString method
|
# Register Cthulhu+I keybinding using the plugin's registerGestureByString method
|
||||||
gesture_string = "kb:cthulhu+i"
|
gesture_string = "kb:cthulhu+i"
|
||||||
description = "Toggle indentation audio feedback"
|
description = "Toggle indentation alerts"
|
||||||
|
|
||||||
self._kb_binding = self.registerGestureByString(
|
self._kb_binding = self.registerGestureByString(
|
||||||
self._toggle_indentation_audio,
|
self._toggle_indentation_audio,
|
||||||
@@ -169,7 +177,7 @@ class IndentationAudio(Plugin):
|
|||||||
def _on_caret_moved(self, event):
|
def _on_caret_moved(self, event):
|
||||||
"""Handle caret movement events."""
|
"""Handle caret movement events."""
|
||||||
try:
|
try:
|
||||||
if not self._enabled:
|
if not self._beeps_enabled():
|
||||||
return
|
return
|
||||||
|
|
||||||
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: Caret moved in {event.source}", True)
|
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: Caret moved in {event.source}", True)
|
||||||
@@ -292,18 +300,41 @@ class IndentationAudio(Plugin):
|
|||||||
def _toggle_indentation_audio(self, script, inputEvent=None):
|
def _toggle_indentation_audio(self, script, inputEvent=None):
|
||||||
"""Toggle the indentation audio feedback on/off."""
|
"""Toggle the indentation audio feedback on/off."""
|
||||||
try:
|
try:
|
||||||
self._enabled = not self._enabled
|
current_mode = _settingsManager.getSetting('indentationPresentationMode') \
|
||||||
state = "enabled" if self._enabled else "disabled"
|
or settings.indentationPresentationMode
|
||||||
|
current_speech = _settingsManager.getSetting('enableSpeechIndentation')
|
||||||
|
|
||||||
|
if self._alerts_suspended:
|
||||||
|
new_mode = self._saved_presentation_mode
|
||||||
|
if new_mode is None:
|
||||||
|
new_mode = current_mode
|
||||||
|
_settingsManager.setSetting('indentationPresentationMode', new_mode)
|
||||||
|
if self._saved_speech_indentation is None:
|
||||||
|
self._sync_speech_setting(new_mode)
|
||||||
|
else:
|
||||||
|
_settingsManager.setSetting('enableSpeechIndentation', self._saved_speech_indentation)
|
||||||
|
self._alerts_suspended = False
|
||||||
|
state = "enabled"
|
||||||
|
else:
|
||||||
|
self._saved_presentation_mode = current_mode
|
||||||
|
self._saved_speech_indentation = current_speech
|
||||||
|
_settingsManager.setSetting(
|
||||||
|
'indentationPresentationMode',
|
||||||
|
settings.INDENTATION_PRESENTATION_OFF,
|
||||||
|
)
|
||||||
|
_settingsManager.setSetting('enableSpeechIndentation', False)
|
||||||
|
self._alerts_suspended = True
|
||||||
|
state = "disabled"
|
||||||
|
|
||||||
# Announce the state change
|
# Announce the state change
|
||||||
message = f"Indentation audio {state}"
|
message = f"Indentation alerts {state}"
|
||||||
if hasattr(script, 'speakMessage'):
|
if hasattr(script, 'speakMessage'):
|
||||||
script.speakMessage(message)
|
script.speakMessage(message)
|
||||||
|
|
||||||
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: Toggled to {state}", True)
|
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: Alerts toggled to {state}", True)
|
||||||
|
|
||||||
# Test the indentation detection on current line when enabled
|
# Test the indentation detection on current line when enabled
|
||||||
if self._enabled and script:
|
if state == "enabled" and script:
|
||||||
try:
|
try:
|
||||||
# Try to get current focus object and line text
|
# Try to get current focus object and line text
|
||||||
from cthulhu import cthulhu_state
|
from cthulhu import cthulhu_state
|
||||||
@@ -324,62 +355,107 @@ class IndentationAudio(Plugin):
|
|||||||
logger.error(f"IndentationAudio: Error toggling state: {e}")
|
logger.error(f"IndentationAudio: Error toggling state: {e}")
|
||||||
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: Error toggling: {e}", True)
|
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: Error toggling: {e}", True)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _calculate_indentation_level(self, line_text):
|
def _sync_speech_setting(self, presentation_mode):
|
||||||
"""Calculate the indentation level of a line."""
|
enable_speech = presentation_mode in (
|
||||||
|
settings.INDENTATION_PRESENTATION_SPEECH,
|
||||||
|
settings.INDENTATION_PRESENTATION_SPEECH_AND_BEEPS,
|
||||||
|
)
|
||||||
|
_settingsManager.setSetting('enableSpeechIndentation', enable_speech)
|
||||||
|
|
||||||
|
def _beeps_enabled(self):
|
||||||
|
if not self._enabled:
|
||||||
|
return False
|
||||||
|
presentation_mode = _settingsManager.getSetting('indentationPresentationMode') \
|
||||||
|
or settings.indentationPresentationMode
|
||||||
|
return presentation_mode in (
|
||||||
|
settings.INDENTATION_PRESENTATION_BEEPS,
|
||||||
|
settings.INDENTATION_PRESENTATION_SPEECH_AND_BEEPS,
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _extract_indentation(line_text):
|
||||||
if not line_text:
|
if not line_text:
|
||||||
return 0
|
return ""
|
||||||
|
|
||||||
# Remove non-breaking spaces and convert to regular spaces
|
|
||||||
line = line_text.replace("\u00a0", " ")
|
line = line_text.replace("\u00a0", " ")
|
||||||
|
|
||||||
# Find the first non-whitespace character
|
|
||||||
match = re.search(r"[^ \t]", line)
|
match = re.search(r"[^ \t]", line)
|
||||||
if not match:
|
if not match:
|
||||||
return 0 # Empty or whitespace-only line
|
return line
|
||||||
|
|
||||||
indent_text = line[:match.start()]
|
return line[:match.start()]
|
||||||
|
|
||||||
# Calculate indentation level (4 spaces = 1 level, 1 tab = 1 level)
|
@staticmethod
|
||||||
level = 0
|
def _count_columns(indentation, tab_width):
|
||||||
for char in indent_text:
|
columns = 0
|
||||||
if char == '\t':
|
tab_width = max(1, tab_width)
|
||||||
level += 1
|
for char in indentation:
|
||||||
elif char == ' ':
|
if char == "\t":
|
||||||
level += 0.25 # 4 spaces = 1 level
|
columns += tab_width - (columns % tab_width)
|
||||||
|
else:
|
||||||
return int(level)
|
columns += 1
|
||||||
|
|
||||||
|
return columns
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _count_levels(columns, spaces_per_level):
|
||||||
|
spaces_per_level = max(1, spaces_per_level)
|
||||||
|
if columns <= 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return int(math.ceil(columns / spaces_per_level))
|
||||||
|
|
||||||
|
def _get_indentation_data(self, line_text):
|
||||||
|
indentation = self._extract_indentation(line_text)
|
||||||
|
tab_width = _settingsManager.getSetting('indentationTabWidth') \
|
||||||
|
or settings.indentationTabWidth
|
||||||
|
spaces_per_level = _settingsManager.getSetting('indentationSpacesPerLevel') \
|
||||||
|
or settings.indentationSpacesPerLevel
|
||||||
|
columns = self._count_columns(indentation, tab_width)
|
||||||
|
levels = self._count_levels(columns, spaces_per_level)
|
||||||
|
return indentation, columns, levels
|
||||||
|
|
||||||
def _generate_indentation_tone(self, new_level, old_level):
|
def _generate_indentation_tone(self, new_units, old_units):
|
||||||
"""Generate an audio tone for indentation level change."""
|
"""Generate an audio tone for indentation change."""
|
||||||
if not self._enabled:
|
if not self._beeps_enabled():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
base_frequency = _settingsManager.getSetting('indentationAudioBaseFrequency') \
|
||||||
|
or self._base_frequency
|
||||||
|
frequency_step = _settingsManager.getSetting('indentationAudioStepFrequency') \
|
||||||
|
or self._frequency_step
|
||||||
|
max_frequency = _settingsManager.getSetting('indentationAudioMaxFrequency') \
|
||||||
|
or self._max_frequency
|
||||||
|
tone_duration = _settingsManager.getSetting('indentationAudioDuration') \
|
||||||
|
or self._tone_duration
|
||||||
|
volume_multiplier = _settingsManager.getSetting('indentationAudioVolume') \
|
||||||
|
or self._volume_multiplier
|
||||||
|
|
||||||
# Calculate frequency based on new indentation level
|
# Calculate frequency based on new indentation units
|
||||||
base_frequency = min(
|
base_frequency = min(
|
||||||
self._base_frequency + (new_level * self._frequency_step),
|
base_frequency + (new_units * frequency_step),
|
||||||
self._max_frequency
|
max_frequency
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add directional audio cues
|
# Add directional audio cues
|
||||||
if new_level > old_level:
|
if new_units > old_units:
|
||||||
# Indentation increased - higher pitch
|
# Indentation increased - higher pitch
|
||||||
frequency = base_frequency + 50
|
frequency = base_frequency + 50
|
||||||
elif new_level < old_level:
|
elif new_units < old_units:
|
||||||
# Indentation decreased - lower pitch
|
# Indentation decreased - lower pitch
|
||||||
frequency = max(base_frequency - 50, 100)
|
frequency = max(base_frequency - 50, 100)
|
||||||
else:
|
else:
|
||||||
# Same level (shouldn't happen but just in case)
|
# Same level (shouldn't happen but just in case)
|
||||||
frequency = base_frequency
|
frequency = base_frequency
|
||||||
|
|
||||||
try:
|
try:
|
||||||
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: About to generate tone for level {new_level} (freq: {frequency}Hz)", True)
|
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: About to generate tone for units {new_units} (freq: {frequency}Hz)", True)
|
||||||
|
|
||||||
if not SOUND_AVAILABLE or not self._player:
|
if not SOUND_AVAILABLE or not self._player:
|
||||||
debug.printMessage(debug.LEVEL_INFO, "IndentationAudio: Sound player not available, using fallback", True)
|
debug.printMessage(debug.LEVEL_INFO, "IndentationAudio: Sound player not available, using fallback", True)
|
||||||
# Fallback to ASCII bell
|
# Fallback to ASCII bell
|
||||||
if new_level > 0:
|
if new_units > 0:
|
||||||
beeps = min(new_level, 5)
|
beeps = min(new_units, 5)
|
||||||
for i in range(beeps):
|
for i in range(beeps):
|
||||||
print("\a", end="", flush=True)
|
print("\a", end="", flush=True)
|
||||||
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: Sent {beeps} ASCII bell beeps", True)
|
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: Sent {beeps} ASCII bell beeps", True)
|
||||||
@@ -388,8 +464,7 @@ class IndentationAudio(Plugin):
|
|||||||
# Use Cthulhu's proper sound system
|
# Use Cthulhu's proper sound system
|
||||||
try:
|
try:
|
||||||
# Create a tone based on indentation level
|
# Create a tone based on indentation level
|
||||||
duration = self._tone_duration
|
duration = tone_duration
|
||||||
volume_multiplier = 0.7
|
|
||||||
|
|
||||||
tone = Tone(
|
tone = Tone(
|
||||||
duration=duration,
|
duration=duration,
|
||||||
@@ -400,13 +475,13 @@ class IndentationAudio(Plugin):
|
|||||||
|
|
||||||
# Play the tone
|
# Play the tone
|
||||||
self._player.play(tone, interrupt=False)
|
self._player.play(tone, interrupt=False)
|
||||||
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: Played Cthulhu tone - Level: {new_level}, Freq: {frequency}Hz", True)
|
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: Played Cthulhu tone - Units: {new_units}, Freq: {frequency}Hz", True)
|
||||||
|
|
||||||
except Exception as sound_e:
|
except Exception as sound_e:
|
||||||
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: Cthulhu sound failed: {sound_e}", True)
|
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: Cthulhu sound failed: {sound_e}", True)
|
||||||
# Fallback to ASCII bell
|
# Fallback to ASCII bell
|
||||||
if new_level > 0:
|
if new_units > 0:
|
||||||
beeps = min(new_level, 5)
|
beeps = min(new_units, 5)
|
||||||
for i in range(beeps):
|
for i in range(beeps):
|
||||||
print("\a", end="", flush=True)
|
print("\a", end="", flush=True)
|
||||||
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: Used fallback ASCII bell ({beeps} beeps)", True)
|
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: Used fallback ASCII bell ({beeps} beeps)", True)
|
||||||
@@ -420,31 +495,57 @@ class IndentationAudio(Plugin):
|
|||||||
|
|
||||||
This method is intended to be called by scripts during line navigation.
|
This method is intended to be called by scripts during line navigation.
|
||||||
"""
|
"""
|
||||||
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: check_indentation_change called: enabled={self._enabled}, line='{line_text}'", True)
|
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: check_indentation_change called: line='{line_text}'", True)
|
||||||
|
|
||||||
if not self._enabled or not line_text:
|
if not line_text or not self._beeps_enabled():
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Get object identifier for tracking
|
# Get object identifier for tracking
|
||||||
obj_id = str(obj) if obj else "unknown"
|
obj_id = str(obj) if obj else "unknown"
|
||||||
|
|
||||||
# Calculate current indentation level
|
# Calculate current indentation data
|
||||||
current_level = self._calculate_indentation_level(line_text)
|
indentation, columns, levels = self._get_indentation_data(line_text)
|
||||||
|
audio_unit = _settingsManager.getSetting('indentationAudioUnit') \
|
||||||
# Get previous level for this object
|
or settings.indentationAudioUnit
|
||||||
previous_level = self._last_indentation_level.get(obj_id, current_level)
|
current_units = columns if audio_unit == settings.INDENTATION_UNIT_COLUMNS else levels
|
||||||
|
|
||||||
# Update tracking
|
previous_data = self._last_indentation_data.get(obj_id)
|
||||||
self._last_indentation_level[obj_id] = current_level
|
previous_units = previous_data.get("units") if previous_data else current_units
|
||||||
|
|
||||||
debug.printMessage(debug.LEVEL_INFO, f"IndentationAudio: Levels - previous: {previous_level}, current: {current_level}", True)
|
self._last_indentation_data[obj_id] = {
|
||||||
|
"signature": indentation,
|
||||||
|
"levels": levels,
|
||||||
|
"columns": columns,
|
||||||
|
"units": current_units,
|
||||||
|
}
|
||||||
|
|
||||||
|
change_mode = _settingsManager.getSetting('indentationChangeMode') \
|
||||||
|
or settings.indentationChangeMode
|
||||||
|
only_if_changed = _settingsManager.getSetting('speakIndentationOnlyIfChanged')
|
||||||
|
|
||||||
|
if not only_if_changed:
|
||||||
|
changed = True
|
||||||
|
elif previous_data is None:
|
||||||
|
changed = True
|
||||||
|
elif change_mode == settings.INDENTATION_CHANGE_ANY:
|
||||||
|
changed = previous_data.get("signature") != indentation
|
||||||
|
elif change_mode == settings.INDENTATION_CHANGE_LEVEL:
|
||||||
|
changed = previous_data.get("levels") != levels
|
||||||
|
else:
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
debug.printMessage(
|
||||||
|
debug.LEVEL_INFO,
|
||||||
|
f"IndentationAudio: Units - previous: {previous_units}, current: {current_units}, changed={changed}",
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
|
||||||
# Play audio cue if indentation changed
|
# Play audio cue if indentation changed
|
||||||
if current_level != previous_level:
|
if changed:
|
||||||
self._generate_indentation_tone(current_level, previous_level)
|
self._generate_indentation_tone(current_units, previous_units)
|
||||||
|
|
||||||
debug_msg = f"IndentationAudio: Indentation changed from {previous_level} to {current_level}"
|
debug_msg = f"IndentationAudio: Indentation units changed from {previous_units} to {current_units}"
|
||||||
debug.printMessage(debug.LEVEL_INFO, debug_msg, True)
|
debug.printMessage(debug.LEVEL_INFO, debug_msg, True)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -469,7 +570,7 @@ class IndentationAudio(Plugin):
|
|||||||
self._monkey_patch_script_methods()
|
self._monkey_patch_script_methods()
|
||||||
|
|
||||||
# Clear tracking data for new context
|
# Clear tracking data for new context
|
||||||
self._last_indentation_level.clear()
|
self._last_indentation_data.clear()
|
||||||
|
|
||||||
logger.info("IndentationAudio: Handled script change")
|
logger.info("IndentationAudio: Handled script change")
|
||||||
|
|
||||||
|
|||||||
+177
-10
@@ -118,6 +118,7 @@ class Utilities:
|
|||||||
|
|
||||||
self._script = script
|
self._script = script
|
||||||
self._clipboardHandlerId = None
|
self._clipboardHandlerId = None
|
||||||
|
self._lastIndentationData = {}
|
||||||
self._selectedMenuBarMenu = {}
|
self._selectedMenuBarMenu = {}
|
||||||
|
|
||||||
#########################################################################
|
#########################################################################
|
||||||
@@ -3126,27 +3127,193 @@ class Utilities:
|
|||||||
|
|
||||||
return string
|
return string
|
||||||
|
|
||||||
def indentationDescription(self, line):
|
def _get_indentation_key(self, obj):
|
||||||
if _settingsManager.getSetting('onlySpeakDisplayedText') \
|
if obj is None:
|
||||||
or not _settingsManager.getSetting('enableSpeechIndentation'):
|
return "global"
|
||||||
|
|
||||||
|
try:
|
||||||
|
return id(obj)
|
||||||
|
except Exception:
|
||||||
|
return str(obj)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _extract_indentation(line):
|
||||||
|
if not line:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
line = line.replace("\u00a0", " ")
|
line = line.replace("\u00a0", " ")
|
||||||
end = re.search("[^ \t]", line)
|
end = re.search("[^ \t]", line)
|
||||||
if end:
|
if end:
|
||||||
line = line[:end.start()]
|
return line[:end.start()]
|
||||||
|
|
||||||
result = ""
|
return line
|
||||||
spaces = [m.span() for m in re.finditer(" +", line)]
|
|
||||||
tabs = [m.span() for m in re.finditer("\t+", line)]
|
@staticmethod
|
||||||
|
def _get_indentation_segments(indentation):
|
||||||
|
if not indentation:
|
||||||
|
return []
|
||||||
|
|
||||||
|
spaces = [m.span() for m in re.finditer(" +", indentation)]
|
||||||
|
tabs = [m.span() for m in re.finditer("\t+", indentation)]
|
||||||
spans = sorted(spaces + tabs)
|
spans = sorted(spaces + tabs)
|
||||||
|
segments = []
|
||||||
for (start, end) in spans:
|
for (start, end) in spans:
|
||||||
if (start, end) in spaces:
|
if (start, end) in spaces:
|
||||||
result += f"{messages.spacesCount(end - start)} "
|
segments.append(("spaces", end - start))
|
||||||
else:
|
else:
|
||||||
result += f"{messages.tabsCount(end - start)} "
|
segments.append(("tabs", end - start))
|
||||||
|
|
||||||
return result
|
return segments
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_indentation_columns(indentation, tab_width):
|
||||||
|
columns = 0
|
||||||
|
tab_width = max(1, tab_width)
|
||||||
|
for char in indentation:
|
||||||
|
if char == "\t":
|
||||||
|
columns += tab_width - (columns % tab_width)
|
||||||
|
else:
|
||||||
|
columns += 1
|
||||||
|
|
||||||
|
return columns
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_indentation_levels(columns, spaces_per_level):
|
||||||
|
spaces_per_level = max(1, spaces_per_level)
|
||||||
|
if columns <= 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return int(math.ceil(columns / spaces_per_level))
|
||||||
|
|
||||||
|
def _get_indentation_data(self, line):
|
||||||
|
indentation = self._extract_indentation(line)
|
||||||
|
tab_width = _settingsManager.getSetting('indentationTabWidth') \
|
||||||
|
or settings.indentationTabWidth
|
||||||
|
spaces_per_level = _settingsManager.getSetting('indentationSpacesPerLevel') \
|
||||||
|
or settings.indentationSpacesPerLevel
|
||||||
|
columns = self._get_indentation_columns(indentation, tab_width)
|
||||||
|
levels = self._get_indentation_levels(columns, spaces_per_level)
|
||||||
|
segments = self._get_indentation_segments(indentation)
|
||||||
|
return {
|
||||||
|
"indentation": indentation,
|
||||||
|
"segments": segments,
|
||||||
|
"columns": columns,
|
||||||
|
"levels": levels,
|
||||||
|
}
|
||||||
|
|
||||||
|
def _remember_indentation(self, obj, data):
|
||||||
|
key = self._get_indentation_key(obj)
|
||||||
|
self._lastIndentationData[key] = {
|
||||||
|
"signature": data["indentation"],
|
||||||
|
"levels": data["levels"],
|
||||||
|
"columns": data["columns"],
|
||||||
|
}
|
||||||
|
|
||||||
|
def _indentation_has_changed(self, obj, data):
|
||||||
|
key = self._get_indentation_key(obj)
|
||||||
|
previous = self._lastIndentationData.get(key)
|
||||||
|
self._remember_indentation(obj, data)
|
||||||
|
if previous is None:
|
||||||
|
return True
|
||||||
|
|
||||||
|
change_mode = _settingsManager.getSetting('indentationChangeMode') \
|
||||||
|
or settings.indentationChangeMode
|
||||||
|
if change_mode == settings.INDENTATION_CHANGE_ANY:
|
||||||
|
return previous.get("signature") != data["indentation"]
|
||||||
|
if change_mode == settings.INDENTATION_CHANGE_LEVEL:
|
||||||
|
return previous.get("levels") != data["levels"]
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _indentation_speech_enabled(self):
|
||||||
|
if _settingsManager.getSetting('onlySpeakDisplayedText'):
|
||||||
|
return False
|
||||||
|
if not _settingsManager.getSetting('enableSpeechIndentation'):
|
||||||
|
return False
|
||||||
|
|
||||||
|
presentation_mode = _settingsManager.getSetting('indentationPresentationMode') \
|
||||||
|
or settings.indentationPresentationMode
|
||||||
|
return presentation_mode in (
|
||||||
|
settings.INDENTATION_PRESENTATION_SPEECH,
|
||||||
|
settings.INDENTATION_PRESENTATION_SPEECH_AND_BEEPS,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _format_indentation_description(self, data):
|
||||||
|
style = _settingsManager.getSetting('indentationSpeechStyle') \
|
||||||
|
or settings.indentationSpeechStyle
|
||||||
|
if style == settings.INDENTATION_SPEECH_STYLE_LEVELS:
|
||||||
|
return messages.indentationLevelCount(data["levels"])
|
||||||
|
if style == settings.INDENTATION_SPEECH_STYLE_COLUMNS:
|
||||||
|
return messages.indentationColumnCount(data["columns"])
|
||||||
|
|
||||||
|
result = ""
|
||||||
|
for kind, count in data["segments"]:
|
||||||
|
if kind == "spaces":
|
||||||
|
result += f"{messages.spacesCount(count)} "
|
||||||
|
else:
|
||||||
|
result += f"{messages.tabsCount(count)} "
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
return messages.spacesCount(0)
|
||||||
|
|
||||||
|
return result.strip()
|
||||||
|
|
||||||
|
def get_indentation_presentation(self, line, obj=None):
|
||||||
|
data = self._get_indentation_data(line)
|
||||||
|
has_indentation = bool(data["indentation"])
|
||||||
|
presentation_mode = _settingsManager.getSetting('indentationPresentationMode') \
|
||||||
|
or settings.indentationPresentationMode
|
||||||
|
only_if_changed = _settingsManager.getSetting('speakIndentationOnlyIfChanged')
|
||||||
|
change_mode = _settingsManager.getSetting('indentationChangeMode') \
|
||||||
|
or settings.indentationChangeMode
|
||||||
|
indent_debug = data["indentation"].replace("\t", "\\t").replace(" ", ".")
|
||||||
|
|
||||||
|
if not self._indentation_speech_enabled():
|
||||||
|
self._remember_indentation(obj, data)
|
||||||
|
msg = (
|
||||||
|
f"INDENTATION: speech disabled mode={presentation_mode} "
|
||||||
|
f"onlyIfChanged={only_if_changed} changeMode={change_mode} "
|
||||||
|
f"levels={data['levels']} columns={data['columns']} indent='{indent_debug}'"
|
||||||
|
)
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
return "", has_indentation
|
||||||
|
|
||||||
|
if only_if_changed:
|
||||||
|
changed = self._indentation_has_changed(obj, data)
|
||||||
|
else:
|
||||||
|
changed = True
|
||||||
|
self._remember_indentation(obj, data)
|
||||||
|
|
||||||
|
if not changed:
|
||||||
|
msg = (
|
||||||
|
f"INDENTATION: unchanged mode={presentation_mode} "
|
||||||
|
f"onlyIfChanged={only_if_changed} changeMode={change_mode} "
|
||||||
|
f"levels={data['levels']} columns={data['columns']} indent='{indent_debug}'"
|
||||||
|
)
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
return "", has_indentation
|
||||||
|
|
||||||
|
description = self._format_indentation_description(data)
|
||||||
|
msg = (
|
||||||
|
f"INDENTATION: speaking '{description}' mode={presentation_mode} "
|
||||||
|
f"onlyIfChanged={only_if_changed} changeMode={change_mode} "
|
||||||
|
f"levels={data['levels']} columns={data['columns']} indent='{indent_debug}'"
|
||||||
|
)
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
return description, has_indentation
|
||||||
|
|
||||||
|
def should_strip_indentation(self, line):
|
||||||
|
presentation_mode = _settingsManager.getSetting('indentationPresentationMode') \
|
||||||
|
or settings.indentationPresentationMode
|
||||||
|
if presentation_mode == settings.INDENTATION_PRESENTATION_OFF:
|
||||||
|
return False
|
||||||
|
|
||||||
|
data = self._get_indentation_data(line)
|
||||||
|
return bool(data["indentation"])
|
||||||
|
|
||||||
|
def indentationDescription(self, line, obj=None):
|
||||||
|
description, _has_indentation = self.get_indentation_presentation(line, obj=obj)
|
||||||
|
return description
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def absoluteMouseCoordinates():
|
def absoluteMouseCoordinates():
|
||||||
|
|||||||
@@ -2354,9 +2354,11 @@ class Script(script.Script):
|
|||||||
|
|
||||||
[line, caretOffset, startOffset] = self.getTextLineAtCaret(obj)
|
[line, caretOffset, startOffset] = self.getTextLineAtCaret(obj)
|
||||||
if len(line) and line != "\n":
|
if len(line) and line != "\n":
|
||||||
indentationDescription = self.utilities.indentationDescription(line)
|
indentationDescription, hasIndentation = \
|
||||||
|
self.utilities.get_indentation_presentation(line, obj=obj)
|
||||||
if indentationDescription:
|
if indentationDescription:
|
||||||
self.speakMessage(indentationDescription)
|
self.speakMessage(indentationDescription)
|
||||||
|
stripIndentation = hasIndentation and self.utilities.should_strip_indentation(line)
|
||||||
|
|
||||||
endOffset = startOffset + len(line)
|
endOffset = startOffset + len(line)
|
||||||
cthulhu.emitRegionChanged(obj, startOffset, endOffset, cthulhu.CARET_TRACKING)
|
cthulhu.emitRegionChanged(obj, startOffset, endOffset, cthulhu.CARET_TRACKING)
|
||||||
@@ -2376,7 +2378,7 @@ class Script(script.Script):
|
|||||||
|
|
||||||
# Some synthesizers will verbalize the whitespace, so if we've already
|
# Some synthesizers will verbalize the whitespace, so if we've already
|
||||||
# described it, prevent double-presentation by stripping it off.
|
# described it, prevent double-presentation by stripping it off.
|
||||||
if not utterance and indentationDescription:
|
if not utterance and stripIndentation:
|
||||||
string = string.lstrip()
|
string = string.lstrip()
|
||||||
|
|
||||||
result = [string]
|
result = [string]
|
||||||
@@ -2406,13 +2408,16 @@ class Script(script.Script):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if len(phrase) > 1 or phrase.isalnum():
|
if len(phrase) > 1 or phrase.isalnum():
|
||||||
result = self.utilities.indentationDescription(phrase)
|
indentationDescription, hasIndentation = \
|
||||||
if result:
|
self.utilities.get_indentation_presentation(phrase, obj=obj)
|
||||||
self.speakMessage(result)
|
if indentationDescription:
|
||||||
|
self.speakMessage(indentationDescription)
|
||||||
|
|
||||||
cthulhu.emitRegionChanged(obj, startOffset, endOffset, cthulhu.CARET_TRACKING)
|
cthulhu.emitRegionChanged(obj, startOffset, endOffset, cthulhu.CARET_TRACKING)
|
||||||
|
|
||||||
voice = self.speechGenerator.voice(obj=obj, string=phrase)
|
voice = self.speechGenerator.voice(obj=obj, string=phrase)
|
||||||
|
if hasIndentation and self.utilities.should_strip_indentation(phrase):
|
||||||
|
phrase = phrase.lstrip()
|
||||||
phrase = self.utilities.adjustForRepeats(phrase)
|
phrase = self.utilities.adjustForRepeats(phrase)
|
||||||
if self.utilities.shouldVerbalizeAllPunctuation(obj):
|
if self.utilities.shouldVerbalizeAllPunctuation(obj):
|
||||||
phrase = self.utilities.verbalizeAllPunctuation(phrase)
|
phrase = self.utilities.verbalizeAllPunctuation(phrase)
|
||||||
|
|||||||
+42
-2
@@ -48,6 +48,18 @@ userCustomizableSettings = [
|
|||||||
"readFullRowInDocumentTable",
|
"readFullRowInDocumentTable",
|
||||||
"readFullRowInSpreadSheet",
|
"readFullRowInSpreadSheet",
|
||||||
"enableSpeechIndentation",
|
"enableSpeechIndentation",
|
||||||
|
"indentationPresentationMode",
|
||||||
|
"indentationChangeMode",
|
||||||
|
"speakIndentationOnlyIfChanged",
|
||||||
|
"indentationSpeechStyle",
|
||||||
|
"indentationAudioUnit",
|
||||||
|
"indentationSpacesPerLevel",
|
||||||
|
"indentationTabWidth",
|
||||||
|
"indentationAudioBaseFrequency",
|
||||||
|
"indentationAudioStepFrequency",
|
||||||
|
"indentationAudioMaxFrequency",
|
||||||
|
"indentationAudioDuration",
|
||||||
|
"indentationAudioVolume",
|
||||||
"enableEchoByCharacter",
|
"enableEchoByCharacter",
|
||||||
"enableEchoByWord",
|
"enableEchoByWord",
|
||||||
"enableEchoBySentence",
|
"enableEchoBySentence",
|
||||||
@@ -218,6 +230,22 @@ AI_SCREENSHOT_QUALITY_LOW = "low"
|
|||||||
AI_SCREENSHOT_QUALITY_MEDIUM = "medium"
|
AI_SCREENSHOT_QUALITY_MEDIUM = "medium"
|
||||||
AI_SCREENSHOT_QUALITY_HIGH = "high"
|
AI_SCREENSHOT_QUALITY_HIGH = "high"
|
||||||
|
|
||||||
|
INDENTATION_PRESENTATION_OFF = "off"
|
||||||
|
INDENTATION_PRESENTATION_SPEECH = "speech"
|
||||||
|
INDENTATION_PRESENTATION_BEEPS = "beeps"
|
||||||
|
INDENTATION_PRESENTATION_SPEECH_AND_BEEPS = "speech_and_beeps"
|
||||||
|
|
||||||
|
INDENTATION_CHANGE_ALWAYS = "always"
|
||||||
|
INDENTATION_CHANGE_ANY = "any"
|
||||||
|
INDENTATION_CHANGE_LEVEL = "level"
|
||||||
|
|
||||||
|
INDENTATION_SPEECH_STYLE_SPACES_TABS = "spaces_tabs"
|
||||||
|
INDENTATION_SPEECH_STYLE_LEVELS = "levels"
|
||||||
|
INDENTATION_SPEECH_STYLE_COLUMNS = "columns"
|
||||||
|
|
||||||
|
INDENTATION_UNIT_LEVELS = "levels"
|
||||||
|
INDENTATION_UNIT_COLUMNS = "columns"
|
||||||
|
|
||||||
DEFAULT_VOICE = "default"
|
DEFAULT_VOICE = "default"
|
||||||
UPPERCASE_VOICE = "uppercase"
|
UPPERCASE_VOICE = "uppercase"
|
||||||
HYPERLINK_VOICE = "hyperlink"
|
HYPERLINK_VOICE = "hyperlink"
|
||||||
@@ -252,7 +280,19 @@ silenceSpeech = False
|
|||||||
enableTutorialMessages = False
|
enableTutorialMessages = False
|
||||||
enableMnemonicSpeaking = False
|
enableMnemonicSpeaking = False
|
||||||
enablePositionSpeaking = False
|
enablePositionSpeaking = False
|
||||||
enableSpeechIndentation = False
|
enableSpeechIndentation = True
|
||||||
|
indentationPresentationMode = INDENTATION_PRESENTATION_SPEECH_AND_BEEPS
|
||||||
|
indentationChangeMode = INDENTATION_CHANGE_ANY
|
||||||
|
speakIndentationOnlyIfChanged = True
|
||||||
|
indentationSpeechStyle = INDENTATION_SPEECH_STYLE_COLUMNS
|
||||||
|
indentationAudioUnit = INDENTATION_UNIT_COLUMNS
|
||||||
|
indentationSpacesPerLevel = 4
|
||||||
|
indentationTabWidth = 4
|
||||||
|
indentationAudioBaseFrequency = 200
|
||||||
|
indentationAudioStepFrequency = 30
|
||||||
|
indentationAudioMaxFrequency = 2700
|
||||||
|
indentationAudioDuration = 0.15
|
||||||
|
indentationAudioVolume = 0.7
|
||||||
onlySpeakDisplayedText = False
|
onlySpeakDisplayedText = False
|
||||||
presentToolTips = False
|
presentToolTips = False
|
||||||
speakBlankLines = True
|
speakBlankLines = True
|
||||||
@@ -449,7 +489,7 @@ presentChatRoomLast = False
|
|||||||
presentLiveRegionFromInactiveTab = False
|
presentLiveRegionFromInactiveTab = False
|
||||||
|
|
||||||
# Plugins
|
# Plugins
|
||||||
activePlugins = ['AIAssistant', 'DisplayVersion', 'OCR', 'PluginManager', 'HelloCthulhu', 'ByeCthulhu']
|
activePlugins = ['AIAssistant', 'DisplayVersion', 'OCR', 'PluginManager', 'HelloCthulhu', 'ByeCthulhu', 'IndentationAudio']
|
||||||
|
|
||||||
# AI Assistant settings (disabled by default for opt-in behavior)
|
# AI Assistant settings (disabled by default for opt-in behavior)
|
||||||
aiAssistantEnabled = True
|
aiAssistantEnabled = True
|
||||||
|
|||||||
@@ -967,11 +967,29 @@ class SpeechAndVerbosityManager:
|
|||||||
"""Returns whether speaking of indentation and justification is enabled."""
|
"""Returns whether speaking of indentation and justification is enabled."""
|
||||||
return _settings_manager.getSetting('enableSpeechIndentation')
|
return _settings_manager.getSetting('enableSpeechIndentation')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _sync_indentation_presentation_mode(enable_speech):
|
||||||
|
mode = _settings_manager.getSetting('indentationPresentationMode') \
|
||||||
|
or settings.indentationPresentationMode
|
||||||
|
if enable_speech:
|
||||||
|
if mode == settings.INDENTATION_PRESENTATION_OFF:
|
||||||
|
mode = settings.INDENTATION_PRESENTATION_SPEECH
|
||||||
|
elif mode == settings.INDENTATION_PRESENTATION_BEEPS:
|
||||||
|
mode = settings.INDENTATION_PRESENTATION_SPEECH_AND_BEEPS
|
||||||
|
else:
|
||||||
|
if mode == settings.INDENTATION_PRESENTATION_SPEECH:
|
||||||
|
mode = settings.INDENTATION_PRESENTATION_OFF
|
||||||
|
elif mode == settings.INDENTATION_PRESENTATION_SPEECH_AND_BEEPS:
|
||||||
|
mode = settings.INDENTATION_PRESENTATION_BEEPS
|
||||||
|
|
||||||
|
_settings_manager.setSetting('indentationPresentationMode', mode)
|
||||||
|
|
||||||
@dbus_service.setter
|
@dbus_service.setter
|
||||||
def set_speak_indentation_and_justification(self, value: bool) -> bool:
|
def set_speak_indentation_and_justification(self, value: bool) -> bool:
|
||||||
"""Sets whether speaking of indentation and justification is enabled."""
|
"""Sets whether speaking of indentation and justification is enabled."""
|
||||||
try:
|
try:
|
||||||
_settings_manager.setSetting('enableSpeechIndentation', value)
|
_settings_manager.setSetting('enableSpeechIndentation', value)
|
||||||
|
self._sync_indentation_presentation_mode(value)
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
debug.printMessage(debug.LEVEL_WARNING, f"Error setting speak indentation: {e}", True)
|
debug.printMessage(debug.LEVEL_WARNING, f"Error setting speak indentation: {e}", True)
|
||||||
@@ -1804,6 +1822,7 @@ class SpeechAndVerbosityManager:
|
|||||||
|
|
||||||
value = _settings_manager.getSetting('enableSpeechIndentation')
|
value = _settings_manager.getSetting('enableSpeechIndentation')
|
||||||
_settings_manager.setSetting('enableSpeechIndentation', not value)
|
_settings_manager.setSetting('enableSpeechIndentation', not value)
|
||||||
|
self._sync_indentation_presentation_mode(not value)
|
||||||
if _settings_manager.getSetting('enableSpeechIndentation'):
|
if _settings_manager.getSetting('enableSpeechIndentation'):
|
||||||
full = messages.INDENTATION_JUSTIFICATION_ON_FULL
|
full = messages.INDENTATION_JUSTIFICATION_ON_FULL
|
||||||
brief = messages.INDENTATION_JUSTIFICATION_ON_BRIEF
|
brief = messages.INDENTATION_JUSTIFICATION_ON_BRIEF
|
||||||
|
|||||||
@@ -193,6 +193,22 @@ class SpeechDBusManager:
|
|||||||
|
|
||||||
return self._settings_manager.getSetting("enableSpeechIndentation")
|
return self._settings_manager.getSetting("enableSpeechIndentation")
|
||||||
|
|
||||||
|
def _sync_indentation_presentation_mode(self, enable_speech):
|
||||||
|
mode = self._settings_manager.getSetting("indentationPresentationMode") \
|
||||||
|
or settings.indentationPresentationMode
|
||||||
|
if enable_speech:
|
||||||
|
if mode == settings.INDENTATION_PRESENTATION_OFF:
|
||||||
|
mode = settings.INDENTATION_PRESENTATION_SPEECH
|
||||||
|
elif mode == settings.INDENTATION_PRESENTATION_BEEPS:
|
||||||
|
mode = settings.INDENTATION_PRESENTATION_SPEECH_AND_BEEPS
|
||||||
|
else:
|
||||||
|
if mode == settings.INDENTATION_PRESENTATION_SPEECH:
|
||||||
|
mode = settings.INDENTATION_PRESENTATION_OFF
|
||||||
|
elif mode == settings.INDENTATION_PRESENTATION_SPEECH_AND_BEEPS:
|
||||||
|
mode = settings.INDENTATION_PRESENTATION_BEEPS
|
||||||
|
|
||||||
|
self._settings_manager.setSetting("indentationPresentationMode", mode)
|
||||||
|
|
||||||
@dbus_service.setter
|
@dbus_service.setter
|
||||||
def set_speak_indentation_and_justification(self, value: bool) -> bool:
|
def set_speak_indentation_and_justification(self, value: bool) -> bool:
|
||||||
"""Sets whether speaking of indentation and justification is enabled."""
|
"""Sets whether speaking of indentation and justification is enabled."""
|
||||||
@@ -200,6 +216,7 @@ class SpeechDBusManager:
|
|||||||
msg = f"SPEECH DBUS MANAGER: Setting speak indentation and justification to {value}."
|
msg = f"SPEECH DBUS MANAGER: Setting speak indentation and justification to {value}."
|
||||||
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
self._settings_manager.setSetting("enableSpeechIndentation", value)
|
self._settings_manager.setSetting("enableSpeechIndentation", value)
|
||||||
|
self._sync_indentation_presentation_mode(value)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@dbus_service.command
|
@dbus_service.command
|
||||||
@@ -512,4 +529,4 @@ class SpeechDBusManager:
|
|||||||
self._settings_manager.setSetting("enableEchoBySentence", new_sentence)
|
self._settings_manager.setSetting("enableEchoBySentence", new_sentence)
|
||||||
|
|
||||||
if script is not None:
|
if script is not None:
|
||||||
script.presentMessage(full, brief)
|
script.presentMessage(full, brief)
|
||||||
|
|||||||
@@ -1685,7 +1685,8 @@ class SpeechGenerator(generator.Generator):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
line, caretOffset, startOffset = self._script.getTextLineAtCaret(obj)
|
line, caretOffset, startOffset = self._script.getTextLineAtCaret(obj)
|
||||||
description = self._script.utilities.indentationDescription(line)
|
description, _hasIndentation = \
|
||||||
|
self._script.utilities.get_indentation_presentation(line, obj=obj)
|
||||||
if not description:
|
if not description:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user