Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a graphical user interface for the vision framework #10082

Closed
wants to merge 117 commits into from
Closed
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
117 commits
Select commit Hold shift + click to select a range
3a83cf8
Add a graphical user interface for the vision framework
Dec 13, 2018
f76da24
Layout adjustments to vision framework
feerrenrut Aug 22, 2019
641ccdc
Update user guide
Aug 22, 2019
1816b28
Many gui and framework updates and improvements, including a load war…
Aug 23, 2019
5a8de04
Fix last (linting) issues
Sep 6, 2019
99ea075
Apply user guide suggestions from code review
LeonarddeR Sep 9, 2019
985dc51
Revert accidental change to liblouis submodule
Sep 9, 2019
a419254
Fix translator comments
Sep 9, 2019
3fdc434
Apply additional review action for the highlighter user guide descrip…
Sep 9, 2019
f76ee19
Tidy ctypes declarations for screen curtain
feerrenrut Sep 21, 2019
8a6fac2
List each vision provider in it's own group.
feerrenrut Sep 21, 2019
a39fca9
Use a custom GUI for highlighter
feerrenrut Oct 4, 2019
5a226b1
Highligher custom gui works
feerrenrut Oct 4, 2019
2b8701c
Highlighter works without custom gui
feerrenrut Oct 4, 2019
82ea428
dynamic addition of settings at runtime is possible with auto (not cu…
feerrenrut Oct 7, 2019
e40f864
move driver settings and utils
feerrenrut Oct 17, 2019
920ca6d
Move percent/param conversion helpers
feerrenrut Oct 17, 2019
5f7df99
Move settings related content to AutoSettings class
feerrenrut Oct 17, 2019
e78d376
Tidy up config save reg / unreg
feerrenrut Oct 17, 2019
bdc2c72
Adapt identifier, section, and productName to AutoSettings class
feerrenrut Oct 17, 2019
a57b6b2
Add type hinting and comments
feerrenrut Oct 19, 2019
8c1043d
Fix: don't hide 'id'
feerrenrut Oct 19, 2019
5526dd1
Fix non-existent id attribute on DriverSetting instance.
feerrenrut Oct 19, 2019
b4df54b
Update DriverSettingsMixin and derived
feerrenrut Oct 26, 2019
e2803ab
Code cleanup
feerrenrut Oct 28, 2019
42aede5
Fix error on exit
feerrenrut Oct 28, 2019
ed6f3f7
Better docs in autoSettings class
feerrenrut Oct 30, 2019
5749543
Rename VisionEnhancementProviderStaticSettings
feerrenrut Oct 30, 2019
9cc72ce
Remove saveSettings param from terminate method on visionEnhancementP…
feerrenrut Oct 30, 2019
4730e47
Clarify naming, consolidate classes
feerrenrut Oct 30, 2019
15a285c
Make screen curtain work
feerrenrut Oct 30, 2019
94ed26e
Use preInitSettings for NVDAHighlighter
feerrenrut Oct 30, 2019
42ee9d0
Clarify abstract methods
feerrenrut Oct 30, 2019
3338ef9
Prettify screen curtain and highlighter settings
feerrenrut Oct 30, 2019
3a32607
Fix up toggle screen curtain command
feerrenrut Oct 31, 2019
19ab265
Add Example auto gui provider
feerrenrut Nov 1, 2019
4bb5cbf
Add visionEnhancementProvider Docs
feerrenrut Nov 1, 2019
76e93ce
Fix highlighter checkboxes being overwritten
feerrenrut Nov 3, 2019
8a85637
Fix auto gui example
feerrenrut Nov 3, 2019
66a0ca6
Rename autoGui.py
feerrenrut Nov 3, 2019
6fe7ba6
Match name with filename
feerrenrut Nov 3, 2019
357b6fb
Demo different sources for GUI values
feerrenrut Nov 3, 2019
574887b
Add copyright header and module doc.
feerrenrut Nov 3, 2019
b2662db
Use dataclass for "provider info"
feerrenrut Nov 3, 2019
365f7ec
Use providerInfo rather than providerId: str to control providers
feerrenrut Nov 4, 2019
dcef2db
Use a class to control start/stop of providers
feerrenrut Nov 4, 2019
59f8276
Improve docs
feerrenrut Nov 4, 2019
edd78ce
Provider ID no longer has to match module name
feerrenrut Nov 4, 2019
46ef9c4
Fix linting errors
feerrenrut Nov 4, 2019
8d812df
Remove unused role concept
feerrenrut Nov 4, 2019
f5ef622
Fix instance/class used in getSettingsPanelClass docs
feerrenrut Nov 4, 2019
06b296d
Clarify return types of starting/stopping a provider
feerrenrut Nov 4, 2019
ae5d686
Give NVDA highlighter enable checkbox a better name and accelerator
feerrenrut Nov 4, 2019
e92319a
Merge remote-tracking branch 'origin/master' into visionGui, fixing m…
Nov 4, 2019
122784f
Fix bad merge
Nov 4, 2019
cd4b563
Fix lint error not caught by previous version of flake8tabs
Nov 4, 2019
8761bdd
fixup merge
feerrenrut Nov 4, 2019
3634252
Fix case error in name of internal function
feerrenrut Nov 4, 2019
4007756
Add copyright headers, and fix docs
feerrenrut Nov 4, 2019
6bbea60
Use single definition for SupportedSettingType
feerrenrut Nov 4, 2019
24e648e
Remove copied base __init__ implementation in Driver class
feerrenrut Nov 4, 2019
520b9e4
Comments for dialog announcement in toggle Screen curtain gesture
feerrenrut Nov 4, 2019
5ddfbc6
Fix lint error
feerrenrut Nov 4, 2019
b5e0ba4
Use type hinting rather than docstring
feerrenrut Nov 5, 2019
e682631
Rename DriverSettingsMixin to AutoSettingsMixin
feerrenrut Nov 5, 2019
0ed5b0d
Add requirements doc string for classes using the AutoSettingsMixin
feerrenrut Nov 5, 2019
34552c4
Remove debug logging from AutoSettingsMixin
feerrenrut Nov 5, 2019
ddd371e
Fix some issues in docs
feerrenrut Nov 5, 2019
ef1932b
Fix multiple provider error handling.
feerrenrut Nov 6, 2019
94b28c9
Ensure destruction of warning dialog for screencurtain
feerrenrut Nov 6, 2019
3b886f9
Improve readability of make settings method.
feerrenrut Nov 6, 2019
07a5637
Fix ScreenCurtain enable checkbox state after initialisation error
feerrenrut Nov 7, 2019
0697bad
Fix initial state of screenCurtain enabled checkbox
feerrenrut Nov 7, 2019
edb662f
Refactor updateDriverSettings in in AutoSettingsMixin
feerrenrut Nov 7, 2019
9a3dd87
Remove noqa comment for bare Except
feerrenrut Nov 7, 2019
a35cdc2
Change error message for a provider GUI that can not be created
feerrenrut Nov 7, 2019
a8d5165
Simplify _enableToggle logic
feerrenrut Nov 7, 2019
e3f3998
Simplify and reorder imports
feerrenrut Nov 7, 2019
5b6e86d
Remove package level getProviderList method
feerrenrut Nov 7, 2019
5c1c93a
Fix typo in comment
feerrenrut Nov 7, 2019
25ad61a
Clarify comment
feerrenrut Nov 7, 2019
5ca437d
Use US spelling for initialize
feerrenrut Nov 7, 2019
2ba8a2c
Clarify comments on getSettingsPanelClass(cls)
feerrenrut Nov 7, 2019
b1362e9
Fix spelling of NVDAHighlighter class
feerrenrut Nov 7, 2019
ecfb700
Fix unused imports
feerrenrut Nov 7, 2019
c5116af
Remove duplicated methods
feerrenrut Nov 7, 2019
ee52b65
Fix missing call to super from terminate
feerrenrut Nov 7, 2019
4a02c38
Change getSettings to abstract
feerrenrut Nov 8, 2019
64794f0
Catch any error on re-init
feerrenrut Nov 8, 2019
fe4bc91
Fix lint
feerrenrut Nov 8, 2019
20813a2
Fix translation test
feerrenrut Nov 8, 2019
d587e5a
Rename example provider
feerrenrut Nov 8, 2019
3f3f7c0
Add instructions to test the example provider
feerrenrut Nov 8, 2019
62820ca
Clean up param/percent conv functions
feerrenrut Nov 13, 2019
e52d2b6
Add missing translator comments
feerrenrut Nov 13, 2019
223d4dd
remove unused properties
feerrenrut Nov 13, 2019
6b4e7dd
Fix incorrect type hint
feerrenrut Nov 13, 2019
9c25e25
Fix doc-string
feerrenrut Nov 13, 2019
6436b1d
Use ABC from base class
feerrenrut Nov 13, 2019
f8da0c5
Refactor provider list generation
feerrenrut Nov 13, 2019
0753c54
Make getProviderClass private
feerrenrut Nov 13, 2019
226d436
Move getProviderList and getProviderInfo functions
feerrenrut Nov 13, 2019
71d30da
Fix no contextmanager
feerrenrut Nov 13, 2019
eb4498f
Fix documentation for runtime settings
feerrenrut Nov 13, 2019
5be590a
Fix error on termination handling for autoGui providers
feerrenrut Nov 13, 2019
2701d41
Fix parent windows binding to AutoSettingsMixin controls
feerrenrut Nov 13, 2019
b4962c5
AutoSettings.percentToParam should be private, with an underscore
Nov 14, 2019
16717ff
Make VisionHandler.providers private
feerrenrut Nov 14, 2019
7ebc511
Update user guide
Nov 14, 2019
ef9b4fa
Fix square brackets
Nov 14, 2019
a9f179a
User docs: visual aide> visual aid
Nov 14, 2019
01dfbab
Fix spelling: aides vs aids
feerrenrut Nov 14, 2019
0a09c26
Handle providers with no options with auto gui
feerrenrut Nov 14, 2019
77ac29a
Remove saveSettings param from Driver.terminate
feerrenrut Nov 18, 2019
c4b8492
Remove preInitSettings property
feerrenrut Nov 18, 2019
e31e3a2
Rename getTranalatedName -> getDisplayName
feerrenrut Nov 18, 2019
4daa3de
Fix consistency of imports.
feerrenrut Nov 18, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions source/autoSettingsUtils/autoSettings.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,26 +243,20 @@ def loadSettings(self, onlyChanged: bool = False):
self._loadSpecificSettings(self, self.supportedSettings, onlyChanged)

@classmethod
def _paramToPercent(cls, current, min, max):
def _paramToPercent(cls, current: int, min: int, max: int) -> int:
"""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):
def percentToParam(cls, 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.
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)
17 changes: 7 additions & 10 deletions source/autoSettingsUtils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"""


def paramToPercent(current, min, max):
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.
@param current: The current value.
@type current: int
Expand All @@ -17,10 +17,10 @@ def paramToPercent(current, min, max):
@param max: The maximum value.
@type max: int
"""
return int(round(float(current - min) / (max - min) * 100))
return round(float(current - min) / (max - min) * 100)


def percentToParam(percent, min, max):
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.
@param percent: The current percentage.
Expand All @@ -30,7 +30,7 @@ def percentToParam(percent, min, max):
@param max: The maximum raw parameter value.
@type max: int
"""
return int(round(float(percent) / 100 * (max - min) + min))
return round(float(percent) / 100 * (max - min) + min)


class UnsupportedConfigParameterError(NotImplementedError):
Expand All @@ -43,16 +43,13 @@ class StringParameterInfo(object):
"""
Used to represent a value of a DriverSetting instance.
"""
id: str
displayName: str

def __init__(self, id, displayName):
def __init__(self, id: str, displayName: str):
feerrenrut marked this conversation as resolved.
Show resolved Hide resolved
"""
@param id: The unique identifier of the value.
@type id: str
@param displayName: The name of the value, visible to the user.
@type displayName: str
"""
self.id = id
self.displayName = displayName
# Keep backwards compatibility
self.ID = id
self.name = displayName
4 changes: 2 additions & 2 deletions source/globalCommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -2358,7 +2358,7 @@ def script_toggleScreenCurtain(self, gesture):

from visionEnhancementProviders.screenCurtain import ScreenCurtainProvider
screenCurtainId = ScreenCurtainProvider.getSettings().getId()
screenCurtainProviderInfo = vision.visionHandler.getProviderInfo(screenCurtainId)
screenCurtainProviderInfo = vision.handler.getProviderInfo(screenCurtainId)
alreadyRunning = screenCurtainId in vision.handler.providers

GlobalCommands._tempEnableScreenCurtain = scriptCount == 0
Expand Down Expand Up @@ -2418,7 +2418,7 @@ def script_toggleScreenCurtain(self, gesture):
scriptCount in (0, 1) # 1 press (temp enable) or 2 presses (enable)
):
# Check if screen curtain is available, exit early if not.
if not vision.getProviderClass(screenCurtainId).canStart():
if not screenCurtainProviderInfo.providerClass.canStart():
# Translators: Reported when the screen curtain is not available.
message = _("Screen curtain not available")
self._toggleScreenCurtainMessage = message
Expand Down
64 changes: 38 additions & 26 deletions source/gui/settingsDialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ def _buildGui(self):
self.SetSizer(self.mainSizer)

