Skip to content

Commit 903daa0

Browse files
committed
qml: introduce ThemeManager
1 parent af0ddf6 commit 903daa0

File tree

6 files changed

+151
-5
lines changed

6 files changed

+151
-5
lines changed

src/Makefile.qt.include

+3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ QT_MOC_CPP = \
4343
qml/models/moc_options_model.cpp \
4444
qml/models/moc_peerlistsortproxy.cpp \
4545
qml/moc_appmode.cpp \
46+
qml/moc_thememanager.cpp \
4647
qt/moc_addressbookpage.cpp \
4748
qt/moc_addresstablemodel.cpp \
4849
qt/moc_askpassphrasedialog.cpp \
@@ -124,6 +125,7 @@ BITCOIN_QT_H = \
124125
qml/appmode.h \
125126
qml/bitcoin.h \
126127
qml/imageprovider.h \
128+
qml/thememanager.h \
127129
qml/util.h \
128130
qt/addressbookpage.h \
129131
qt/addresstablemodel.h \
@@ -309,6 +311,7 @@ BITCOIN_QML_BASE_CPP = \
309311
qml/models/options_model.cpp \
310312
qml/models/peerlistsortproxy.cpp \
311313
qml/imageprovider.cpp \
314+
qml/thememanager.cpp \
312315
qml/util.cpp
313316

314317
QML_RES_FONTS = \

src/qml/bitcoin.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <qml/models/options_model.h>
2222
#include <qml/models/peerlistsortproxy.h>
2323
#include <qml/imageprovider.h>
24+
#include <qml/thememanager.h>
2425
#include <qml/util.h>
2526
#include <qt/guiconstants.h>
2627
#include <qt/guiutil.h>
@@ -232,6 +233,7 @@ int QmlGuiMain(int argc, char* argv[])
232233
QObject::connect(&init_executor, &InitExecutor::shutdownResult, qGuiApp, &QGuiApplication::quit, Qt::QueuedConnection);
233234
// QObject::connect(&init_executor, &InitExecutor::runawayException, &node_model, &NodeModel::handleRunawayException);
234235

236+
ThemeManager theme_manager{};
235237
NetworkTrafficTower network_traffic_tower{node_model};
236238

237239
ChainModel chain_model{*chain};
@@ -264,6 +266,7 @@ int QmlGuiMain(int argc, char* argv[])
264266
engine.rootContext()->setContextProperty("chainModel", &chain_model);
265267
engine.rootContext()->setContextProperty("peerTableModel", &peer_model);
266268
engine.rootContext()->setContextProperty("peerListModelProxy", &peer_model_sort_proxy);
269+
engine.rootContext()->setContextProperty("themeManager", &theme_manager);
267270

268271
OptionsQmlModel options_model{*node};
269272
engine.rootContext()->setContextProperty("optionsModel", &options_model);

src/qml/components/ThemeSettings.qml

+36-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ ColumnLayout {
2121
header: qsTr("Light")
2222
actionItem: Button {
2323
anchors.centerIn: parent
24-
visible: !Theme.dark
24+
visible: !Theme.manualDark && Theme.manualTheme
2525
icon.source: "image://images/check"
2626
icon.color: Theme.color.neutral9
2727
icon.height: 24
@@ -33,7 +33,8 @@ ColumnLayout {
3333
}
3434
}
3535
onClicked: {
36-
Theme.dark = false
36+
Theme.manualTheme = true;
37+
Theme.manualDark = false;
3738
}
3839
}
3940
Separator { Layout.fillWidth: true }
@@ -42,7 +43,7 @@ ColumnLayout {
4243
header: qsTr("Dark")
4344
actionItem: Button {
4445
anchors.centerIn: parent
45-
visible: Theme.dark
46+
visible: Theme.manualDark && Theme.manualTheme
4647
icon.source: "image://images/check"
4748
icon.color: Theme.color.neutral9
4849
icon.height: 24
@@ -54,7 +55,38 @@ ColumnLayout {
5455
}
5556
}
5657
onClicked: {
57-
Theme.dark = true;
58+
Theme.manualTheme = true;
59+
Theme.manualDark = true;
60+
}
61+
}
62+
Separator { Layout.fillWidth: true }
63+
Setting {
64+
id: systemThemeSetting
65+
property bool systemThemeAvailable: Theme.systemThemeAvailable
66+
Layout.fillWidth: true
67+
header: qsTr("System")
68+
actionItem: Button {
69+
anchors.centerIn: parent
70+
visible: !Theme.manualTheme
71+
icon.source: "image://images/check"
72+
icon.color: Theme.color.neutral9
73+
icon.height: 24
74+
icon.width: 24
75+
background: null
76+
77+
Behavior on icon.color {
78+
ColorAnimation { duration: 150 }
79+
}
80+
}
81+
Component.onCompleted: {
82+
if (systemThemeAvailable) {
83+
systemThemeSetting.state = "FILLED"
84+
} else {
85+
systemThemeSetting.state = "DISABLED"
86+
}
87+
}
88+
onClicked: {
89+
Theme.manualTheme = false
5890
}
5991
}
6092
}

