Skip to content
Permalink
Browse files

Add a GUI for the vision framework

- Each provider has it's own group for settings.
- Providers can use "driverSettings" to define GUI for configurable
  options, these controls will be constructed automatically.
- Auto constructed GUI will have an enable checkbox as a minimum.
- Custom controls for configuration is possible. See NVDA Highlighter.
- Runtime / static settings support. See example provider.
- Rename example provider (removing first underscore) to make it run.

Other notable changes:

- Focus Highlight:
  - Turning on any one option will enable the highlighter.
  - Convenience checkbox to enable/disable all.

- Screen Curtain:
  - A warning is displayed before enable (settings and gesture)
  - Warning can be disabled
  - Gesture: Use 1 press for temporary enable, and 2 presses for permanent.

- Use dataclass ProviderInfo rather than string providerId to control
  providers.
  - The providerInfo allows for differentiating providerId and moduleName.
    Helpful when a provider wants a single implementation to
    work with several versions of an app which have incompatible
    configurations.
    In this case, they will need different config sections, hence
    different providerId's.

- Remove unused role concept

- Partial rewrite of class DriverSettingsMixin:
  - Rename to AutoSettingsMixin
    - Provides better consistency with the AutoSettings class.
    - An alias mapping DriverSettingsMixin to AutoSettingsMixin is provided
      for backwards compatibility, however DriverSettingsMixin should be
      considered deprecated. Use AutoSettingsMixin instead.
  - rename self._curDriverRef -> self._currentSettingsRef
  - replace driver method with getSettings and _getSettingsStorage
    - getSettings to get settings definitions
    - _getSettingsStorage to load / save configuration values.
  - renamed various internal only methods:
    - makeSliderSettingControl -> _makeSliderSettingControl
    - makeBooleanSettingControl -> _makeBooleanSettingControl
    - makeStringSettingControl -> _makeStringSettingControl
  - settingsStorage is passed into the following:
    - _makeSliderSettingControl
    - _makeBooleanSettingControl
    - _makeStringSettingControl
  • Loading branch information
feerrenrut committed Nov 13, 2019
1 parent e3a0232 commit e8f8a898772892623080a2b189b12f0ebe11fc88
@@ -7,25 +7,30 @@
"""autoSettings for add-ons"""
from abc import abstractmethod
from copy import deepcopy
from typing import Union, Dict, Type, Any, Iterable
from typing import Dict, Type, Any, Iterable

import config
from autoSettingsUtils.utils import paramToPercent, percentToParam, UnsupportedConfigParameterError
from baseObject import AutoPropertyObject
from logHandler import log
from .driverSetting import DriverSetting

SupportedSettingType: Type = Union[
Iterable[DriverSetting]
]
SupportedSettingType: Type = Iterable[DriverSetting]


class AutoSettings(AutoPropertyObject):
"""
""" An AutoSettings instance is used to simplify the load/save of user config for NVDA extensions
(Synth drivers, braille drivers, vision providers) and make it possible to automatically provide a
standard GUI for these settings.
Derived classes must implement:
- getId
- getDisplayName
- _get_supportedSettings
"""

def __init__(self):
"""
"""Perform any initialisation
@note: registers with the config save action extension point
"""
super().__init__()
self._registerConfigSaveAction()
@@ -34,27 +39,40 @@ def __del__(self):
self._unregisterConfigSaveAction()

def _registerConfigSaveAction(self):
"""Overrideable pre_configSave registration"""
""" Overrideable pre_configSave registration
"""
log.debug(f"registering pre_configSave action: {self.__class__!r}")
config.pre_configSave.register(self.saveSettings)

def _unregisterConfigSaveAction(self):
"""Overrideable pre_configSave de-registration"""
""" Overrideable pre_configSave de-registration
"""
config.pre_configSave.unregister(self.saveSettings)

@classmethod
@abstractmethod
def getId(cls) -> str:
"""
@return: Application friendly name, should be globally unique, however since this is used in the config file
human readable is also beneficial.
"""
...

@classmethod
@abstractmethod
def getDisplayName(cls) -> str:
"""
@return: The translated name for this collection of settings. This is for use in the GUI to represent the
group of these settings.
"""
...

@classmethod
@abstractmethod
def _getConfigSection(cls) -> str:
"""
@return: The section of the config that these settings belong in.
"""
...