@abstractmethod
def makeSettings(self, sizer) -> wx.BoxSizer:
def makeSettings(self, sizer: wx.BoxSizer):
"""Populate the panel with settings controls.
Subclasses must override this method.
@param sizer: The sizer to which to add the settings controls.
Expand Down Expand Up @@ -1018,6 +1018,7 @@ def driver(self):
return self._driverRef()

def __call__(self,evt):
evt.Skip() # allow other handlers to also process this event.
feerrenrut marked this conversation as resolved.
Show resolved Hide resolved
val=evt.GetSelection()
setattr(self.driver,self.setting.id,val)

Expand All @@ -1028,6 +1029,7 @@ def __init__(self,driver,setting,container):
super(StringDriverSettingChanger,self).__init__(driver,setting)

def __call__(self,evt):
evt.Skip() # allow other handlers to also process this event.
# Quick workaround to deal with voice changes.
if self.setting.id == "voice":
# Cancel speech first so that the voice will change immediately instead of the change being queued.
Expand Down Expand Up @@ -2845,10 +2847,17 @@ def onOk(self, evt):
port = self.possiblePorts[self.portsList.GetSelection()][0]
config.conf["braille"][display]["port"] = port
if not braille.handler.setDisplayByName(display):
# Translators: This message is presented when
# NVDA is unable to load the selected
# braille display.
gui.messageBox(_("Could not load the %s display.")%display, _("Braille Display Error"), wx.OK|wx.ICON_WARNING, self)

gui.messageBox(
# Translators: The message in a dialog presented when NVDA is unable to load the selected
# braille display.
message=_(f"Could not load the {display} display."),
# Translators: The title in a dialog presented when NVDA is unable to load the selected
# braille display.
caption=_("Braille Display Error"),
style=wx.OK | wx.ICON_WARNING,
parent=self
)
return

if self.IsModal():
Expand Down Expand Up @@ -3121,13 +3130,13 @@ def showTerminationErrorForProviders(
"Could not gracefully terminate the following vision enhancement providers:\n"
f"{providerNames }"
)
gui.messageBox(
message,
# Translators: The title of the vision enhancement provider error message box.
_("Vision Enhancement Provider Error"),
wx.OK | wx.ICON_WARNING,
parent,
)
gui.messageBox(
message,
# Translators: The title of the vision enhancement provider error message box.
_("Vision Enhancement Provider Error"),
wx.OK | wx.ICON_WARNING,
parent,
)


class VisionProviderStateControl(vision.providerBase.VisionProviderStateControl):
feerrenrut marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -3221,7 +3230,7 @@ class VisionSettingsPanel(SettingsPanel):

def _getProviderInfos(self) -> List[vision.providerInfo.ProviderInfo]:
return list(
vision.visionHandler.getProviderInfo(providerId) for providerId in vision.handler.providers
vision.handler.getProviderInfo(providerId) for providerId in vision.handler.providers
)

def _createProviderSettingsPanel(
Expand Down Expand Up @@ -3255,7 +3264,7 @@ def makeSettings(self, settingsSizer: wx.BoxSizer):
self.settingsSizerHelper = guiHelper.BoxSizerHelper(self, sizer=settingsSizer)
self.settingsSizerHelper.addItem(wx.StaticText(self, label=self.panelDescription))

for providerInfo in vision.visionHandler.getProviderList():
for providerInfo in vision.handler.getProviderList(reloadFromSystem=True):
providerSizer = self.settingsSizerHelper.addItem(
wx.StaticBoxSizer(wx.StaticBox(self, label=providerInfo.translatedName), wx.VERTICAL),
flag=wx.EXPAND
Expand Down Expand Up @@ -3296,8 +3305,7 @@ def safeTerminateProviders(
"""
errorProviders: List[vision.providerInfo.ProviderInfo] = []
for provider in providers:
with VisionProviderStateControl(self, provider) as control:
success = control.terminateProvider(shouldPromptOnError=False)
success = VisionProviderStateControl(self, provider).terminateProvider(shouldPromptOnError=False)
if not success:
errorProviders.append(provider)
if verbose:
Expand Down Expand Up @@ -3331,7 +3339,7 @@ def onDiscard(self):
providerInfo.providerId for providerInfo in self.initialProviders
]
providersToTerminate = [
vision.visionHandler.getProviderInfo(providerId) for providerId in vision.handler.providers
vision.handler.getProviderInfo(providerId) for providerId in vision.handler.providers
if providerId not in initialProviderIds
]
self.safeTerminateProviders(providersToTerminate)
Expand All @@ -3345,7 +3353,7 @@ def onSave(self):
except Exception:
log.debug(f"Error saving providerPanel: {panel.__class__!r}", exc_info=True)
self.initialProviders = list(
vision.visionHandler.getProviderInfo(providerId)
vision.handler.getProviderInfo(providerId)
for providerId in vision.handler.providers
)