src/qml/controls/Theme.qml

+20-1
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,38 @@ import QtQuick 2.15
33
import QtQuick.Controls 2.15
44
import Qt.labs.settings 1.0
55

6+
import org.bitcoincore.qt 1.0
7+
68
Control {
79
id: root
8-
property bool dark: true
10+
property bool dark: manualTheme ? manualDark : themeManager.darkMode
11+
property bool systemThemeAvailable: themeManager.systemThemeAvailable
12+
property bool manualTheme: false
13+
property bool manualDark: true
914
property real blockclocksize: (5/12)
1015
readonly property ColorSet color: dark ? darkColorSet : lightColorSet
1116
readonly property ImageSet image: dark ? darkImageSet : lightImageSet
1217

1318
Settings {
1419
id: settings
1520
property alias dark: root.dark
21+
property alias manualTheme: root.manualTheme
22+
property alias manualDark: root.manualDark
1623
property alias blockclocksize: root.blockclocksize
1724
}
1825

26+
SystemPalette {
27+
id: systemColor
28+
29+
onBaseChanged: {
30+
themeManager.systemBaseColor = systemColor.base
31+
}
32+
}
33+
34+
Component.onCompleted: {
35+
themeManager.systemBaseColor = systemColor.base
36+
}
37+
1938
component ColorSet: QtObject {
2039
required property color white
2140
required property color background

src/qml/thememanager.cpp

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (c) 2023 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <qml/thememanager.h>
6+
7+
ThemeManager::ThemeManager(QObject* parent)
8+
: QObject(parent)
9+
{
10+
}
11+
12+
void ThemeManager::setSystemBaseColor(QColor base_color)
13+
{
14+
// Convert QColor's 8-bit RGB values to linear RGB values
15+
double linearR = base_color.redF();
16+
double linearG = base_color.greenF();
17+
double linearB = base_color.blueF();
18+
19+
// Constants for the luminance formula
20+
const double RED_FACTOR = 0.2126;
21+
const double GREEN_FACTOR = 0.7152;
22+
const double BLUE_FACTOR = 0.0722;
23+
24+
// Calculate luminance using the formula
25+
double luminance = RED_FACTOR * linearR + GREEN_FACTOR * linearG + BLUE_FACTOR * linearB;
26+
27+
if (luminance <= 0.5) {
28+
m_dark_mode = true;
29+
} else {
30+
m_dark_mode = false;
31+
}
32+
33+
m_system_base_color = base_color;
34+
35+
#ifdef Q_OS_MAC
36+
setSystemThemeAvailable(true);
37+
#endif
38+
39+
Q_EMIT darkModeChanged();
40+
}
41+
42+
void ThemeManager::setSystemThemeAvailable(bool available)
43+
{
44+
if (m_system_theme_available != available) {
45+
m_system_theme_available = available;
46+
Q_EMIT systemThemeAvailableChanged();
47+
}
48+
}

src/qml/thememanager.h

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) 2023 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#ifndef BITCOIN_QT_THEMEMANAGER_H
6+
#define BITCOIN_QT_THEMEMANAGER_H
7+
8+
#include <QObject>
9+
#include <QColor>
10+
#include <QProcess>
11+
12+
13+
class ThemeManager : public QObject
14+
{
15+
Q_OBJECT
16+
Q_PROPERTY(bool darkMode READ darkMode NOTIFY darkModeChanged)
17+
Q_PROPERTY(QColor systemBaseColor READ systemBaseColor WRITE setSystemBaseColor)
18+
Q_PROPERTY(bool systemThemeAvailable READ systemThemeAvailable WRITE setSystemThemeAvailable NOTIFY systemThemeAvailableChanged)
19+
20+
public:
21+
explicit ThemeManager(QObject* parent = nullptr);
22+
23+
bool darkMode() const { return m_dark_mode; };
24+
QColor systemBaseColor() const { return m_system_base_color; };
25+
bool systemThemeAvailable() const { return m_system_theme_available; };
26+
27+
public Q_SLOTS:
28+
void setSystemBaseColor(QColor base_color);
29+
void setSystemThemeAvailable(bool available);
30+
31+
Q_SIGNALS:
32+
void darkModeChanged();
33+
void systemThemeAvailableChanged();
34+
35+
private:
36+
bool m_dark_mode{ true };
37+
QColor m_system_base_color;
38+
bool m_system_theme_available{ false };
39+
};
40+
41+
#endif // BITCOIN_QT_THEMEMANAGER_H

0 commit comments

Comments
 (0)