Skip to content

Commit

Permalink
Merge 4bcc01b into 286de6e
Browse files Browse the repository at this point in the history
  • Loading branch information
TristanBurchett authored Jul 29, 2024
2 parents 286de6e + 4bcc01b commit 9a40244
Show file tree
Hide file tree
Showing 14 changed files with 90 additions and 1 deletion.
1 change: 1 addition & 0 deletions source/brailleViewer/brailleViewerGui.py
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ def _updateGui(self):
"""Ensure all GUI updates happen in one place to create a smooth update, all changes should happen
between freeze and thaw.
"""
gui.guiHelper.enableDarkMode(self)
self.Freeze()
if self._newBraille is not None:
self._brailleOutput.SetValue(self._newBraille)
Expand Down
21 changes: 21 additions & 0 deletions source/config/configFlags.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,24 @@ def _displayStringLabels(self):
# Translators: A label for an option to choose a method of reporting information, e.g. font attributes.
self.SPEECH_AND_BRAILLE: _("Speech and braille"),
}


@unique
class ColorTheme(DisplayStringStrEnum):
"""Enumeration for what foreground and background colors to use.
"""

AUTO = "auto"
DARK = "dark"
LIGHT = "light"

@property
def _displayStringLabels(self):
return {
# Translators: One of the color theme choices in the visual settings category panel (this choice uses the system's Dark Mode setting).
self.AUTO: _("Auto"),
# Translators: One of the color theme choices in the visual settings category panel (this choice uses light background with dark text).
self.LIGHT: _("Light"),
# Translators: One of the color theme choices in the visual settings category panel (this choice uses dark background with light text).
self.DARK: _("Dark"),
}
1 change: 1 addition & 0 deletions source/config/configSpec.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
# Vision enhancement provider settings
[vision]
colorTheme = option("auto", "light", "dark", default="auto")
# Vision enhancement provider settings
[[__many__]]
Expand Down
4 changes: 4 additions & 0 deletions source/gui/configProfiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ def __init__(self, parent):
self.Sizer = mainSizer
self.profileList.SetFocus()
self.CentreOnScreen()
guiHelper.enableDarkMode(self)

def __del__(self):
ProfilesDialog._instance = None
Expand Down Expand Up @@ -407,6 +408,7 @@ def __init__(self, parent):
mainSizer.Fit(self)
self.Sizer = mainSizer
self.CentreOnScreen()
guiHelper.enableDarkMode(self)

def onTriggerListChoice(self, evt):
trig = self.triggers[self.triggerList.Selection]
Expand Down Expand Up @@ -482,6 +484,8 @@ def __init__(self, parent):
self.Sizer = mainSizer
self.profileName.SetFocus()
self.CentreOnScreen()
# Note: we don't call guiHelper.enableDarkMode() here because wx.RadioBox doesn't support
# changing the foreground color (https://github.com/wxWidgets/Phoenix/issues/1512)

def onOk(self, evt):
confTrigs = config.conf.triggersToProfiles
Expand Down
1 change: 1 addition & 0 deletions source/gui/exit.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ def __init__(self, parent):
self.Sizer = mainSizer
self.actionsList.SetFocus()
self.CentreOnScreen()
guiHelper.enableDarkMode(self)

