diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4256abdf..d743a9b0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
- Minor: Added setting for character limit of deleted messages. (#6491)
- Minor: Added link support to plugin message API. (#6386, #6527)
- Minor: Added a description for the logging option under moderation tab. (#6514)
+- Minor: Consolidate font picking into one dialog. (#6531)
- Minor: Added a menu action to sort tabs alphabetically. (#6551)
- Minor: Fixed "edit hotkey" dialog opening like a normal window. (#6540)
- Bugfix: Expose the "Extra extension IDs" setting on non-Windows systems too. (#6509)
diff --git a/resources/buttons/edit.svg b/resources/buttons/edit.svg
new file mode 100644
index 00000000..f18c2b9e
--- /dev/null
+++ b/resources/buttons/edit.svg
@@ -0,0 +1 @@
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4ff72e04..a4c04de2 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -646,6 +646,22 @@ set(SOURCE_FILES
widgets/dialogs/EditUserNotesDialog.hpp
widgets/dialogs/EmotePopup.cpp
widgets/dialogs/EmotePopup.hpp
+
+ widgets/dialogs/font/FontDialog.cpp
+ widgets/dialogs/font/FontDialog.hpp
+ widgets/dialogs/font/FontFamilyWidget.cpp
+ widgets/dialogs/font/FontFamilyWidget.hpp
+ widgets/dialogs/font/FontSettingDialog.cpp
+ widgets/dialogs/font/FontSettingDialog.hpp
+ widgets/dialogs/font/FontSizeWidget.cpp
+ widgets/dialogs/font/FontSizeWidget.hpp
+ widgets/dialogs/font/FontWeightWidget.cpp
+ widgets/dialogs/font/FontWeightWidget.hpp
+ widgets/dialogs/font/IntItem.cpp
+ widgets/dialogs/font/IntItem.hpp
+ widgets/dialogs/font/PreviewWidget.cpp
+ widgets/dialogs/font/PreviewWidget.hpp
+
widgets/dialogs/LastRunCrashDialog.cpp
widgets/dialogs/LastRunCrashDialog.hpp
widgets/dialogs/LoginDialog.cpp
@@ -700,6 +716,8 @@ set(SOURCE_FILES
widgets/helper/DebugPopup.hpp
widgets/helper/EditableModelView.cpp
widgets/helper/EditableModelView.hpp
+ widgets/helper/FontSettingWidget.cpp
+ widgets/helper/FontSettingWidget.hpp
widgets/helper/IconDelegate.cpp
widgets/helper/IconDelegate.hpp
widgets/helper/InvisibleSizeGrip.cpp
diff --git a/src/widgets/dialogs/font/FontDialog.cpp b/src/widgets/dialogs/font/FontDialog.cpp
new file mode 100644
index 00000000..136411e6
--- /dev/null
+++ b/src/widgets/dialogs/font/FontDialog.cpp
@@ -0,0 +1,86 @@
+#include "widgets/dialogs/font/FontDialog.hpp"
+
+#include "widgets/dialogs/font/FontFamilyWidget.hpp"
+#include "widgets/dialogs/font/FontSizeWidget.hpp"
+#include "widgets/dialogs/font/FontWeightWidget.hpp"
+#include "widgets/dialogs/font/PreviewWidget.hpp"
+
+#include
+#include
+#include
+
+namespace chatterino {
+
+FontDialog::FontDialog(const QFont &startFont, QWidget *parent)
+ : QDialog(parent)
+ , preview(new PreviewWidget(startFont))
+ , familyW(new FontFamilyWidget(startFont))
+ , sizeW(new FontSizeWidget(startFont))
+ , weightW(new FontWeightWidget(startFont))
+{
+ auto *layout = new QVBoxLayout;
+ auto *choiceLayout = new QHBoxLayout;
+ auto *choiceSideLayout = new QVBoxLayout;
+ auto *buttonLayout = new QHBoxLayout;
+
+ auto *applyButton = new QPushButton("Apply");
+ auto *acceptButton = new QPushButton("Ok");
+ auto *rejectButton = new QPushButton("Cancel");
+
+ this->setWindowTitle("Pick Font");
+ this->setLayout(layout);
+ this->resize(450, 450);
+
+ layout->addLayout(choiceLayout, 5);
+ layout->addWidget(new QLabel("Preview"));
+ layout->addWidget(this->preview, 1);
+ layout->addLayout(buttonLayout);
+
+ choiceLayout->addWidget(this->familyW, 5);
+ choiceLayout->addLayout(choiceSideLayout, 3);
+
+ choiceSideLayout->addWidget(this->sizeW);
+ choiceSideLayout->addWidget(this->weightW);
+
+ buttonLayout->addWidget(applyButton);
+ buttonLayout->addStretch();
+ buttonLayout->addWidget(acceptButton);
+ buttonLayout->addWidget(rejectButton);
+
+ QObject::connect(applyButton, &QPushButton::clicked, this,
+ &FontDialog::applied);
+
+ QObject::connect(acceptButton, &QPushButton::clicked, this,
+ &FontDialog::accept);
+
+ QObject::connect(rejectButton, &QPushButton::clicked, this,
+ &FontDialog::reject);
+
+ QObject::connect(this->familyW, &FontFamilyWidget::selectedChanged, this,
+ [this] {
+ this->weightW->setFamily(this->familyW->getSelected());
+ this->updatePreview();
+ });
+
+ QObject::connect(this->weightW, &FontWeightWidget::selectedChanged, this,
+ &FontDialog::updatePreview);
+
+ QObject::connect(this->sizeW, &FontSizeWidget::selectedChanged, this,
+ &FontDialog::updatePreview);
+}
+
+QFont FontDialog::getSelected() const
+{
+ return {
+ this->familyW->getSelected(),
+ this->sizeW->getSelected(),
+ this->weightW->getSelected(),
+ };
+}
+
+void FontDialog::updatePreview()
+{
+ this->preview->setFont(this->getSelected());
+}
+
+} // namespace chatterino
diff --git a/src/widgets/dialogs/font/FontDialog.hpp b/src/widgets/dialogs/font/FontDialog.hpp
new file mode 100644
index 00000000..3a15b30e
--- /dev/null
+++ b/src/widgets/dialogs/font/FontDialog.hpp
@@ -0,0 +1,36 @@
+#pragma once
+
+#include
+#include
+#include
+
+namespace chatterino {
+
+class PreviewWidget;
+class FontFamilyWidget;
+class FontSizeWidget;
+class FontWeightWidget;
+
+class FontDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ FontDialog(const QFont &startFont, QWidget *parent = nullptr);
+
+ /// Gets the currently selected font.
+ QFont getSelected() const;
+
+Q_SIGNALS:
+ void applied();
+
+private:
+ void updatePreview();
+
+ PreviewWidget *preview;
+ FontFamilyWidget *familyW;
+ FontSizeWidget *sizeW;
+ FontWeightWidget *weightW;
+};
+
+} // namespace chatterino
diff --git a/src/widgets/dialogs/font/FontFamilyWidget.cpp b/src/widgets/dialogs/font/FontFamilyWidget.cpp
new file mode 100644
index 00000000..7e5a3054
--- /dev/null
+++ b/src/widgets/dialogs/font/FontFamilyWidget.cpp
@@ -0,0 +1,89 @@
+#include "widgets/dialogs/font/FontFamilyWidget.hpp"
+
+#include
+#include
+#include
+#include
+
+namespace chatterino {
+
+namespace {
+
+/// Gets a list of available font families available on this system
+QStringList getFontFamilies()
+{
+ QStringList families = QFontDatabase::families();
+ families.removeIf(QFontDatabase::isPrivateFamily);
+ return families;
+}
+
+} // namespace
+
+FontFamilyWidget::FontFamilyWidget(const QFont &startFont, QWidget *parent)
+ : QWidget(parent)
+ , list(new QListView)
+ , model(new QStringListModel(getFontFamilies(), this))
+ , proxy(new QSortFilterProxyModel(this))
+{
+ auto *layout = new QVBoxLayout;
+ auto *header = new QHBoxLayout;
+ auto *search = new QLineEdit;
+
+ this->setLayout(layout);
+
+ this->list->setModel(this->proxy);
+ this->list->setEditTriggers(QAbstractItemView::NoEditTriggers);
+
+ this->proxy->setSourceModel(this->model);
+ this->proxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
+
+ this->setSelected(startFont.family());
+
+ layout->addLayout(header);
+ layout->addWidget(this->list);
+ layout->setContentsMargins(0, 0, 0, 0);
+
+ header->addWidget(new QLabel("Font"));
+ header->addWidget(search);
+
+ search->setPlaceholderText("Search...");
+
+ QObject::connect(search, &QLineEdit::textChanged, this->proxy,
+ &QSortFilterProxyModel::setFilterFixedString);
+
+ QObject::connect(
+ this->list->selectionModel(), &QItemSelectionModel::currentChanged,
+ this, [this](const QModelIndex &proxyIndex, const QModelIndex &) {
+ if (proxyIndex.isValid())
+ {
+ Q_EMIT this->selectedChanged();
+ }
+ });
+}
+
+void FontFamilyWidget::setSelected(const QString &family)
+{
+ qsizetype row = this->model->stringList().indexOf(family);
+ if (row >= 0)
+ {
+ QModelIndex modelIndex = this->model->index(static_cast(row));
+ QModelIndex proxyIndex = this->proxy->mapFromSource(modelIndex);
+
+ this->list->selectionModel()->setCurrentIndex(
+ proxyIndex, QItemSelectionModel::ClearAndSelect);
+ }
+}
+
+QString FontFamilyWidget::getSelected() const
+{
+ QModelIndex proxyIndex = this->list->currentIndex();
+ if (!proxyIndex.isValid())
+ {
+ return {};
+ }
+
+ QModelIndex modelIndex = this->proxy->mapToSource(proxyIndex);
+ return this->model->data(modelIndex).toString();
+}
+
+} // namespace chatterino
diff --git a/src/widgets/dialogs/font/FontFamilyWidget.hpp b/src/widgets/dialogs/font/FontFamilyWidget.hpp
new file mode 100644
index 00000000..725ca5ab
--- /dev/null
+++ b/src/widgets/dialogs/font/FontFamilyWidget.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace chatterino {
+
+class FontFamilyWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ FontFamilyWidget(const QFont &startFont, QWidget *parent = nullptr);
+
+ /// Gets the currently selected font family (e.g. "Arial").
+ QString getSelected() const;
+
+Q_SIGNALS:
+ void selectedChanged();
+
+private:
+ void setSelected(const QString &family);
+
+ QListView *list;
+ QStringListModel *model;
+ QSortFilterProxyModel *proxy;
+};
+
+} // namespace chatterino
diff --git a/src/widgets/dialogs/font/FontSettingDialog.cpp b/src/widgets/dialogs/font/FontSettingDialog.cpp
new file mode 100644
index 00000000..1bf08e61
--- /dev/null
+++ b/src/widgets/dialogs/font/FontSettingDialog.cpp
@@ -0,0 +1,45 @@
+#include "widgets/dialogs/font/FontSettingDialog.hpp"
+
+#include "util/RapidJsonSerializeQString.hpp" // IWYU pragma: keep
+
+namespace chatterino {
+
+FontSettingDialog::FontSettingDialog(QStringSetting &family, IntSetting &size,
+ IntSetting &weight, QWidget *parent)
+ : FontDialog({family, size, weight}, parent)
+ , familySetting(family)
+ , sizeSetting(size)
+ , weightSetting(weight)
+ , oldFamily(family)
+ , oldSize(size)
+ , oldWeight(weight)
+{
+ this->setAttribute(Qt::WA_DeleteOnClose);
+
+ QObject::connect(this, &FontDialog::applied, this,
+ &FontSettingDialog::setSettings);
+
+ QObject::connect(this, &FontDialog::rejected, this,
+ &FontSettingDialog::restoreSettings);
+
+ QObject::connect(this, &FontDialog::accepted, this,
+ &FontSettingDialog::setSettings);
+}
+
+void FontSettingDialog::setSettings()
+{
+ const auto selected = this->getSelected();
+
+ this->familySetting.setValue(selected.family());
+ this->sizeSetting.setValue(selected.pointSize());
+ this->weightSetting.setValue(selected.weight());
+}
+
+void FontSettingDialog::restoreSettings()
+{
+ this->familySetting.setValue(this->oldFamily);
+ this->sizeSetting.setValue(this->oldSize);
+ this->weightSetting.setValue(this->oldWeight);
+}
+
+} // namespace chatterino
diff --git a/src/widgets/dialogs/font/FontSettingDialog.hpp b/src/widgets/dialogs/font/FontSettingDialog.hpp
new file mode 100644
index 00000000..fecbfc0b
--- /dev/null
+++ b/src/widgets/dialogs/font/FontSettingDialog.hpp
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "common/ChatterinoSetting.hpp"
+#include "widgets/dialogs/font/FontDialog.hpp"
+
+#include
+
+namespace chatterino {
+
+class FontSettingDialog : public FontDialog
+{
+ Q_OBJECT
+
+public:
+ FontSettingDialog(QStringSetting &family, IntSetting &size,
+ IntSetting &weight, QWidget *parent = nullptr);
+
+private:
+ /// Apply the current dialog's values to the font settings
+ void setSettings();
+
+ /// Restore the original setting values to the font settings
+ void restoreSettings();
+
+ QStringSetting &familySetting;
+ IntSetting &sizeSetting;
+ IntSetting &weightSetting;
+
+ QString oldFamily;
+ int oldSize;
+ int oldWeight;
+};
+
+} // namespace chatterino
diff --git a/src/widgets/dialogs/font/FontSizeWidget.cpp b/src/widgets/dialogs/font/FontSizeWidget.cpp
new file mode 100644
index 00000000..20d6f8d5
--- /dev/null
+++ b/src/widgets/dialogs/font/FontSizeWidget.cpp
@@ -0,0 +1,79 @@
+#include "widgets/dialogs/font/FontSizeWidget.hpp"
+
+#include "widgets/dialogs/font/IntItem.hpp"
+
+#include
+#include
+#include
+#include
+
+namespace chatterino {
+
+FontSizeWidget::FontSizeWidget(const QFont &startFont, QWidget *parent)
+ : QWidget(parent)
+ , customItem(new IntItem)
+ , list(new QListWidget)
+ , edit(new QSpinBox)
+{
+ auto *layout = new QVBoxLayout;
+ auto *header = new QHBoxLayout;
+
+ this->setLayout(layout);
+
+ this->edit->setMinimum(1);
+ this->list->setSortingEnabled(true);
+ this->list->addItem(this->customItem);
+
+ for (int size : QFontDatabase::standardSizes())
+ {
+ this->list->addItem(new IntItem(size));
+ }
+
+ this->edit->setValue(startFont.pointSize());
+ this->setListSelected(startFont.pointSize());
+
+ layout->addLayout(header);
+ layout->addWidget(this->list);
+ layout->setContentsMargins(0, 0, 0, 0);
+
+ header->addWidget(new QLabel("Size"));
+ header->addWidget(this->edit);
+
+ QObject::connect(this->edit, &QSpinBox::valueChanged, this,
+ [this](int value) {
+ QSignalBlocker listSignalBlocker(this->list);
+ this->setListSelected(value);
+ Q_EMIT this->selectedChanged();
+ });
+
+ QObject::connect(this->list, &QListWidget::currentItemChanged, this,
+ [this](QListWidgetItem *item) {
+ auto *cast = dynamic_cast(item);
+ assert(cast);
+ QSignalBlocker editSignalBlocker(this->edit);
+ this->edit->setValue(cast->getValue());
+ Q_EMIT this->selectedChanged();
+ });
+}
+
+int FontSizeWidget::getSelected() const
+{
+ auto *item = dynamic_cast(this->list->currentItem());
+ return item ? item->getValue() : -1;
+}
+
+void FontSizeWidget::setListSelected(int size)
+{
+ if (IntItem *item = findIntItemInList(this->list, size))
+ {
+ this->customItem->setHidden(item != this->customItem);
+ this->list->setCurrentItem(item);
+ return;
+ }
+
+ this->customItem->setValue(size);
+ this->customItem->setHidden(false);
+ this->list->setCurrentItem(this->customItem);
+}
+
+} // namespace chatterino
diff --git a/src/widgets/dialogs/font/FontSizeWidget.hpp b/src/widgets/dialogs/font/FontSizeWidget.hpp
new file mode 100644
index 00000000..5e4578a9
--- /dev/null
+++ b/src/widgets/dialogs/font/FontSizeWidget.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+namespace chatterino {
+
+class IntItem;
+
+/// FontSizeWidget shows a subset of the possible font sizes in a list,
+/// alongside a spinbox where the user can enter their exact font size.
+class FontSizeWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ FontSizeWidget(const QFont &startFont, QWidget *parent = nullptr);
+
+ /// Gets the currently selected font size.
+ int getSelected() const;
+
+Q_SIGNALS:
+ void selectedChanged();
+
+private:
+ void setListSelected(int size);
+
+ IntItem *customItem; // displays the value from `edit`
+ QListWidget *list;
+ QSpinBox *edit;
+};
+
+} // namespace chatterino
diff --git a/src/widgets/dialogs/font/FontWeightWidget.cpp b/src/widgets/dialogs/font/FontWeightWidget.cpp
new file mode 100644
index 00000000..bd18168b
--- /dev/null
+++ b/src/widgets/dialogs/font/FontWeightWidget.cpp
@@ -0,0 +1,110 @@
+#include "widgets/dialogs/font/FontWeightWidget.hpp"
+
+#include "widgets/dialogs/font/IntItem.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace chatterino {
+
+namespace {
+
+/// Get a list of weights available for the given font family
+QList getWeights(const QString &family)
+{
+ QList weights;
+ QStringList styles = QFontDatabase::styles(family);
+
+ for (const QString &style : styles)
+ {
+ int weight = QFontDatabase::weight(family, style);
+ if (!weights.contains(weight))
+ {
+ weights.append(weight);
+ }
+ }
+
+ return weights;
+}
+
+} // namespace
+
+FontWeightWidget::FontWeightWidget(const QFont &startFont, QWidget *parent)
+ : QWidget(parent)
+ , list(new QListWidget)
+{
+ auto *layout = new QVBoxLayout;
+
+ this->setLayout(layout);
+
+ this->setFamily(startFont.family());
+ if (IntItem *item = findIntItemInList(this->list, startFont.weight()))
+ {
+ this->list->setCurrentItem(item);
+ }
+
+ layout->addWidget(new QLabel("Weight"));
+ layout->addWidget(this->list);
+ layout->setContentsMargins(0, 0, 0, 0);
+
+ QObject::connect(this->list, &QListWidget::currentRowChanged, this,
+ [this](int row) {
+ if (row >= 0)
+ {
+ Q_EMIT this->selectedChanged();
+ }
+ });
+}
+
+void FontWeightWidget::setFamily(const QString &family)
+{
+ QSignalBlocker listSignalBlocker{this->list};
+
+ QList weights = getWeights(family);
+ int currentCount = this->list->count();
+ int newCount = static_cast(weights.count());
+ int leastCount = std::min(currentCount, newCount);
+
+ std::ranges::sort(weights);
+
+ for (int i = 0; i < leastCount; ++i)
+ {
+ auto *cast = dynamic_cast(this->list->item(i));
+ assert(cast);
+ cast->setValue(weights[i]);
+ cast->setHidden(false);
+ }
+ for (int i = currentCount; i < newCount; ++i)
+ {
+ this->list->addItem(new IntItem(weights[i]));
+ }
+ for (int i = newCount; i < currentCount; ++i)
+ {
+ this->list->item(i)->setHidden(true);
+ }
+
+ int startRow = 0;
+ for (int closest = INT_MAX, i = 0; i < weights.count(); ++i)
+ {
+ int diff = std::abs(weights[i] - QFont::Normal);
+ if (diff < closest)
+ {
+ closest = diff;
+ startRow = i;
+ }
+ }
+
+ this->list->setCurrentRow(startRow);
+}
+
+int FontWeightWidget::getSelected() const
+{
+ auto *cast = dynamic_cast(this->list->currentItem());
+ return cast ? cast->getValue() : -1;
+}
+
+} // namespace chatterino
diff --git a/src/widgets/dialogs/font/FontWeightWidget.hpp b/src/widgets/dialogs/font/FontWeightWidget.hpp
new file mode 100644
index 00000000..ab14a48b
--- /dev/null
+++ b/src/widgets/dialogs/font/FontWeightWidget.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+namespace chatterino {
+
+/// FontWeightWidget shows a list of available font weights for a given font family.
+class FontWeightWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ FontWeightWidget(const QFont &startFont, QWidget *parent = nullptr);
+
+ /// Update the font family, resetting the selected font weight to the weight
+ /// that's closest to "normal".
+ void setFamily(const QString &family);
+
+ /// Gets the currently selected font weight.
+ int getSelected() const;
+
+Q_SIGNALS:
+ void selectedChanged();
+
+private:
+ QListWidget *list;
+};
+
+} // namespace chatterino
diff --git a/src/widgets/dialogs/font/IntItem.cpp b/src/widgets/dialogs/font/IntItem.cpp
new file mode 100644
index 00000000..39f3cee9
--- /dev/null
+++ b/src/widgets/dialogs/font/IntItem.cpp
@@ -0,0 +1,50 @@
+#include "widgets/dialogs/font/IntItem.hpp"
+
+namespace chatterino {
+
+IntItem::IntItem(int v, QListWidget *parent)
+ : QListWidgetItem(QString::number(v), parent, IntItem::TYPE_ID)
+ , value(v)
+{
+}
+
+bool IntItem::operator<(const QListWidgetItem &other) const
+{
+ const auto *cast = dynamic_cast(&other);
+ if (cast == nullptr)
+ {
+ assert(cast && "IntItem may only be compared with other list items");
+ return false;
+ }
+
+ return this->value < cast->value;
+}
+
+void IntItem::setValue(int v)
+{
+ this->value = v;
+ QListWidgetItem::setText(QString::number(v));
+}
+
+int IntItem::getValue() const
+{
+ return this->value;
+}
+
+IntItem *findIntItemInList(QListWidget *list, int value)
+{
+ int numItems = list->count();
+
+ for (int i = 0; i < numItems; ++i)
+ {
+ auto *item = dynamic_cast(list->item(i));
+ if (item && item->getValue() == value)
+ {
+ return item;
+ }
+ }
+
+ return nullptr;
+}
+
+} // namespace chatterino
diff --git a/src/widgets/dialogs/font/IntItem.hpp b/src/widgets/dialogs/font/IntItem.hpp
new file mode 100644
index 00000000..adc1bbec
--- /dev/null
+++ b/src/widgets/dialogs/font/IntItem.hpp
@@ -0,0 +1,34 @@
+#pragma once
+
+#include
+#include
+#include
+
+namespace chatterino {
+
+class IntItem : public QListWidgetItem
+{
+public:
+ static constexpr int TYPE_ID = QListWidgetItem::UserType + 101;
+
+ IntItem(int v = 0, QListWidget *parent = nullptr);
+
+ /// setText should not be used, we only store int values in this item
+ ///
+ /// use setValue instead.
+ void setText(const QString &) = delete;
+
+ bool operator<(const QListWidgetItem &other) const override;
+
+ void setValue(int v);
+ int getValue() const;
+
+private:
+ int value;
+};
+
+/// Iterate through all items in the given list and return the item
+/// matching the given value
+IntItem *findIntItemInList(QListWidget *list, int value);
+
+} // namespace chatterino
diff --git a/src/widgets/dialogs/font/PreviewWidget.cpp b/src/widgets/dialogs/font/PreviewWidget.cpp
new file mode 100644
index 00000000..f0f08007
--- /dev/null
+++ b/src/widgets/dialogs/font/PreviewWidget.cpp
@@ -0,0 +1,32 @@
+#include "widgets/dialogs/font/PreviewWidget.hpp"
+
+#include
+
+namespace chatterino {
+
+PreviewWidget::PreviewWidget(const QFont &startFont, QWidget *parent)
+ : QWidget(parent)
+ , font(startFont)
+{
+ this->setMinimumHeight(60);
+}
+
+void PreviewWidget::paintEvent(QPaintEvent * /* event */)
+{
+ QPainter painter{this};
+
+ painter.fillRect(this->rect(), this->palette().base());
+ painter.setFont(this->font);
+ painter.drawText(
+ this->rect().adjusted(3, 3, -3, -3),
+ Qt::AlignCenter | Qt::TextSingleLine,
+ QStringLiteral("The quick brown fox jumps over the lazy dog"));
+}
+
+void PreviewWidget::setFont(const QFont &font)
+{
+ this->font = font;
+ this->update();
+}
+
+} // namespace chatterino
diff --git a/src/widgets/dialogs/font/PreviewWidget.hpp b/src/widgets/dialogs/font/PreviewWidget.hpp
new file mode 100644
index 00000000..2e1aa864
--- /dev/null
+++ b/src/widgets/dialogs/font/PreviewWidget.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include
+#include
+#include
+
+namespace chatterino {
+
+class PreviewWidget : public QWidget
+{
+public:
+ PreviewWidget(const QFont &startFont, QWidget *parent = nullptr);
+
+ void setFont(const QFont &font);
+
+ void paintEvent(QPaintEvent *event) override;
+
+private:
+ QFont font;
+};
+
+} // namespace chatterino
diff --git a/src/widgets/helper/FontSettingWidget.cpp b/src/widgets/helper/FontSettingWidget.cpp
new file mode 100644
index 00000000..172c8f51
--- /dev/null
+++ b/src/widgets/helper/FontSettingWidget.cpp
@@ -0,0 +1,69 @@
+#include "widgets/helper/FontSettingWidget.hpp"
+
+#include "Application.hpp"
+#include "singletons/Fonts.hpp"
+#include "singletons/Settings.hpp"
+#include "widgets/dialogs/font/FontSettingDialog.hpp"
+
+#include
+#include
+#include
+#include
+
+namespace chatterino {
+
+FontSettingWidget::FontSettingWidget(QStringSetting &family, IntSetting &size,
+ IntSetting &weight, QWidget *parent)
+ : QWidget(parent)
+ , familySetting(family)
+ , sizeSetting(size)
+ , weightSetting(weight)
+ , currentLabel(new QLabel)
+ , listener([this] {
+ this->updateCurrentLabel();
+ })
+{
+ auto *layout = new QHBoxLayout;
+ auto *button = new QToolButton;
+
+ this->setLayout(layout);
+ this->updateCurrentLabel();
+
+ this->listener.add(getApp()->getFonts()->fontChanged);
+
+ layout->addWidget(new QLabel("Font:"));
+ layout->addStretch(1);
+ layout->addWidget(this->currentLabel);
+ layout->addWidget(button);
+ layout->setContentsMargins(0, 0, 0, 0);
+
+ button->setIcon(QIcon(":/buttons/edit.svg"));
+
+ QObject::connect(button, &QToolButton::clicked, this,
+ &FontSettingWidget::showDialog);
+}
+
+void FontSettingWidget::updateCurrentLabel()
+{
+ QFont font = getApp()->getFonts()->getFont(FontStyle::ChatMedium, 1);
+ QString family = font.family();
+ QString ptSize = QString::number(font.pointSize());
+ this->currentLabel->setText(family + ", " + ptSize + "pt");
+}
+
+void FontSettingWidget::showDialog()
+{
+ if (!this->dialog)
+ {
+ this->dialog = new FontSettingDialog(
+ this->familySetting, this->sizeSetting, this->weightSetting, this);
+
+ QObject::connect(this->dialog, &QObject::destroyed, [this] {
+ this->dialog = nullptr;
+ });
+ }
+
+ this->dialog->show();
+}
+
+} // namespace chatterino
diff --git a/src/widgets/helper/FontSettingWidget.hpp b/src/widgets/helper/FontSettingWidget.hpp
new file mode 100644
index 00000000..8277c97e
--- /dev/null
+++ b/src/widgets/helper/FontSettingWidget.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "common/ChatterinoSetting.hpp"
+#include "util/SignalListener.hpp"
+
+#include
+#include
+
+namespace chatterino {
+
+class FontSettingDialog;
+
+/// FontSettingWidget includes a label showing the current font and its size, with a button
+/// that opens a FontSettingDialog
+class FontSettingWidget : public QWidget
+{
+public:
+ FontSettingWidget(QStringSetting &family, IntSetting &size,
+ IntSetting &weight, QWidget *parent = nullptr);
+
+private:
+ void updateCurrentLabel();
+ void showDialog();
+
+ FontSettingDialog *dialog = nullptr;
+
+ QStringSetting &familySetting;
+ IntSetting &sizeSetting;
+ IntSetting &weightSetting;
+
+ QLabel *currentLabel;
+ SignalListener listener;
+};
+
+} // namespace chatterino
diff --git a/src/widgets/settingspages/GeneralPage.cpp b/src/widgets/settingspages/GeneralPage.cpp
index 73fa5907..81ae2793 100644
--- a/src/widgets/settingspages/GeneralPage.cpp
+++ b/src/widgets/settingspages/GeneralPage.cpp
@@ -17,6 +17,7 @@
#include "util/Helpers.hpp"
#include "util/IncognitoBrowser.hpp"
#include "widgets/BaseWindow.hpp"
+#include "widgets/helper/FontSettingWidget.hpp"
#include "widgets/settingspages/GeneralPageView.hpp"
#include "widgets/settingspages/SettingWidget.hpp"
@@ -153,34 +154,6 @@ void GeneralPage::initLayout(GeneralPageView &layout)
#endif
}
- layout.addDropdown(
- "Font", {"Segoe UI", "Arial", "Choose..."}, s.chatFontFamily,
- [](auto val) {
- return val;
- },
- [this](auto args) {
- return this->getFont(args);
- },
- true, "", true);
- layout.addDropdown(
- "Font size", {"9pt", "10pt", "12pt", "14pt", "16pt", "20pt"},
- s.chatFontSize,
- [](auto val) {
- return QString::number(val) + "pt";
- },
- [](auto args) {
- return fuzzyToInt(args.value, 10);
- });
- layout.addDropdown(
- "Font weight",
- {"100", "200", "300", "400", "500", "600", "700", "800", "900"},
- s.chatFontWeight,
- [](auto val) {
- return QString::number(val);
- },
- [](auto args) {
- return fuzzyToInt(args.value, 400);
- });
layout.addDropdown(
"Zoom", ZOOM_LEVELS, s.uiScale,
[](auto val) {
@@ -263,6 +236,10 @@ void GeneralPage::initLayout(GeneralPageView &layout)
SettingWidget::dropdown("Tab style", s.tabStyle)->addTo(layout);
+ layout.addWidget(new FontSettingWidget(s.chatFontFamily, s.chatFontSize,
+ s.chatFontWeight),
+ {"font", "weight", "size"});
+
SettingWidget::inverseCheckbox("Show message reply context",
s.hideReplyContext)
->setTooltip(
@@ -1541,25 +1518,4 @@ void GeneralPage::initExtra()
}
}
-QString GeneralPage::getFont(const DropdownArgs &args) const
-{
- if (args.combobox->currentIndex() == args.combobox->count() - 1)
- {
- args.combobox->setEditText("Choosing...");
-
- auto ok = bool();
- auto previousFont =
- getApp()->getFonts()->getFont(FontStyle::ChatMedium, 1.);
- auto font = QFontDialog::getFont(&ok, previousFont, this->window());
-
- if (ok)
- {
- return font.family();
- }
-
- return previousFont.family();
- }
- return args.value;
-}
-
} // namespace chatterino