Dark mode rework#2
Open
aniro wants to merge 6 commits into
Open
Conversation
Implements a clean dark mode that drives all theming from a single ApplicationSettings::darkMode boolean. Live toggle: no restart required. The Lua side defines a `theme` table that is rebuilt from a `dark_mode` global injected by C++. SetStyle() sets STYLE_DEFAULT from theme and calls StyleClearAll, then auto-translates canonical light-mode colors (black text, white background) to theme equivalents per-style. Language `.lua` files therefore work in either mode without modification: the vast majority specify black on white, which gets converted, while deliberate syntax colors (blue keywords, green comments, etc.) pass through unchanged. EditorManager::applyEditorTheme() handles all Scintilla UI surfaces (margins, caret line, fold markers, line numbers, brace match) for both modes. NotepadNextApplication::refreshEditorTheme() updates the Lua theme and re-applies styles to every open editor when the setting changes. For Qt widgets, MainWindow::applyStyleSheet() switches between Fusion-based light and dark QPalettes and loads either npp.css or the new npp-dark.css for ADS dock tabs and the QuickFindWidget. No third-party stylesheet dependency. LuaConsoleDock takes ApplicationSettings and reapplies its lexer styles on darkModeChanged so the console's Lua syntax highlighting tracks the theme. A "Dark mode" checkbox is added to the GUI section of Preferences.
Lua SetStyle() calls StyleClearAll on language load, which resets STYLE_LINENUMBER, STYLE_BRACELIGHT, STYLE_BRACEBAD, and STYLE_INDENTGUIDE to STYLE_DEFAULT values, wiping the colors set by applyEditorTheme. Split applyEditorTheme into two methods: the full theme (including STYLE_DEFAULT + StyleClearAll) and a separate applyEditorNamedStyles for the colors that need re-applying after each language load. NotepadNextApplication::setEditorLanguage calls applyEditorNamedStyles after the Lua SetLanguage call so line numbers and brace match retain their themed colors regardless of which language is active.
Qt 6.5+ has Fusion::standardPalette() honor QStyleHints::colorScheme(), so on systems where the user has selected dark mode at the OS level (GNOME, KDE, etc.) Fusion::standardPalette() returns dark colors. Setting that as the application palette in light mode left menu bar, toolbar, and dock tabs dark while only the editor and stylesheet-targeted widgets switched to light. Define an explicit light palette parallel to the existing dark one so the palette is fully driven by the user-selected DarkMode setting and ignores the system color scheme. Verified visually: menu bar, toolbar, and ADS tabs render light when DarkMode=false and dark when DarkMode=true, regardless of the GNOME theme.
Replace the DarkMode boolean with a Theme enum (System / Light / Dark, default System). System mode reads QGuiApplication::styleHints()->colorScheme() and listens for colorSchemeChanged so the app follows the desktop environment's light/dark preference, including live changes (e.g. GNOME night-mode auto-switching at sunset). Light and Dark remain explicit overrides for users who want their editor independent of the desktop theme. ApplicationSettings exposes a single effectiveDarkMode() helper plus an effectiveDarkModeChanged(bool) signal that fires on either theme change or system color-scheme change while in System mode. All consumers (EditorManager, NotepadNextApplication, MainWindow, LuaConsoleDock) call effectiveDarkMode() and connect to that signal, so the resolution-to-dark/light logic stays in one place. Preferences gets a "Theme" combo box with three options replacing the previous checkbox.
In System theme mode, applyStyleSheet now applies QApplication::style()->standardPalette() instead of our hardcoded Fusion palette. Qt 6.5+ Fusion already adapts standardPalette to QStyleHints::colorScheme(), so this lets the Qt widgets follow the desktop environment's palette rather than imposing our own interpretation of "dark" or "light". Light and Dark explicit modes still use the hardcoded palettes since the user has chosen to override the system, and Qt's standardPalette would leak through the system color scheme there. Scintilla editor surfaces still resolve through effectiveDarkMode() since they cannot read the Qt palette directly.
Stop forcing QApplication::setStyle(Fusion) globally and skip QApplication::setPalette() entirely when the user has selected System theme. Qt 6.5+ already syncs the palette with QStyleHints::colorScheme() and the platform integration picks the right style on its own; re-applying both on every applyStyleSheet call only re-emits paletteChange events and overrides legitimate platform choices. Light and Dark explicit modes still apply their hardcoded Fusion-derived palettes since the user has chosen to override the system there.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds dark mode to NotepadNext with a tristate theme setting (System / Light / Dark, default System). When set to System, the application follows the desktop environment's color scheme via
QStyleHints::colorScheme()and updates live when the system preference changes. Light and Dark are explicit overrides for users who want their editor's theme independent of the rest of the desktop.Design
A single
ApplicationSettings::themeenum drives everything.effectiveDarkMode()resolves System against the currentQStyleHints::colorScheme(). A singleeffectiveDarkModeChanged(bool)signal fires on either user-initiated theme changes or system color-scheme changes (when in System mode), and every consumer connects to that one signal.Theming layers:
Qt widgets.
MainWindow::applyStyleSheet()switches between Qt's adaptivestandardPalette()(System mode) and explicit Fusion palettes (Light / Dark mode). Targeted CSS instylesheets/npp.css(light) and the newstylesheets/npp-dark.css(dark) covers ADS dock tabs, status bar, andQuickFindWidget. No third-party stylesheet dependency.Scintilla editor surfaces.
EditorManager::applyEditorTheme()sets fold markers, element colors (caret line, selection inactive, whitespace, fold line), fold margin colors, andSTYLE_DEFAULT. A separateapplyEditorNamedStyles()setsSTYLE_LINENUMBER,STYLE_BRACELIGHT,STYLE_BRACEBAD,STYLE_INDENTGUIDE. The split is needed because Lua'sSetStylecallsStyleClearAllon every language load, which would otherwise wipe these named styles.Syntax highlighting.
init.luabuilds athemetable from adark_modeglobal injected by C++.SetStyle()writesSTYLE_DEFAULTfrom the theme, callsStyleClearAll, then auto-translates canonical light-mode colors per language style:style.fgColor == light_fg → theme.default_fgandstyle.bgColor == light_bg → theme.default_bg. The vast majority of language.luafiles specify black on white and get auto-converted; deliberate syntax colors (blue keywords, green comments, gray strings, orange numbers) pass through unchanged and remain readable on a dark background. No language definition files were edited.LuaConsoleDock. Now takesApplicationSettings*, applies theme-aware Lua lexer styles, and reapplies them oneffectiveDarkModeChanged.Preferences UI. New "Theme" combo box (Follow system / Light / Dark) replacing the original boolean checkbox idea.
Files
ApplicationSettings.{h,cpp}Themeenum setting +effectiveDarkMode()helper +effectiveDarkModeChangedsignal; subscribes toQStyleHints::colorSchemeChangedEditorManager.{h,cpp}applyEditorTheme()+applyEditorNamedStyles(); signal connectionNotepadNextApplication.{h,cpp}dark_modeLua injection;refreshEditorTheme()slot;applyEditorNamedStylesafter Lua language loadscripts/init.luaUpdateTheme(),themetable,SetStyle()rewrite with auto-translationdialogs/MainWindow.cppapplyStyleSheet()rewritten for tristate; signal connectiondialogs/PreferencesDialog.{ui,cpp}docks/LuaConsoleDock.{h,cpp}stylesheets/npp-dark.css(new)QuickFindWidgetresources.qrcnpp-dark.cssVerification
prefer-dark: app starts dark; switching GNOME to light makes the app re-theme live.#E4E4E4, menu/toolbar/tabs all light.#1E1E1E, line numbers#858585-on-#252526, full Qt widget palette dark.~/.config/NotepadNext/NotepadNext.iniunder[Gui]/Theme(0 = System, 1 = Light, 2 = Dark).Test Plan
gsettings set org.gnome.desktop.interface color-scheme prefer-dark/default); confirm the app re-themes live.