]> sigrok.org Git - pulseview.git/blob - pv/dialogs/settings.cpp
d17f5d04c35cd61d02be0fec28da8af89750701f
[pulseview.git] / pv / dialogs / settings.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 "config.h"
21
22 #include <glib.h>
23
24 #include <QApplication>
25 #include <QComboBox>
26 #include <QDialogButtonBox>
27 #include <QFileDialog>
28 #include <QFormLayout>
29 #include <QGroupBox>
30 #include <QHBoxLayout>
31 #include <QLabel>
32 #include <QMainWindow>
33 #include <QMessageBox>
34 #include <QPushButton>
35 #include <QScrollBar>
36 #include <QSpinBox>
37 #include <QString>
38 #include <QTextBrowser>
39 #include <QTextDocument>
40 #include <QTextStream>
41 #include <QVBoxLayout>
42
43 #include "settings.hpp"
44
45 #include "pv/application.hpp"
46 #include "pv/devicemanager.hpp"
47 #include "pv/globalsettings.hpp"
48 #include "pv/logging.hpp"
49 #include "pv/widgets/colorbutton.hpp"
50
51 #include <libsigrokcxx/libsigrokcxx.hpp>
52
53 #ifdef ENABLE_DECODE
54 #include <libsigrokdecode/libsigrokdecode.h>
55 #endif
56
57 using pv::widgets::ColorButton;
58
59 namespace pv {
60 namespace dialogs {
61
62 /**
63  * Special version of a QListView that has the width of the first column as minimum size.
64  *
65  * @note Inspired by https://github.com/qt-creator/qt-creator/blob/master/src/plugins/coreplugin/dialogs/settingsdialog.cpp
66  */
67 class PageListWidget: public QListWidget
68 {
69 public:
70         PageListWidget() :
71                 QListWidget()
72         {
73                 setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
74         }
75
76         QSize sizeHint() const final
77         {
78                 int width = sizeHintForColumn(0) + frameWidth() * 2 + 5;
79                 if (verticalScrollBar()->isVisible())
80                         width += verticalScrollBar()->width();
81                 return QSize(width, 100);
82         }
83 };
84
85 Settings::Settings(DeviceManager &device_manager, QWidget *parent) :
86         QDialog(parent, nullptr),
87         device_manager_(device_manager)
88 {
89         resize(600, 400);
90
91         // Create log view
92         log_view_ = create_log_view();
93
94         // Create pages
95         page_list = new PageListWidget();
96         page_list->setViewMode(QListView::ListMode);
97         page_list->setMovement(QListView::Static);
98         page_list->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
99
100         pages = new QStackedWidget;
101         create_pages();
102         page_list->setCurrentIndex(page_list->model()->index(0, 0));
103
104         // Create the rest of the dialog
105         QHBoxLayout *tab_layout = new QHBoxLayout;
106         tab_layout->addWidget(page_list);
107         tab_layout->addWidget(pages, Qt::AlignLeft);
108
109         QDialogButtonBox *button_box = new QDialogButtonBox(
110                 QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
111
112         QVBoxLayout* root_layout = new QVBoxLayout(this);
113         root_layout->addLayout(tab_layout);
114         root_layout->addWidget(button_box);
115
116         connect(button_box, SIGNAL(accepted()), this, SLOT(accept()));
117         connect(button_box, SIGNAL(rejected()), this, SLOT(reject()));
118         connect(page_list, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
119                 this, SLOT(on_page_changed(QListWidgetItem*, QListWidgetItem*)));
120
121         // Start to record changes
122         GlobalSettings settings;
123         settings.start_tracking();
124 }
125
126 void Settings::create_pages()
127 {
128         // General page
129         pages->addWidget(get_general_settings_form(pages));
130
131         QListWidgetItem *generalButton = new QListWidgetItem(page_list);
132         generalButton->setIcon(QIcon(":/icons/settings-general.png"));
133         generalButton->setText(tr("General"));
134         generalButton->setTextAlignment(Qt::AlignVCenter);
135         generalButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
136
137         // View page
138         pages->addWidget(get_view_settings_form(pages));
139
140         QListWidgetItem *viewButton = new QListWidgetItem(page_list);
141         viewButton->setIcon(QIcon(":/icons/settings-views.svg"));
142         viewButton->setText(tr("Views"));
143         viewButton->setTextAlignment(Qt::AlignVCenter);
144         viewButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
145
146 #ifdef ENABLE_DECODE
147         // Decoder page
148         pages->addWidget(get_decoder_settings_form(pages));
149
150         QListWidgetItem *decoderButton = new QListWidgetItem(page_list);
151         decoderButton->setIcon(QIcon(":/icons/add-decoder.svg"));
152         decoderButton->setText(tr("Decoders"));
153         decoderButton->setTextAlignment(Qt::AlignVCenter);
154         decoderButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
155 #endif
156
157         // About page
158         pages->addWidget(get_about_page(pages));
159
160         QListWidgetItem *aboutButton = new QListWidgetItem(page_list);
161         aboutButton->setIcon(QIcon(":/icons/information.svg"));
162         aboutButton->setText(tr("About"));
163         aboutButton->setTextAlignment(Qt::AlignVCenter);
164         aboutButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
165
166         // Logging page
167         pages->addWidget(get_logging_page(pages));
168
169         QListWidgetItem *loggingButton = new QListWidgetItem(page_list);
170         loggingButton->setIcon(QIcon(":/icons/information.svg"));
171         loggingButton->setText(tr("Logging"));
172         loggingButton->setTextAlignment(Qt::AlignVCenter);
173         loggingButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
174 }
175
176 QCheckBox *Settings::create_checkbox(const QString& key, const char* slot) const
177 {
178         GlobalSettings settings;
179
180         QCheckBox *cb = new QCheckBox();
181         cb->setChecked(settings.value(key).toBool());
182         connect(cb, SIGNAL(stateChanged(int)), this, slot);
183         return cb;
184 }
185
186 QPlainTextEdit *Settings::create_log_view() const
187 {
188         GlobalSettings settings;
189
190         QPlainTextEdit *log_view = new QPlainTextEdit();
191
192         log_view->setReadOnly(true);
193         log_view->setWordWrapMode(QTextOption::NoWrap);
194         log_view->setCenterOnScroll(true);
195
196         log_view->appendHtml(logging.get_log());
197         connect(&logging, SIGNAL(logged_text(QString)),
198                 log_view, SLOT(appendHtml(QString)));
199
200         return log_view;
201 }
202
203 QWidget *Settings::get_general_settings_form(QWidget *parent) const
204 {
205         GlobalSettings settings;
206
207         QWidget *form = new QWidget(parent);
208         QVBoxLayout *form_layout = new QVBoxLayout(form);
209
210         // General settings
211         QGroupBox *general_group = new QGroupBox(tr("General"));
212         form_layout->addWidget(general_group);
213
214         QFormLayout *general_layout = new QFormLayout();
215         general_group->setLayout(general_layout);
216
217         QComboBox *theme_cb = new QComboBox();
218         for (pair<QString, QString> entry : Themes)
219                 theme_cb->addItem(entry.first, entry.second);
220
221         theme_cb->setCurrentIndex(
222                 settings.value(GlobalSettings::Key_General_Theme).toInt());
223         connect(theme_cb, SIGNAL(currentIndexChanged(int)),
224                 this, SLOT(on_general_theme_changed_changed(int)));
225         general_layout->addRow(tr("User interface theme"), theme_cb);
226
227         QLabel *description_1 = new QLabel(tr("(You may need to restart PulseView for all UI elements to update)"));
228         description_1->setAlignment(Qt::AlignRight);
229         general_layout->addRow(description_1);
230
231         return form;
232 }
233
234 QWidget *Settings::get_view_settings_form(QWidget *parent) const
235 {
236         GlobalSettings settings;
237         QCheckBox *cb;
238
239         QWidget *form = new QWidget(parent);
240         QVBoxLayout *form_layout = new QVBoxLayout(form);
241
242         // Trace view settings
243         QGroupBox *trace_view_group = new QGroupBox(tr("Trace View"));
244         form_layout->addWidget(trace_view_group);
245
246         QFormLayout *trace_view_layout = new QFormLayout();
247         trace_view_group->setLayout(trace_view_layout);
248
249         cb = create_checkbox(GlobalSettings::Key_View_ColoredBG,
250                 SLOT(on_view_coloredBG_changed(int)));
251         trace_view_layout->addRow(tr("Use colored trace &background"), cb);
252
253         cb = create_checkbox(GlobalSettings::Key_View_ZoomToFitDuringAcq,
254                 SLOT(on_view_zoomToFitDuringAcq_changed(int)));
255         trace_view_layout->addRow(tr("Constantly perform &zoom-to-fit during acquisition"), cb);
256
257         cb = create_checkbox(GlobalSettings::Key_View_ZoomToFitAfterAcq,
258                 SLOT(on_view_zoomToFitAfterAcq_changed(int)));
259         trace_view_layout->addRow(tr("Perform a zoom-to-&fit when acquisition stops"), cb);
260
261         cb = create_checkbox(GlobalSettings::Key_View_TriggerIsZeroTime,
262                 SLOT(on_view_triggerIsZero_changed(int)));
263         trace_view_layout->addRow(tr("Show time zero at the trigger"), cb);
264
265         cb = create_checkbox(GlobalSettings::Key_View_StickyScrolling,
266                 SLOT(on_view_stickyScrolling_changed(int)));
267         trace_view_layout->addRow(tr("Always keep &newest samples at the right edge during capture"), cb);
268
269         cb = create_checkbox(GlobalSettings::Key_View_ShowSamplingPoints,
270                 SLOT(on_view_showSamplingPoints_changed(int)));
271         trace_view_layout->addRow(tr("Show data &sampling points"), cb);
272
273         cb = create_checkbox(GlobalSettings::Key_View_FillSignalHighAreas,
274                 SLOT(on_view_fillSignalHighAreas_changed(int)));
275         trace_view_layout->addRow(tr("Fill high areas of logic signals"), cb);
276
277         ColorButton* high_fill_cb = new ColorButton(parent);
278         high_fill_cb->set_color(QColor::fromRgba(
279                 settings.value(GlobalSettings::Key_View_FillSignalHighAreaColor).value<uint32_t>()));
280         connect(high_fill_cb, SIGNAL(selected(QColor)),
281                 this, SLOT(on_view_fillSignalHighAreaColor_changed(QColor)));
282         trace_view_layout->addRow(tr("Fill high areas of logic signals"), high_fill_cb);
283
284         cb = create_checkbox(GlobalSettings::Key_View_ShowAnalogMinorGrid,
285                 SLOT(on_view_showAnalogMinorGrid_changed(int)));
286         trace_view_layout->addRow(tr("Show analog minor grid in addition to div grid"), cb);
287
288         cb = create_checkbox(GlobalSettings::Key_View_ShowHoverMarker,
289                 SLOT(on_view_showHoverMarker_changed(int)));
290         trace_view_layout->addRow(tr("Highlight mouse cursor using a vertical marker line"), cb);
291
292         QSpinBox *snap_distance_sb = new QSpinBox();
293         snap_distance_sb->setRange(0, 1000);
294         snap_distance_sb->setSuffix(tr(" pixels"));
295         snap_distance_sb->setValue(
296                 settings.value(GlobalSettings::Key_View_SnapDistance).toInt());
297         connect(snap_distance_sb, SIGNAL(valueChanged(int)), this,
298                 SLOT(on_view_snapDistance_changed(int)));
299         trace_view_layout->addRow(tr("Maximum distance from edges before cursors snap to them"), snap_distance_sb);
300
301         QComboBox *thr_disp_mode_cb = new QComboBox();
302         thr_disp_mode_cb->addItem(tr("None"), GlobalSettings::ConvThrDispMode_None);
303         thr_disp_mode_cb->addItem(tr("Background"), GlobalSettings::ConvThrDispMode_Background);
304         thr_disp_mode_cb->addItem(tr("Dots"), GlobalSettings::ConvThrDispMode_Dots);
305         thr_disp_mode_cb->setCurrentIndex(
306                 settings.value(GlobalSettings::Key_View_ConversionThresholdDispMode).toInt());
307         connect(thr_disp_mode_cb, SIGNAL(currentIndexChanged(int)),
308                 this, SLOT(on_view_conversionThresholdDispMode_changed(int)));
309         trace_view_layout->addRow(tr("Conversion threshold display mode (analog traces only)"), thr_disp_mode_cb);
310
311         QSpinBox *default_div_height_sb = new QSpinBox();
312         default_div_height_sb->setRange(20, 1000);
313         default_div_height_sb->setSuffix(tr(" pixels"));
314         default_div_height_sb->setValue(
315                 settings.value(GlobalSettings::Key_View_DefaultDivHeight).toInt());
316         connect(default_div_height_sb, SIGNAL(valueChanged(int)), this,
317                 SLOT(on_view_defaultDivHeight_changed(int)));
318         trace_view_layout->addRow(tr("Default analog trace div height"), default_div_height_sb);
319
320         QSpinBox *default_logic_height_sb = new QSpinBox();
321         default_logic_height_sb->setRange(5, 1000);
322         default_logic_height_sb->setSuffix(tr(" pixels"));
323         default_logic_height_sb->setValue(
324                 settings.value(GlobalSettings::Key_View_DefaultLogicHeight).toInt());
325         connect(default_logic_height_sb, SIGNAL(valueChanged(int)), this,
326                 SLOT(on_view_defaultLogicHeight_changed(int)));
327         trace_view_layout->addRow(tr("Default logic trace height"), default_logic_height_sb);
328
329         return form;
330 }
331
332 QWidget *Settings::get_decoder_settings_form(QWidget *parent)
333 {
334 #ifdef ENABLE_DECODE
335         GlobalSettings settings;
336         QCheckBox *cb;
337
338         QWidget *form = new QWidget(parent);
339         QVBoxLayout *form_layout = new QVBoxLayout(form);
340
341         // Decoder settings
342         QGroupBox *decoder_group = new QGroupBox(tr("Decoders"));
343         form_layout->addWidget(decoder_group);
344
345         QFormLayout *decoder_layout = new QFormLayout();
346         decoder_group->setLayout(decoder_layout);
347
348         cb = create_checkbox(GlobalSettings::Key_Dec_InitialStateConfigurable,
349                 SLOT(on_dec_initialStateConfigurable_changed(int)));
350         decoder_layout->addRow(tr("Allow configuration of &initial signal state"), cb);
351
352         // Annotation export settings
353         ann_export_format_ = new QLineEdit();
354         ann_export_format_->setText(
355                 settings.value(GlobalSettings::Key_Dec_ExportFormat).toString());
356         connect(ann_export_format_, SIGNAL(textChanged(const QString&)),
357                 this, SLOT(on_dec_exportFormat_changed(const QString&)));
358         decoder_layout->addRow(tr("Annotation export format"), ann_export_format_);
359         QLabel *description_1 = new QLabel(tr("%s = sample range; %d: decoder name; %c: row name; %q: use quotations marks"));
360         description_1->setAlignment(Qt::AlignRight);
361         decoder_layout->addRow(description_1);
362         QLabel *description_2 = new QLabel(tr("%1: longest annotation text; %a: all annotation texts"));
363         description_2->setAlignment(Qt::AlignRight);
364         decoder_layout->addRow(description_2);
365
366         return form;
367 #else
368         (void)parent;
369         return nullptr;
370 #endif
371 }
372
373 QWidget *Settings::get_about_page(QWidget *parent) const
374 {
375         Application* a = qobject_cast<Application*>(QApplication::instance());
376
377         QLabel *icon = new QLabel();
378         icon->setPixmap(QPixmap(QString::fromUtf8(":/icons/pulseview.svg")));
379
380         // Setup the license field with the project homepage link
381         QLabel *gpl_home_info = new QLabel();
382         gpl_home_info->setText(tr("%1<br /><a href=\"http://%2\">%2</a>").arg(
383                 tr("GNU GPL, version 3 or later"),
384                 QApplication::organizationDomain()));
385         gpl_home_info->setOpenExternalLinks(true);
386
387         QString s;
388
389         s.append("<style type=\"text/css\"> tr .id { white-space: pre; padding-right: 5px; } </style>");
390
391         s.append("<table>");
392
393         s.append("<tr><td colspan=\"2\"><b>" +
394                 tr("Versions, libraries and features:") + "</b></td></tr>");
395         for (pair<QString, QString> &entry : a->get_version_info())
396                 s.append(QString("<tr><td><i>%1</i></td><td>%2</td></tr>")
397                         .arg(entry.first, entry.second));
398
399         s.append("<tr><td colspan=\"2\"></td></tr>");
400         s.append("<tr><td colspan=\"2\"><b>" +
401                 tr("Firmware search paths:") + "</b></td></tr>");
402         for (QString &entry : a->get_fw_path_list())
403                 s.append(QString("<tr><td colspan=\"2\">%1</td></tr>").arg(entry));
404
405 #ifdef ENABLE_DECODE
406         s.append("<tr><td colspan=\"2\"></td></tr>");
407         s.append("<tr><td colspan=\"2\"><b>" +
408                 tr("Protocol decoder search paths:") + "</b></td></tr>");
409         for (QString &entry : a->get_pd_path_list())
410                 s.append(QString("<tr><td colspan=\"2\">%1</td></tr>").arg(entry));
411 #endif
412
413         s.append("<tr><td colspan=\"2\"></td></tr>");
414         s.append("<tr><td colspan=\"2\"><b>" +
415                 tr("Supported hardware drivers:") + "</b></td></tr>");
416         for (pair<QString, QString> &entry : a->get_driver_list())
417                 s.append(QString("<tr><td class=\"id\"><i>%1</i></td><td>%2</td></tr>")
418                         .arg(entry.first, entry.second));
419
420         s.append("<tr><td colspan=\"2\"></td></tr>");
421         s.append("<tr><td colspan=\"2\"><b>" +
422                 tr("Supported input formats:") + "</b></td></tr>");
423         for (pair<QString, QString> &entry : a->get_input_format_list())
424                 s.append(QString("<tr><td class=\"id\"><i>%1</i></td><td>%2</td></tr>")
425                         .arg(entry.first, entry.second));
426
427         s.append("<tr><td colspan=\"2\"></td></tr>");
428         s.append("<tr><td colspan=\"2\"><b>" +
429                 tr("Supported output formats:") + "</b></td></tr>");
430         for (pair<QString, QString> &entry : a->get_output_format_list())
431                 s.append(QString("<tr><td class=\"id\"><i>%1</i></td><td>%2</td></tr>")
432                         .arg(entry.first, entry.second));
433
434 #ifdef ENABLE_DECODE
435         s.append("<tr><td colspan=\"2\"></td></tr>");
436         s.append("<tr><td colspan=\"2\"><b>" +
437                 tr("Supported protocol decoders:") + "</b></td></tr>");
438         for (pair<QString, QString> &entry : a->get_pd_list())
439                 s.append(QString("<tr><td class=\"id\"><i>%1</i></td><td>%2</td></tr>")
440                         .arg(entry.first, entry.second));
441 #endif
442
443         s.append("</table>");
444
445         QTextDocument *supported_doc = new QTextDocument();
446         supported_doc->setHtml(s);
447
448         QTextBrowser *support_list = new QTextBrowser();
449         support_list->setDocument(supported_doc);
450
451         QHBoxLayout *h_layout = new QHBoxLayout();
452         h_layout->setAlignment(Qt::AlignLeft);
453         h_layout->addWidget(icon);
454         h_layout->addWidget(gpl_home_info);
455
456         QVBoxLayout *layout = new QVBoxLayout();
457         layout->addLayout(h_layout);
458         layout->addWidget(support_list);
459
460         QWidget *page = new QWidget(parent);
461         page->setLayout(layout);
462
463         return page;
464 }
465
466 QWidget *Settings::get_logging_page(QWidget *parent) const
467 {
468         GlobalSettings settings;
469
470         // Log level
471         QSpinBox *loglevel_sb = new QSpinBox();
472         loglevel_sb->setMaximum(SR_LOG_SPEW);
473         loglevel_sb->setValue(logging.get_log_level());
474         connect(loglevel_sb, SIGNAL(valueChanged(int)), this,
475                 SLOT(on_log_logLevel_changed(int)));
476
477         QHBoxLayout *loglevel_layout = new QHBoxLayout();
478         loglevel_layout->addWidget(new QLabel(tr("Log level:")));
479         loglevel_layout->addWidget(loglevel_sb);
480
481         // Background buffer size
482         QSpinBox *buffersize_sb = new QSpinBox();
483         buffersize_sb->setSuffix(tr(" lines"));
484         buffersize_sb->setMinimum(Logging::MIN_BUFFER_SIZE);
485         buffersize_sb->setMaximum(Logging::MAX_BUFFER_SIZE);
486         buffersize_sb->setValue(
487                 settings.value(GlobalSettings::Key_Log_BufferSize).toInt());
488         connect(buffersize_sb, SIGNAL(valueChanged(int)), this,
489                 SLOT(on_log_bufferSize_changed(int)));
490
491         QHBoxLayout *buffersize_layout = new QHBoxLayout();
492         buffersize_layout->addWidget(new QLabel(tr("Length of background buffer:")));
493         buffersize_layout->addWidget(buffersize_sb);
494
495         // Save to file
496         QPushButton *save_log_pb = new QPushButton(
497                 QIcon::fromTheme("document-save-as", QIcon(":/icons/document-save-as.png")),
498                 tr("&Save to File"));
499         connect(save_log_pb, SIGNAL(clicked(bool)),
500                 this, SLOT(on_log_saveToFile_clicked(bool)));
501
502         // Pop out
503         QPushButton *pop_out_pb = new QPushButton(
504                 QIcon::fromTheme("window-new", QIcon(":/icons/window-new.png")),
505                 tr("&Pop out"));
506         connect(pop_out_pb, SIGNAL(clicked(bool)),
507                 this, SLOT(on_log_popOut_clicked(bool)));
508
509         QHBoxLayout *control_layout = new QHBoxLayout();
510         control_layout->addLayout(loglevel_layout);
511         control_layout->addLayout(buffersize_layout);
512         control_layout->addWidget(save_log_pb);
513         control_layout->addWidget(pop_out_pb);
514
515         QVBoxLayout *root_layout = new QVBoxLayout();
516         root_layout->addLayout(control_layout);
517         root_layout->addWidget(log_view_);
518
519         QWidget *page = new QWidget(parent);
520         page->setLayout(root_layout);
521
522         return page;
523 }
524
525 void Settings::accept()
526 {
527         GlobalSettings settings;
528         settings.stop_tracking();
529
530         QDialog::accept();
531 }
532
533 void Settings::reject()
534 {
535         GlobalSettings settings;
536         settings.undo_tracked_changes();
537
538         QDialog::reject();
539 }
540
541 void Settings::on_page_changed(QListWidgetItem *current, QListWidgetItem *previous)
542 {
543         if (!current)
544                 current = previous;
545
546         pages->setCurrentIndex(page_list->row(current));
547 }
548
549 void Settings::on_general_theme_changed_changed(int state)
550 {
551         GlobalSettings settings;
552         settings.setValue(GlobalSettings::Key_General_Theme, state);
553         settings.apply_theme();
554 }
555
556 void Settings::on_view_zoomToFitDuringAcq_changed(int state)
557 {
558         GlobalSettings settings;
559         settings.setValue(GlobalSettings::Key_View_ZoomToFitDuringAcq, state ? true : false);
560 }
561
562 void Settings::on_view_zoomToFitAfterAcq_changed(int state)
563 {
564         GlobalSettings settings;
565         settings.setValue(GlobalSettings::Key_View_ZoomToFitAfterAcq, state ? true : false);
566 }
567
568 void Settings::on_view_triggerIsZero_changed(int state)
569 {
570         GlobalSettings settings;
571         settings.setValue(GlobalSettings::Key_View_TriggerIsZeroTime, state ? true : false);
572 }
573
574 void Settings::on_view_coloredBG_changed(int state)
575 {
576         GlobalSettings settings;
577         settings.setValue(GlobalSettings::Key_View_ColoredBG, state ? true : false);
578 }
579
580 void Settings::on_view_stickyScrolling_changed(int state)
581 {
582         GlobalSettings settings;
583         settings.setValue(GlobalSettings::Key_View_StickyScrolling, state ? true : false);
584 }
585
586 void Settings::on_view_showSamplingPoints_changed(int state)
587 {
588         GlobalSettings settings;
589         settings.setValue(GlobalSettings::Key_View_ShowSamplingPoints, state ? true : false);
590 }
591
592 void Settings::on_view_fillSignalHighAreas_changed(int state)
593 {
594         GlobalSettings settings;
595         settings.setValue(GlobalSettings::Key_View_FillSignalHighAreas, state ? true : false);
596 }
597
598 void Settings::on_view_fillSignalHighAreaColor_changed(QColor color)
599 {
600         GlobalSettings settings;
601         settings.setValue(GlobalSettings::Key_View_FillSignalHighAreaColor, color.rgba());
602 }
603
604 void Settings::on_view_showAnalogMinorGrid_changed(int state)
605 {
606         GlobalSettings settings;
607         settings.setValue(GlobalSettings::Key_View_ShowAnalogMinorGrid, state ? true : false);
608 }
609
610 void Settings::on_view_showHoverMarker_changed(int state)
611 {
612         GlobalSettings settings;
613         settings.setValue(GlobalSettings::Key_View_ShowHoverMarker, state ? true : false);
614 }
615
616 void Settings::on_view_snapDistance_changed(int value)
617 {
618         GlobalSettings settings;
619         settings.setValue(GlobalSettings::Key_View_SnapDistance, value);
620 }
621
622 void Settings::on_view_conversionThresholdDispMode_changed(int state)
623 {
624         GlobalSettings settings;
625         settings.setValue(GlobalSettings::Key_View_ConversionThresholdDispMode, state);
626 }
627
628 void Settings::on_view_defaultDivHeight_changed(int value)
629 {
630         GlobalSettings settings;
631         settings.setValue(GlobalSettings::Key_View_DefaultDivHeight, value);
632 }
633
634 void Settings::on_view_defaultLogicHeight_changed(int value)
635 {
636         GlobalSettings settings;
637         settings.setValue(GlobalSettings::Key_View_DefaultLogicHeight, value);
638 }
639
640 #ifdef ENABLE_DECODE
641 void Settings::on_dec_initialStateConfigurable_changed(int state)
642 {
643         GlobalSettings settings;
644         settings.setValue(GlobalSettings::Key_Dec_InitialStateConfigurable, state ? true : false);
645 }
646
647 void Settings::on_dec_exportFormat_changed(const QString &text)
648 {
649         GlobalSettings settings;
650         settings.setValue(GlobalSettings::Key_Dec_ExportFormat, text);
651 }
652 #endif
653
654 void Settings::on_log_logLevel_changed(int value)
655 {
656         logging.set_log_level(value);
657 }
658
659 void Settings::on_log_bufferSize_changed(int value)
660 {
661         GlobalSettings settings;
662         settings.setValue(GlobalSettings::Key_Log_BufferSize, value);
663 }
664
665 void Settings::on_log_saveToFile_clicked(bool checked)
666 {
667         (void)checked;
668
669         const QString file_name = QFileDialog::getSaveFileName(
670                 this, tr("Save Log"), "", tr("Log Files (*.txt *.log);;All Files (*)"));
671
672         if (file_name.isEmpty())
673                 return;
674
675         QFile file(file_name);
676         if (file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
677                 QTextStream out_stream(&file);
678                 out_stream << log_view_->toPlainText();
679
680                 if (out_stream.status() == QTextStream::Ok) {
681                         QMessageBox msg(this);
682                         msg.setText(tr("Success"));
683                         msg.setInformativeText(tr("Log saved to %1.").arg(file_name));
684                         msg.setStandardButtons(QMessageBox::Ok);
685                         msg.setIcon(QMessageBox::Information);
686                         msg.exec();
687
688                         return;
689                 }
690         }
691
692         QMessageBox msg(this);
693         msg.setText(tr("Error"));
694         msg.setInformativeText(tr("File %1 could not be written to.").arg(file_name));
695         msg.setStandardButtons(QMessageBox::Ok);
696         msg.setIcon(QMessageBox::Warning);
697         msg.exec();
698 }
699
700 void Settings::on_log_popOut_clicked(bool checked)
701 {
702         (void)checked;
703
704         // Create the window as a sub-window so it closes when the main window closes
705         QMainWindow *window = new QMainWindow(nullptr, Qt::SubWindow);
706
707         window->setObjectName(QString::fromUtf8("Log Window"));
708         window->setWindowTitle(tr("%1 Log").arg(PV_TITLE));
709
710         // Use same width/height as the settings dialog
711         window->resize(width(), height());
712
713         window->setCentralWidget(create_log_view());
714         window->show();
715 }
716
717 } // namespace dialogs
718 } // namespace pv