@classmethod
@@ -83,22 +101,24 @@ def _initSpecificSettings(
cls._loadSpecificSettings(clsOrInst, settings)

def initSettings(self):
"""
Initializes the configuration for this driver.
This method is called when initializing the driver.
"""Initializes the configuration for this AutoSettings instance.
This method is called when initializing the AutoSettings instance.
"""
self._initSpecificSettings(self, self.supportedSettings)

#: Typing for auto property L{_get_supportedSettings}
supportedSettings: SupportedSettingType

# make supportedSettings an abstract property
_abstract_supportedSettings = True

def _get_supportedSettings(self) -> SupportedSettingType:
"""The settings supported by the driver.
@rtype: list or tuple of L{DriverSetting}
"""The settings supported by the AutoSettings instance. Abstract.
"""
return []

def isSupported(self, settingID) -> bool:
"""Checks whether given setting is supported by the driver.
"""Checks whether given setting is supported by the AutoSettings instance.
"""
for s in self.supportedSettings:
if s.id == settingID:
@@ -152,8 +172,8 @@ def _saveSpecificSettings(

def saveSettings(self):
"""
Saves the current settings for the driver to the configuration.
This method is also executed when the driver is loaded for the first time,
Saves the current settings for the AutoSettings instance to the configuration.
This method is also executed when the AutoSettings instance is loaded for the first time,
in order to populate the configuration with the initial settings..
"""
self._saveSpecificSettings(self, self.supportedSettings)
@@ -200,7 +220,7 @@ def _loadSpecificSettings(

def loadSettings(self, onlyChanged: bool = False):
"""
Loads settings for this driver from the configuration.
Loads settings for this AutoSettings instance from the configuration.
This method assumes that the instance has attributes o/properties
corresponding with the name of every setting in L{supportedSettings}.
@param onlyChanged: When loading settings, only apply those for which
@@ -1,11 +1,25 @@
from numbers import Number
from typing import Optional
# -*- coding: UTF-8 -*-
# A part of NonVisual Desktop Access (NVDA)
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.
# Copyright (C) 2019 NV Access Limited

"""Classes used to represent settings for Drivers and other AutoSettings instances
Naming of these classes is historical, kept for backwards compatibility purposes.
"""

from typing import Optional
from baseObject import AutoPropertyObject


class DriverSetting(AutoPropertyObject):
"""Represents a synthesizer or braille display setting such as voice, variant or dot firmness.
"""As a base class, represents a setting to be shown in GUI and saved to config.
GUI representation is a string selection GUI control, a wx.Choice control.
Used for synthesizer or braille display setting such as voice, variant or dot firmness as
well as for settings in Vision Providers
"""
id: str
displayName: str
@@ -54,7 +68,9 @@ def __init__(


class NumericDriverSetting(DriverSetting):
"""Represents a numeric driver setting such as rate, volume, pitch or dot firmness."""
"""Represents a numeric driver setting such as rate, volume, pitch or dot firmness.
GUI representation is a slider control.
"""

defaultVal: int

@@ -104,6 +120,7 @@ def __init__(

class BooleanDriverSetting(DriverSetting):
"""Represents a boolean driver setting such as rate boost or automatic time sync.
GUI representation is a wx.Checkbox
"""
defaultVal: bool

@@ -1,3 +1,12 @@
# -*- coding: UTF-8 -*-
# A part of NonVisual Desktop Access (NVDA)
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.
# Copyright (C) 2019 NV Access Limited

"""Utility methods for Driver and AutoSettings instances
"""


def paramToPercent(current: int, min: int, max: int) -> int:
"""Convert a raw parameter value to a percentage given the current, minimum and maximum raw values.
@@ -12,7 +21,8 @@ def paramToPercent(current: int, min: int, max: int) -> int:


def percentToParam(percent: int, min: int, max: int) -> int:
"""Convert a percentage to a raw parameter value given the current percentage and the minimum and maximum raw parameter values.
"""Convert a percentage to a raw parameter value given the current percentage and the minimum and maximum
raw parameter values.
@param percent: The current percentage.
@type percent: int
@param min: The minimum raw parameter value.
@@ -28,9 +38,10 @@ class UnsupportedConfigParameterError(NotImplementedError):
Raised when changing or retrieving a driver setting that is unsupported for the connected device.
"""


class StringParameterInfo(object):
"""
The base class used to represent a value of a string driver setting.
Used to represent a value of a DriverSetting instance.
"""
id: str
displayName: str
@@ -6,10 +6,6 @@

"""Handler for driver functionality that is global to synthesizers and braille displays."""
from autoSettingsUtils.autoSettings import AutoSettings
from autoSettingsUtils.utils import (
paramToPercent,
percentToParam
)

# F401: the following imports, while unused in this file, are provided for backwards compatibility.
from autoSettingsUtils.driverSetting import ( # noqa: F401
@@ -22,11 +18,6 @@
UnsupportedConfigParameterError,
StringParameterInfo,
)
from baseObject import AutoPropertyObject
import config
from copy import deepcopy
from logHandler import log
from typing import List, Tuple, Dict, Union


class Driver(AutoSettings):
@@ -59,17 +50,14 @@ def __init__(self):
@postcondition: This driver can be used.
"""
super(Driver, self).__init__()
self._registerConfigSaveAction()

def terminate(self, saveSettings: bool = True):
"""Terminate this driver.
def terminate(self):
"""Save settings and terminate this driver.
This should be used for any required clean up.
@param saveSettings: Whether settings should be saved on termination.
@precondition: L{initialize} has been called.
@postcondition: This driver can no longer be used.
"""
if saveSettings:
self.saveSettings()
self.saveSettings()
self._unregisterConfigSaveAction()

@classmethod
@@ -82,32 +70,7 @@ def check(cls):
"""
return False


@classmethod
def _paramToPercent(cls, current, min, max):
"""Convert a raw parameter value to a percentage given the current, minimum and maximum raw values.
@param current: The current value.
@type current: int
@param min: The minimum value.
@type current: int
@param max: The maximum value.
@type max: int
"""
return paramToPercent(current, min, max)

@classmethod
def _percentToParam(cls, percent, min, max):
"""Convert a percentage to a raw parameter value given the current percentage and the minimum and maximum raw parameter values.
@param percent: The current percentage.
@type percent: int
@param min: The minimum raw parameter value.
@type min: int
@param max: The maximum raw parameter value.
@type max: int
"""
return percentToParam(percent, min, max)

# Impl for abstract methods in AutoSettings class
# Impl for abstract methods in AutoSettings class
@classmethod
def getId(cls) -> str:
return cls.name

0 comments on commit e8f8a89

Please sign in to comment.
You can’t perform that action at this time.