diff --git a/addon/globalPlugins/MathCAT/MathCAT.py b/addon/globalPlugins/MathCAT/MathCAT.py
index 93983bb..e8dbd46 100644
--- a/addon/globalPlugins/MathCAT/MathCAT.py
+++ b/addon/globalPlugins/MathCAT/MathCAT.py
@@ -92,7 +92,11 @@
def getLanguageToUse(mathMl: str = "") -> str:
- """Get the language specified in a math tag if the language pref is Auto, else the language preference."""
+ """Get the language specified in a math tag if the language pref is Auto, else the language preference.
+
+ :param mathMl: The MathML string to examine for language. Defaults to an empty string.
+ :returns: The language string to use.
+ """
mathCATLanguageSetting: str = "Auto"
try:
# ignore regional differences if the MathCAT language setting doesn't have it.
@@ -117,8 +121,13 @@ def getLanguageToUse(mathMl: str = "") -> str:
def convertSSMLTextForNVDA(text: str) -> list[str | SpeechCommand]:
- """Change the SSML in the text into NVDA's command structure.
- The environment is examined to determine whether a language switch is needed"""
+ """
+ Change the SSML in the text into NVDA's command structure.
+ The environment is examined to determine whether a language switch is needed.
+
+ :param text: The SSML text to convert.
+ :returns: A list of strings and SpeechCommand objects.
+ """
# MathCAT's default rate is 180 wpm.
# Assume that 0% is 80 wpm and 100% is 450 wpm and scale accordingly.
# log.info(f"\nSpeech str: '{text}'")
@@ -212,6 +221,8 @@ def convertSSMLTextForNVDA(text: str) -> list[str | SpeechCommand]:
class MathCATInteraction(mathPres.MathInteractionNVDAObject):
+ """An NVDA object used to interact with MathML."""
+
# Put MathML or other formats on the clipboard.
# MathML is put on the clipboard using the two formats below (defined by MathML spec)
# We use both formats because some apps may only use one or the other
@@ -225,9 +236,14 @@ class MathCATInteraction(mathPres.MathInteractionNVDAObject):
def __init__(
self,
- provider: mathPres.MathPresentationProvider = None,
+ provider: mathPres.MathPresentationProvider | None = None,
mathMl: str | None = None,
):
+ """Initialize the MathCATInteraction object.
+
+ :param provider: Optional presentation provider.
+ :param mathMl: Optional initial MathML string.
+ """
super(MathCATInteraction, self).__init__(provider=provider, mathMl=mathMl)
if mathMl is None:
self.initMathML = ""
@@ -235,6 +251,7 @@ def __init__(
self.initMathML = mathMl
def reportFocus(self) -> None:
+ """Calls MathCAT's ZoomIn command and speaks the resulting text."""
super(MathCATInteraction, self).reportFocus()
# try to get around espeak bug where voice slows down
if _synthesizerRate and getSynth().name == "espeak":
@@ -256,6 +273,7 @@ def getBrailleRegions(
self,
review: bool = False,
) -> Generator[braille.Region, None, None]:
+ """Yields braille.Region objects for this MathCATInteraction object."""
# log.info("***MathCAT start getBrailleRegions")
yield braille.NVDAObjectRegion(self, appendText=" ")
region: braille.Region = braille.Region()
@@ -276,7 +294,12 @@ def getScript(
self,
gesture: KeyboardInputGesture,
) -> Callable[KeyboardInputGesture, None] | None:
- # Pass most keys to MathCAT. Pretty ugly.
+ """
+ Returns the script function bound to the given gesture.
+
+ :param gesture: A KeyboardInputGesture sent to this object.
+ :returns: The script bound to that gesture.
+ """
if (
isinstance(gesture, KeyboardInputGesture)
and "NVDA" not in gesture.modifierNames
@@ -309,6 +332,10 @@ def getScript(
return super().getScript(gesture)
def script_navigate(self, gesture: KeyboardInputGesture) -> None:
+ """Performs the specified navigation command.
+
+ :param gesture: They keyboard command which specified the navigation command to perform.
+ """
try:
# try to get around espeak bug where voice slows down
if _synthesizerRate and getSynth().name == "espeak":
@@ -365,6 +392,10 @@ def script_navigate(self, gesture: KeyboardInputGesture) -> None:
gesture="kb:control+c",
)
def script_rawdataToClip(self, gesture: KeyboardInputGesture) -> None:
+ """Copies the raw data to the clipboard, either as MathML, ASCII math, or LaTeX, depending on user preferences.
+
+ :param gesture: The gesture which activated this script.
+ """
try:
copyAs: str = "mathml" # value used even if "CopyAs" pref is invalid
textToCopy: str = ""
@@ -416,7 +447,7 @@ def script_rawdataToClip(self, gesture: KeyboardInputGesture) -> None:
_hasDataAttr: re.Pattern = re.compile(" data-[^=]+='[^']*'")
def _wrapMathMLForClipBoard(self, text: str) -> str:
- # cleanup the MathML a little
+ """Cleanup the MathML a little."""
text = re.sub(self._hasAddedId, "", text)
mathMLWithNS: str = re.sub(self._hasDataAttr, "", text)
if not re.match(self._mathTagHasNameSpace, mathMLWithNS):
@@ -434,9 +465,10 @@ def _copyToClipAsMathML(
notify: bool | None = False,
) -> bool:
"""Copies the given text to the windows clipboard.
- @returns: True if it succeeds, False otherwise.
- @param text: the text which will be copied to the clipboard
- @param notify: whether to emit a confirmation message
+
+ :param text: the text which will be copied to the clipboard.
+ :param notify: whether to emit a confirmation message.
+ :returns: True if it succeeds, False otherwise.
"""
# copied from api.py and modified to use CF_MathML_Presentation
if not isinstance(text, str) or len(text) == 0:
@@ -463,6 +495,12 @@ def _copyToClipAsMathML(
return False
def _setClipboardData(self, format: int, data: str) -> None:
+ """Sets the clipboard data to the given data with the specified format.
+
+ :param format: The format for the clipboard data.
+ This is an integer format code returned by windll.user32.RegisterClipboardFormatW.
+ :param data: The data to set on the clipboard.
+ """
# Need to support MathML Presentation, so this copied from winUser.py and the first two lines are commented out
# For now only unicode is a supported format
# if format!=CF_UNICODETEXT:
@@ -485,6 +523,7 @@ def _setClipboardData(self, format: int, data: str) -> None:
class MathCAT(mathPres.MathPresentationProvider):
def __init__(self):
+ """Initializes MathCAT, loading the rules specified in the rules directory."""
# super(MathCAT, self).__init__(*args, **kwargs)
try:
@@ -502,6 +541,11 @@ def getSpeechForMathMl(
self,
mathml: str,
) -> list[str | SpeechCommand]:
+ """Outputs a MathML string as speech.
+
+ :param mathml: A MathML string.
+ :returns: A list of speech commands and strings representing the given MathML.
+ """
global _synthesizerRate
synth: SynthDriver = getSynth()
synthConfig = config.conf["speech"][synth.name]
@@ -557,6 +601,10 @@ def getSpeechForMathMl(
getSynth()._set_rate(_synthesizerRate)
def _addSounds(self) -> bool:
+ """Queries the user preferences to determine whether or not sounds should be added.
+
+ :returns: True if MathCAT's `SpeechSound` preference is set, and False otherwise.
+ """
try:
return libmathcat.GetPreference("SpeechSound") != "None"
except Exception as e:
@@ -564,6 +612,11 @@ def _addSounds(self) -> bool:
return False
def getBrailleForMathMl(self, mathml: str) -> str:
+ """Gets the braille representation of a given MathML string by calling MathCAT's GetBraille function.
+
+ :param mathml: A MathML string.
+ :returns: A braille string representing the input MathML.
+ """
# log.info("***MathCAT getBrailleForMathMl")
try:
libmathcat.SetMathML(mathml)
@@ -582,6 +635,10 @@ def getBrailleForMathMl(self, mathml: str) -> str:
return ""
def interactWithMathMl(self, mathml: str) -> None:
+ """Interact with a MathML string, creating a MathCATInteraction object.
+
+ :param mathml: The MathML representing the math to interact with.
+ """
MathCATInteraction(provider=self, mathMl=mathml).setFocus()
MathCATInteraction(provider=self, mathMl=mathml).script_navigate(None)
@@ -590,6 +647,7 @@ def interactWithMathMl(self, mathml: str) -> None:
def _monkeyPatchESpeak() -> None:
+ """Patches an eSpeak bug where the voice slows down."""
global CACHED_SYNTH
currentSynth: SynthDriver = getSynth()
if currentSynth.name != "espeak" or CACHED_SYNTH == currentSynth:
diff --git a/addon/globalPlugins/MathCAT/MathCATPreferences.py b/addon/globalPlugins/MathCAT/MathCATPreferences.py
index 8f2ed1e..8424707 100644
--- a/addon/globalPlugins/MathCAT/MathCATPreferences.py
+++ b/addon/globalPlugins/MathCAT/MathCATPreferences.py
@@ -42,7 +42,20 @@
class UserInterface(MathCATgui.MathCATPreferencesDialog):
- def __init__(self, parent):
+ """UI class for the MathCAT Preferences Dialog.
+
+ Initializes and manages user preferences, including language, speech, braille,
+ and navigation settings. Extends MathCATgui.MathCATPreferencesDialog.
+ """
+
+ def __init__(self, parent: wx.Window | None):
+ """Initialize the preferences dialog.
+
+ Sets up the UI, loads preferences, applies defaults and saved settings,
+ and restores the previous UI state.
+
+ :param parent: The parent window for the dialog.
+ """
# initialize parent class
MathCATgui.MathCATPreferencesDialog.__init__(self, parent)
@@ -79,16 +92,36 @@ def __init__(self, parent):
@staticmethod
def pathToLanguagesFolder() -> str:
- # the user preferences file is stored at: MathCAT\Rules\Languages
+ r"""Returns the full path to the Languages rules folder.
+
+ The language rules are stored in:
+ MathCAT\Rules\Languages, relative to the location of this file.
+
+ :return: Absolute path to the Languages folder as a string.
+ """
return os.path.join(os.path.dirname(os.path.abspath(__file__)), "Rules", "Languages")
@staticmethod
def pathToBrailleFolder() -> str:
- # the user preferences file is stored at: MathCAT\Rules\Languages
+ r"""Returns the full path to the Braille rules folder.
+
+ The Braille rules are stored in:
+ MathCAT\Rules\Braille, relative to the location of this file.
+
+ :return: Absolute path to the Braille folder as a string.
+ """
return os.path.join(os.path.dirname(os.path.abspath(__file__)), "Rules", "Braille")
@staticmethod
def languagesDict() -> dict[str, str]:
+ """Returns a dictionary mapping language codes to their corresponding language names.
+
+ This dictionary includes standard language codes, as well as regional variants such as
+ 'en-GB', 'zh-HANT', and others.
+
+ :return: A dictionary where the key is the language code (e.g., 'en', 'fr', 'zh-HANS')
+ and the value is the language name (e.g. 'English', 'Français', 'Chinese, Simplified').
+ """
languages = {
"aa": "Afar",
"ab": "Аҧсуа",
@@ -270,6 +303,18 @@ def getRulesFiles(
pathToDir: str,
processSubDirs: Callable[[str, str], list[str]] | None,
) -> list[str]:
+ """
+ Get the rule files from a directory, optionally processing subdirectories.
+
+ Searches for files ending with '_Rules.yaml' in the specified directory.
+ If no rule files are found, attempts to find them inside a corresponding ZIP archive,
+ including checking any subdirectories inside the ZIP.
+
+ :param pathToDir: Path to the directory to search for rule files.
+ :param processSubDirs: Optional callable to process subdirectories. It should take the subdirectory name
+ and the language code as arguments, returning a list of rule filenames found in that subdirectory.
+ :return: A list of rule file names found either directly in the directory or inside the ZIP archive.
+ """
language: str = os.path.basename(pathToDir)
ruleFiles: list[str] = [
os.path.basename(file) for file in glob.glob(os.path.join(pathToDir, "*_Rules.yaml"))
@@ -294,6 +339,14 @@ def getRulesFiles(
return ruleFiles
def getLanguages(self) -> None:
+ """Populate the language choice dropdown with available languages and their regional variants.
+
+ This method scans the language folders and adds entries for each language and its
+ regional dialects. Language folders use ISO 639-1 codes and regional variants use ISO 3166-1 alpha-2 codes.
+
+ It also adds a special "Use Voice's Language (Auto)" option at the top.
+ """
+
def addRegionalLanguages(subDir: str, language: str) -> list[str]:
# the language variants are in folders named using ISO 3166-1 alpha-2
# codes https://en.wikipedia.org/wiki/ISO_3166-2
@@ -334,19 +387,34 @@ def addRegionalLanguages(subDir: str, language: str) -> list[str]:
self._choiceLanguage.Append(language + " (" + language + ")")
def getLanguageCode(self) -> str:
+ """Extract the language code from the selected language string in the UI.
+
+ The selected language string is expected to contain the language code in parentheses,
+ for example: "English (en)".
+
+ :return: The language code extracted from the selection.
+ """
langSelection: str = self._choiceLanguage.GetStringSelection()
langCode: str = langSelection[langSelection.find("(") + 1 : langSelection.find(")")]
return langCode
- def getSpeechStyles(self, thisSpeechStyle: str):
+ def getSpeechStyles(self, thisSpeechStyle: str) -> None:
"""Get all the speech styles for the current language.
- This sets the SpeechStyles dialog entry"""
+ This sets the SpeechStyles dialog entry.
+
+ :param thisSpeechStyle: The speech style to set or highlight in the dialog.
+ """
from speech import getCurrentLanguage
def getSpeechStyleFromDirectory(dir: str, lang: str) -> list[str]:
r"""Get the speech styles from any regional dialog, from the main language, dir and if there isn't from the zip file.
The 'lang', if it has a region dialect, is of the form 'en\uk'
- The returned list is sorted alphabetically"""
+ The returned list is sorted alphabetically
+
+ :param dir: The directory path to search for speech styles.
+ :param lang: Language code which may include a regional dialect (e.g., 'en\uk').
+ :return: A list of speech styles sorted alphabetically.
+ """
# start with the regional dialect, then add on any (unique) styles in the main dir
mainLang: str = lang.split("\\")[0] # does the right thing even if there is no regional directory
allStyleFiles: list[str] = []
@@ -407,6 +475,11 @@ def getSpeechStyleFromDirectory(dir: str, lang: str) -> list[str]:
self._choiceSpeechStyle.SetSelection(0)
def getBrailleCodes(self) -> None:
+ """Initializes and populates the braille code choice control with available braille codes.
+
+ Scans the braille codes folder for valid directories containing rules files, and adds them
+ to the braille code dropdown in the dialog.
+ """
# initialise the braille code list
self._choiceBrailleMathCode.Clear()
# populate the available braille codes in the dialog
@@ -419,7 +492,11 @@ def getBrailleCodes(self) -> None:
self._choiceBrailleMathCode.Append(brailleCode)
def setUIValues(self) -> None:
- # set the UI elements to the ones read from the preference file(s)
+ """Sets the UI elements based on the values read from the user preferences.
+
+ Attempts to match preference values to UI controls; falls back to defaults if values are invalid
+ or missing.
+ """
try:
self._choiceImpairment.SetSelection(
Speech_Impairment.index(userPreferences["Speech"]["Impairment"]),
@@ -512,6 +589,7 @@ def setUIValues(self) -> None:
print("Key not found", err)
def getUIValues(self) -> None:
+ """Reads the current values from the UI controls and updates the user preferences accordingly."""
global userPreferences
# read the values from the UI and update the user preferences dictionary
userPreferences["Speech"]["Impairment"] = Speech_Impairment[self._choiceImpairment.GetSelection()]
@@ -556,20 +634,24 @@ def getUIValues(self) -> None:
@staticmethod
def pathToDefaultPreferences() -> str:
+ """Returns the full path to the default preferences file."""
return os.path.join(os.path.dirname(os.path.abspath(__file__)), "Rules", "prefs.yaml")
@staticmethod
def pathToUserPreferencesFolder() -> str:
+ """Returns the path to the folder where user preferences are stored."""
# the user preferences file is stored at: C:\Users\AppData\Roaming\MathCAT\prefs.yaml
return os.path.join(os.path.expandvars("%APPDATA%"), "MathCAT")
@staticmethod
def pathToUserPreferences() -> str:
+ """Returns the full path to the user preferences file."""
# the user preferences file is stored at: C:\Users\AppData\Roaming\MathCAT\prefs.yaml
return os.path.join(UserInterface.pathToUserPreferencesFolder(), "prefs.yaml")
@staticmethod
def loadDefaultPreferences() -> None:
+ """Loads the default preferences, overwriting any existing user preferences."""
global userPreferences
# load default preferences into the user preferences data structure (overwrites existing)
if os.path.exists(UserInterface.pathToDefaultPreferences()):
@@ -581,6 +663,10 @@ def loadDefaultPreferences() -> None:
@staticmethod
def loadUserPreferences() -> None:
+ """Loads user preferences from a file and merges them into the current preferences.
+
+ If the user preferences file exists, its values overwrite the defaults.
+ """
global userPreferences
# merge user file values into the user preferences data structure
if os.path.exists(UserInterface.pathToUserPreferences()):
@@ -595,6 +681,15 @@ def validate(
validValues: list[str | bool],
defaultValue: str | bool,
) -> None:
+ """Validates that a preference value is in a list of valid options or non-empty if no list is given.
+
+ If the value is missing or invalid, sets it to the default.
+
+ :param key1: The first-level key in the preferences dictionary.
+ :param key2: The second-level key in the preferences dictionary.
+ :param validValues: A list of valid values; if empty, any non-empty value is valid.
+ :param defaultValue: The default value to set if validation fails.
+ """
global userPreferences
try:
if validValues == []:
@@ -621,6 +716,15 @@ def validateInt(
validValues: list[int],
defaultValue: int,
) -> None:
+ """Validates that an integer preference is within a specified range.
+
+ If the value is missing or out of bounds, sets it to the default.
+
+ :param key1: The first-level key in the preferences dictionary.
+ :param key2: The second-level key in the preferences dictionary.
+ :param validValues: A list with two integers [min, max] representing valid bounds.
+ :param defaultValue: The default value to set if validation fails.
+ """
global userPreferences
try:
# any value between lower and upper bounds is valid
@@ -639,7 +743,11 @@ def validateInt(
@staticmethod
def validateUserPreferences():
- # check each user preference value to ensure it is present and valid, set default value if not
+ """Validates all user preferences, ensuring each is present and valid.
+
+ If a preference is missing or invalid, it is reset to its default value.
+ Validation covers speech, navigation, and braille settings.
+ """
# Speech:
# Impairment: Blindness # LearningDisability, LowVision, Blindness
UserInterface.validate(
@@ -693,6 +801,11 @@ def validateUserPreferences():
@staticmethod
def writeUserPreferences() -> None:
+ """Writes the current user preferences to a file and updates special settings.
+
+ Sets the language preference through the native library, ensures the preferences
+ folder exists, and saves the preferences to disk.
+ """
# Language is special because it is set elsewhere by SetPreference which overrides the user_prefs -- so set it here
from . import libmathcat_py as libmathcat
@@ -710,6 +823,13 @@ def writeUserPreferences() -> None:
yaml.dump(userPreferences, stream=f, allow_unicode=True)
def onRelativeSpeedChanged(self, event: wx.ScrollEvent) -> None:
+ """Handles changes to the relative speed slider and updates speech output.
+
+ Adjusts the speech rate based on the slider value and speaks a test phrase
+ with the updated rate.
+
+ :param event: The scroll event triggered by adjusting the relative speed slider.
+ """
rate: int = self._sliderRelativeSpeed.GetValue()
# Translators: this is a test string that is spoken. Only translate "the square root of x squared plus y squared"
text: str = _("the square root of x squared plus y squared").replace(
@@ -720,6 +840,13 @@ def onRelativeSpeedChanged(self, event: wx.ScrollEvent) -> None:
speak(convertSSMLTextForNVDA(text))
def onPauseFactorChanged(self, event: wx.ScrollEvent) -> None:
+ """Handles changes to the pause factor slider and updates speech output accordingly.
+
+ Calculates the pause durations based on the slider value, constructs an SSML string
+ with adjusted prosody and breaks, and sends it for speech synthesis.
+
+ :param event: The scroll event triggered by adjusting the pause factor slider.
+ """
rate: int = self._sliderRelativeSpeed.GetValue()
pfSlider = self._sliderPauseFactor.GetValue()
pauseFactor = (
@@ -747,35 +874,91 @@ def onPauseFactorChanged(self, event: wx.ScrollEvent) -> None:
speak(convertSSMLTextForNVDA(text))
def onClickOK(self, event: wx.CommandEvent) -> None:
+ """Saves current preferences and closes the dialog.
+
+ Retrieves values from the UI, writes them to the preferences, and then closes the window.
+
+ :param event: The event triggered by clicking the OK button.
+ """
UserInterface.getUIValues(self)
UserInterface.writeUserPreferences()
self.Destroy()
def onClickCancel(self, event: wx.CommandEvent) -> None:
+ """Closes the preferences dialog without saving changes.
+
+ :param event: The event triggered by clicking the Cancel button.
+ """
self.Destroy()
def onClickApply(self, event: wx.CommandEvent) -> None:
+ """Applies the current UI settings to the user preferences.
+
+ Retrieves values from the UI and writes them to the preferences configuration.
+
+ :param event: The event triggered by clicking the Apply button.
+ """
UserInterface.getUIValues(self)
UserInterface.writeUserPreferences()
def onClickReset(self, event: wx.CommandEvent) -> None:
+ """Resets preferences to their default values.
+
+ Loads the default preferences, validates them, and updates the UI accordingly.
+
+ :param event: The event triggered by clicking the Reset button.
+ """
UserInterface.loadDefaultPreferences()
UserInterface.validateUserPreferences()
UserInterface.setUIValues(self)
def onClickHelp(self, event: wx.CommandEvent) -> None:
+ """Opens the MathCAT user guide in the default web browser.
+
+ Triggered when the Help button is clicked.
+
+ :param event: The event triggered by clicking the Help button.
+ """
webbrowser.open("https://nsoiffer.github.io/MathCAT/users.html")
def onListBoxCategories(self, event: wx.CommandEvent) -> None:
- # the category changed, now show the appropriate dialogue page
+ """Handles category selection changes in the preferences list box.
+
+ Updates the displayed panel in the dialog to match the newly selected category.
+
+ :param event: The event triggered by selecting a different category.
+ """
self._simplebookPanelsCategories.SetSelection(self._listBoxPreferencesTopic.GetSelection())
def onLanguage(self, event: wx.CommandEvent) -> None:
- # the language changed, get the SpeechStyles for the new language
+ """Handles the event when the user changes the selected language.
+
+ Retrieves and updates the available speech styles for the newly selected language
+ in the preferences dialog.
+
+ :param event: The event triggered by changing the language selection.
+ """
UserInterface.getSpeechStyles(self, self._choiceSpeechStyle.GetStringSelection())
def mathCATPreferencesDialogOnCharHook(self, event: wx.KeyEvent) -> None:
- # designed choice is that Enter is the same as clicking OK, and Escape is the same as clicking Cancel
+ """Handles character key events within the MathCAT Preferences dialog.
+
+ This method interprets specific key presses to mimic button clicks or
+ navigate within the preferences dialog:
+
+ - escape: Triggers the Cancel button functionality.
+ - enter: Triggers the OK button functionality.
+ - ctrl+tab: Cycles forward through the preference categories.
+ - ctrl+shift+tab: Cycles backward through the preference categories.
+ - tab: Moves focus to the first control in the currently selected category,
+ if the category list has focus.
+ - shift+tab: Moves focus to the second row of controls,
+ if the OK button has focus.
+
+ If none of these keys are matched, the event is skipped to allow default processing.
+
+ :param event: The keyboard event to handle.
+ """
keyCode: int = event.GetKeyCode()
if keyCode == wx.WXK_ESCAPE:
UserInterface.onClickCancel(self, event)
diff --git a/addon/globalPlugins/MathCAT/MathCATgui.py b/addon/globalPlugins/MathCAT/MathCATgui.py
index e0bacf3..fdf06b8 100644
--- a/addon/globalPlugins/MathCAT/MathCATgui.py
+++ b/addon/globalPlugins/MathCAT/MathCATgui.py
@@ -13,7 +13,16 @@
class MathCATPreferencesDialog(wx.Dialog):
- def __init__(self, parent):
+ """Main dialog window for configuring MathCAT preferences.
+
+ This base class sets up the layout and controls.
+ """
+
+ def __init__(self, parent: wx.Window | None):
+ """Initialize the preferences dialog.
+
+ :param parent: The parent window for this dialog.
+ """
wx.Dialog.__init__(
self,
parent,
@@ -825,38 +834,50 @@ def __init__(self, parent):
self._buttonHelp.Bind(wx.EVT_BUTTON, self.onClickHelp)
def __del__(self):
+ """Destructor placeholder; override if cleanup is needed."""
pass
# Virtual event handlers, override them in your derived class
def mathCATPreferencesDialogOnCharHook(self, event: wx.KeyEvent) -> None:
+ """Handle character input events; override in subclass as needed."""
event.Skip()
def mathCATPreferencesDialogOnKeyUp(self, event: wx.KeyEvent) -> None:
+ """Handle key release events; override in subclass as needed."""
event.Skip()
def onListBoxCategories(self, event: wx.CommandEvent) -> None:
+ """Handle selection events in the categories list box; override in subclass as needed."""
event.Skip()
def onLanguage(self, event: wx.CommandEvent) -> None:
+ """Handle language selection; override in subclass as needed."""
event.Skip()
def onRelativeSpeedChanged(self, event: wx.ScrollEvent) -> None:
+ """Handle change in relative speed; override in subclass as needed."""
event.Skip()
def onPauseFactorChanged(self, event: wx.ScrollEvent) -> None:
+ """Handle change in pause factor; override in subclass as needed."""
event.Skip()
def onClickOK(self, event: wx.CommandEvent) -> None:
+ """Handle OK button click; override in subclass as needed."""
event.Skip()
def onClickCancel(self, event: wx.CommandEvent) -> None:
+ """Handle Cancel button click; override in subclass as needed."""
event.Skip()
def onClickApply(self, event: wx.CommandEvent) -> None:
+ """Handle Apply button click; override in subclass as needed."""
event.Skip()
def onClickReset(self, event: wx.CommandEvent) -> None:
+ """Handle Reset button click; override in subclass as needed."""
event.Skip()
def onClickHelp(self, event: wx.CommandEvent) -> None:
+ """Handle Help button click; override in subclass as needed."""
event.Skip()
diff --git a/addon/globalPlugins/MathCAT/__init__.py b/addon/globalPlugins/MathCAT/__init__.py
index cfbae9f..4bc4da4 100644
--- a/addon/globalPlugins/MathCAT/__init__.py
+++ b/addon/globalPlugins/MathCAT/__init__.py
@@ -1,14 +1,15 @@
# -*- coding: UTF-8 -*-
-# MathCAT add-on: generates speech, braille, and allows exploration of expressions written in MathML
-# The goal of this add-on is to replicate/improve upon the functionality of MathPlayer which has been discontinued.
-# Author: Neil Soiffer
-# Copyright: this file is copyright GPL2
-# The code additionally makes use of the MathCAT library (written in Rust) which is covered by the MIT license
-# and also (obviously) requires external speech engines and braille drivers.
-# The plugin also requires the use of a small python dll: python3.dll
-# python3.dll has "Copyright © 2001-2022 Python Software Foundation; All Rights Reserved"
-
+"""
+MathCAT add-on: generates speech, braille, and allows exploration of expressions written in MathML.
+The goal of this add-on is to replicate/improve upon the functionality of MathPlayer which has been discontinued.
+Author: Neil Soiffer
+Copyright: this file is copyright GPL2
+ The code additionally makes use of the MathCAT library (written in Rust) which is covered by the MIT license
+ and also (obviously) requires external speech engines and braille drivers.
+ The plugin also requires the use of a small python dll: python3.dll
+ python3.dll has "Copyright © 2001-2022 Python Software Foundation; All Rights Reserved
+"""
import globalPluginHandler # we are a global plugin
import globalVars
@@ -26,12 +27,25 @@
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
+ """
+ Global plugin for the MathCAT add-on.
+ """
+
def __init__(self, *args, **kwargs):
+ """
+ Initialize the Global Plugin and add the MathCAT menu.
+
+ :param args: Additional positional arguments.
+ :param kwargs: Additional keyword arguments.
+ """
super().__init__(*args, **kwargs)
# MathCAT.__init__(self)
self.addMathCATMenu()
def addMathCATMenu(self) -> None:
+ """
+ Adds the MathCAT settings menu to the NVDA preferences.
+ """
if not globalVars.appArgs.secure:
self.preferencesMenu = mainFrame.sysTrayIcon.preferencesMenu
# Translators: this show up in the NVDA preferences dialog. It opens the MathCAT preferences dialog
@@ -39,9 +53,17 @@ def addMathCATMenu(self) -> None:
mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onSettings, self.settings)
def onSettings(self, evt: wx.CommandEvent) -> None:
+ """
+ Opens the MathCAT preferences dialog.
+
+ :param evt: The event that triggered this action.
+ """
mainFrame.popupSettingsDialog(UserInterface)
def terminate(self) -> None:
+ """
+ Cleans up by removing the MathCAT menu item upon termination.
+ """
try:
if not globalVars.appArgs.secure:
self.preferencesMenu.Remove(self.settings)