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

Support Windows 10/11 Dark Mode #16908

Draft
wants to merge 35 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
9584208
first draft at dark mode support for settings dialog
TristanBurchett Jul 20, 2024
c1abae3
respect custom themes that have bg darker than fg, even if they aren'…
TristanBurchett Jul 20, 2024
af23692
generalize dark mode beyond the settings dialogs to several other dia…
TristanBurchett Jul 20, 2024
5fe2f7e
tidy up the diff
TristanBurchett Jul 20, 2024
74c8134
lint
TristanBurchett Jul 20, 2024
127dd93
Added darkmode to changes.md.
Jul 25, 2024
8ca57af
The python console, add-on store, braille viewer, and speech viewer a…
Jul 28, 2024
ae9599e
link to wxPython issue for RadioButton not supporting SetForegroundCo…
TristanBurchett Jul 28, 2024
e627f94
Merge branch 'darkmode' of https://github.com/TristanBurchett/nvda in…
TristanBurchett Jul 28, 2024
81db549
Added dark mode capabilities for create portable copy and NVDA instal…
Jul 28, 2024
754e6cd
Make dark mode configurable
TristanBurchett Jul 29, 2024
4bcc01b
Merge branch 'darkmode' of https://github.com/TristanBurchett/nvda in…
TristanBurchett Jul 29, 2024
ea49b57
use FilterEvent to apply color theme, rather than explicitly enabling…
TristanBurchett Aug 3, 2024
bf83e69
Merge branch 'master' into darkmode
TristanBurchett Aug 3, 2024
76fd24d
Pre-commit auto-fix
pre-commit-ci[bot] Aug 3, 2024
e16e79d
Change speechDict.py so it works in dark mode
TristanBurchett Aug 3, 2024
faaf99a
make the Apply button work again when changing color theme
TristanBurchett Aug 3, 2024
d71db37
Pre-commit auto-fix
pre-commit-ci[bot] Aug 3, 2024
28ea900
update user guide
TristanBurchett Aug 4, 2024
4d60121
Merge branch 'darkmode' of https://github.com/TristanBurchett/nvda in…
TristanBurchett Aug 4, 2024
35cfaa1
update changes.md to indicate that dark mode is now configurable
TristanBurchett Aug 4, 2024
e5e4654
Major refactor to use actual windows APIs
TristanBurchett Aug 18, 2024
7c7c844
tidy up code, include TODOs
TristanBurchett Aug 18, 2024
9c723ac
Pre-commit auto-fix
pre-commit-ci[bot] Aug 18, 2024
9bf17c0
Fix TextCtrl foreground colors
TristanBurchett Aug 25, 2024
65ed8b8
Add comment for translators
TristanBurchett Aug 25, 2024
b3fefa9
ListCtrl needs the same foregroundColor logic as TextCtrl
TristanBurchett Aug 25, 2024
900f9b5
Add (probably unnecessary) error handling, to make CodeRabbit happy
TristanBurchett Aug 25, 2024
3fb781a
Pre-commit auto-fix
pre-commit-ci[bot] Aug 25, 2024
d0efee7
more exception handling, to make CodeRabbit happy
TristanBurchett Aug 25, 2024
3563f2d
Merge branch 'nvaccess:master' into darkmode
TristanBurchett Sep 14, 2024
b083b5c
revert changes to speechDict.py
TristanBurchett Nov 13, 2024
245f058
missed a spot in previous reversion of speechDict.py
TristanBurchett Nov 13, 2024
d3ad7cd
revert changes to configProfiles.py
TristanBurchett Nov 13, 2024
b0f1355
Merge branch 'nvaccess:master' into darkmode
TristanBurchett Nov 15, 2024
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
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
TristanBurchett marked this conversation as resolved.
Show resolved Hide resolved
# changing the foreground color

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
20 changes: 20 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 Down Expand Up @@ -84,6 +85,25 @@ 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):
systemAppearance: wx.SystemAppearance = wx.SystemSettings.GetAppearance()
if systemAppearance.IsDark() or systemAppearance.IsUsingDarkBackground():
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
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
4 changes: 3 additions & 1 deletion source/gui/settingsDialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,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 +369,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 +393,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
1 change: 1 addition & 0 deletions source/gui/speechDict.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ 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

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 user_docs/en/changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,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