From de0fbae5303bc36546fc8c1bb69d98f52e3d6173 Mon Sep 17 00:00:00 2001 From: Roland Pallai Date: Sun, 23 Jun 2019 22:42:16 +0200 Subject: [PATCH 1/2] Turn settings menu into a dialog window Closes #553. --- CMakeLists.txt | 9 +- client/mainwindow.cpp | 139 +++++----------------- client/mainwindow.h | 1 + client/settingsdialog.cpp | 120 +++++++++++++++++++ client/settingsdialog.h | 73 ++++++++++++ client/settingsgeneralpage.ui | 216 ++++++++++++++++++++++++++++++++++ 6 files changed, 447 insertions(+), 111 deletions(-) create mode 100644 client/settingsdialog.cpp create mode 100644 client/settingsdialog.h create mode 100644 client/settingsgeneralpage.ui diff --git a/CMakeLists.txt b/CMakeLists.txt index 49bce33e1..071842b4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,6 +152,7 @@ set(quaternion_SRCS client/activitydetector.cpp client/dialog.cpp client/logindialog.cpp + client/settingsdialog.cpp client/networkconfigdialog.cpp client/roomdialogs.cpp client/mainwindow.cpp @@ -173,6 +174,10 @@ set(quaternion_QRC client/resources.qrc ) +set(quaternion_UI + client/settingsgeneralpage.ui + ) + # quaternion_en.ts is updated explicitly by building trbase target, # while all other translation files are created and updated externally at # Lokalise.co @@ -188,6 +193,8 @@ set(quaternion_TS ) QT5_ADD_TRANSLATION(quaternion_QM ${quaternion_TS}) +qt5_wrap_ui(quaternion_UI_OUT ${quaternion_UI}) + QT5_ADD_RESOURCES(quaternion_QRC_SRC ${quaternion_QRC}) set_property(SOURCE qrc_resources.cpp PROPERTY SKIP_AUTOMOC ON) @@ -216,7 +223,7 @@ endif(APPLE) # Windows, this is a GUI executable; OSX, make a bundle add_executable(${PROJECT_NAME} WIN32 MACOSX_BUNDLE - ${quaternion_SRCS} ${quaternion_QRC_SRC} ${quaternion_QM} + ${quaternion_SRCS} ${quaternion_UI_OUT} ${quaternion_QRC_SRC} ${quaternion_QM} ${quaternion_WINRC} ${${PROJECT_NAME}_MAC_ICON}) target_link_libraries(${PROJECT_NAME} diff --git a/client/mainwindow.cpp b/client/mainwindow.cpp index 5bfe2367d..6b8896c75 100644 --- a/client/mainwindow.cpp +++ b/client/mainwindow.cpp @@ -23,6 +23,7 @@ #include "userlistdock.h" #include "chatroomwidget.h" #include "logindialog.h" +#include "settingsdialog.h" #include "networkconfigdialog.h" #include "roomdialogs.h" #include "systemtrayicon.h" @@ -168,6 +169,24 @@ void MainWindow::createMenu() { using Quotient::Settings; + // Application menu + auto applicationMenu = menuBar()->addMenu(tr("A&pplication")); + applicationMenu->addAction(QIcon::fromTheme("preferences"), tr("&Preferences..."), + this, [=]{ showSettingsWindow(); } ); + + applicationMenu->addAction(QIcon::fromTheme("preferences-system-network"), + tr("Configure &network proxy..."), [this] + { + static QPointer dlg; + summon(dlg, this); + }); + + // Augment poor Windows users with a handy Ctrl-Q shortcut. + static const auto quitShortcut = QSysInfo::productType() == "windows" + ? QKeySequence(Qt::CTRL + Qt::Key_Q) : QKeySequence::Quit; + applicationMenu->addAction(QIcon::fromTheme("application-exit"), + tr("&Quit"), qApp, &QApplication::quit, quitShortcut); + // Connection menu connectionMenu = menuBar()->addMenu(tr("&Accounts")); @@ -178,12 +197,6 @@ void MainWindow::createMenu() // Account submenus will be added in this place - see addConnection() accountListGrowthPoint = connectionMenu->addSeparator(); - // Augment poor Windows users with a handy Ctrl-Q shortcut. - static const auto quitShortcut = QSysInfo::productType() == "windows" - ? QKeySequence(Qt::CTRL + Qt::Key_Q) : QKeySequence::Quit; - connectionMenu->addAction(QIcon::fromTheme("application-exit"), - tr("&Quit"), qApp, &QApplication::quit, quitShortcut); - // View menu auto viewMenu = menuBar()->addMenu(tr("&View")); @@ -307,114 +320,10 @@ void MainWindow::createMenu() tr("&Close current room"), [this] { selectRoom(nullptr); }, QKeySequence::Close); - // Settings menu - auto settingsMenu = menuBar()->addMenu(tr("&Settings")); - // Help menu auto helpMenu = menuBar()->addMenu(tr("&Help")); helpMenu->addAction(QIcon::fromTheme("help-about"), tr("&About"), [=]{ showAboutWindow(); }); - - { - auto notifGroup = new QActionGroup(this); - connect(notifGroup, &QActionGroup::triggered, this, - [] (QAction* notifAction) - { - notifAction->setChecked(true); - Settings().setValue("UI/notifications", - notifAction->data().toString()); - }); - - auto noNotif = notifGroup->addAction(tr("&Highlight only")); - noNotif->setData(QStringLiteral("none")); - noNotif->setStatusTip(tr("Notifications are entirely suppressed")); - auto gentleNotif = notifGroup->addAction(tr("&Non-intrusive")); - gentleNotif->setData(QStringLiteral("non-intrusive")); - gentleNotif->setStatusTip( - tr("Show notifications but do not activate the window")); - auto fullNotif = notifGroup->addAction(tr("&Full")); - fullNotif->setData(QStringLiteral("intrusive")); - fullNotif->setStatusTip( - tr("Show notifications and activate the window")); - - auto notifMenu = settingsMenu->addMenu( - QIcon::fromTheme("preferences-desktop-notification"), - tr("Notifications")); - for (auto a: {noNotif, gentleNotif, fullNotif}) - { - a->setCheckable(true); - notifMenu->addAction(a); - } - - const auto curSetting = Settings().value("UI/notifications", - fullNotif->data().toString()); - if (curSetting == noNotif->data().toString()) - noNotif->setChecked(true); - else if (curSetting == gentleNotif->data().toString()) - gentleNotif->setChecked(true); - else - fullNotif->setChecked(true); - } - { - auto layoutGroup = new QActionGroup(this); - connect(layoutGroup, &QActionGroup::triggered, this, - [this] (QAction* action) - { - action->setChecked(true); - Settings().setValue("UI/timeline_style", action->data().toString()); - chatRoomWidget->setRoom(nullptr); - chatRoomWidget->setRoom(currentRoom); - }); - - auto defaultLayout = layoutGroup->addAction(tr("Default")); - defaultLayout->setStatusTip( - tr("The layout with author labels above blocks of messages")); - auto xchatLayout = layoutGroup->addAction("XChat"); - xchatLayout->setData(QStringLiteral("xchat")); - xchatLayout->setStatusTip( - tr("The layout with author labels to the left from each message")); - - auto layoutMenu = settingsMenu->addMenu(QIcon::fromTheme("table"), - tr("Timeline layout")); - for (auto a: {defaultLayout, xchatLayout}) - { - a->setCheckable(true); - layoutMenu->addAction(a); - } - - const auto curSetting = Settings().value("UI/timeline_style", - defaultLayout->data().toString()); - if (curSetting == xchatLayout->data().toString()) - xchatLayout->setChecked(true); - else - defaultLayout->setChecked(true); - } - addTimelineOptionCheckbox( - settingsMenu, - tr("Use shuttle scrollbar (requires restart)"), - tr("Control scroll velocity instead of position with the timeline scrollbar"), - QStringLiteral("use_shuttle_dial"), true - ); - addTimelineOptionCheckbox( - settingsMenu, - tr("Load full-size images at once"), - tr("Automatically download a full-size image instead of a thumbnail"), - QStringLiteral("autoload_images"), true - ); - addTimelineOptionCheckbox( - settingsMenu, - tr("Close to tray"), - tr("Make close button [X] minimize to tray instead of closing main window"), - QStringLiteral("close_to_tray"), false - ); - - settingsMenu->addSeparator(); - settingsMenu->addAction(QIcon::fromTheme("preferences-system-network"), - tr("Configure &network proxy..."), [this] - { - static QPointer dlg; - summon(dlg, this); - }); } void MainWindow::loadSettings() @@ -875,6 +784,16 @@ void MainWindow::processLogin(LoginDialog& dialog) addConnection(connection, deviceName); } +void MainWindow::showSettingsWindow() +{ + SettingsDialog settingsDialog(this); + connect(&settingsDialog, &SettingsDialog::timelineChanged, this, [=]() { + chatRoomWidget->setRoom(nullptr); + chatRoomWidget->setRoom(currentRoom); + }); + settingsDialog.exec(); +} + void MainWindow::showAboutWindow() { Dialog aboutDialog(tr("About Quaternion"), QDialogButtonBox::Close, diff --git a/client/mainwindow.h b/client/mainwindow.h index 0547d4ef1..b763628a8 100644 --- a/client/mainwindow.h +++ b/client/mainwindow.h @@ -104,6 +104,7 @@ class MainWindow: public QMainWindow void showLoginWindow(const QString& statusMessage = {}); void showLoginWindow(const QString& statusMessage, Quotient::AccountSettings& reloginAccount); + void showSettingsWindow(); void showAboutWindow(); void logout(Connection* c); diff --git a/client/settingsdialog.cpp b/client/settingsdialog.cpp new file mode 100644 index 000000000..693c70bcf --- /dev/null +++ b/client/settingsdialog.cpp @@ -0,0 +1,120 @@ +/************************************************************************** + * * + * Copyright (C) 2019 Roland Pallai * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ + +#include "settingsdialog.h" +#include "mainwindow.h" +#include + +#include +#include +#include + +using Quotient::SettingsGroup; + +SettingsDialog::SettingsDialog(MainWindow *parent) : QDialog(parent) { + setWindowTitle(tr("Settings")); + + QVBoxLayout *layout = new QVBoxLayout(this); + stack = new QTabWidget(this); + stack->setTabBarAutoHide(true); + layout->addWidget(stack); + stack->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + + auto generalPage = new GeneralPage(this); + connect(generalPage, &GeneralPage::timelineChanged, this, [this] { + emit timelineChanged(); + }); + addPage(generalPage, tr("&General")); +} + +SettingsDialog::~SettingsDialog() = default; + +void SettingsDialog::addPage(ConfigurationWidgetInterface *page, const QString &title) +{ + stack->addTab(page->asWidget(), title); + pages << page; +} + +// +// GeneralPage +// +GeneralPage::GeneralPage(SettingsDialog *parent): + QWidget(parent), Ui_GeneralPage(), m_parent(parent) +{ + Ui_GeneralPage::setupUi(this); + + // closeToTray + closeToTray->setChecked(SettingsGroup("UI").value("close_to_tray", false).toBool()); + connect(closeToTray, &QAbstractButton::toggled, this, [=](bool checked) { + SettingsGroup("UI").setValue("close_to_tray", checked); + }); + + // timeline_layout + const auto curTimelineStyle = SettingsGroup("UI").value("timeline_style", "default"); + timeline_layout->addItem(tr("Default"), QVariant(QStringLiteral("default"))); + timeline_layout->addItem(tr("XChat"), QVariant(QStringLiteral("xchat"))); + if (curTimelineStyle == "xchat") + timeline_layout->setCurrentText(tr("XChat")); + + connect(timeline_layout, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int index) { + auto new_layout = timeline_layout->itemData(index).toString(); + SettingsGroup("UI").setValue("timeline_style", new_layout); + emit timelineChanged(); + }); + + // useShuttleScrollbar + useShuttleScrollbar->setChecked(SettingsGroup("UI").value("use_shuttle_dial", true).toBool()); + connect(useShuttleScrollbar, &QAbstractButton::toggled, this, [=](bool checked) { + SettingsGroup("UI").setValue("use_shuttle_dial", checked); + // needs restart instead + //emit timelineChanged(); + }); + + // loadFullSizeImages + loadFullSizeImages->setChecked(SettingsGroup("UI").value("autoload_images", true).toBool()); + connect(loadFullSizeImages, &QAbstractButton::toggled, this, [=](bool checked) { + SettingsGroup("UI").setValue("autoload_images", checked); + emit timelineChanged(); + }); + + // *Notif + const auto curNotifications = SettingsGroup("UI").value("notifications", "intrusive"); + if (curNotifications == "intrusive") { + fullNotif->setChecked(true); + } else if (curNotifications == "non-intrusive") { + gentleNotif->setChecked(true); + } else if (curNotifications == "none") { + noNotif->setChecked(true); + } + + connect(noNotif, &QAbstractButton::clicked, this, [=]() { + SettingsGroup("UI").setValue("notifications", "none"); + }); + connect(gentleNotif, &QAbstractButton::clicked, this, [=]() { + SettingsGroup("UI").setValue("notifications", "non-intrusive"); + }); + connect(fullNotif, &QAbstractButton::clicked, this, [=]() { + SettingsGroup("UI").setValue("notifications", "intrusive"); + }); +} + +QWidget *GeneralPage::asWidget() +{ + return this; +} diff --git a/client/settingsdialog.h b/client/settingsdialog.h new file mode 100644 index 000000000..5b93fccac --- /dev/null +++ b/client/settingsdialog.h @@ -0,0 +1,73 @@ +/************************************************************************** + * * + * Copyright (C) 2019 Roland Pallai * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ + +#ifndef SETTINGSDIALOG_H +#define SETTINGSDIALOG_H + +#include "ui_settingsgeneralpage.h" + +#include + +class SettingsDialog; +class MainWindow; +class QTabWidget; + +/** Common interface for settings' tabs + */ +class ConfigurationWidgetInterface { +public: + virtual QWidget *asWidget() = 0; +}; + +class SettingsDialog : public QDialog +{ + Q_OBJECT +public: + SettingsDialog(MainWindow *parent); + ~SettingsDialog() override; + +private: + QTabWidget *stack; + QVector pages; + + void addPage(ConfigurationWidgetInterface *page, const QString &title); + +signals: + // it should be the job of the model + void timelineChanged(); +}; + +// +// GeneralPage +// +class GeneralPage : public QWidget, Ui_GeneralPage, public ConfigurationWidgetInterface +{ + Q_OBJECT +public: + GeneralPage(SettingsDialog *parent); + virtual QWidget *asWidget(); + +private: + SettingsDialog *m_parent; + +signals: + void timelineChanged(); +}; + +#endif /* SETTINGSDIALOG_H */ diff --git a/client/settingsgeneralpage.ui b/client/settingsgeneralpage.ui new file mode 100644 index 000000000..5291039a8 --- /dev/null +++ b/client/settingsgeneralpage.ui @@ -0,0 +1,216 @@ + + + GeneralPage + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + + + + 12 + false + + + + General + + + + + + + Qt::Horizontal + + + + + + + Make close button [X] minimize to tray instead of closing main window. + + + Close to tray + + + + + + + + + + QFrame::NoFrame + + + + + + + 12 + false + + + + Timeline + + + + + + + Qt::Horizontal + + + + + + + QFormLayout::FieldsStayAtSizeHint + + + + + Layout + + + + + + + + + + + + Control scroll velocity instead of position with the timeline scrollbar. Requires restart. + + + Use shuttle scrollbar + + + + + + + Automatically download a full-size image instead of a thumbnail. + + + Load full-size images + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + + + + 12 + + + + Notifications + + + + + + + Qt::Horizontal + + + + + + + + + Show notifications and activate the window. + + + Full + + + + + + + Show notifications but do not activate the window. + + + Non-intrusive + + + + + + + Notifications are entirely suppressed. + + + Highlight only + + + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + From cf4ba059b550fc3d2496ead0b6716cdb3ffe9ac8 Mon Sep 17 00:00:00 2001 From: Roland Pallai Date: Sat, 31 Aug 2019 18:18:02 +0200 Subject: [PATCH 2/2] Expose UI/Fonts/* settings --- README.md | 18 ++++----- client/settingsdialog.cpp | 75 +++++++++++++++++++++++++++++++++++ client/settingsgeneralpage.ui | 49 +++++++++++++++++++++++ 3 files changed, 133 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index acc915cf5..469e882e8 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,15 @@ Some settings exposed in UI (Settings and View menus): If a tag is not mentioned and does not fit any namespace, it will be put at the end in lexicographic order. Tags within the same namespace are also ordered lexicographically. +- `UI/Fonts/family` - override the font family for the whole application. + If not specified, the default font for your environment is used. +- `UI/Fonts/pointSize` - override the font size (in points) for the whole + application. If not specified, the default size for your environment is used. +- `UI/Fonts/timeline_family` - font family (for example `Monospace`) to + display messages in the timeline. If not specified, the application-wide font + family is used. +- `UI/Fonts/timeline_pointSize` - font size (in points) to display messages + in the timeline. If not specified, the application-wide point size is used. Settings not exposed in UI: @@ -194,15 +203,6 @@ Settings not exposed in UI: the beginning and end of the quote. By default it's `(.+)(?:\n|$)`. - `UI/Fonts/render_type` - select how to render fonts in Quaternion timeline; possible values are "NativeRendering" (default) and "QtRendering". -- `UI/Fonts/family` - override the font family for the whole application. - If not specified, the default font for your environment is used. -- `UI/Fonts/pointSize` - override the font size (in points) for the whole - application. If not specified, the default size for your environment is used. -- `UI/Fonts/timeline_family` - font family (for example `Monospace`) to - display messages in the timeline. If not specified, the application-wide font - family is used. -- `UI/Fonts/timeline_pointSize` - font size (in points) to display messages - in the timeline. If not specified, the application-wide point size is used. Since version 0.0.9.4, AppImage binaries for Linux and .dmg files for macOS are compiled with Qt Keychain support. It means that Quaternion will try diff --git a/client/settingsdialog.cpp b/client/settingsdialog.cpp index 693c70bcf..465177e01 100644 --- a/client/settingsdialog.cpp +++ b/client/settingsdialog.cpp @@ -24,6 +24,7 @@ #include #include #include +#include using Quotient::SettingsGroup; @@ -59,6 +60,42 @@ GeneralPage::GeneralPage(SettingsDialog *parent): { Ui_GeneralPage::setupUi(this); + // uiFont + const auto curUIFontFamily = SettingsGroup("UI").value("Fonts/family", "").toString(); + uiFontFamily->insertItem(0, tr("system default")); + if (curUIFontFamily == "") { + uiFontFamily->setCurrentIndex(0); + uiFontPointSize->setDisabled(true); + } else { + uiFontFamily->setCurrentIndex(uiFontFamily->findText(curUIFontFamily)); + } + + connect(uiFontFamily, &QFontComboBox::currentFontChanged, this, [this](const QFont &font) { + QString value; + if (font.family() == tr("system default")) { + uiFontPointSize->setDisabled(true); + SettingsGroup("UI").setValue("Fonts/pointSize", ""); + value = ""; + } else { + uiFontPointSize->setDisabled(false); + if (uiFontPointSize->currentIndex() == -1) { + uiFontPointSize->setCurrentIndex(3); + SettingsGroup("UI").setValue("Fonts/pointSize", "9"); + } + value = font.family(); + } + SettingsGroup("UI").setValue("Fonts/family", value); + }); + + for (int i = 6; i <= 18; i++) + uiFontPointSize->addItem(QString::number(i)); + const auto curUIFontPointSize = SettingsGroup("UI").value("Fonts/pointSize", ""); + uiFontPointSize->setCurrentIndex(curUIFontPointSize.toInt() - 6); + + connect(uiFontPointSize, QOverload::of(&QComboBox::currentIndexChanged), this, [this](const QString &text) { + SettingsGroup("UI").setValue("Fonts/pointSize", text); + }); + // closeToTray closeToTray->setChecked(SettingsGroup("UI").value("close_to_tray", false).toBool()); connect(closeToTray, &QAbstractButton::toggled, this, [=](bool checked) { @@ -78,6 +115,44 @@ GeneralPage::GeneralPage(SettingsDialog *parent): emit timelineChanged(); }); + // timelineFont + const auto curTimelineFontFamily = SettingsGroup("UI").value("Fonts/timeline_family", "").toString(); + timelineFontFamily->insertItem(0, tr("system default")); + if (curTimelineFontFamily == "") { + timelineFontFamily->setCurrentIndex(0); + timelineFontPointSize->setDisabled(true); + } else { + timelineFontFamily->setCurrentIndex(timelineFontFamily->findText(curTimelineFontFamily)); + } + + connect(timelineFontFamily, &QFontComboBox::currentFontChanged, this, [this](const QFont &font) { + QString value; + if (font.family() == tr("system default")) { + timelineFontPointSize->setDisabled(true); + SettingsGroup("UI").setValue("Fonts/timeline_pointSize", ""); + value = ""; + } else { + timelineFontPointSize->setDisabled(false); + if (timelineFontPointSize->currentIndex() == -1) { + timelineFontPointSize->setCurrentIndex(3); + SettingsGroup("UI").setValue("Fonts/timeline_pointSize", "9"); + } + value = font.family(); + } + SettingsGroup("UI").setValue("Fonts/timeline_family", value); + emit timelineChanged(); + }); + + for (int i = 6; i <= 18; i++) + timelineFontPointSize->addItem(QString::number(i)); + const auto curTimelineFontPointSize = SettingsGroup("UI").value("Fonts/timeline_pointSize", ""); + timelineFontPointSize->setCurrentIndex(curTimelineFontPointSize.toInt() - 6); + + connect(timelineFontPointSize, QOverload::of(&QComboBox::currentIndexChanged), this, [this](const QString &text) { + SettingsGroup("UI").setValue("Fonts/timeline_pointSize", text); + emit timelineChanged(); + }); + // useShuttleScrollbar useShuttleScrollbar->setChecked(SettingsGroup("UI").value("use_shuttle_dial", true).toBool()); connect(useShuttleScrollbar, &QAbstractButton::toggled, this, [=](bool checked) { diff --git a/client/settingsgeneralpage.ui b/client/settingsgeneralpage.ui index 5291039a8..6d8563608 100644 --- a/client/settingsgeneralpage.ui +++ b/client/settingsgeneralpage.ui @@ -42,6 +42,34 @@ + + + + QFormLayout::FieldsStayAtSizeHint + + + + + UI font + + + + + + + + + + + + false + + + + + + + @@ -96,6 +124,27 @@ + + + + Font + + + + + + + + + + + + false + + + + +