Expand Down Expand Up @@ -3440,14 +3448,18 @@ def _nonEnableableGUI(self, evt):
self._checkBox.SetValue(False)

def _enableToggle(self, evt):
if evt.IsChecked():
self._providerControl.startProvider()
self._providerSettings.updateDriverSettings()
self._providerSettings.onPanelActivated()
else:
self._providerControl.terminateProvider()
self._providerSettings.updateDriverSettings()
self._providerSettings.onPanelActivated()
shouldBeRunning = evt.IsChecked()
if shouldBeRunning and not self._providerControl.startProvider():
self._checkBox.SetValue(False)
return
elif not shouldBeRunning and not self._providerControl.terminateProvider():
# When there is an error on termination, don't leave the checkbox checked.
# The provider should not be left configured to startup.
self._checkBox.SetValue(False)
return
# Able to successfully start / terminate:
self._providerSettings.updateDriverSettings()
self._providerSettings.onPanelActivated()
LeonarddeR marked this conversation as resolved.
Show resolved Hide resolved
self._sendLayoutUpdatedEvent()

def onDiscard(self):
Expand Down
2 changes: 1 addition & 1 deletion source/vision/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
Add-ons can provide their own provider
using modules in the visionEnhancementProviders package containing a L{VisionEnhancementProvider} class.
"""
from .visionHandler import VisionHandler, getProviderClass
from .visionHandler import VisionHandler
import visionEnhancementProviders
import config
from typing import Optional
Expand Down
22 changes: 16 additions & 6 deletions source/vision/providerBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,37 @@
"""Module within the vision framework that contains the base vision enhancement provider class.
"""

from abc import abstractmethod, ABC
from abc import abstractmethod

from autoSettingsUtils.autoSettings import AutoSettings
from baseObject import AutoPropertyObject
from .visionHandlerExtensionPoints import EventExtensionPoints
from typing import Optional, Any


class VisionEnhancementProviderSettings(AutoSettings, ABC):
class VisionEnhancementProviderSettings(AutoSettings):
"""
Base class for settings for a vision enhancement provider.
Ensure that the following are implemented:
- AutoSettings.getId:
This is case sensitive. Used in the config file. Does not have to match the module name.
- AutoSettings.getTranslatedName:
The string that should appear in the GUI as the name
The string that should appear in the GUI as the name.
- AutoSettings._get_supportedSettings:
The "runtime" settings for your provider
The "runtime" settings for your provider. By default this just returns L{_get_preInitSettings}.
The implementation must handle how to modify the returned settings based on external (software,
hardware) dependencies.
Although technically optional, derived classes probably need to implement:
- AutoSettings._get_preInitSettings:
The settings always configurable for your provider
The settings that are always configurable for your provider.
@note
If the vision enhancement provider has settings, it will provide an implementation of this class.
The provider will hold a reference to an instance of this class, this is accessed through the class method
L{VisionEnhancementProvider.getSettings}.
One way to handle settings that are strictly runtime:
- During initialization, the vision enhancement provider can instruct the settings instance what it should
expose using the L{utoSettings._get_supportedSettings} property.
- "_exampleProvider_autoGui.py" provides an example of this.
feerrenrut marked this conversation as resolved.
Show resolved Hide resolved
"""
def __init__(self):
super().__init__()
Expand Down Expand Up @@ -122,7 +132,7 @@ def reinitialize(self) -> None:

@abstractmethod
def terminate(self) -> None:
"""Terminate this driver.
"""Terminate this provider.
This should be used for any required clean up.
@precondition: L{initialize} has been called.
@postcondition: This provider can no longer be used.
Expand Down
Loading