def onOk(self, evt):
action = [a for a in _ExitAction if a.displayString == self.actionsList.GetStringSelection()][0]
Expand Down
28 changes: 28 additions & 0 deletions source/gui/guiHelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def __init__(self, parent):
from contextlib import contextmanager
import weakref
from typing import (
Generator,
Generic,
Optional,
Type,
Expand All @@ -57,6 +58,8 @@ def __init__(self, parent):
import wx
from wx.lib import scrolledpanel, newevent
from abc import ABCMeta
import config
from config.configFlags import ColorTheme

#: border space to be used around all controls in dialogs
BORDER_FOR_DIALOGS = 10
Expand Down Expand Up @@ -84,6 +87,31 @@ def autoThaw(control: wx.Window):
control.Thaw()


def _getDescendants(widget: wx.Window) -> Generator[wx.Window, None, None]:
yield widget
if hasattr(widget, "GetChildren"):
for child in widget.GetChildren():
for descendant in _getDescendants(child):
yield descendant


def enableDarkMode(widget: wx.Window):
curTheme = config.conf["vision"]["colorTheme"]
if curTheme == ColorTheme.AUTO:
systemAppearance: wx.SystemAppearance = wx.SystemSettings.GetAppearance()
isDark = systemAppearance.IsDark() or systemAppearance.IsUsingDarkBackground()
else:
isDark = curTheme == ColorTheme.DARK

if isDark:
fgColor, bgColor = "White", "Dark Grey"
else:
fgColor, bgColor = "Black", "White"
for child in _getDescendants(widget):
child.SetBackgroundColour(bgColor)
child.SetForegroundColour(fgColor)


class ButtonHelper(object):
"""Class used to ensure that the appropriate space is added between each button, whether in horizontal or vertical
arrangement. This class should be used for groups of buttons. While it won't cause problems to use this class with a
Expand Down
2 changes: 2 additions & 0 deletions source/gui/installerGui.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ def __init__(self, parent, isUpdate):
self.Sizer = mainSizer
mainSizer.Fit(self)
self.CentreOnScreen()
gui.guiHelper.enableDarkMode(self)

def onInstall(self, evt):
self.Hide()
Expand Down Expand Up @@ -487,6 +488,7 @@ def __init__(self, parent):
self.Sizer = mainSizer
mainSizer.Fit(self)
self.CentreOnScreen()
gui.guiHelper.enableDarkMode(self)

def onCreatePortable(self, evt):
if not self.portableDirectoryEdit.Value:
Expand Down
1 change: 1 addition & 0 deletions source/gui/logViewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def __init__(self, parent):

self.refresh()
self.outputCtrl.SetFocus()
gui.guiHelper.enableDarkMode(self)

def refresh(self, evt=None):
# Ignore if log is not initialized
Expand Down
24 changes: 23 additions & 1 deletion source/gui/settingsDialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import config
from config.configFlags import (
AddonsAutomaticUpdate,
ColorTheme,
NVDAKey,
ShowMessages,
TetherTo,
Expand Down Expand Up @@ -252,6 +253,7 @@ def __init__(
if resizeable:
self.SetMinSize(self.mainSizer.GetMinSize())
self.CentreOnScreen()
guiHelper.enableDarkMode(self)
if gui._isDebug():
log.debug("Loading %s took %.2f seconds" % (self.__class__.__name__, time.time() - startTime))

Expand Down Expand Up @@ -368,6 +370,7 @@ def __init__(self, parent: wx.Window):
super().__init__(parent)

self._buildGui()
guiHelper.enableDarkMode(self)

if gui._isDebug():
elapsedSeconds = time.time() - startTime
Expand All @@ -391,7 +394,7 @@ def makeSettings(self, sizer: wx.BoxSizer):
raise NotImplementedError

def onPanelActivated(self):
"""Called after the panel has been activated (i.e. de corresponding category is selected in the list of categories).
"""Called after the panel has been activated (i.e. the corresponding category is selected in the list of categories).
For example, this might be used for resource intensive tasks.
Sub-classes should extend this method.
"""
Expand Down Expand Up @@ -4685,6 +4688,21 @@ def makeSettings(self, settingsSizer: wx.BoxSizer):
providerSizer.Add(settingsPanel, flag=wx.EXPAND)
self.providerPanelInstances.append(settingsPanel)

# Translators: label for a choice in the vision settings category panel
colorThemeLabelText = _("&Color theme")
self.colorThemeList = self.settingsSizerHelper.addLabeledControl(
colorThemeLabelText,
wx.Choice,
choices=[theme.displayString for theme in ColorTheme],
)
self.bindHelpEvent("VisionSettingsColorTheme", self.colorThemeList)
curTheme = config.conf["vision"]["colorTheme"]
for i, theme in enumerate(ColorTheme):
if theme == curTheme:
self.colorThemeList.SetSelection(i)
else:
log.debugWarning("Could not set color theme list to current theme")

def safeInitProviders(
self,
providers: List[vision.providerInfo.ProviderInfo],
Expand Down Expand Up @@ -4758,6 +4776,10 @@ def onSave(self):
except Exception:
log.debug(f"Error saving providerPanel: {panel.__class__!r}", exc_info=True)
self.initialProviders = vision.handler.getActiveProviderInfos()
colorTheme = list(ColorTheme)[self.colorThemeList.GetSelection()]
config.conf["vision"]["colorTheme"] = colorTheme.value
guiHelper.enableDarkMode(self.TopLevelParent)
self.TopLevelParent.Refresh()


class VisionProviderSubPanel_Settings(
Expand Down
2 changes: 2 additions & 0 deletions source/gui/speechDict.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ def __init__(self, parent, title=_("Edit Dictionary Entry")):
self.setType(speechDictHandler.ENTRY_TYPE_ANYWHERE)
self.patternTextCtrl.SetFocus()
self.Bind(wx.EVT_BUTTON, self.onOk, id=wx.ID_OK)
# Note: don't call guiHelper.enableDarkMode() here because wx.RadioBox doesn't support
# changing the foreground color (https://github.com/wxWidgets/Phoenix/issues/1512)

def getType(self):
typeRadioValue = self.typeRadioBox.GetSelection()
Expand Down
3 changes: 3 additions & 0 deletions source/gui/startupDialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def __init__(self, parent):
self.SetSizer(mainSizer)
self.kbdList.SetFocus()
self.CentreOnScreen()
gui.guiHelper.enableDarkMode(self)

def onOk(self, evt):
layout = self.kbdNames[self.kbdList.GetSelection()]
Expand Down Expand Up @@ -220,6 +221,7 @@ def __init__(self, parent):
self.Sizer = mainSizer
mainSizer.Fit(self)
self.CentreOnScreen()
gui.guiHelper.enableDarkMode(self)

def _createLicenseAgreementGroup(self) -> wx.StaticBoxSizer:
# Translators: The label of the license text which will be shown when NVDA installation program starts.
Expand Down Expand Up @@ -326,6 +328,7 @@ def __init__(self, parent):
self.Sizer = mainSizer
mainSizer.Fit(self)
self.CentreOnScreen()
gui.guiHelper.enableDarkMode(self)

def onYesButton(self, evt):
log.debug("Usage stats gathering has been allowed")
Expand Down
1 change: 1 addition & 0 deletions source/pythonConsole.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ def __init__(self, parent):
mainSizer.Add(inputSizer, proportion=1, flag=wx.EXPAND)
self.SetSizer(mainSizer)
mainSizer.Fit(self)
gui.guiHelper.enableDarkMode(self)

self.console = PythonConsole(
outputFunc=self.output,
Expand Down
1 change: 1 addition & 0 deletions source/speechViewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def __init__(self, onDestroyCallBack: Callable[[], None]):

# Don't let speech viewer to steal keyboard focus when opened
self.ShowWithoutActivating()
gui.guiHelper.enableDarkMode(self)

def onSessionLockStateChange(self, isNowLocked: bool):
"""
Expand Down
1 change: 1 addition & 0 deletions user_docs/en/changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ Unicode CLDR has also been updated.
* NVDA checks daily for add-on updates.
* Only updates within the same channel will be checked (e.g. installed beta add-ons will only notify for updates in the beta channel).
* Added support for the Help Tech Activator Pro displays. (#16668)
* Added support for dark mode. (#16683)

### Changes

Expand Down

0 comments on commit 9a40244

Please sign in to comment.