[LyX/master] Introduce dark/light mode preference (#12224)
Juergen Spitzmueller
spitz at lyx.org
Sun Nov 10 09:43:24 UTC 2024
commit 7bf14813d7bec0d7e970b579552e9cf28d3c40a0
Author: Juergen Spitzmueller <spitz at lyx.org>
Date: Sun Nov 10 10:42:20 2024 +0100
Introduce dark/light mode preference (#12224)
This requires Qt 6.8 and only works on Win and Mac.
---
lib/RELEASE-NOTES | 4 +++
lib/configure.py | 2 +-
lib/scripts/prefs2prefs_prefs.py | 7 ++++-
src/LyXRC.cpp | 22 +++++++++++++-
src/LyXRC.h | 3 ++
src/frontends/qt/GuiApplication.cpp | 10 +++++++
src/frontends/qt/GuiPrefs.cpp | 35 +++++++++++++++++++++++
src/frontends/qt/GuiView.cpp | 10 ++++---
src/frontends/qt/ui/PrefUi.ui | 57 ++++++++++++++++++++++++-------------
9 files changed, 123 insertions(+), 27 deletions(-)
diff --git a/lib/RELEASE-NOTES b/lib/RELEASE-NOTES
index 03364a06fb..0ca44c7805 100644
--- a/lib/RELEASE-NOTES
+++ b/lib/RELEASE-NOTES
@@ -7,6 +7,10 @@
!!!The following pref variables were added in 2.5:
+- \color_scheme {system,light,dark} allows to override the system-wide
+ color scheme (i.e., dark or light mode). This requires LyX to be built
+ against Qt >= 6.8.0.
+
!!!The following pref variables were changed in 2.5:
!!!The following pref variables are obsoleted in 2.5:
diff --git a/lib/configure.py b/lib/configure.py
index 7c944e72b3..50497eca55 100644
--- a/lib/configure.py
+++ b/lib/configure.py
@@ -1982,7 +1982,7 @@ if __name__ == '__main__':
lyx_check_config = True
lyx_kpsewhich = True
outfile = 'lyxrc.defaults'
- lyxrc_fileformat = 38
+ lyxrc_fileformat = 39
rc_entries = ''
lyx_keep_temps = False
version_suffix = ''
diff --git a/lib/scripts/prefs2prefs_prefs.py b/lib/scripts/prefs2prefs_prefs.py
index fe7e0a1ff4..5544c6aed2 100644
--- a/lib/scripts/prefs2prefs_prefs.py
+++ b/lib/scripts/prefs2prefs_prefs.py
@@ -170,6 +170,10 @@
# Add option to configure ui style
# No conversion necessary.
+# Incremented to format 39, by spitz
+# Add \color_scheme {system|light|dark}
+# No conversion necessary.
+
# NOTE: The format should also be updated in LYXRC.cpp and
# in configure.py (search for lyxrc_fileformat).
@@ -558,5 +562,6 @@ conversions = [
[ 35, [add_dark_color]],
[ 36, [add_spellcheck_default]],
[ 37, [remove_fullscreen_widthlimit]],
- [ 38, []]
+ [ 38, []],
+ [ 39, []]
]
diff --git a/src/LyXRC.cpp b/src/LyXRC.cpp
index 60c7f23814..e130fbf584 100644
--- a/src/LyXRC.cpp
+++ b/src/LyXRC.cpp
@@ -60,7 +60,7 @@ namespace {
// The format should also be updated in configure.py, and conversion code
// should be added to prefs2prefs_prefs.py.
-static unsigned int const LYXRC_FILEFORMAT = 38; // chillenb: screen_width and screen_limit
+static unsigned int const LYXRC_FILEFORMAT = 39; // spitz: \color_scheme {system|light|dark}
// when adding something to this array keep it sorted!
LexerKeyword lyxrcTags[] = {
{ "\\accept_compound", LyXRC::RC_ACCEPT_COMPOUND },
@@ -81,6 +81,7 @@ LexerKeyword lyxrcTags[] = {
{ "\\citation_search_pattern", LyXRC::RC_CITATION_SEARCH_PATTERN },
{ "\\citation_search_view", LyXRC::RC_CITATION_SEARCH_VIEW },
{ "\\close_buffer_with_last_view", LyXRC::RC_CLOSE_BUFFER_WITH_LAST_VIEW },
+ { "\\color_scheme", LyXRC::RC_COLOR_SCHEME },
{ "\\completion_cursor_text", LyXRC::RC_COMPLETION_CURSOR_TEXT },
{ "\\completion_inline_delay", LyXRC::RC_COMPLETION_INLINE_DELAY },
{ "\\completion_inline_dots", LyXRC::RC_COMPLETION_INLINE_DOTS },
@@ -707,6 +708,11 @@ LyXRC::ReturnValues LyXRC::read(Lexer & lexrc, bool check_format)
citation_search_view = lexrc.getString();
break;
+ case RC_COLOR_SCHEME:
+ if (lexrc.next())
+ color_scheme = lexrc.getString();
+ break;
+
case RC_CT_ADDITIONS_UNDERLINED:
lexrc >> ct_additions_underlined;
break;
@@ -1704,6 +1710,15 @@ void LyXRC::write(ostream & os, bool ignore_system_lyxrc, string const & name) c
if (tag != RC_LAST)
break;
// fall through
+ case RC_COLOR_SCHEME:
+ if (ignore_system_lyxrc ||
+ color_scheme != system_lyxrc.color_scheme) {
+ os << "# Set color scheme (system|light|dark)\n";
+ os << "\\color_scheme " << color_scheme << '\n';
+ }
+ if (tag != RC_LAST)
+ break;
+ // fall through
case RC_CT_ADDITIONS_UNDERLINED:
if (ignore_system_lyxrc ||
ct_additions_underlined
@@ -2926,6 +2941,7 @@ void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
case LyXRC::RC_CITATION_SEARCH_PATTERN:
case LyXRC::RC_CITATION_SEARCH_VIEW:
case LyXRC::RC_CHECKLASTFILES:
+ case LyXRC::RC_COLOR_SCHEME:
case LyXRC::RC_COMPLETION_CURSOR_TEXT:
case LyXRC::RC_COMPLETION_INLINE_DELAY:
case LyXRC::RC_COMPLETION_INLINE_DOTS:
@@ -3210,6 +3226,10 @@ string const LyXRC::getDescription(LyXRCTags tag)
str = _("Show a small box around a Math Macro with the macro name when the cursor is inside.");
break;
+ case LyXRC::RC_COLOR_SCHEME:
+ str = _("Possibility to enforce a particular color scheme (system|dark|light)");
+ break;
+
case RC_DEFFILE:
str = _("Command definition file. Can either specify an absolute path, or LyX will look in its global and local commands/ directories.");
break;
diff --git a/src/LyXRC.h b/src/LyXRC.h
index 8c34712d90..ed86e97da9 100644
--- a/src/LyXRC.h
+++ b/src/LyXRC.h
@@ -58,6 +58,7 @@ public:
RC_CITATION_SEARCH,
RC_CITATION_SEARCH_PATTERN,
RC_CITATION_SEARCH_VIEW,
+ RC_COLOR_SCHEME,
RC_COMPLETION_CURSOR_TEXT,
RC_COMPLETION_INLINE_DELAY,
RC_COMPLETION_INLINE_MATH,
@@ -550,6 +551,8 @@ public:
std::string forward_search_dvi;
///
std::string forward_search_pdf;
+ /// specifiy color scheme (system|dark|light)
+ std::string color_scheme;
///
int export_overwrite = NO_FILES;
/// Default decimal point when aligning table columns on decimal
diff --git a/src/frontends/qt/GuiApplication.cpp b/src/frontends/qt/GuiApplication.cpp
index 65ed25013e..019088ea71 100644
--- a/src/frontends/qt/GuiApplication.cpp
+++ b/src/frontends/qt/GuiApplication.cpp
@@ -116,6 +116,9 @@
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include <QStyle>
+#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
+#include <QStyleHints>
+#endif
#include <QSvgRenderer>
#include <QTimer>
#include <QTranslator>
@@ -1256,6 +1259,13 @@ void Application::applyPrefs()
{
if (lyxrc.ui_style != "default")
lyx::frontend::GuiApplication::setStyle(toqstr(lyxrc.ui_style));
+#if (defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN) || defined(Q_OS_MAC)) && QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
+ // Set color scheme from prefs
+ if (lyxrc.color_scheme == "dark")
+ guiApp->styleHints()->setColorScheme(Qt::ColorScheme::Dark);
+ else if (lyxrc.color_scheme == "light")
+ guiApp->styleHints()->setColorScheme(Qt::ColorScheme::Light);
+#endif
}
FuncStatus GuiApplication::getStatus(FuncRequest const & cmd) const
diff --git a/src/frontends/qt/GuiPrefs.cpp b/src/frontends/qt/GuiPrefs.cpp
index 8a25e20451..f94eeeea90 100644
--- a/src/frontends/qt/GuiPrefs.cpp
+++ b/src/frontends/qt/GuiPrefs.cpp
@@ -64,6 +64,9 @@
#include <QSpinBox>
#include <QString>
#include <QStyleFactory>
+#if (defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN) || defined(Q_OS_MAC)) && QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
+#include <QStyleHints>
+#endif
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QValidator>
@@ -2523,6 +2526,10 @@ PrefUserInterface::PrefUserInterface(GuiPreferences * form)
this, SIGNAL(changed()));
connect(uiStyleCO, SIGNAL(activated(int)),
this, SIGNAL(changed()));
+#if (defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN) || defined(Q_OS_MAC)) && QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
+ connect(colorSchemeCO, SIGNAL(activated(int)),
+ this, SIGNAL(changed()));
+#endif
connect(useSystemThemeIconsCB, SIGNAL(clicked()),
this, SIGNAL(changed()));
connect(lastfilesSB, SIGNAL(valueChanged(int)),
@@ -2545,6 +2552,15 @@ PrefUserInterface::PrefUserInterface(GuiPreferences * form)
iconSetCO->addItem(qt_("Classic"), "classic");
iconSetCO->addItem(qt_("Oxygen"), "oxygen");
+#if (defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN) || defined(Q_OS_MAC)) && QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
+ colorSchemeCO->addItem(qt_("System Default"), "system");
+ colorSchemeCO->addItem(qt_("Light Mode"), "light");
+ colorSchemeCO->addItem(qt_("Dark Mode"), "dark");
+#else
+ colorSchemeCO->setVisible(false);
+ colorSchemeLA->setVisible(false);
+#endif
+
uiStyleCO->addItem(qt_("Default"), toqstr("default"));
for (auto const & style : QStyleFactory::keys())
uiStyleCO->addItem(style, style.toLower());
@@ -2575,6 +2591,19 @@ void PrefUserInterface::applyRC(LyXRC & rc) const
else
frontend::GuiApplication::setStyle(uistyle);
}
+#if (defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN) || defined(Q_OS_MAC)) && QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
+ QString const color_scheme = colorSchemeCO->itemData(
+ colorSchemeCO->currentIndex()).toString();
+ if (rc.color_scheme != fromqstr(color_scheme)) {
+ if (lyxrc.color_scheme == "dark")
+ guiApp->styleHints()->setColorScheme(Qt::ColorScheme::Dark);
+ else if (lyxrc.color_scheme == "light")
+ guiApp->styleHints()->setColorScheme(Qt::ColorScheme::Light);
+ else
+ guiApp->styleHints()->unsetColorScheme();
+ }
+ rc.color_scheme = fromqstr(color_scheme);
+#endif
rc.ui_file = internal_path(fromqstr(uiFileED->text()));
rc.use_system_theme_icons = useSystemThemeIconsCB->isChecked();
@@ -2607,6 +2636,12 @@ void PrefUserInterface::updateRC(LyXRC const & rc)
toggleToolbarsCB->setChecked(rc.full_screen_toolbars);
toggleTabbarCB->setChecked(rc.full_screen_tabbar);
toggleMenubarCB->setChecked(rc.full_screen_menubar);
+#if (defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN) || defined(Q_OS_MAC)) && QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
+ int colorscheme = colorSchemeCO->findData(toqstr(rc.color_scheme));
+ if (colorscheme < 0)
+ colorscheme = 0;
+ colorSchemeCO->setCurrentIndex(colorscheme);
+#endif
}
diff --git a/src/frontends/qt/GuiView.cpp b/src/frontends/qt/GuiView.cpp
index 4163affb52..29a450a8b4 100644
--- a/src/frontends/qt/GuiView.cpp
+++ b/src/frontends/qt/GuiView.cpp
@@ -1792,10 +1792,12 @@ bool GuiView::event(QEvent * e)
// dark/light mode runtime switch support
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
case QEvent::ThemeChange: {
- guiApp->setPalette(guiApp->style()->standardPalette());
- // We need to update metrics here to avoid a crash (#12786)
- theBufferList().changed(true);
- refillToolbars();
+ if (lyxrc.color_scheme != "dark" && lyxrc.color_scheme != "light") {
+ guiApp->setPalette(guiApp->style()->standardPalette());
+ // We need to update metrics here to avoid a crash (#12786)
+ theBufferList().changed(true);
+ refillToolbars();
+ }
return QMainWindow::event(e);
}
#else
diff --git a/src/frontends/qt/ui/PrefUi.ui b/src/frontends/qt/ui/PrefUi.ui
index 877d5de4ca..59e40edba8 100644
--- a/src/frontends/qt/ui/PrefUi.ui
+++ b/src/frontends/qt/ui/PrefUi.ui
@@ -42,23 +42,22 @@
</item>
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0">
- <item row="1" column="2">
- <layout class="QHBoxLayout" name="horizontalLayout"/>
- </item>
- <item row="0" column="2">
- <widget class="QPushButton" name="uiFilePB">
- <property name="text">
- <string>Bro&wse...</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QComboBox" name="iconSetCO">
+ <item row="2" column="1">
+ <widget class="QComboBox" name="uiStyleCO">
<property name="toolTip">
- <string>The icon set to use. Warning: normal size of icons may be wrong until you save the preferences and restart LyX.</string>
+ <string>You can set a custom style here. Note that only certain styles may support dark mode, e.g. fusion on Windows.</string>
</property>
</widget>
</item>
+ <item row="2" column="2">
+ <layout class="QHBoxLayout" name="horizontalLayout_2"/>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="uiFileED"/>
+ </item>
+ <item row="1" column="2">
+ <layout class="QHBoxLayout" name="horizontalLayout"/>
+ </item>
<item row="1" column="0">
<widget class="QLabel" name="iconSetLA">
<property name="text">
@@ -79,8 +78,12 @@
</property>
</widget>
</item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="uiFileED"/>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="iconSetCO">
+ <property name="toolTip">
+ <string>The icon set to use. Warning: normal size of icons may be wrong until you save the preferences and restart LyX.</string>
+ </property>
+ </widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="uiStyleLA">
@@ -92,15 +95,29 @@
</property>
</widget>
</item>
- <item row="2" column="1">
- <widget class="QComboBox" name="uiStyleCO">
+ <item row="0" column="2">
+ <widget class="QPushButton" name="uiFilePB">
+ <property name="text">
+ <string>Bro&wse...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QComboBox" name="colorSchemeCO">
<property name="toolTip">
- <string>You can set a custom style here. Note that only certain styles may support dark mode, e.g. fusion on Windows.</string>
+ <string>You can override the system's color scheme here if the selected style supports multiple schemes.</string>
</property>
</widget>
</item>
- <item row="2" column="2">
- <layout class="QHBoxLayout" name="horizontalLayout_2"/>
+ <item row="3" column="0">
+ <widget class="QLabel" name="colorSchemeLA">
+ <property name="text">
+ <string>C&olor scheme:</string>
+ </property>
+ <property name="buddy">
+ <cstring>colorSchemeCO</cstring>
+ </property>
+ </widget>
</item>
</layout>
</item>
More information about the lyx-cvs
mailing list