mirror-chatterino2/src/widgets/settingsdialog.cpp

611 lines
21 KiB
C++
Raw Normal View History

2017-06-11 09:31:45 +02:00
#include "widgets/settingsdialog.hpp"
#include "accountmanager.hpp"
#include "twitch/twitchmessagebuilder.hpp"
2017-06-11 09:31:45 +02:00
#include "twitch/twitchuser.hpp"
#include "widgets/logindialog.hpp"
2017-06-11 09:31:45 +02:00
#include "widgets/settingsdialogtab.hpp"
#include "windowmanager.hpp"
2017-01-02 03:02:32 +01:00
2017-01-18 04:33:30 +01:00
#include <QComboBox>
#include <QDebug>
2017-01-18 04:33:30 +01:00
#include <QFile>
2017-07-31 00:57:42 +02:00
#include <QFileDialog>
#include <QFontDialog>
2017-01-18 04:33:30 +01:00
#include <QFormLayout>
#include <QGroupBox>
#include <QLabel>
2017-04-13 16:06:23 +02:00
#include <QListWidget>
2017-01-18 04:33:30 +01:00
#include <QPalette>
#include <QResource>
2017-07-31 00:57:42 +02:00
#include <QTextEdit>
2017-01-01 18:43:52 +01:00
2017-04-14 17:52:22 +02:00
namespace chatterino {
namespace widgets {
2017-01-18 21:30:23 +01:00
2017-01-01 18:43:52 +01:00
SettingsDialog::SettingsDialog()
2017-07-02 12:36:50 +02:00
: snapshot(SettingsManager::getInstance().createSnapshot())
, usernameDisplayMode(
"/appearance/messages/usernameDisplayMode",
twitch::TwitchMessageBuilder::UsernameDisplayMode::UsernameAndLocalizedName)
2017-01-01 18:43:52 +01:00
{
2017-01-02 03:02:32 +01:00
QFile file(":/qss/settings.qss");
file.open(QFile::ReadOnly);
QString styleSheet = QLatin1String(file.readAll());
2017-07-02 12:36:50 +02:00
this->setStyleSheet(styleSheet);
2017-01-02 03:02:32 +01:00
QPalette palette;
palette.setColor(QPalette::Background, QColor("#444"));
2017-07-02 12:36:50 +02:00
this->setPalette(palette);
2017-01-02 03:02:32 +01:00
2017-07-02 12:36:50 +02:00
this->ui.pageStack.setObjectName("pages");
2017-01-02 03:02:32 +01:00
2017-07-02 12:36:50 +02:00
this->setLayout(&this->ui.vbox);
2017-01-02 03:02:32 +01:00
2017-07-02 12:36:50 +02:00
this->ui.vbox.addLayout(&this->ui.hbox);
2017-01-02 03:02:32 +01:00
2017-07-02 12:36:50 +02:00
this->ui.vbox.addWidget(&this->ui.buttonBox);
2017-01-02 03:02:32 +01:00
auto tabWidget = new QWidget();
tabWidget->setObjectName("tabWidget");
2017-07-02 12:36:50 +02:00
tabWidget->setLayout(&this->ui.tabs);
2017-01-02 03:02:32 +01:00
tabWidget->setFixedWidth(200);
2017-07-02 12:36:50 +02:00
this->ui.hbox.addWidget(tabWidget);
this->ui.hbox.addLayout(&this->ui.pageStack);
2017-01-02 03:02:32 +01:00
2017-07-02 12:36:50 +02:00
this->ui.buttonBox.addButton(&this->ui.okButton, QDialogButtonBox::ButtonRole::AcceptRole);
this->ui.buttonBox.addButton(&this->ui.cancelButton, QDialogButtonBox::ButtonRole::RejectRole);
2017-01-24 19:51:57 +01:00
2017-07-02 12:36:50 +02:00
QObject::connect(&this->ui.okButton, &QPushButton::clicked, this,
&SettingsDialog::okButtonClicked);
QObject::connect(&this->ui.cancelButton, &QPushButton::clicked, this,
2017-01-24 19:51:57 +01:00
&SettingsDialog::cancelButtonClicked);
2017-07-02 12:36:50 +02:00
this->ui.okButton.setText("OK");
this->ui.cancelButton.setText("Cancel");
2017-01-02 03:02:32 +01:00
2017-07-02 12:36:50 +02:00
this->resize(600, 500);
2017-01-02 03:02:32 +01:00
2017-07-02 12:36:50 +02:00
this->addTabs();
2017-01-02 03:02:32 +01:00
}
2017-04-12 17:46:44 +02:00
void SettingsDialog::addTabs()
2017-01-02 03:02:32 +01:00
{
2017-04-12 17:46:44 +02:00
SettingsManager &settings = SettingsManager::getInstance();
2017-01-22 12:46:35 +01:00
2017-01-11 18:52:09 +01:00
QVBoxLayout *vbox;
2017-01-02 03:02:32 +01:00
2017-04-13 16:06:23 +02:00
// Accounts
vbox = new QVBoxLayout();
{
// add remove buttons
auto buttonBox = new QDialogButtonBox(this);
auto addButton = new QPushButton("Add", this);
auto removeButton = new QPushButton("Remove", this);
connect(addButton, &QPushButton::clicked, []() {
// TODO: fix memory leak :bbaper:
auto loginWidget = new LoginWidget();
loginWidget->show();
});
connect(removeButton, &QPushButton::clicked, []() {
qDebug() << "TODO: Implement"; //
});
2017-04-13 16:06:23 +02:00
buttonBox->addButton(addButton, QDialogButtonBox::YesRole);
buttonBox->addButton(removeButton, QDialogButtonBox::NoRole);
vbox->addWidget(buttonBox);
// listview
auto listWidget = new QListWidget(this);
for (auto &user : AccountManager::getInstance().getTwitchUsers()) {
listWidget->addItem(user.getUserName());
}
2017-07-31 00:57:42 +02:00
if (listWidget->count()) {
int itemIndex = 0;
2017-07-31 00:57:42 +02:00
for (; itemIndex < listWidget->count(); ++itemIndex) {
if (listWidget->item(itemIndex)->text().compare(settings.selectedUser.get(),
Qt::CaseInsensitive)) {
++itemIndex;
break;
}
}
listWidget->setCurrentRow(itemIndex);
}
2017-07-31 00:57:42 +02:00
QObject::connect(listWidget, &QListWidget::clicked, this, [&, listWidget] {
if (!listWidget->selectedItems().isEmpty()) {
settings.selectedUser.set(listWidget->currentItem()->text());
}
});
2017-04-13 16:06:23 +02:00
vbox->addWidget(listWidget);
}
// vbox->addStretch(1);
addTab(vbox, "Accounts", ":/images/Message_16xLG.png");
2017-01-02 03:02:32 +01:00
// Appearance
vbox = new QVBoxLayout();
{
2017-01-03 21:19:33 +01:00
auto group = new QGroupBox("Application");
2017-01-02 03:02:32 +01:00
auto form = new QFormLayout();
auto combo = new QComboBox();
auto fontLayout = new QHBoxLayout();
auto fontFamilyLabel = new QLabel("Current font family");
auto fontSizeLabel = new QLabel("Current font size");
auto fontButton = new QPushButton("Select");
fontLayout->addWidget(fontButton);
fontLayout->addWidget(fontFamilyLabel);
fontLayout->addWidget(fontSizeLabel);
{
auto fontManager = FontManager::getInstance();
fontManager.currentFontFamily.getValueChangedSignal().connect(
[fontFamilyLabel](const std::string &newValue) {
fontFamilyLabel->setText(QString::fromStdString(newValue)); //
});
fontManager.currentFontSize.getValueChangedSignal().connect(
[fontSizeLabel](const int &newValue) {
fontSizeLabel->setText(QString(QString::number(newValue))); //
});
}
fontButton->connect(fontButton, &QPushButton::clicked, []() {
auto fontManager = FontManager::getInstance();
QFontDialog dialog(fontManager.getFont(FontManager::Medium));
dialog.connect(&dialog, &QFontDialog::fontSelected, [&dialog](const QFont &font) {
auto fontManager = FontManager::getInstance();
fontManager.currentFontFamily = font.family().toStdString();
fontManager.currentFontSize = font.pointSize();
});
dialog.show();
dialog.exec();
});
2017-02-02 02:46:33 +01:00
auto compactTabs = createCheckbox("Hide tab X", settings.hideTabX);
2017-04-12 17:46:44 +02:00
auto hidePreferencesButton = createCheckbox("Hide preferences button (ctrl+p to show)",
settings.hidePreferencesButton);
auto hideUserButton = createCheckbox("Hide user button", settings.hideUserButton);
2017-01-02 03:02:32 +01:00
form->addRow("Theme:", combo);
{
auto hbox = new QHBoxLayout();
auto slider = new QSlider(Qt::Horizontal);
// Theme hue
slider->setMinimum(0);
slider->setMaximum(1000);
2017-07-02 12:36:50 +02:00
pajlada::Settings::Setting<double> themeHue("/appearance/theme/hue");
slider->setValue(std::min(std::max(themeHue.getValue(), 0.0), 1.0) * 1000);
hbox->addWidget(slider);
auto button = new QPushButton();
button->setFlat(true);
hbox->addWidget(button);
form->addRow("Theme color:", hbox);
2017-07-02 12:36:50 +02:00
QObject::connect(slider, &QSlider::valueChanged, this, [button](int value) mutable {
double newValue = value / 1000.0;
pajlada::Settings::Setting<double> themeHue("/appearance/theme/hue");
themeHue.setValue(newValue);
QPalette pal = button->palette();
QColor color;
2017-07-02 12:36:50 +02:00
color.setHsvF(newValue, 1.0, 1.0, 1.0);
pal.setColor(QPalette::Button, color);
button->setAutoFillBackground(true);
button->setPalette(pal);
button->update();
// TODO(pajlada): re-implement
// this->windowManager.updateAll();
});
}
form->addRow("Font:", fontLayout);
form->addRow("Tab bar:", compactTabs);
2017-02-02 02:46:33 +01:00
form->addRow("", hidePreferencesButton);
form->addRow("", hideUserButton);
2017-01-02 03:02:32 +01:00
2017-07-02 12:36:50 +02:00
{
// Theme name
combo->addItems({
"White", //
"Light", //
"Dark", //
"Black", //
});
// combo->addItem("White");
// combo->addItem("Light");
// combo->addItem("Dark");
// combo->addItem("Black");
2017-02-02 01:23:26 +01:00
2017-07-02 12:36:50 +02:00
QString currentComboText = QString::fromStdString(
pajlada::Settings::Setting<std::string>::get("/appearance/theme/name"));
2017-02-02 01:23:26 +01:00
2017-07-02 12:36:50 +02:00
combo->setCurrentText(currentComboText);
2017-02-02 01:23:26 +01:00
2017-07-02 12:36:50 +02:00
QObject::connect(combo, &QComboBox::currentTextChanged, this, [](const QString &value) {
pajlada::Settings::Setting<std::string>::set("/appearance/theme/name",
value.toStdString());
});
}
2017-02-02 01:23:26 +01:00
2017-01-03 21:19:33 +01:00
group->setLayout(form);
vbox->addWidget(group);
}
{
auto group = new QGroupBox("Messages");
auto v = new QVBoxLayout();
v->addWidget(createCheckbox("Show timestamp", settings.showTimestamps));
2017-04-12 17:46:44 +02:00
v->addWidget(createCheckbox("Show seconds in timestamp", settings.showTimestampSeconds));
v->addWidget(createCheckbox("Show badges", settings.showBadges));
2017-04-12 17:46:44 +02:00
v->addWidget(createCheckbox("Allow sending duplicate messages (add a space at the end)",
settings.allowDouplicateMessages));
v->addWidget(createCheckbox("Seperate messages", settings.seperateMessages));
v->addWidget(createCheckbox("Show message length", settings.showMessageLength));
v->addLayout(this->createCombobox(
"Username display mode", this->usernameDisplayMode,
{"Username (Localized name)", "Username", "Localized name"},
[](const QString &newValue, pajlada::Settings::Setting<int> &setting) {
if (newValue == "Username (Localized name)") {
setting =
twitch::TwitchMessageBuilder::UsernameDisplayMode::UsernameAndLocalizedName;
} else if (newValue == "Username") {
setting = twitch::TwitchMessageBuilder::UsernameDisplayMode::Username;
} else if (newValue == "Localized name") {
setting = twitch::TwitchMessageBuilder::UsernameDisplayMode::LocalizedName;
}
}));
2017-01-03 21:19:33 +01:00
group->setLayout(v);
vbox->addWidget(group);
2017-01-02 03:02:32 +01:00
}
vbox->addStretch(1);
addTab(vbox, "Appearance", ":/images/AppearanceEditorPart_16x.png");
2017-01-03 21:19:33 +01:00
// Behaviour
vbox = new QVBoxLayout();
{
2017-04-13 16:06:23 +02:00
auto form = new QFormLayout();
form->addRow("Window:", createCheckbox("Window always on top", settings.windowTopMost));
form->addRow("Messages:", createCheckbox("Mention users with a @ (except in commands)",
settings.mentionUsersWithAt));
form->addRow("", createCheckbox("Hide input box if empty", settings.hideEmptyInput));
form->addRow("", createCheckbox("Show last read message indicator",
settings.showLastMessageIndicator));
// auto v = new QVBoxLayout();
// v->addWidget(new QLabel("Mouse scroll speed"));
2017-01-03 21:19:33 +01:00
auto scroll = new QSlider(Qt::Horizontal);
2017-04-13 16:06:23 +02:00
form->addRow("Mouse scroll speed:", scroll);
2017-01-03 21:19:33 +01:00
2017-04-13 16:06:23 +02:00
// v->addWidget(scroll);
// v->addStretch(1);
// vbox->addLayout(v);
vbox->addLayout(form);
2017-01-03 21:19:33 +01:00
}
vbox->addStretch(1);
addTab(vbox, "Behaviour", ":/images/AppearanceEditorPart_16x.png");
2017-01-02 03:02:32 +01:00
// Commands
vbox = new QVBoxLayout();
vbox->addWidget(new QLabel());
vbox->addStretch(1);
addTab(vbox, "Commands", ":/images/CustomActionEditor_16x.png");
2017-01-22 12:46:35 +01:00
// Emotes
vbox = new QVBoxLayout();
2017-04-12 17:46:44 +02:00
vbox->addWidget(createCheckbox("Enable Twitch Emotes", settings.enableTwitchEmotes));
vbox->addWidget(createCheckbox("Enable BetterTTV Emotes", settings.enableBttvEmotes));
vbox->addWidget(createCheckbox("Enable FrankerFaceZ Emotes", settings.enableFfzEmotes));
vbox->addWidget(createCheckbox("Enable Gif Emotes", settings.enableGifs));
vbox->addWidget(createCheckbox("Enable Emojis", settings.enableEmojis));
2017-01-22 12:46:35 +01:00
2017-04-12 17:46:44 +02:00
vbox->addWidget(createCheckbox("Enable Twitch Emotes", settings.enableTwitchEmotes));
2017-01-22 12:46:35 +01:00
vbox->addStretch(1);
addTab(vbox, "Emotes", ":/images/Emoji_Color_1F60A_19.png");
// Ignored Users
vbox = new QVBoxLayout();
vbox->addStretch(1);
2017-04-12 17:46:44 +02:00
addTab(vbox, "Ignored Users", ":/images/StatusAnnotations_Blocked_16xLG_color.png");
2017-01-22 12:46:35 +01:00
// Ignored Messages
vbox = new QVBoxLayout();
vbox->addStretch(1);
addTab(vbox, "Ignored Messages", ":/images/Filter_16x.png");
// Links
vbox = new QVBoxLayout();
vbox->addStretch(1);
addTab(vbox, "Links", ":/images/VSO_Link_blue_16x.png");
2017-01-29 13:23:22 +01:00
// Logging
vbox = new QVBoxLayout();
vbox->addStretch(1);
addTab(vbox, "Logs", ":/images/VSO_Link_blue_16x.png");
2017-01-22 12:46:35 +01:00
// Highlighting
vbox = new QVBoxLayout();
auto highlights = new QListWidget();
globalHighlights = highlights;
QStringList items = settings.highlightProperties.get().keys();
highlights->addItems(items);
auto customSound = new QHBoxLayout();
auto soundForm = new QFormLayout();
{
vbox->addWidget(createCheckbox("Enable Highlighting", settings.enableHighlights));
2017-07-31 00:57:42 +02:00
vbox->addWidget(createCheckbox("Highlight messages containing your name",
settings.enableHighlightsSelf));
vbox->addWidget(createCheckbox("Play sound when your name is mentioned",
settings.enableHighlightSound));
vbox->addWidget(createCheckbox("Flash taskbar when your name is mentioned",
settings.enableHighlightTaskbar));
customSound->addWidget(createCheckbox("Custom sound", settings.customHighlightSound));
auto selectBtn = new QPushButton("Select");
2017-07-31 00:57:42 +02:00
QObject::connect(selectBtn, &QPushButton::clicked, this, [&settings, this] {
auto fileName = QFileDialog::getOpenFileName(this, tr("Open Sound"), "",
tr("Image Files (*.mp3 *.wav)"));
settings.pathHighlightSound.set(fileName);
});
customSound->addWidget(selectBtn);
}
soundForm->addRow(customSound);
{
2017-07-31 00:57:42 +02:00
auto hbox = new QHBoxLayout();
auto addBtn = new QPushButton("Add");
auto editBtn = new QPushButton("Edit");
auto delBtn = new QPushButton("Remove");
QObject::connect(addBtn, &QPushButton::clicked, this, [highlights, this, &settings] {
auto show = new QWidget();
auto box = new QBoxLayout(QBoxLayout::TopToBottom);
auto edit = new QLineEdit();
auto add = new QPushButton("Add");
auto sound = new QCheckBox("Play sound");
auto task = new QCheckBox("Flash taskbar");
QObject::connect(add, &QPushButton::clicked, this, [=, &settings] {
if (edit->text().length()) {
highlights->addItem(edit->text());
settings.highlightProperties.insertMap(edit->text(), sound->isChecked(),
task->isChecked());
show->close();
}
});
box->addWidget(edit);
box->addWidget(add);
box->addWidget(sound);
box->addWidget(task);
show->setLayout(box);
show->show();
});
QObject::connect(editBtn, &QPushButton::clicked, this, [highlights, this, &settings] {
if (!highlights->selectedItems().isEmpty()) {
auto show = new QWidget();
auto box = new QBoxLayout(QBoxLayout::TopToBottom);
auto edit = new QLineEdit();
edit->setText(highlights->selectedItems().first()->text());
auto add = new QPushButton("Apply");
auto sound = new QCheckBox("Play sound");
auto task = new QCheckBox("Flash taskbar");
QObject::connect(add, &QPushButton::clicked, this, [=, &settings] {
if (edit->text().length()) {
settings.highlightProperties.getnonConst().remove(
highlights->selectedItems().first()->text());
delete highlights->selectedItems().first();
highlights->addItem(edit->text());
settings.highlightProperties.insertMap(edit->text(), sound->isChecked(),
task->isChecked());
show->close();
}
});
box->addWidget(edit);
box->addWidget(add);
box->addWidget(sound);
sound->setChecked(settings.highlightProperties.get()
.value(highlights->selectedItems().first()->text())
.first);
box->addWidget(task);
task->setChecked(settings.highlightProperties.get()
.value(highlights->selectedItems().first()->text())
.second);
show->setLayout(box);
show->show();
}
});
2017-07-31 00:57:42 +02:00
QObject::connect(delBtn, &QPushButton::clicked, this, [highlights, &settings] {
if (!highlights->selectedItems().isEmpty()) {
settings.highlightProperties.getnonConst().remove(
highlights->selectedItems().first()->text());
delete highlights->selectedItems().first();
}
});
2017-07-31 00:57:42 +02:00
vbox->addLayout(soundForm);
vbox->addWidget(highlights);
2017-07-31 00:57:42 +02:00
hbox->addWidget(addBtn);
hbox->addWidget(editBtn);
hbox->addWidget(delBtn);
2017-07-31 00:57:42 +02:00
vbox->addLayout(hbox);
}
2017-01-22 12:46:35 +01:00
vbox->addStretch(1);
addTab(vbox, "Highlighting", ":/images/format_Bold_16xLG.png");
// Whispers
vbox = new QVBoxLayout();
vbox->addStretch(1);
addTab(vbox, "Whispers", ":/images/Message_16xLG.png");
2017-01-02 03:02:32 +01:00
// Add stretch
2017-07-02 12:36:50 +02:00
this->ui.tabs.addStretch(1);
2017-01-02 03:02:32 +01:00
}
2017-04-12 17:46:44 +02:00
void SettingsDialog::addTab(QLayout *layout, QString title, QString imageRes)
2017-01-02 03:02:32 +01:00
{
auto widget = new QWidget();
widget->setLayout(layout);
auto tab = new SettingsDialogTab(this, title, imageRes);
2017-01-18 04:33:30 +01:00
tab->setWidget(widget);
2017-01-02 03:02:32 +01:00
2017-07-02 12:36:50 +02:00
this->ui.tabs.addWidget(tab, 0, Qt::AlignTop);
2017-01-02 03:02:32 +01:00
2017-07-02 12:36:50 +02:00
this->ui.pageStack.addWidget(widget);
2017-01-02 03:02:32 +01:00
2017-07-02 12:36:50 +02:00
if (this->ui.tabs.count() == 1) {
this->select(tab);
2017-01-02 03:02:32 +01:00
}
}
2017-04-12 17:46:44 +02:00
void SettingsDialog::select(SettingsDialogTab *tab)
2017-01-02 03:02:32 +01:00
{
2017-07-02 12:36:50 +02:00
this->ui.pageStack.setCurrentWidget(tab->getWidget());
2017-01-02 03:02:32 +01:00
2017-07-02 12:36:50 +02:00
if (this->selectedTab != nullptr) {
this->selectedTab->setSelected(false);
this->selectedTab->setStyleSheet("color: #FFF");
2017-01-02 03:02:32 +01:00
}
2017-01-01 18:43:52 +01:00
2017-01-02 03:02:32 +01:00
tab->setSelected(true);
2017-02-02 00:25:57 +01:00
tab->setStyleSheet("background: #555; color: #FFF");
2017-07-02 12:36:50 +02:00
this->selectedTab = tab;
2017-01-01 18:43:52 +01:00
}
void SettingsDialog::showDialog()
{
static SettingsDialog *instance = new SettingsDialog();
instance->show();
instance->activateWindow();
instance->raise();
instance->setFocus();
}
/// Widget creation helpers
2017-04-12 17:46:44 +02:00
QCheckBox *SettingsDialog::createCheckbox(const QString &title, Setting<bool> &setting)
{
auto checkbox = new QCheckBox(title);
// Set checkbox initial state
checkbox->setChecked(setting.get());
2017-07-02 12:36:50 +02:00
QObject::connect(checkbox, &QCheckBox::toggled, this, [&setting](bool state) {
setting.set(state); //
});
return checkbox;
2017-01-18 21:30:23 +01:00
}
QCheckBox *SettingsDialog::createCheckbox(const QString &title,
pajlada::Settings::Setting<bool> &setting)
{
auto checkbox = new QCheckBox(title);
// Set checkbox initial state
checkbox->setChecked(setting.getValue());
QObject::connect(checkbox, &QCheckBox::toggled, this, [&setting](bool state) {
qDebug() << "update checkbox value";
setting = state; //
});
return checkbox;
}
QHBoxLayout *SettingsDialog::createCombobox(
const QString &title, pajlada::Settings::Setting<int> &setting, QStringList items,
std::function<void(QString, pajlada::Settings::Setting<int> &)> cb)
{
auto box = new QHBoxLayout();
auto label = new QLabel(title);
auto widget = new QComboBox();
widget->addItems(items);
QObject::connect(widget, &QComboBox::currentTextChanged, this,
[&setting, cb](const QString &newValue) {
cb(newValue, setting); //
});
box->addWidget(label);
box->addWidget(widget);
return box;
}
2017-04-12 17:46:44 +02:00
void SettingsDialog::okButtonClicked()
2017-01-24 19:51:57 +01:00
{
this->close();
}
2017-04-12 17:46:44 +02:00
void SettingsDialog::cancelButtonClicked()
2017-01-24 19:51:57 +01:00
{
2017-07-02 12:36:50 +02:00
// TODO: Re-implement the snapshot feature properly
auto &instance = SettingsManager::getInstance();
2017-07-02 12:36:50 +02:00
this->snapshot.apply();
instance.highlightProperties.set(this->snapshot._mapItems);
QStringList list = instance.highlightProperties.get().keys();
list.removeDuplicates();
2017-07-31 00:57:42 +02:00
while (globalHighlights->count() > 0) {
delete globalHighlights->takeItem(0);
}
globalHighlights->addItems(list);
2017-01-24 19:51:57 +01:00
this->close();
}
2017-04-14 17:52:22 +02:00
} // namespace widgets
} // namespace chatterino