]> sigrok.org Git - pulseview.git/blob - pv/globalsettings.cpp
GlobalSettings: Always use Fusion style on Windows for dark themes
[pulseview.git] / pv / globalsettings.cpp
1 /*
2  * This file is part of the PulseView project.
3  *
4  * Copyright (C) 2017 Soeren Apel <soeren@apelpie.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "globalsettings.hpp"
21
22 #include <QApplication>
23 #include <QColor>
24 #include <QDebug>
25 #include <QFile>
26 #include <QFontMetrics>
27 #include <QPixmapCache>
28 #include <QString>
29 #include <QStyleFactory>
30 #include <QtGlobal>
31
32 using std::map;
33 using std::pair;
34 using std::string;
35 using std::vector;
36
37 namespace pv {
38
39 const vector< pair<QString, QString> > Themes {
40         {"None" , ""},
41         {"QDarkStyleSheet", ":/themes/qdarkstyle/style.qss"},
42         {"DarkStyle", ":/themes/darkstyle/darkstyle.qss"}
43 };
44
45 const QString GlobalSettings::Key_General_Theme = "General_Theme";
46 const QString GlobalSettings::Key_View_ZoomToFitDuringAcq = "View_ZoomToFitDuringAcq";
47 const QString GlobalSettings::Key_View_ZoomToFitAfterAcq = "View_ZoomToFitAfterAcq";
48 const QString GlobalSettings::Key_View_TriggerIsZeroTime = "View_TriggerIsZeroTime";
49 const QString GlobalSettings::Key_View_ColoredBG = "View_ColoredBG";
50 const QString GlobalSettings::Key_View_StickyScrolling = "View_StickyScrolling";
51 const QString GlobalSettings::Key_View_ShowSamplingPoints = "View_ShowSamplingPoints";
52 const QString GlobalSettings::Key_View_FillSignalHighAreas = "View_FillSignalHighAreas";
53 const QString GlobalSettings::Key_View_FillSignalHighAreaColor = "View_FillSignalHighAreaColor";
54 const QString GlobalSettings::Key_View_ShowAnalogMinorGrid = "View_ShowAnalogMinorGrid";
55 const QString GlobalSettings::Key_View_ConversionThresholdDispMode = "View_ConversionThresholdDispMode";
56 const QString GlobalSettings::Key_View_DefaultDivHeight = "View_DefaultDivHeight";
57 const QString GlobalSettings::Key_View_DefaultLogicHeight = "View_DefaultLogicHeight";
58 const QString GlobalSettings::Key_View_ShowHoverMarker = "View_ShowHoverMarker";
59 const QString GlobalSettings::Key_View_SnapDistance = "View_SnapDistance";
60 const QString GlobalSettings::Key_Dec_InitialStateConfigurable = "Dec_InitialStateConfigurable";
61 const QString GlobalSettings::Key_Dec_ExportFormat = "Dec_ExportFormat";
62 const QString GlobalSettings::Key_Log_BufferSize = "Log_BufferSize";
63 const QString GlobalSettings::Key_Log_NotifyOfStacktrace = "Log_NotifyOfStacktrace";
64
65 vector<GlobalSettingsInterface*> GlobalSettings::callbacks_;
66 bool GlobalSettings::tracking_ = false;
67 map<QString, QVariant> GlobalSettings::tracked_changes_;
68 QPalette GlobalSettings::default_palette_;
69
70 GlobalSettings::GlobalSettings() :
71         QSettings()
72 {
73         beginGroup("Settings");
74 }
75
76 void GlobalSettings::set_defaults_where_needed()
77 {
78         // Use no theme by default
79         if (!contains(Key_General_Theme))
80                 setValue(Key_General_Theme, 0);
81
82         // Enable zoom-to-fit after acquisition by default
83         if (!contains(Key_View_ZoomToFitAfterAcq))
84                 setValue(Key_View_ZoomToFitAfterAcq, true);
85
86         // Enable colored trace backgrounds by default
87         if (!contains(Key_View_ColoredBG))
88                 setValue(Key_View_ColoredBG, true);
89
90         // Enable showing sampling points by default
91         if (!contains(Key_View_ShowSamplingPoints))
92                 setValue(Key_View_ShowSamplingPoints, true);
93
94         // Enable filling logic signal high areas by default
95         if (!contains(Key_View_FillSignalHighAreas))
96                 setValue(Key_View_FillSignalHighAreas, true);
97         if (!contains(Key_View_FillSignalHighAreaColor))
98                 setValue(Key_View_FillSignalHighAreaColor,
99                         QColor(0, 0, 0, 5 * 256 / 100).rgba());
100
101         if (!contains(Key_View_DefaultDivHeight))
102                 setValue(Key_View_DefaultDivHeight,
103                 3 * QFontMetrics(QApplication::font()).height());
104
105         if (!contains(Key_View_DefaultLogicHeight))
106                 setValue(Key_View_DefaultLogicHeight,
107                 2 * QFontMetrics(QApplication::font()).height());
108
109         if (!contains(Key_View_ShowHoverMarker))
110                 setValue(Key_View_ShowHoverMarker, true);
111
112         if (!contains(Key_View_SnapDistance))
113                 setValue(Key_View_SnapDistance, 15);
114
115         if (!contains(Key_Dec_ExportFormat))
116                 setValue(Key_Dec_ExportFormat, "%s %d: %c: %1");
117
118         // Default to 500 lines of backlog
119         if (!contains(Key_Log_BufferSize))
120                 setValue(Key_Log_BufferSize, 500);
121
122         // Notify user of existing stack trace by default
123         if (!contains(Key_Log_NotifyOfStacktrace))
124                 setValue(Key_Log_NotifyOfStacktrace, true);
125 }
126
127 void GlobalSettings::save_default_palette()
128 {
129         default_palette_ = QApplication::palette();
130 }
131
132 void GlobalSettings::apply_theme()
133 {
134         QString theme_name    = Themes.at(value(Key_General_Theme).toInt()).first;
135         QString resource_name = Themes.at(value(Key_General_Theme).toInt()).second;
136
137         if (!resource_name.isEmpty()) {
138                 QFile file(resource_name);
139                 file.open(QFile::ReadOnly | QFile::Text);
140                 qApp->setStyleSheet(file.readAll());
141         } else
142                 qApp->setStyleSheet("");
143
144         qApp->setPalette(default_palette_);
145
146         if (theme_name.compare("QDarkStyleSheet") == 0) {
147 #ifdef Q_OS_WIN
148                 qApp->setStyle(QStyleFactory::create("Fusion"));
149 #endif
150                 QPalette dark_palette;
151                 dark_palette.setColor(QPalette::Window, QColor(53, 53, 53));
152                 dark_palette.setColor(QPalette::WindowText, Qt::white);
153                 dark_palette.setColor(QPalette::Base, QColor(42, 42, 42));
154                 dark_palette.setColor(QPalette::Dark, QColor(35, 35, 35));
155                 dark_palette.setColor(QPalette::Highlight, QColor(42, 130, 218));
156                 qApp->setPalette(dark_palette);
157         } else if (theme_name.compare("DarkStyle") == 0) {
158 #ifdef Q_OS_WIN
159                 qApp->setStyle(QStyleFactory::create("Fusion"));
160 #endif
161                 QPalette dark_palette;
162                 dark_palette.setColor(QPalette::Window, QColor(53, 53, 53));
163                 dark_palette.setColor(QPalette::WindowText, Qt::white);
164                 dark_palette.setColor(QPalette::Disabled, QPalette::WindowText, QColor(127, 127, 127));
165                 dark_palette.setColor(QPalette::Base, QColor(42, 42, 42));
166                 dark_palette.setColor(QPalette::AlternateBase, QColor(66, 66, 66));
167                 dark_palette.setColor(QPalette::ToolTipBase, Qt::white);
168                 dark_palette.setColor(QPalette::ToolTipText, QColor(53, 53, 53));
169                 dark_palette.setColor(QPalette::Text, Qt::white);
170                 dark_palette.setColor(QPalette::Disabled, QPalette::Text, QColor(127, 127, 127));
171                 dark_palette.setColor(QPalette::Dark, QColor(35, 35, 35));
172                 dark_palette.setColor(QPalette::Shadow, QColor(20, 20, 20));
173                 dark_palette.setColor(QPalette::Button, QColor(53, 53, 53));
174                 dark_palette.setColor(QPalette::ButtonText, Qt::white);
175                 dark_palette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(127, 127, 127));
176                 dark_palette.setColor(QPalette::BrightText, Qt::red);
177                 dark_palette.setColor(QPalette::Link, QColor(42, 130, 218));
178                 dark_palette.setColor(QPalette::Highlight, QColor(42, 130, 218));
179                 dark_palette.setColor(QPalette::Disabled, QPalette::Highlight, QColor(80, 80, 80));
180                 dark_palette.setColor(QPalette::HighlightedText, Qt::white);
181                 dark_palette.setColor(QPalette::Disabled, QPalette::HighlightedText, QColor(127, 127, 127));
182                 qApp->setPalette(dark_palette);
183         }
184
185         QPixmapCache::clear();
186 }
187
188 void GlobalSettings::add_change_handler(GlobalSettingsInterface *cb)
189 {
190         callbacks_.push_back(cb);
191 }
192
193 void GlobalSettings::remove_change_handler(GlobalSettingsInterface *cb)
194 {
195         for (auto cb_it = callbacks_.begin(); cb_it != callbacks_.end(); cb_it++)
196                 if (*cb_it == cb) {
197                         callbacks_.erase(cb_it);
198                         break;
199                 }
200 }
201
202 void GlobalSettings::setValue(const QString &key, const QVariant &value)
203 {
204         // Save previous value if we're tracking changes,
205         // not altering an already-existing saved setting
206         if (tracking_)
207                 tracked_changes_.emplace(key, QSettings::value(key));
208
209         QSettings::setValue(key, value);
210
211         // TODO Emulate noquote()
212         qDebug() << "Setting" << key << "changed to" << value;
213
214         // Call all registered callbacks
215         for (GlobalSettingsInterface *cb : callbacks_)
216                 cb->on_setting_changed(key, value);
217 }
218
219 void GlobalSettings::start_tracking()
220 {
221         tracking_ = true;
222         tracked_changes_.clear();
223 }
224
225 void GlobalSettings::stop_tracking()
226 {
227         tracking_ = false;
228         tracked_changes_.clear();
229 }
230
231 void GlobalSettings::undo_tracked_changes()
232 {
233         tracking_ = false;
234
235         for (auto& entry : tracked_changes_)
236                 setValue(entry.first, entry.second);
237
238         tracked_changes_.clear();
239 }
240
241 void GlobalSettings::store_gvariant(QSettings &settings, GVariant *v)
242 {
243         const GVariantType *var_type = g_variant_get_type(v);
244         char *var_type_str = g_variant_type_dup_string(var_type);
245
246         QByteArray var_data = QByteArray((const char*)g_variant_get_data(v),
247                 g_variant_get_size(v));
248
249         settings.setValue("value", var_data);
250         settings.setValue("type", var_type_str);
251
252         g_free(var_type_str);
253 }
254
255 GVariant* GlobalSettings::restore_gvariant(QSettings &settings)
256 {
257         QString raw_type = settings.value("type").toString();
258         GVariantType *var_type = g_variant_type_new(raw_type.toUtf8());
259
260         QByteArray data = settings.value("value").toByteArray();
261
262         gpointer var_data = g_memdup((gconstpointer)data.constData(),
263                 (guint)data.size());
264
265         GVariant *value = g_variant_new_from_data(var_type, var_data,
266                 data.size(), false, g_free, var_data);
267
268         g_variant_type_free(var_type);
269
270         return value;
271 }
272
273 void GlobalSettings::store_variantbase(QSettings &settings, Glib::VariantBase v)
274 {
275         const QByteArray var_data = QByteArray((const char*)v.get_data(), v.get_size());
276
277         settings.setValue("value", var_data);
278         settings.setValue("type", QString::fromStdString(v.get_type_string()));
279 }
280
281 Glib::VariantBase GlobalSettings::restore_variantbase(QSettings &settings)
282 {
283         QString raw_type = settings.value("type").toString();
284         GVariantType *var_type = g_variant_type_new(raw_type.toUtf8());
285
286         QByteArray data = settings.value("value").toByteArray();
287
288         gpointer var_data = g_memdup((gconstpointer)data.constData(),
289                 (guint)data.size());
290
291         GVariant *value = g_variant_new_from_data(var_type, var_data,
292                 data.size(), false, g_free, var_data);
293
294         Glib::VariantBase ret_val = Glib::VariantBase(value, true);
295
296         g_variant_type_free(var_type);
297         g_variant_unref(value);
298
299         return ret_val;
300 }
301
302 } // namespace pv