Normalize line endings in already existing files
This commit is contained in:
@@ -1,222 +1,222 @@
|
||||
#include "AboutPage.hpp"
|
||||
|
||||
#include "debug/Log.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "util/RemoveScrollAreaBackground.hpp"
|
||||
#include "widgets/helper/SignalLabel.hpp"
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
#include <QTextEdit>
|
||||
#include <QTextStream>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#define PIXMAP_WIDTH 500
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
AboutPage::AboutPage()
|
||||
: SettingsPage("About", ":/settings/about.svg")
|
||||
{
|
||||
LayoutCreator<AboutPage> layoutCreator(this);
|
||||
|
||||
auto scroll = layoutCreator.emplace<QScrollArea>();
|
||||
auto widget = scroll.emplaceScrollAreaWidget();
|
||||
removeScrollAreaBackground(scroll.getElement(), widget.getElement());
|
||||
|
||||
auto layout = widget.setLayoutType<QVBoxLayout>();
|
||||
{
|
||||
QPixmap pixmap;
|
||||
pixmap.load(":/settings/aboutlogo.png");
|
||||
|
||||
auto logo = layout.emplace<QLabel>().assign(&this->logo_);
|
||||
logo->setPixmap(pixmap);
|
||||
logo->setFixedSize(PIXMAP_WIDTH,
|
||||
PIXMAP_WIDTH * pixmap.height() / pixmap.width());
|
||||
logo->setScaledContents(true);
|
||||
|
||||
// this does nothing
|
||||
// QPalette palette;
|
||||
// palette.setColor(QPalette::Text, Qt::white);
|
||||
// palette.setColor(QPalette::Link, "#a5cdff");
|
||||
// palette.setColor(QPalette::LinkVisited, "#a5cdff");
|
||||
|
||||
/*auto xd = layout.emplace<QGroupBox>("Created by...");
|
||||
{
|
||||
auto created = xd.emplace<QLabel>();
|
||||
{
|
||||
created->setText("Created by <a
|
||||
href=\"https://github.com/fourtf\">fourtf</a><br>" "with big help from
|
||||
pajlada."); created->setTextFormat(Qt::RichText);
|
||||
created->setTextInteractionFlags(Qt::TextBrowserInteraction |
|
||||
Qt::LinksAccessibleByKeyboard |
|
||||
Qt::LinksAccessibleByKeyboard);
|
||||
created->setOpenExternalLinks(true);
|
||||
// created->setPalette(palette);
|
||||
}
|
||||
|
||||
// auto github = xd.emplace<QLabel>();
|
||||
// {
|
||||
// github->setText(
|
||||
// "<a
|
||||
href=\"https://github.com/fourtf/chatterino2\">Chatterino on
|
||||
// Github</a>");
|
||||
// github->setTextFormat(Qt::RichText);
|
||||
// github->setTextInteractionFlags(Qt::TextBrowserInteraction |
|
||||
// Qt::LinksAccessibleByKeyboard |
|
||||
// Qt::LinksAccessibleByKeyboard);
|
||||
// github->setOpenExternalLinks(true);
|
||||
// // github->setPalette(palette);
|
||||
// }
|
||||
}*/
|
||||
|
||||
auto licenses =
|
||||
layout.emplace<QGroupBox>("Open source software used...");
|
||||
{
|
||||
auto form = licenses.emplace<QFormLayout>();
|
||||
|
||||
addLicense(form.getElement(), "Qt Framework", "https://www.qt.io",
|
||||
":/licenses/qt_lgpl-3.0.txt");
|
||||
addLicense(form.getElement(), "Boost", "https://www.boost.org/",
|
||||
":/licenses/boost_boost.txt");
|
||||
addLicense(form.getElement(), "Fmt", "http://fmtlib.net/",
|
||||
":/licenses/fmt_bsd2.txt");
|
||||
addLicense(form.getElement(), "LibCommuni",
|
||||
"https://github.com/communi/libcommuni",
|
||||
":/licenses/libcommuni_BSD3.txt");
|
||||
addLicense(form.getElement(), "OpenSSL", "https://www.openssl.org/",
|
||||
":/licenses/openssl.txt");
|
||||
addLicense(form.getElement(), "RapidJson", "http://rapidjson.org/",
|
||||
":/licenses/rapidjson.txt");
|
||||
addLicense(form.getElement(), "Pajlada/Settings",
|
||||
"https://github.com/pajlada/settings",
|
||||
":/licenses/pajlada_settings.txt");
|
||||
addLicense(form.getElement(), "Pajlada/Signals",
|
||||
"https://github.com/pajlada/signals",
|
||||
":/licenses/pajlada_signals.txt");
|
||||
addLicense(form.getElement(), "Websocketpp",
|
||||
"https://www.zaphoyd.com/websocketpp/",
|
||||
":/licenses/websocketpp.txt");
|
||||
}
|
||||
|
||||
auto attributions = layout.emplace<QGroupBox>("Attributions...");
|
||||
{
|
||||
auto l = attributions.emplace<QVBoxLayout>();
|
||||
|
||||
// clang-format off
|
||||
l.emplace<QLabel>("EmojiOne 2 and 3 emojis provided by <a href=\"https://www.emojione.com/\">EmojiOne</a>")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Twemoji emojis provided by <a href=\"https://github.com/twitter/twemoji\">Twitter's Twemoji</a>")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Facebook emojis provided by <a href=\"https://facebook.com\">Facebook</a>")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Apple emojis provided by <a href=\"https://apple.com\">Apple</a>")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Google emojis provided by <a href=\"https://google.com\">Google</a>")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Messenger emojis provided by <a href=\"https://facebook.com\">Facebook</a>")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Emoji datasource provided by <a href=\"https://www.iamcal.com/\">Cal Henderson</a>"
|
||||
"(<a href=\"https://github.com/iamcal/emoji-data/blob/master/LICENSE\">show license</a>)")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Twitch emote data provided by <a href=\"https://twitchemotes.com/\">twitchemotes.com</a> through the <a href=\"https://github.com/Chatterino/api\">Chatterino API</a>")->setOpenExternalLinks(true);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// Contributors
|
||||
auto contributors = layout.emplace<QGroupBox>("Contributors");
|
||||
{
|
||||
auto l = contributors.emplace<QVBoxLayout>();
|
||||
|
||||
QFile contributorsFile(":/contributors.txt");
|
||||
contributorsFile.open(QFile::ReadOnly);
|
||||
|
||||
QTextStream stream(&contributorsFile);
|
||||
stream.setCodec("UTF-8");
|
||||
|
||||
QString line;
|
||||
|
||||
while (stream.readLineInto(&line))
|
||||
{
|
||||
if (line.isEmpty() || line.startsWith('#'))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
QStringList contributorParts = line.split("|");
|
||||
|
||||
if (contributorParts.size() != 4)
|
||||
{
|
||||
log("Missing parts in line '{}'", line);
|
||||
continue;
|
||||
}
|
||||
|
||||
QString username = contributorParts[0].trimmed();
|
||||
QString url = contributorParts[1].trimmed();
|
||||
QString avatarUrl = contributorParts[2].trimmed();
|
||||
QString role = contributorParts[3].trimmed();
|
||||
|
||||
auto *usernameLabel =
|
||||
new QLabel("<a href=\"" + url + "\">" + username + "</a>");
|
||||
usernameLabel->setOpenExternalLinks(true);
|
||||
auto *roleLabel = new QLabel(role);
|
||||
|
||||
auto contributorBox2 = l.emplace<QHBoxLayout>();
|
||||
|
||||
const auto addAvatar = [&avatarUrl, &contributorBox2] {
|
||||
if (!avatarUrl.isEmpty())
|
||||
{
|
||||
QPixmap avatarPixmap;
|
||||
avatarPixmap.load(avatarUrl);
|
||||
|
||||
auto avatar = contributorBox2.emplace<QLabel>();
|
||||
avatar->setPixmap(avatarPixmap);
|
||||
avatar->setFixedSize(64, 64);
|
||||
avatar->setScaledContents(true);
|
||||
}
|
||||
};
|
||||
|
||||
const auto addLabels = [&contributorBox2, &usernameLabel,
|
||||
&roleLabel] {
|
||||
auto labelBox = new QVBoxLayout();
|
||||
contributorBox2->addLayout(labelBox);
|
||||
|
||||
labelBox->addWidget(usernameLabel);
|
||||
labelBox->addWidget(roleLabel);
|
||||
};
|
||||
|
||||
addLabels();
|
||||
addAvatar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto buildInfo = QStringList();
|
||||
buildInfo += "Qt " QT_VERSION_STR;
|
||||
#ifdef USEWINSDK
|
||||
buildInfo += "Windows SDK";
|
||||
#endif
|
||||
#ifdef _MSC_FULL_VER
|
||||
buildInfo += "MSVC " + QString::number(_MSC_FULL_VER, 10);
|
||||
#endif
|
||||
|
||||
auto buildText = QString("Built with " + buildInfo.join(", "));
|
||||
layout.emplace<QLabel>(buildText);
|
||||
|
||||
layout->addStretch(1);
|
||||
}
|
||||
|
||||
void AboutPage::addLicense(QFormLayout *form, const QString &name,
|
||||
const QString &website, const QString &licenseLink)
|
||||
{
|
||||
auto *a = new QLabel("<a href=\"" + website + "\">" + name + "</a>");
|
||||
a->setOpenExternalLinks(true);
|
||||
auto *b = new QLabel("<a href=\"" + licenseLink + "\">show license</a>");
|
||||
QObject::connect(b, &QLabel::linkActivated, [licenseLink] {
|
||||
auto *edit = new QTextEdit;
|
||||
|
||||
QFile file(licenseLink);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
edit->setText(file.readAll());
|
||||
edit->setReadOnly(true);
|
||||
edit->show();
|
||||
});
|
||||
|
||||
form->addRow(a, b);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
#include "AboutPage.hpp"
|
||||
|
||||
#include "debug/Log.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "util/RemoveScrollAreaBackground.hpp"
|
||||
#include "widgets/helper/SignalLabel.hpp"
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
#include <QTextEdit>
|
||||
#include <QTextStream>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#define PIXMAP_WIDTH 500
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
AboutPage::AboutPage()
|
||||
: SettingsPage("About", ":/settings/about.svg")
|
||||
{
|
||||
LayoutCreator<AboutPage> layoutCreator(this);
|
||||
|
||||
auto scroll = layoutCreator.emplace<QScrollArea>();
|
||||
auto widget = scroll.emplaceScrollAreaWidget();
|
||||
removeScrollAreaBackground(scroll.getElement(), widget.getElement());
|
||||
|
||||
auto layout = widget.setLayoutType<QVBoxLayout>();
|
||||
{
|
||||
QPixmap pixmap;
|
||||
pixmap.load(":/settings/aboutlogo.png");
|
||||
|
||||
auto logo = layout.emplace<QLabel>().assign(&this->logo_);
|
||||
logo->setPixmap(pixmap);
|
||||
logo->setFixedSize(PIXMAP_WIDTH,
|
||||
PIXMAP_WIDTH * pixmap.height() / pixmap.width());
|
||||
logo->setScaledContents(true);
|
||||
|
||||
// this does nothing
|
||||
// QPalette palette;
|
||||
// palette.setColor(QPalette::Text, Qt::white);
|
||||
// palette.setColor(QPalette::Link, "#a5cdff");
|
||||
// palette.setColor(QPalette::LinkVisited, "#a5cdff");
|
||||
|
||||
/*auto xd = layout.emplace<QGroupBox>("Created by...");
|
||||
{
|
||||
auto created = xd.emplace<QLabel>();
|
||||
{
|
||||
created->setText("Created by <a
|
||||
href=\"https://github.com/fourtf\">fourtf</a><br>" "with big help from
|
||||
pajlada."); created->setTextFormat(Qt::RichText);
|
||||
created->setTextInteractionFlags(Qt::TextBrowserInteraction |
|
||||
Qt::LinksAccessibleByKeyboard |
|
||||
Qt::LinksAccessibleByKeyboard);
|
||||
created->setOpenExternalLinks(true);
|
||||
// created->setPalette(palette);
|
||||
}
|
||||
|
||||
// auto github = xd.emplace<QLabel>();
|
||||
// {
|
||||
// github->setText(
|
||||
// "<a
|
||||
href=\"https://github.com/fourtf/chatterino2\">Chatterino on
|
||||
// Github</a>");
|
||||
// github->setTextFormat(Qt::RichText);
|
||||
// github->setTextInteractionFlags(Qt::TextBrowserInteraction |
|
||||
// Qt::LinksAccessibleByKeyboard |
|
||||
// Qt::LinksAccessibleByKeyboard);
|
||||
// github->setOpenExternalLinks(true);
|
||||
// // github->setPalette(palette);
|
||||
// }
|
||||
}*/
|
||||
|
||||
auto licenses =
|
||||
layout.emplace<QGroupBox>("Open source software used...");
|
||||
{
|
||||
auto form = licenses.emplace<QFormLayout>();
|
||||
|
||||
addLicense(form.getElement(), "Qt Framework", "https://www.qt.io",
|
||||
":/licenses/qt_lgpl-3.0.txt");
|
||||
addLicense(form.getElement(), "Boost", "https://www.boost.org/",
|
||||
":/licenses/boost_boost.txt");
|
||||
addLicense(form.getElement(), "Fmt", "http://fmtlib.net/",
|
||||
":/licenses/fmt_bsd2.txt");
|
||||
addLicense(form.getElement(), "LibCommuni",
|
||||
"https://github.com/communi/libcommuni",
|
||||
":/licenses/libcommuni_BSD3.txt");
|
||||
addLicense(form.getElement(), "OpenSSL", "https://www.openssl.org/",
|
||||
":/licenses/openssl.txt");
|
||||
addLicense(form.getElement(), "RapidJson", "http://rapidjson.org/",
|
||||
":/licenses/rapidjson.txt");
|
||||
addLicense(form.getElement(), "Pajlada/Settings",
|
||||
"https://github.com/pajlada/settings",
|
||||
":/licenses/pajlada_settings.txt");
|
||||
addLicense(form.getElement(), "Pajlada/Signals",
|
||||
"https://github.com/pajlada/signals",
|
||||
":/licenses/pajlada_signals.txt");
|
||||
addLicense(form.getElement(), "Websocketpp",
|
||||
"https://www.zaphoyd.com/websocketpp/",
|
||||
":/licenses/websocketpp.txt");
|
||||
}
|
||||
|
||||
auto attributions = layout.emplace<QGroupBox>("Attributions...");
|
||||
{
|
||||
auto l = attributions.emplace<QVBoxLayout>();
|
||||
|
||||
// clang-format off
|
||||
l.emplace<QLabel>("EmojiOne 2 and 3 emojis provided by <a href=\"https://www.emojione.com/\">EmojiOne</a>")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Twemoji emojis provided by <a href=\"https://github.com/twitter/twemoji\">Twitter's Twemoji</a>")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Facebook emojis provided by <a href=\"https://facebook.com\">Facebook</a>")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Apple emojis provided by <a href=\"https://apple.com\">Apple</a>")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Google emojis provided by <a href=\"https://google.com\">Google</a>")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Messenger emojis provided by <a href=\"https://facebook.com\">Facebook</a>")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Emoji datasource provided by <a href=\"https://www.iamcal.com/\">Cal Henderson</a>"
|
||||
"(<a href=\"https://github.com/iamcal/emoji-data/blob/master/LICENSE\">show license</a>)")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Twitch emote data provided by <a href=\"https://twitchemotes.com/\">twitchemotes.com</a> through the <a href=\"https://github.com/Chatterino/api\">Chatterino API</a>")->setOpenExternalLinks(true);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// Contributors
|
||||
auto contributors = layout.emplace<QGroupBox>("Contributors");
|
||||
{
|
||||
auto l = contributors.emplace<QVBoxLayout>();
|
||||
|
||||
QFile contributorsFile(":/contributors.txt");
|
||||
contributorsFile.open(QFile::ReadOnly);
|
||||
|
||||
QTextStream stream(&contributorsFile);
|
||||
stream.setCodec("UTF-8");
|
||||
|
||||
QString line;
|
||||
|
||||
while (stream.readLineInto(&line))
|
||||
{
|
||||
if (line.isEmpty() || line.startsWith('#'))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
QStringList contributorParts = line.split("|");
|
||||
|
||||
if (contributorParts.size() != 4)
|
||||
{
|
||||
log("Missing parts in line '{}'", line);
|
||||
continue;
|
||||
}
|
||||
|
||||
QString username = contributorParts[0].trimmed();
|
||||
QString url = contributorParts[1].trimmed();
|
||||
QString avatarUrl = contributorParts[2].trimmed();
|
||||
QString role = contributorParts[3].trimmed();
|
||||
|
||||
auto *usernameLabel =
|
||||
new QLabel("<a href=\"" + url + "\">" + username + "</a>");
|
||||
usernameLabel->setOpenExternalLinks(true);
|
||||
auto *roleLabel = new QLabel(role);
|
||||
|
||||
auto contributorBox2 = l.emplace<QHBoxLayout>();
|
||||
|
||||
const auto addAvatar = [&avatarUrl, &contributorBox2] {
|
||||
if (!avatarUrl.isEmpty())
|
||||
{
|
||||
QPixmap avatarPixmap;
|
||||
avatarPixmap.load(avatarUrl);
|
||||
|
||||
auto avatar = contributorBox2.emplace<QLabel>();
|
||||
avatar->setPixmap(avatarPixmap);
|
||||
avatar->setFixedSize(64, 64);
|
||||
avatar->setScaledContents(true);
|
||||
}
|
||||
};
|
||||
|
||||
const auto addLabels = [&contributorBox2, &usernameLabel,
|
||||
&roleLabel] {
|
||||
auto labelBox = new QVBoxLayout();
|
||||
contributorBox2->addLayout(labelBox);
|
||||
|
||||
labelBox->addWidget(usernameLabel);
|
||||
labelBox->addWidget(roleLabel);
|
||||
};
|
||||
|
||||
addLabels();
|
||||
addAvatar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto buildInfo = QStringList();
|
||||
buildInfo += "Qt " QT_VERSION_STR;
|
||||
#ifdef USEWINSDK
|
||||
buildInfo += "Windows SDK";
|
||||
#endif
|
||||
#ifdef _MSC_FULL_VER
|
||||
buildInfo += "MSVC " + QString::number(_MSC_FULL_VER, 10);
|
||||
#endif
|
||||
|
||||
auto buildText = QString("Built with " + buildInfo.join(", "));
|
||||
layout.emplace<QLabel>(buildText);
|
||||
|
||||
layout->addStretch(1);
|
||||
}
|
||||
|
||||
void AboutPage::addLicense(QFormLayout *form, const QString &name,
|
||||
const QString &website, const QString &licenseLink)
|
||||
{
|
||||
auto *a = new QLabel("<a href=\"" + website + "\">" + name + "</a>");
|
||||
a->setOpenExternalLinks(true);
|
||||
auto *b = new QLabel("<a href=\"" + licenseLink + "\">show license</a>");
|
||||
QObject::connect(b, &QLabel::linkActivated, [licenseLink] {
|
||||
auto *edit = new QTextEdit;
|
||||
|
||||
QFile file(licenseLink);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
edit->setText(file.readAll());
|
||||
edit->setReadOnly(true);
|
||||
edit->show();
|
||||
});
|
||||
|
||||
form->addRow(a, b);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
class QLabel;
|
||||
class QFormLayout;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class AboutPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
AboutPage();
|
||||
|
||||
private:
|
||||
void addLicense(QFormLayout *form, const QString &name_,
|
||||
const QString &website, const QString &licenseLink);
|
||||
|
||||
QLabel *logo_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
#pragma once
|
||||
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
class QLabel;
|
||||
class QFormLayout;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class AboutPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
AboutPage();
|
||||
|
||||
private:
|
||||
void addLicense(QFormLayout *form, const QString &name_,
|
||||
const QString &website, const QString &licenseLink);
|
||||
|
||||
QLabel *logo_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,69 +1,69 @@
|
||||
#include "AccountsPage.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "controllers/accounts/AccountController.hpp"
|
||||
#include "controllers/accounts/AccountModel.hpp"
|
||||
#include "providers/twitch/TwitchCommon.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "widgets/dialogs/LoginDialog.hpp"
|
||||
#include "widgets/helper/EditableModelView.hpp"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QHeaderView>
|
||||
#include <QTableView>
|
||||
#include <QVBoxLayout>
|
||||
#include <algorithm>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
AccountsPage::AccountsPage()
|
||||
: SettingsPage("Accounts", ":/settings/accounts.svg")
|
||||
{
|
||||
auto *app = getApp();
|
||||
|
||||
LayoutCreator<AccountsPage> layoutCreator(this);
|
||||
auto layout = layoutCreator.emplace<QVBoxLayout>().withoutMargin();
|
||||
|
||||
EditableModelView *view =
|
||||
layout.emplace<EditableModelView>(app->accounts->createModel(nullptr))
|
||||
.getElement();
|
||||
|
||||
view->getTableView()->horizontalHeader()->setVisible(false);
|
||||
view->getTableView()->horizontalHeader()->setStretchLastSection(true);
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
static auto loginWidget = new LoginWidget();
|
||||
|
||||
loginWidget->show();
|
||||
loginWidget->raise();
|
||||
});
|
||||
|
||||
view->getTableView()->setStyleSheet("background: #333");
|
||||
|
||||
// auto buttons = layout.emplace<QDialogButtonBox>();
|
||||
// {
|
||||
// this->addButton = buttons->addButton("Add",
|
||||
// QDialogButtonBox::YesRole); this->removeButton =
|
||||
// buttons->addButton("Remove", QDialogButtonBox::NoRole);
|
||||
// }
|
||||
|
||||
// layout.emplace<AccountSwitchWidget>(this).assign(&this->accSwitchWidget);
|
||||
|
||||
// ----
|
||||
// QObject::connect(this->addButton, &QPushButton::clicked, []() {
|
||||
// static auto loginWidget = new LoginWidget();
|
||||
// loginWidget->show();
|
||||
// });
|
||||
|
||||
// QObject::connect(this->removeButton, &QPushButton::clicked, [this] {
|
||||
// auto selectedUser = this->accSwitchWidget->currentItem()->text();
|
||||
// if (selectedUser == ANONYMOUS_USERNAME_LABEL) {
|
||||
// // Do nothing
|
||||
// return;
|
||||
// }
|
||||
|
||||
// getApp()->accounts->Twitch.removeUser(selectedUser);
|
||||
// });
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
#include "AccountsPage.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "controllers/accounts/AccountController.hpp"
|
||||
#include "controllers/accounts/AccountModel.hpp"
|
||||
#include "providers/twitch/TwitchCommon.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "widgets/dialogs/LoginDialog.hpp"
|
||||
#include "widgets/helper/EditableModelView.hpp"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QHeaderView>
|
||||
#include <QTableView>
|
||||
#include <QVBoxLayout>
|
||||
#include <algorithm>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
AccountsPage::AccountsPage()
|
||||
: SettingsPage("Accounts", ":/settings/accounts.svg")
|
||||
{
|
||||
auto *app = getApp();
|
||||
|
||||
LayoutCreator<AccountsPage> layoutCreator(this);
|
||||
auto layout = layoutCreator.emplace<QVBoxLayout>().withoutMargin();
|
||||
|
||||
EditableModelView *view =
|
||||
layout.emplace<EditableModelView>(app->accounts->createModel(nullptr))
|
||||
.getElement();
|
||||
|
||||
view->getTableView()->horizontalHeader()->setVisible(false);
|
||||
view->getTableView()->horizontalHeader()->setStretchLastSection(true);
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
static auto loginWidget = new LoginWidget();
|
||||
|
||||
loginWidget->show();
|
||||
loginWidget->raise();
|
||||
});
|
||||
|
||||
view->getTableView()->setStyleSheet("background: #333");
|
||||
|
||||
// auto buttons = layout.emplace<QDialogButtonBox>();
|
||||
// {
|
||||
// this->addButton = buttons->addButton("Add",
|
||||
// QDialogButtonBox::YesRole); this->removeButton =
|
||||
// buttons->addButton("Remove", QDialogButtonBox::NoRole);
|
||||
// }
|
||||
|
||||
// layout.emplace<AccountSwitchWidget>(this).assign(&this->accSwitchWidget);
|
||||
|
||||
// ----
|
||||
// QObject::connect(this->addButton, &QPushButton::clicked, []() {
|
||||
// static auto loginWidget = new LoginWidget();
|
||||
// loginWidget->show();
|
||||
// });
|
||||
|
||||
// QObject::connect(this->removeButton, &QPushButton::clicked, [this] {
|
||||
// auto selectedUser = this->accSwitchWidget->currentItem()->text();
|
||||
// if (selectedUser == ANONYMOUS_USERNAME_LABEL) {
|
||||
// // Do nothing
|
||||
// return;
|
||||
// }
|
||||
|
||||
// getApp()->accounts->Twitch.removeUser(selectedUser);
|
||||
// });
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/AccountSwitchWidget.hpp"
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class AccountsPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
AccountsPage();
|
||||
|
||||
private:
|
||||
QPushButton *addButton_;
|
||||
QPushButton *removeButton_;
|
||||
AccountSwitchWidget *accountSwitchWidget_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
#pragma once
|
||||
|
||||
#include "widgets/AccountSwitchWidget.hpp"
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class AccountsPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
AccountsPage();
|
||||
|
||||
private:
|
||||
QPushButton *addButton_;
|
||||
QPushButton *removeButton_;
|
||||
AccountSwitchWidget *accountSwitchWidget_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,88 +1,88 @@
|
||||
#include "CommandPage.hpp"
|
||||
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QStandardItemModel>
|
||||
#include <QTableView>
|
||||
#include <QTextEdit>
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "controllers/commands/CommandController.hpp"
|
||||
#include "controllers/commands/CommandModel.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "util/StandardItemHelper.hpp"
|
||||
#include "widgets/helper/EditableModelView.hpp"
|
||||
//#include "widgets/helper/ComboBoxItemDelegate.hpp"
|
||||
#include "util/CombinePath.hpp"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QTextEdit>
|
||||
|
||||
// clang-format off
|
||||
#define TEXT "{1} => first word {1+} => first word and after {{ => { <a href='https://chatterino.com/help/commands'>more info</a>"
|
||||
// clang-format on
|
||||
|
||||
namespace chatterino {
|
||||
namespace {
|
||||
QString c1settingsPath()
|
||||
{
|
||||
return combinePath(qgetenv("appdata"),
|
||||
"Chatterino\\Custom\\Commands.txt");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
CommandPage::CommandPage()
|
||||
: SettingsPage("Commands", ":/settings/commands.svg")
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
LayoutCreator<CommandPage> layoutCreator(this);
|
||||
auto layout = layoutCreator.setLayoutType<QVBoxLayout>();
|
||||
|
||||
EditableModelView *view =
|
||||
layout.emplace<EditableModelView>(app->commands->createModel(nullptr))
|
||||
.getElement();
|
||||
|
||||
view->setTitles({"Trigger", "Command"});
|
||||
view->getTableView()->horizontalHeader()->setStretchLastSection(true);
|
||||
view->addButtonPressed.connect([] {
|
||||
getApp()->commands->items_.appendItem(
|
||||
Command{"/command", "I made a new command HeyGuys"});
|
||||
});
|
||||
|
||||
if (QFile(c1settingsPath()).exists())
|
||||
{
|
||||
auto button = new QPushButton("Import commands from Chatterino 1");
|
||||
view->addCustomButton(button);
|
||||
|
||||
QObject::connect(button, &QPushButton::clicked, this, [] {
|
||||
QFile c1settings = c1settingsPath();
|
||||
c1settings.open(QIODevice::ReadOnly);
|
||||
for (auto line : QString(c1settings.readAll())
|
||||
.split(QRegularExpression("[\r\n]"),
|
||||
QString::SkipEmptyParts))
|
||||
{
|
||||
if (int index = line.indexOf(' '); index != -1)
|
||||
{
|
||||
getApp()->commands->items_.insertItem(
|
||||
Command(line.mid(0, index), line.mid(index + 1)));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
layout.append(
|
||||
this->createCheckBox("Also match the trigger at the end of the message",
|
||||
getSettings()->allowCommandsAtEnd));
|
||||
|
||||
QLabel *text = layout.emplace<QLabel>(TEXT).getElement();
|
||||
text->setWordWrap(true);
|
||||
text->setStyleSheet("color: #bbb");
|
||||
text->setOpenExternalLinks(true);
|
||||
|
||||
// ---- end of layout
|
||||
this->commandsEditTimer_.setSingleShot(true);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
#include "CommandPage.hpp"
|
||||
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QStandardItemModel>
|
||||
#include <QTableView>
|
||||
#include <QTextEdit>
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "controllers/commands/CommandController.hpp"
|
||||
#include "controllers/commands/CommandModel.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "util/StandardItemHelper.hpp"
|
||||
#include "widgets/helper/EditableModelView.hpp"
|
||||
//#include "widgets/helper/ComboBoxItemDelegate.hpp"
|
||||
#include "util/CombinePath.hpp"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QTextEdit>
|
||||
|
||||
// clang-format off
|
||||
#define TEXT "{1} => first word {1+} => first word and after {{ => { <a href='https://chatterino.com/help/commands'>more info</a>"
|
||||
// clang-format on
|
||||
|
||||
namespace chatterino {
|
||||
namespace {
|
||||
QString c1settingsPath()
|
||||
{
|
||||
return combinePath(qgetenv("appdata"),
|
||||
"Chatterino\\Custom\\Commands.txt");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
CommandPage::CommandPage()
|
||||
: SettingsPage("Commands", ":/settings/commands.svg")
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
LayoutCreator<CommandPage> layoutCreator(this);
|
||||
auto layout = layoutCreator.setLayoutType<QVBoxLayout>();
|
||||
|
||||
EditableModelView *view =
|
||||
layout.emplace<EditableModelView>(app->commands->createModel(nullptr))
|
||||
.getElement();
|
||||
|
||||
view->setTitles({"Trigger", "Command"});
|
||||
view->getTableView()->horizontalHeader()->setStretchLastSection(true);
|
||||
view->addButtonPressed.connect([] {
|
||||
getApp()->commands->items_.appendItem(
|
||||
Command{"/command", "I made a new command HeyGuys"});
|
||||
});
|
||||
|
||||
if (QFile(c1settingsPath()).exists())
|
||||
{
|
||||
auto button = new QPushButton("Import commands from Chatterino 1");
|
||||
view->addCustomButton(button);
|
||||
|
||||
QObject::connect(button, &QPushButton::clicked, this, [] {
|
||||
QFile c1settings = c1settingsPath();
|
||||
c1settings.open(QIODevice::ReadOnly);
|
||||
for (auto line : QString(c1settings.readAll())
|
||||
.split(QRegularExpression("[\r\n]"),
|
||||
QString::SkipEmptyParts))
|
||||
{
|
||||
if (int index = line.indexOf(' '); index != -1)
|
||||
{
|
||||
getApp()->commands->items_.insertItem(
|
||||
Command(line.mid(0, index), line.mid(index + 1)));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
layout.append(
|
||||
this->createCheckBox("Also match the trigger at the end of the message",
|
||||
getSettings()->allowCommandsAtEnd));
|
||||
|
||||
QLabel *text = layout.emplace<QLabel>(TEXT).getElement();
|
||||
text->setWordWrap(true);
|
||||
text->setStyleSheet("color: #bbb");
|
||||
text->setOpenExternalLinks(true);
|
||||
|
||||
// ---- end of layout
|
||||
this->commandsEditTimer_.setSingleShot(true);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <QTextEdit>
|
||||
#include <QTimer>
|
||||
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class CommandPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
CommandPage();
|
||||
|
||||
private:
|
||||
QTimer commandsEditTimer_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
#pragma once
|
||||
|
||||
#include <QTextEdit>
|
||||
#include <QTimer>
|
||||
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class CommandPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
CommandPage();
|
||||
|
||||
private:
|
||||
QTimer commandsEditTimer_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,74 +1,74 @@
|
||||
#include "ExternalToolsPage.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "util/Helpers.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
|
||||
#include <QGroupBox>
|
||||
|
||||
#define STREAMLINK_QUALITY \
|
||||
"Choose", "Source", "High", "Medium", "Low", "Audio only"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
ExternalToolsPage::ExternalToolsPage()
|
||||
: SettingsPage("External tools", ":/settings/externaltools.svg")
|
||||
{
|
||||
LayoutCreator<ExternalToolsPage> layoutCreator(this);
|
||||
auto layout = layoutCreator.setLayoutType<QVBoxLayout>();
|
||||
|
||||
{
|
||||
auto group = layout.emplace<QGroupBox>("Streamlink");
|
||||
auto groupLayout = group.setLayoutType<QFormLayout>();
|
||||
|
||||
auto description = new QLabel(
|
||||
"Streamlink is a command-line utility that pipes video streams "
|
||||
"from various "
|
||||
"services into a video player, such as VLC. Make sure to edit the "
|
||||
"configuration file before you use it!");
|
||||
description->setWordWrap(true);
|
||||
description->setStyleSheet("color: #bbb");
|
||||
|
||||
auto links = new QLabel(
|
||||
createNamedLink("https://streamlink.github.io/", "Website") + " " +
|
||||
createNamedLink(
|
||||
"https://github.com/streamlink/streamlink/releases/latest",
|
||||
"Download"));
|
||||
links->setTextFormat(Qt::RichText);
|
||||
links->setTextInteractionFlags(Qt::TextBrowserInteraction |
|
||||
Qt::LinksAccessibleByKeyboard |
|
||||
Qt::LinksAccessibleByKeyboard);
|
||||
links->setOpenExternalLinks(true);
|
||||
|
||||
groupLayout->setWidget(0, QFormLayout::SpanningRole, description);
|
||||
groupLayout->setWidget(1, QFormLayout::SpanningRole, links);
|
||||
|
||||
auto customPathCb =
|
||||
this->createCheckBox("Use custom path (Enable if using "
|
||||
"non-standard streamlink installation path)",
|
||||
getSettings()->streamlinkUseCustomPath);
|
||||
groupLayout->setWidget(2, QFormLayout::SpanningRole, customPathCb);
|
||||
|
||||
auto customPath = this->createLineEdit(getSettings()->streamlinkPath);
|
||||
customPath->setPlaceholderText(
|
||||
"Path to folder where Streamlink executable can be found");
|
||||
groupLayout->addRow("Custom streamlink path:", customPath);
|
||||
groupLayout->addRow(
|
||||
"Preferred quality:",
|
||||
this->createComboBox({STREAMLINK_QUALITY},
|
||||
getSettings()->preferredQuality));
|
||||
groupLayout->addRow(
|
||||
"Additional options:",
|
||||
this->createLineEdit(getSettings()->streamlinkOpts));
|
||||
|
||||
getSettings()->streamlinkUseCustomPath.connect(
|
||||
[=](const auto &value, auto) {
|
||||
customPath->setEnabled(value); //
|
||||
},
|
||||
this->managedConnections_);
|
||||
}
|
||||
|
||||
layout->addStretch(1);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
#include "ExternalToolsPage.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "util/Helpers.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
|
||||
#include <QGroupBox>
|
||||
|
||||
#define STREAMLINK_QUALITY \
|
||||
"Choose", "Source", "High", "Medium", "Low", "Audio only"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
ExternalToolsPage::ExternalToolsPage()
|
||||
: SettingsPage("External tools", ":/settings/externaltools.svg")
|
||||
{
|
||||
LayoutCreator<ExternalToolsPage> layoutCreator(this);
|
||||
auto layout = layoutCreator.setLayoutType<QVBoxLayout>();
|
||||
|
||||
{
|
||||
auto group = layout.emplace<QGroupBox>("Streamlink");
|
||||
auto groupLayout = group.setLayoutType<QFormLayout>();
|
||||
|
||||
auto description = new QLabel(
|
||||
"Streamlink is a command-line utility that pipes video streams "
|
||||
"from various "
|
||||
"services into a video player, such as VLC. Make sure to edit the "
|
||||
"configuration file before you use it!");
|
||||
description->setWordWrap(true);
|
||||
description->setStyleSheet("color: #bbb");
|
||||
|
||||
auto links = new QLabel(
|
||||
createNamedLink("https://streamlink.github.io/", "Website") + " " +
|
||||
createNamedLink(
|
||||
"https://github.com/streamlink/streamlink/releases/latest",
|
||||
"Download"));
|
||||
links->setTextFormat(Qt::RichText);
|
||||
links->setTextInteractionFlags(Qt::TextBrowserInteraction |
|
||||
Qt::LinksAccessibleByKeyboard |
|
||||
Qt::LinksAccessibleByKeyboard);
|
||||
links->setOpenExternalLinks(true);
|
||||
|
||||
groupLayout->setWidget(0, QFormLayout::SpanningRole, description);
|
||||
groupLayout->setWidget(1, QFormLayout::SpanningRole, links);
|
||||
|
||||
auto customPathCb =
|
||||
this->createCheckBox("Use custom path (Enable if using "
|
||||
"non-standard streamlink installation path)",
|
||||
getSettings()->streamlinkUseCustomPath);
|
||||
groupLayout->setWidget(2, QFormLayout::SpanningRole, customPathCb);
|
||||
|
||||
auto customPath = this->createLineEdit(getSettings()->streamlinkPath);
|
||||
customPath->setPlaceholderText(
|
||||
"Path to folder where Streamlink executable can be found");
|
||||
groupLayout->addRow("Custom streamlink path:", customPath);
|
||||
groupLayout->addRow(
|
||||
"Preferred quality:",
|
||||
this->createComboBox({STREAMLINK_QUALITY},
|
||||
getSettings()->preferredQuality));
|
||||
groupLayout->addRow(
|
||||
"Additional options:",
|
||||
this->createLineEdit(getSettings()->streamlinkOpts));
|
||||
|
||||
getSettings()->streamlinkUseCustomPath.connect(
|
||||
[=](const auto &value, auto) {
|
||||
customPath->setEnabled(value); //
|
||||
},
|
||||
this->managedConnections_);
|
||||
}
|
||||
|
||||
layout->addStretch(1);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class ExternalToolsPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
ExternalToolsPage();
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
#pragma once
|
||||
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class ExternalToolsPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
ExternalToolsPage();
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,191 +1,191 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDebug>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "boost/variant.hpp"
|
||||
#include "pajlada/signals/signal.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "singletons/WindowManager.hpp"
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
class QLabel;
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class TitleLabel : public QLabel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TitleLabel(const QString &text)
|
||||
: QLabel(text)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class DescriptionLabel : public QLabel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DescriptionLabel(const QString &text)
|
||||
: QLabel(text)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct DropdownArgs {
|
||||
QString value;
|
||||
int index;
|
||||
QComboBox *combobox;
|
||||
};
|
||||
|
||||
class ComboBox : public QComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
void wheelEvent(QWheelEvent *event) override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class SettingsLayout : public QVBoxLayout
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TitleLabel *addTitle(const QString &text);
|
||||
/// @param inverse Inverses true to false and vice versa
|
||||
QCheckBox *addCheckbox(const QString &text, BoolSetting &setting,
|
||||
bool inverse = false);
|
||||
ComboBox *addDropdown(const QString &text, const QStringList &items);
|
||||
ComboBox *addDropdown(const QString &text, const QStringList &items,
|
||||
pajlada::Settings::Setting<QString> &setting,
|
||||
bool editable = false);
|
||||
|
||||
template <typename OnClick>
|
||||
QPushButton *makeButton(const QString &text, OnClick onClick)
|
||||
{
|
||||
auto button = new QPushButton(text);
|
||||
this->groups_.back().widgets.push_back({button, {text}});
|
||||
QObject::connect(button, &QPushButton::clicked, onClick);
|
||||
return button;
|
||||
}
|
||||
|
||||
template <typename OnClick>
|
||||
QPushButton *addButton(const QString &text, OnClick onClick)
|
||||
{
|
||||
auto button = makeButton(text, onClick);
|
||||
auto layout = new QHBoxLayout();
|
||||
layout->addWidget(button);
|
||||
layout->addStretch(1);
|
||||
this->addLayout(layout);
|
||||
return button;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ComboBox *addDropdown(
|
||||
const QString &text, const QStringList &items,
|
||||
pajlada::Settings::Setting<T> &setting,
|
||||
std::function<boost::variant<int, QString>(T)> getValue,
|
||||
std::function<T(DropdownArgs)> setValue, bool editable = true)
|
||||
{
|
||||
auto items2 = items;
|
||||
auto selected = getValue(setting.getValue());
|
||||
|
||||
if (selected.which() == 1)
|
||||
{
|
||||
// QString
|
||||
if (!editable && !items2.contains(boost::get<QString>(selected)))
|
||||
items2.insert(0, boost::get<QString>(selected));
|
||||
}
|
||||
|
||||
auto combo = this->addDropdown(text, items2);
|
||||
if (editable)
|
||||
combo->setEditable(true);
|
||||
|
||||
if (selected.which() == 0)
|
||||
{
|
||||
// int
|
||||
auto value = boost::get<int>(selected);
|
||||
if (value >= 0 && value < items2.size())
|
||||
combo->setCurrentIndex(value);
|
||||
}
|
||||
else if (selected.which() == 1)
|
||||
{
|
||||
// QString
|
||||
combo->setEditText(boost::get<QString>(selected));
|
||||
}
|
||||
|
||||
setting.connect(
|
||||
[getValue = std::move(getValue), combo](const T &value, auto) {
|
||||
auto var = getValue(value);
|
||||
if (var.which() == 0)
|
||||
combo->setCurrentIndex(boost::get<int>(var));
|
||||
else
|
||||
{
|
||||
combo->setCurrentText(boost::get<QString>(var));
|
||||
combo->setEditText(boost::get<QString>(var));
|
||||
}
|
||||
},
|
||||
this->managedConnections_);
|
||||
|
||||
QObject::connect(
|
||||
combo,
|
||||
QOverload<const QString &>::of(&QComboBox::currentIndexChanged),
|
||||
// &QComboBox::editTextChanged,
|
||||
[combo, &setting,
|
||||
setValue = std::move(setValue)](const QString &newValue) {
|
||||
setting = setValue(
|
||||
DropdownArgs{newValue, combo->currentIndex(), combo});
|
||||
getApp()->windows->forceLayoutChannelViews();
|
||||
});
|
||||
|
||||
return combo;
|
||||
}
|
||||
DescriptionLabel *addDescription(const QString &text);
|
||||
|
||||
void addSeperator();
|
||||
bool filterElements(const QString &query);
|
||||
|
||||
private:
|
||||
struct Widget {
|
||||
QWidget *element;
|
||||
QStringList keywords;
|
||||
};
|
||||
|
||||
struct Group {
|
||||
QString name;
|
||||
QWidget *title{};
|
||||
std::vector<Widget> widgets;
|
||||
};
|
||||
|
||||
std::vector<Group> groups_;
|
||||
std::vector<pajlada::Signals::ScopedConnection> managedConnections_;
|
||||
};
|
||||
|
||||
class GeneralPage : public SettingsPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GeneralPage();
|
||||
|
||||
bool filterElements(const QString &query);
|
||||
|
||||
private:
|
||||
void initLayout(SettingsLayout &layout);
|
||||
void initExtra();
|
||||
|
||||
QString getFont(const DropdownArgs &args) const;
|
||||
|
||||
DescriptionLabel *cachePath_{};
|
||||
SettingsLayout *settingsLayout_{};
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
#pragma once
|
||||
|
||||
#include <QDebug>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "boost/variant.hpp"
|
||||
#include "pajlada/signals/signal.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "singletons/WindowManager.hpp"
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
class QLabel;
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class TitleLabel : public QLabel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TitleLabel(const QString &text)
|
||||
: QLabel(text)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class DescriptionLabel : public QLabel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DescriptionLabel(const QString &text)
|
||||
: QLabel(text)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct DropdownArgs {
|
||||
QString value;
|
||||
int index;
|
||||
QComboBox *combobox;
|
||||
};
|
||||
|
||||
class ComboBox : public QComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
void wheelEvent(QWheelEvent *event) override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class SettingsLayout : public QVBoxLayout
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TitleLabel *addTitle(const QString &text);
|
||||
/// @param inverse Inverses true to false and vice versa
|
||||
QCheckBox *addCheckbox(const QString &text, BoolSetting &setting,
|
||||
bool inverse = false);
|
||||
ComboBox *addDropdown(const QString &text, const QStringList &items);
|
||||
ComboBox *addDropdown(const QString &text, const QStringList &items,
|
||||
pajlada::Settings::Setting<QString> &setting,
|
||||
bool editable = false);
|
||||
|
||||
template <typename OnClick>
|
||||
QPushButton *makeButton(const QString &text, OnClick onClick)
|
||||
{
|
||||
auto button = new QPushButton(text);
|
||||
this->groups_.back().widgets.push_back({button, {text}});
|
||||
QObject::connect(button, &QPushButton::clicked, onClick);
|
||||
return button;
|
||||
}
|
||||
|
||||
template <typename OnClick>
|
||||
QPushButton *addButton(const QString &text, OnClick onClick)
|
||||
{
|
||||
auto button = makeButton(text, onClick);
|
||||
auto layout = new QHBoxLayout();
|
||||
layout->addWidget(button);
|
||||
layout->addStretch(1);
|
||||
this->addLayout(layout);
|
||||
return button;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ComboBox *addDropdown(
|
||||
const QString &text, const QStringList &items,
|
||||
pajlada::Settings::Setting<T> &setting,
|
||||
std::function<boost::variant<int, QString>(T)> getValue,
|
||||
std::function<T(DropdownArgs)> setValue, bool editable = true)
|
||||
{
|
||||
auto items2 = items;
|
||||
auto selected = getValue(setting.getValue());
|
||||
|
||||
if (selected.which() == 1)
|
||||
{
|
||||
// QString
|
||||
if (!editable && !items2.contains(boost::get<QString>(selected)))
|
||||
items2.insert(0, boost::get<QString>(selected));
|
||||
}
|
||||
|
||||
auto combo = this->addDropdown(text, items2);
|
||||
if (editable)
|
||||
combo->setEditable(true);
|
||||
|
||||
if (selected.which() == 0)
|
||||
{
|
||||
// int
|
||||
auto value = boost::get<int>(selected);
|
||||
if (value >= 0 && value < items2.size())
|
||||
combo->setCurrentIndex(value);
|
||||
}
|
||||
else if (selected.which() == 1)
|
||||
{
|
||||
// QString
|
||||
combo->setEditText(boost::get<QString>(selected));
|
||||
}
|
||||
|
||||
setting.connect(
|
||||
[getValue = std::move(getValue), combo](const T &value, auto) {
|
||||
auto var = getValue(value);
|
||||
if (var.which() == 0)
|
||||
combo->setCurrentIndex(boost::get<int>(var));
|
||||
else
|
||||
{
|
||||
combo->setCurrentText(boost::get<QString>(var));
|
||||
combo->setEditText(boost::get<QString>(var));
|
||||
}
|
||||
},
|
||||
this->managedConnections_);
|
||||
|
||||
QObject::connect(
|
||||
combo,
|
||||
QOverload<const QString &>::of(&QComboBox::currentIndexChanged),
|
||||
// &QComboBox::editTextChanged,
|
||||
[combo, &setting,
|
||||
setValue = std::move(setValue)](const QString &newValue) {
|
||||
setting = setValue(
|
||||
DropdownArgs{newValue, combo->currentIndex(), combo});
|
||||
getApp()->windows->forceLayoutChannelViews();
|
||||
});
|
||||
|
||||
return combo;
|
||||
}
|
||||
DescriptionLabel *addDescription(const QString &text);
|
||||
|
||||
void addSeperator();
|
||||
bool filterElements(const QString &query);
|
||||
|
||||
private:
|
||||
struct Widget {
|
||||
QWidget *element;
|
||||
QStringList keywords;
|
||||
};
|
||||
|
||||
struct Group {
|
||||
QString name;
|
||||
QWidget *title{};
|
||||
std::vector<Widget> widgets;
|
||||
};
|
||||
|
||||
std::vector<Group> groups_;
|
||||
std::vector<pajlada::Signals::ScopedConnection> managedConnections_;
|
||||
};
|
||||
|
||||
class GeneralPage : public SettingsPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GeneralPage();
|
||||
|
||||
bool filterElements(const QString &query);
|
||||
|
||||
private:
|
||||
void initLayout(SettingsLayout &layout);
|
||||
void initExtra();
|
||||
|
||||
QString getFont(const DropdownArgs &args) const;
|
||||
|
||||
DescriptionLabel *cachePath_{};
|
||||
SettingsLayout *settingsLayout_{};
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,175 +1,175 @@
|
||||
#include "HighlightingPage.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "controllers/highlights/HighlightBlacklistModel.hpp"
|
||||
#include "controllers/highlights/HighlightController.hpp"
|
||||
#include "controllers/highlights/HighlightModel.hpp"
|
||||
#include "controllers/highlights/UserHighlightModel.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "util/StandardItemHelper.hpp"
|
||||
#include "widgets/helper/EditableModelView.hpp"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QHeaderView>
|
||||
#include <QListWidget>
|
||||
#include <QPushButton>
|
||||
#include <QStandardItemModel>
|
||||
#include <QTabWidget>
|
||||
#include <QTableView>
|
||||
#include <QTextEdit>
|
||||
|
||||
#define ENABLE_HIGHLIGHTS "Enable Highlighting"
|
||||
#define HIGHLIGHT_MSG "Highlight messages containing your name"
|
||||
#define PLAY_SOUND "Play sound when your name is mentioned"
|
||||
#define FLASH_TASKBAR "Flash taskbar when your name is mentioned"
|
||||
#define ALWAYS_PLAY "Play highlight sound even when Chatterino is focused"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
HighlightingPage::HighlightingPage()
|
||||
: SettingsPage("Highlights", ":/settings/notifications.svg")
|
||||
{
|
||||
auto app = getApp();
|
||||
LayoutCreator<HighlightingPage> layoutCreator(this);
|
||||
|
||||
auto layout = layoutCreator.emplace<QVBoxLayout>().withoutMargin();
|
||||
{
|
||||
// GENERAL
|
||||
// layout.append(this->createCheckBox(ENABLE_HIGHLIGHTS,
|
||||
// getSettings()->enableHighlights));
|
||||
|
||||
// TABS
|
||||
auto tabs = layout.emplace<QTabWidget>();
|
||||
{
|
||||
// HIGHLIGHTS
|
||||
auto highlights = tabs.appendTab(new QVBoxLayout, "Messages");
|
||||
{
|
||||
highlights.emplace<QLabel>("Messages can be highlighted if "
|
||||
"they match a certain pattern.");
|
||||
|
||||
EditableModelView *view =
|
||||
highlights
|
||||
.emplace<EditableModelView>(
|
||||
app->highlights->createModel(nullptr))
|
||||
.getElement();
|
||||
|
||||
view->addRegexHelpLink();
|
||||
view->setTitles({"Pattern", "Flash\ntaskbar", "Play\nsound",
|
||||
"Enable\nregex", "Case-\nsensitive"});
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
QHeaderView::Fixed);
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
0, QHeaderView::Stretch);
|
||||
|
||||
// fourtf: make class extrend BaseWidget and add this to
|
||||
// dpiChanged
|
||||
QTimer::singleShot(1, [view] {
|
||||
view->getTableView()->resizeColumnsToContents();
|
||||
view->getTableView()->setColumnWidth(0, 200);
|
||||
});
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
getApp()->highlights->phrases.appendItem(HighlightPhrase{
|
||||
"my phrase", true, false, false, false});
|
||||
});
|
||||
}
|
||||
|
||||
auto pingUsers = tabs.appendTab(new QVBoxLayout, "Users");
|
||||
{
|
||||
pingUsers.emplace<QLabel>(
|
||||
"Messages from a certain user can be highlighted.");
|
||||
EditableModelView *view =
|
||||
pingUsers
|
||||
.emplace<EditableModelView>(
|
||||
app->highlights->createUserModel(nullptr))
|
||||
.getElement();
|
||||
|
||||
view->addRegexHelpLink();
|
||||
view->getTableView()->horizontalHeader()->hideSection(4);
|
||||
|
||||
// Case-sensitivity doesn't make sense for user names so it is
|
||||
// set to "false" by default & no checkbox is shown
|
||||
view->setTitles({"Username", "Flash\ntaskbar", "Play\nsound",
|
||||
"Enable\nregex"});
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
QHeaderView::Fixed);
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
0, QHeaderView::Stretch);
|
||||
|
||||
// fourtf: make class extrend BaseWidget and add this to
|
||||
// dpiChanged
|
||||
QTimer::singleShot(1, [view] {
|
||||
view->getTableView()->resizeColumnsToContents();
|
||||
view->getTableView()->setColumnWidth(0, 200);
|
||||
});
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
getApp()->highlights->highlightedUsers.appendItem(
|
||||
HighlightPhrase{"highlighted user", true, false, false,
|
||||
false});
|
||||
});
|
||||
}
|
||||
|
||||
auto disabledUsers =
|
||||
tabs.appendTab(new QVBoxLayout, "Excluded Users");
|
||||
{
|
||||
disabledUsers.emplace<QLabel>(
|
||||
"This is a list of users (e.g. bots) whose messages should "
|
||||
"<u>not</u> be highlighted.");
|
||||
EditableModelView *view =
|
||||
disabledUsers
|
||||
.emplace<EditableModelView>(
|
||||
app->highlights->createBlacklistModel(nullptr))
|
||||
.getElement();
|
||||
|
||||
view->addRegexHelpLink();
|
||||
view->setTitles({"Pattern", "Enable\nregex"});
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
QHeaderView::Fixed);
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
0, QHeaderView::Stretch);
|
||||
|
||||
// fourtf: make class extrend BaseWidget and add this to
|
||||
// dpiChanged
|
||||
QTimer::singleShot(1, [view] {
|
||||
view->getTableView()->resizeColumnsToContents();
|
||||
view->getTableView()->setColumnWidth(0, 200);
|
||||
});
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
getApp()->highlights->blacklistedUsers.appendItem(
|
||||
HighlightBlacklistUser{"blacklisted user", false});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// MISC
|
||||
auto customSound = layout.emplace<QHBoxLayout>().withoutMargin();
|
||||
{
|
||||
customSound.append(this->createCheckBox(
|
||||
"Custom sound", getSettings()->customHighlightSound));
|
||||
auto selectFile =
|
||||
customSound.emplace<QPushButton>("Select custom sound file");
|
||||
QObject::connect(selectFile.getElement(), &QPushButton::clicked,
|
||||
this, [this] {
|
||||
auto fileName = QFileDialog::getOpenFileName(
|
||||
this, tr("Open Sound"), "",
|
||||
tr("Audio Files (*.mp3 *.wav)"));
|
||||
getSettings()->pathHighlightSound = fileName;
|
||||
});
|
||||
}
|
||||
|
||||
layout.append(createCheckBox(ALWAYS_PLAY,
|
||||
getSettings()->highlightAlwaysPlaySound));
|
||||
layout.append(createCheckBox(
|
||||
"Flash taskbar only stops highlighting when chatterino is focused",
|
||||
getSettings()->longAlerts));
|
||||
}
|
||||
|
||||
// ---- misc
|
||||
this->disabledUsersChangedTimer_.setSingleShot(true);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
#include "HighlightingPage.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "controllers/highlights/HighlightBlacklistModel.hpp"
|
||||
#include "controllers/highlights/HighlightController.hpp"
|
||||
#include "controllers/highlights/HighlightModel.hpp"
|
||||
#include "controllers/highlights/UserHighlightModel.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "util/StandardItemHelper.hpp"
|
||||
#include "widgets/helper/EditableModelView.hpp"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QHeaderView>
|
||||
#include <QListWidget>
|
||||
#include <QPushButton>
|
||||
#include <QStandardItemModel>
|
||||
#include <QTabWidget>
|
||||
#include <QTableView>
|
||||
#include <QTextEdit>
|
||||
|
||||
#define ENABLE_HIGHLIGHTS "Enable Highlighting"
|
||||
#define HIGHLIGHT_MSG "Highlight messages containing your name"
|
||||
#define PLAY_SOUND "Play sound when your name is mentioned"
|
||||
#define FLASH_TASKBAR "Flash taskbar when your name is mentioned"
|
||||
#define ALWAYS_PLAY "Play highlight sound even when Chatterino is focused"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
HighlightingPage::HighlightingPage()
|
||||
: SettingsPage("Highlights", ":/settings/notifications.svg")
|
||||
{
|
||||
auto app = getApp();
|
||||
LayoutCreator<HighlightingPage> layoutCreator(this);
|
||||
|
||||
auto layout = layoutCreator.emplace<QVBoxLayout>().withoutMargin();
|
||||
{
|
||||
// GENERAL
|
||||
// layout.append(this->createCheckBox(ENABLE_HIGHLIGHTS,
|
||||
// getSettings()->enableHighlights));
|
||||
|
||||
// TABS
|
||||
auto tabs = layout.emplace<QTabWidget>();
|
||||
{
|
||||
// HIGHLIGHTS
|
||||
auto highlights = tabs.appendTab(new QVBoxLayout, "Messages");
|
||||
{
|
||||
highlights.emplace<QLabel>("Messages can be highlighted if "
|
||||
"they match a certain pattern.");
|
||||
|
||||
EditableModelView *view =
|
||||
highlights
|
||||
.emplace<EditableModelView>(
|
||||
app->highlights->createModel(nullptr))
|
||||
.getElement();
|
||||
|
||||
view->addRegexHelpLink();
|
||||
view->setTitles({"Pattern", "Flash\ntaskbar", "Play\nsound",
|
||||
"Enable\nregex", "Case-\nsensitive"});
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
QHeaderView::Fixed);
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
0, QHeaderView::Stretch);
|
||||
|
||||
// fourtf: make class extrend BaseWidget and add this to
|
||||
// dpiChanged
|
||||
QTimer::singleShot(1, [view] {
|
||||
view->getTableView()->resizeColumnsToContents();
|
||||
view->getTableView()->setColumnWidth(0, 200);
|
||||
});
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
getApp()->highlights->phrases.appendItem(HighlightPhrase{
|
||||
"my phrase", true, false, false, false});
|
||||
});
|
||||
}
|
||||
|
||||
auto pingUsers = tabs.appendTab(new QVBoxLayout, "Users");
|
||||
{
|
||||
pingUsers.emplace<QLabel>(
|
||||
"Messages from a certain user can be highlighted.");
|
||||
EditableModelView *view =
|
||||
pingUsers
|
||||
.emplace<EditableModelView>(
|
||||
app->highlights->createUserModel(nullptr))
|
||||
.getElement();
|
||||
|
||||
view->addRegexHelpLink();
|
||||
view->getTableView()->horizontalHeader()->hideSection(4);
|
||||
|
||||
// Case-sensitivity doesn't make sense for user names so it is
|
||||
// set to "false" by default & no checkbox is shown
|
||||
view->setTitles({"Username", "Flash\ntaskbar", "Play\nsound",
|
||||
"Enable\nregex"});
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
QHeaderView::Fixed);
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
0, QHeaderView::Stretch);
|
||||
|
||||
// fourtf: make class extrend BaseWidget and add this to
|
||||
// dpiChanged
|
||||
QTimer::singleShot(1, [view] {
|
||||
view->getTableView()->resizeColumnsToContents();
|
||||
view->getTableView()->setColumnWidth(0, 200);
|
||||
});
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
getApp()->highlights->highlightedUsers.appendItem(
|
||||
HighlightPhrase{"highlighted user", true, false, false,
|
||||
false});
|
||||
});
|
||||
}
|
||||
|
||||
auto disabledUsers =
|
||||
tabs.appendTab(new QVBoxLayout, "Excluded Users");
|
||||
{
|
||||
disabledUsers.emplace<QLabel>(
|
||||
"This is a list of users (e.g. bots) whose messages should "
|
||||
"<u>not</u> be highlighted.");
|
||||
EditableModelView *view =
|
||||
disabledUsers
|
||||
.emplace<EditableModelView>(
|
||||
app->highlights->createBlacklistModel(nullptr))
|
||||
.getElement();
|
||||
|
||||
view->addRegexHelpLink();
|
||||
view->setTitles({"Pattern", "Enable\nregex"});
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
QHeaderView::Fixed);
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
0, QHeaderView::Stretch);
|
||||
|
||||
// fourtf: make class extrend BaseWidget and add this to
|
||||
// dpiChanged
|
||||
QTimer::singleShot(1, [view] {
|
||||
view->getTableView()->resizeColumnsToContents();
|
||||
view->getTableView()->setColumnWidth(0, 200);
|
||||
});
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
getApp()->highlights->blacklistedUsers.appendItem(
|
||||
HighlightBlacklistUser{"blacklisted user", false});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// MISC
|
||||
auto customSound = layout.emplace<QHBoxLayout>().withoutMargin();
|
||||
{
|
||||
customSound.append(this->createCheckBox(
|
||||
"Custom sound", getSettings()->customHighlightSound));
|
||||
auto selectFile =
|
||||
customSound.emplace<QPushButton>("Select custom sound file");
|
||||
QObject::connect(selectFile.getElement(), &QPushButton::clicked,
|
||||
this, [this] {
|
||||
auto fileName = QFileDialog::getOpenFileName(
|
||||
this, tr("Open Sound"), "",
|
||||
tr("Audio Files (*.mp3 *.wav)"));
|
||||
getSettings()->pathHighlightSound = fileName;
|
||||
});
|
||||
}
|
||||
|
||||
layout.append(createCheckBox(ALWAYS_PLAY,
|
||||
getSettings()->highlightAlwaysPlaySound));
|
||||
layout.append(createCheckBox(
|
||||
"Flash taskbar only stops highlighting when chatterino is focused",
|
||||
getSettings()->longAlerts));
|
||||
}
|
||||
|
||||
// ---- misc
|
||||
this->disabledUsersChangedTimer_.setSingleShot(true);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QTimer>
|
||||
|
||||
class QPushButton;
|
||||
class QListWidget;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class HighlightingPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
HighlightingPage();
|
||||
|
||||
private:
|
||||
QTimer disabledUsersChangedTimer_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
#pragma once
|
||||
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QTimer>
|
||||
|
||||
class QPushButton;
|
||||
class QListWidget;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class HighlightingPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
HighlightingPage();
|
||||
|
||||
private:
|
||||
QTimer disabledUsersChangedTimer_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,133 +1,133 @@
|
||||
#include "IgnoresPage.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "controllers/accounts/AccountController.hpp"
|
||||
#include "controllers/ignores/IgnoreController.hpp"
|
||||
#include "controllers/ignores/IgnoreModel.hpp"
|
||||
#include "providers/twitch/TwitchAccount.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "widgets/helper/EditableModelView.hpp"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QGroupBox>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QListView>
|
||||
#include <QPushButton>
|
||||
#include <QTableView>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
// clang-format off
|
||||
#define INFO "/ignore <user> in chat ignores a user.\n/unignore <user> in chat unignores a user.\nYou can also click on a user to open the usercard."
|
||||
// clang-format on
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
static void addPhrasesTab(LayoutCreator<QVBoxLayout> box);
|
||||
static void addUsersTab(IgnoresPage &page, LayoutCreator<QVBoxLayout> box,
|
||||
QStringListModel &model);
|
||||
|
||||
IgnoresPage::IgnoresPage()
|
||||
: SettingsPage("Ignores", ":/settings/ignore.svg")
|
||||
{
|
||||
LayoutCreator<IgnoresPage> layoutCreator(this);
|
||||
auto layout = layoutCreator.setLayoutType<QVBoxLayout>();
|
||||
auto tabs = layout.emplace<QTabWidget>();
|
||||
|
||||
addPhrasesTab(tabs.appendTab(new QVBoxLayout, "Messages"));
|
||||
addUsersTab(*this, tabs.appendTab(new QVBoxLayout, "Users"),
|
||||
this->userListModel_);
|
||||
}
|
||||
|
||||
void addPhrasesTab(LayoutCreator<QVBoxLayout> layout)
|
||||
{
|
||||
layout.emplace<QLabel>("Messages can be ignored if "
|
||||
"they match a certain pattern.");
|
||||
EditableModelView *view =
|
||||
layout
|
||||
.emplace<EditableModelView>(getApp()->ignores->createModel(nullptr))
|
||||
.getElement();
|
||||
view->setTitles(
|
||||
{"Pattern", "Regex", "Case Sensitive", "Block", "Replacement"});
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
QHeaderView::Fixed);
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
0, QHeaderView::Stretch);
|
||||
view->addRegexHelpLink();
|
||||
|
||||
QTimer::singleShot(1, [view] {
|
||||
view->getTableView()->resizeColumnsToContents();
|
||||
view->getTableView()->setColumnWidth(0, 200);
|
||||
});
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
getApp()->ignores->phrases.appendItem(
|
||||
IgnorePhrase{"my pattern", false, false,
|
||||
getSettings()->ignoredPhraseReplace.getValue(), true});
|
||||
});
|
||||
}
|
||||
|
||||
void addUsersTab(IgnoresPage &page, LayoutCreator<QVBoxLayout> users,
|
||||
QStringListModel &userModel)
|
||||
{
|
||||
auto label = users.emplace<QLabel>(INFO);
|
||||
label->setWordWrap(true);
|
||||
users.append(page.createCheckBox("Enable twitch ignored users",
|
||||
getSettings()->enableTwitchIgnoredUsers));
|
||||
|
||||
auto anyways = users.emplace<QHBoxLayout>().withoutMargin();
|
||||
{
|
||||
anyways.emplace<QLabel>("Show messages from ignored users anyways:");
|
||||
|
||||
auto combo = anyways.emplace<QComboBox>().getElement();
|
||||
combo->addItems(
|
||||
{"Never", "If you are Moderator", "If you are Broadcaster"});
|
||||
|
||||
auto &setting = getSettings()->showIgnoredUsersMessages;
|
||||
|
||||
setting.connect(
|
||||
[combo](const int value) { combo->setCurrentIndex(value); });
|
||||
|
||||
QObject::connect(combo,
|
||||
QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
[&setting](int index) {
|
||||
if (index != -1)
|
||||
setting = index;
|
||||
});
|
||||
|
||||
anyways->addStretch(1);
|
||||
}
|
||||
|
||||
/*auto addremove = users.emplace<QHBoxLayout>().withoutMargin();
|
||||
{
|
||||
auto add = addremove.emplace<QPushButton>("Ignore user");
|
||||
auto remove = addremove.emplace<QPushButton>("Unignore User");
|
||||
addremove->addStretch(1);
|
||||
}*/
|
||||
|
||||
users.emplace<QLabel>("List of ignored users:");
|
||||
users.emplace<QListView>()->setModel(&userModel);
|
||||
}
|
||||
|
||||
void IgnoresPage::onShow()
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
auto user = app->accounts->twitch.getCurrent();
|
||||
|
||||
if (user->isAnon())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList users;
|
||||
for (const auto &ignoredUser : user->getIgnores())
|
||||
{
|
||||
users << ignoredUser.name;
|
||||
}
|
||||
users.sort(Qt::CaseInsensitive);
|
||||
this->userListModel_.setStringList(users);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
#include "IgnoresPage.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "controllers/accounts/AccountController.hpp"
|
||||
#include "controllers/ignores/IgnoreController.hpp"
|
||||
#include "controllers/ignores/IgnoreModel.hpp"
|
||||
#include "providers/twitch/TwitchAccount.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "widgets/helper/EditableModelView.hpp"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QGroupBox>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QListView>
|
||||
#include <QPushButton>
|
||||
#include <QTableView>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
// clang-format off
|
||||
#define INFO "/ignore <user> in chat ignores a user.\n/unignore <user> in chat unignores a user.\nYou can also click on a user to open the usercard."
|
||||
// clang-format on
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
static void addPhrasesTab(LayoutCreator<QVBoxLayout> box);
|
||||
static void addUsersTab(IgnoresPage &page, LayoutCreator<QVBoxLayout> box,
|
||||
QStringListModel &model);
|
||||
|
||||
IgnoresPage::IgnoresPage()
|
||||
: SettingsPage("Ignores", ":/settings/ignore.svg")
|
||||
{
|
||||
LayoutCreator<IgnoresPage> layoutCreator(this);
|
||||
auto layout = layoutCreator.setLayoutType<QVBoxLayout>();
|
||||
auto tabs = layout.emplace<QTabWidget>();
|
||||
|
||||
addPhrasesTab(tabs.appendTab(new QVBoxLayout, "Messages"));
|
||||
addUsersTab(*this, tabs.appendTab(new QVBoxLayout, "Users"),
|
||||
this->userListModel_);
|
||||
}
|
||||
|
||||
void addPhrasesTab(LayoutCreator<QVBoxLayout> layout)
|
||||
{
|
||||
layout.emplace<QLabel>("Messages can be ignored if "
|
||||
"they match a certain pattern.");
|
||||
EditableModelView *view =
|
||||
layout
|
||||
.emplace<EditableModelView>(getApp()->ignores->createModel(nullptr))
|
||||
.getElement();
|
||||
view->setTitles(
|
||||
{"Pattern", "Regex", "Case Sensitive", "Block", "Replacement"});
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
QHeaderView::Fixed);
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
0, QHeaderView::Stretch);
|
||||
view->addRegexHelpLink();
|
||||
|
||||
QTimer::singleShot(1, [view] {
|
||||
view->getTableView()->resizeColumnsToContents();
|
||||
view->getTableView()->setColumnWidth(0, 200);
|
||||
});
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
getApp()->ignores->phrases.appendItem(
|
||||
IgnorePhrase{"my pattern", false, false,
|
||||
getSettings()->ignoredPhraseReplace.getValue(), true});
|
||||
});
|
||||
}
|
||||
|
||||
void addUsersTab(IgnoresPage &page, LayoutCreator<QVBoxLayout> users,
|
||||
QStringListModel &userModel)
|
||||
{
|
||||
auto label = users.emplace<QLabel>(INFO);
|
||||
label->setWordWrap(true);
|
||||
users.append(page.createCheckBox("Enable twitch ignored users",
|
||||
getSettings()->enableTwitchIgnoredUsers));
|
||||
|
||||
auto anyways = users.emplace<QHBoxLayout>().withoutMargin();
|
||||
{
|
||||
anyways.emplace<QLabel>("Show messages from ignored users anyways:");
|
||||
|
||||
auto combo = anyways.emplace<QComboBox>().getElement();
|
||||
combo->addItems(
|
||||
{"Never", "If you are Moderator", "If you are Broadcaster"});
|
||||
|
||||
auto &setting = getSettings()->showIgnoredUsersMessages;
|
||||
|
||||
setting.connect(
|
||||
[combo](const int value) { combo->setCurrentIndex(value); });
|
||||
|
||||
QObject::connect(combo,
|
||||
QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
[&setting](int index) {
|
||||
if (index != -1)
|
||||
setting = index;
|
||||
});
|
||||
|
||||
anyways->addStretch(1);
|
||||
}
|
||||
|
||||
/*auto addremove = users.emplace<QHBoxLayout>().withoutMargin();
|
||||
{
|
||||
auto add = addremove.emplace<QPushButton>("Ignore user");
|
||||
auto remove = addremove.emplace<QPushButton>("Unignore User");
|
||||
addremove->addStretch(1);
|
||||
}*/
|
||||
|
||||
users.emplace<QLabel>("List of ignored users:");
|
||||
users.emplace<QListView>()->setModel(&userModel);
|
||||
}
|
||||
|
||||
void IgnoresPage::onShow()
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
auto user = app->accounts->twitch.getCurrent();
|
||||
|
||||
if (user->isAnon())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList users;
|
||||
for (const auto &ignoredUser : user->getIgnores())
|
||||
{
|
||||
users << ignoredUser.name;
|
||||
}
|
||||
users.sort(Qt::CaseInsensitive);
|
||||
this->userListModel_.setStringList(users);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
#include <QStringListModel>
|
||||
|
||||
class QVBoxLayout;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class IgnoresPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
IgnoresPage();
|
||||
|
||||
void onShow() final;
|
||||
|
||||
private:
|
||||
QStringListModel userListModel_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
#pragma once
|
||||
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
#include <QStringListModel>
|
||||
|
||||
class QVBoxLayout;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class IgnoresPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
IgnoresPage();
|
||||
|
||||
void onShow() final;
|
||||
|
||||
private:
|
||||
QStringListModel userListModel_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
#include "KeyboardSettingsPage.hpp"
|
||||
|
||||
#include "util/LayoutCreator.hpp"
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QLabel>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
KeyboardSettingsPage::KeyboardSettingsPage()
|
||||
: SettingsPage("Keybindings", ":/settings/keybinds.svg")
|
||||
{
|
||||
auto layout =
|
||||
LayoutCreator<KeyboardSettingsPage>(this).setLayoutType<QVBoxLayout>();
|
||||
|
||||
auto form = layout.emplace<QFormLayout>().withoutMargin();
|
||||
|
||||
form->addRow(new QLabel("Hold Ctrl"), new QLabel("Show resize handles"));
|
||||
form->addRow(new QLabel("Hold Ctrl + Alt"),
|
||||
new QLabel("Show split overlay"));
|
||||
|
||||
form->addItem(new QSpacerItem(16, 16));
|
||||
form->addRow(new QLabel("Ctrl + T"), new QLabel("Create new split"));
|
||||
form->addRow(new QLabel("Ctrl + W"), new QLabel("Close current split"));
|
||||
|
||||
form->addRow(new QLabel("Ctrl + Shift + T"), new QLabel("Create new tab"));
|
||||
form->addRow(new QLabel("Ctrl + Shift + W"),
|
||||
new QLabel("Close current tab"));
|
||||
|
||||
form->addItem(new QSpacerItem(16, 16));
|
||||
form->addRow(new QLabel("Ctrl + 1/2/3/..."),
|
||||
new QLabel("Select tab 1/2/3/..."));
|
||||
form->addRow(new QLabel("Ctrl + Tab"), new QLabel("Select next tab"));
|
||||
form->addRow(new QLabel("Ctrl + Shift + Tab"),
|
||||
new QLabel("Select previous tab"));
|
||||
|
||||
form->addRow(new QLabel("Alt + Left/Up/Right/Down"),
|
||||
new QLabel("Select split left/up/right/down"));
|
||||
|
||||
form->addItem(new QSpacerItem(16, 16));
|
||||
form->addRow(new QLabel("Ctrl + R"), new QLabel("Change channel"));
|
||||
form->addRow(new QLabel("Ctrl + F"),
|
||||
new QLabel("Search in current channel"));
|
||||
form->addRow(new QLabel("Ctrl + E"), new QLabel("Open Emote menu"));
|
||||
form->addRow(new QLabel("Ctrl + P"), new QLabel("Open Settings menu"));
|
||||
form->addRow(new QLabel("F5"),
|
||||
new QLabel("Reload subscriber and channel emotes"));
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
#include "KeyboardSettingsPage.hpp"
|
||||
|
||||
#include "util/LayoutCreator.hpp"
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QLabel>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
KeyboardSettingsPage::KeyboardSettingsPage()
|
||||
: SettingsPage("Keybindings", ":/settings/keybinds.svg")
|
||||
{
|
||||
auto layout =
|
||||
LayoutCreator<KeyboardSettingsPage>(this).setLayoutType<QVBoxLayout>();
|
||||
|
||||
auto form = layout.emplace<QFormLayout>().withoutMargin();
|
||||
|
||||
form->addRow(new QLabel("Hold Ctrl"), new QLabel("Show resize handles"));
|
||||
form->addRow(new QLabel("Hold Ctrl + Alt"),
|
||||
new QLabel("Show split overlay"));
|
||||
|
||||
form->addItem(new QSpacerItem(16, 16));
|
||||
form->addRow(new QLabel("Ctrl + T"), new QLabel("Create new split"));
|
||||
form->addRow(new QLabel("Ctrl + W"), new QLabel("Close current split"));
|
||||
|
||||
form->addRow(new QLabel("Ctrl + Shift + T"), new QLabel("Create new tab"));
|
||||
form->addRow(new QLabel("Ctrl + Shift + W"),
|
||||
new QLabel("Close current tab"));
|
||||
|
||||
form->addItem(new QSpacerItem(16, 16));
|
||||
form->addRow(new QLabel("Ctrl + 1/2/3/..."),
|
||||
new QLabel("Select tab 1/2/3/..."));
|
||||
form->addRow(new QLabel("Ctrl + Tab"), new QLabel("Select next tab"));
|
||||
form->addRow(new QLabel("Ctrl + Shift + Tab"),
|
||||
new QLabel("Select previous tab"));
|
||||
|
||||
form->addRow(new QLabel("Alt + Left/Up/Right/Down"),
|
||||
new QLabel("Select split left/up/right/down"));
|
||||
|
||||
form->addItem(new QSpacerItem(16, 16));
|
||||
form->addRow(new QLabel("Ctrl + R"), new QLabel("Change channel"));
|
||||
form->addRow(new QLabel("Ctrl + F"),
|
||||
new QLabel("Search in current channel"));
|
||||
form->addRow(new QLabel("Ctrl + E"), new QLabel("Open Emote menu"));
|
||||
form->addRow(new QLabel("Ctrl + P"), new QLabel("Open Settings menu"));
|
||||
form->addRow(new QLabel("F5"),
|
||||
new QLabel("Reload subscriber and channel emotes"));
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class KeyboardSettingsPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
KeyboardSettingsPage();
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
#pragma once
|
||||
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class KeyboardSettingsPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
KeyboardSettingsPage();
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,216 +1,216 @@
|
||||
#include "ModerationPage.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "controllers/moderationactions/ModerationActionModel.hpp"
|
||||
#include "controllers/moderationactions/ModerationActions.hpp"
|
||||
#include "controllers/taggedusers/TaggedUsersController.hpp"
|
||||
#include "controllers/taggedusers/TaggedUsersModel.hpp"
|
||||
#include "singletons/Logging.hpp"
|
||||
#include "singletons/Paths.hpp"
|
||||
#include "util/Helpers.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "widgets/helper/EditableModelView.hpp"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QFormLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QListView>
|
||||
#include <QPushButton>
|
||||
#include <QTableView>
|
||||
#include <QTextEdit>
|
||||
#include <QVBoxLayout>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
qint64 dirSize(QString dirPath)
|
||||
{
|
||||
qint64 size = 0;
|
||||
QDir dir(dirPath);
|
||||
// calculate total size of current directories' files
|
||||
QDir::Filters fileFilters = QDir::Files | QDir::System | QDir::Hidden;
|
||||
for (QString filePath : dir.entryList(fileFilters))
|
||||
{
|
||||
QFileInfo fi(dir, filePath);
|
||||
size += fi.size();
|
||||
}
|
||||
// add size of child directories recursively
|
||||
QDir::Filters dirFilters =
|
||||
QDir::Dirs | QDir::NoDotAndDotDot | QDir::System | QDir::Hidden;
|
||||
for (QString childDirPath : dir.entryList(dirFilters))
|
||||
size += dirSize(dirPath + QDir::separator() + childDirPath);
|
||||
return size;
|
||||
}
|
||||
|
||||
QString formatSize(qint64 size)
|
||||
{
|
||||
QStringList units = {"Bytes", "KB", "MB", "GB", "TB", "PB"};
|
||||
int i;
|
||||
double outputSize = size;
|
||||
for (i = 0; i < units.size() - 1; i++)
|
||||
{
|
||||
if (outputSize < 1024)
|
||||
break;
|
||||
outputSize = outputSize / 1024;
|
||||
}
|
||||
return QString("%0 %1").arg(outputSize, 0, 'f', 2).arg(units[i]);
|
||||
}
|
||||
|
||||
QString fetchLogDirectorySize()
|
||||
{
|
||||
QString logPathDirectory = getSettings()->logPath.getValue().isEmpty()
|
||||
? getPaths()->messageLogDirectory
|
||||
: getSettings()->logPath;
|
||||
|
||||
qint64 logsSize = dirSize(logPathDirectory);
|
||||
QString logsSizeLabel = "Your logs currently take up ";
|
||||
logsSizeLabel += formatSize(logsSize);
|
||||
logsSizeLabel += " of space";
|
||||
return logsSizeLabel;
|
||||
}
|
||||
|
||||
ModerationPage::ModerationPage()
|
||||
: SettingsPage("Moderation", ":/settings/moderation.svg")
|
||||
{
|
||||
auto app = getApp();
|
||||
LayoutCreator<ModerationPage> layoutCreator(this);
|
||||
|
||||
auto tabs = layoutCreator.emplace<QTabWidget>();
|
||||
this->tabWidget_ = tabs.getElement();
|
||||
|
||||
auto logs = tabs.appendTab(new QVBoxLayout, "Logs");
|
||||
{
|
||||
logs.append(this->createCheckBox("Enable logging",
|
||||
getSettings()->enableLogging));
|
||||
auto logsPathLabel = logs.emplace<QLabel>();
|
||||
|
||||
// Logs (copied from LoggingMananger)
|
||||
getSettings()->logPath.connect([logsPathLabel](const QString &logPath,
|
||||
auto) mutable {
|
||||
QString pathOriginal =
|
||||
logPath.isEmpty() ? getPaths()->messageLogDirectory : logPath;
|
||||
|
||||
QString pathShortened =
|
||||
"Logs are saved at <a href=\"file:///" + pathOriginal +
|
||||
"\"><span style=\"color: white;\">" +
|
||||
shortenString(pathOriginal, 50) + "</span></a>";
|
||||
|
||||
logsPathLabel->setText(pathShortened);
|
||||
logsPathLabel->setToolTip(pathOriginal);
|
||||
});
|
||||
|
||||
logsPathLabel->setTextFormat(Qt::RichText);
|
||||
logsPathLabel->setTextInteractionFlags(Qt::TextBrowserInteraction |
|
||||
Qt::LinksAccessibleByKeyboard);
|
||||
logsPathLabel->setOpenExternalLinks(true);
|
||||
|
||||
auto buttons = logs.emplace<QHBoxLayout>().withoutMargin();
|
||||
|
||||
// Select and Reset
|
||||
auto selectDir = buttons.emplace<QPushButton>("Select log directory ");
|
||||
auto resetDir = buttons.emplace<QPushButton>("Reset");
|
||||
|
||||
getSettings()->logPath.connect(
|
||||
[element = resetDir.getElement()](const QString &path) {
|
||||
element->setEnabled(!path.isEmpty());
|
||||
});
|
||||
|
||||
buttons->addStretch();
|
||||
logs->addStretch(1);
|
||||
|
||||
// Show how big (size-wise) the logs are
|
||||
auto logsPathSizeLabel = logs.emplace<QLabel>();
|
||||
logsPathSizeLabel->setText(
|
||||
QtConcurrent::run([] { return fetchLogDirectorySize(); }));
|
||||
|
||||
// Select event
|
||||
QObject::connect(
|
||||
selectDir.getElement(), &QPushButton::clicked, this,
|
||||
[this, logsPathSizeLabel]() mutable {
|
||||
auto dirName = QFileDialog::getExistingDirectory(this);
|
||||
|
||||
getSettings()->logPath = dirName;
|
||||
|
||||
// Refresh: Show how big (size-wise) the logs are
|
||||
logsPathSizeLabel->setText(
|
||||
QtConcurrent::run([] { return fetchLogDirectorySize(); }));
|
||||
});
|
||||
|
||||
buttons->addSpacing(16);
|
||||
|
||||
// Reset custom logpath
|
||||
QObject::connect(resetDir.getElement(), &QPushButton::clicked, this,
|
||||
[logsPathSizeLabel]() mutable {
|
||||
getSettings()->logPath = "";
|
||||
|
||||
// Refresh: Show how big (size-wise) the logs are
|
||||
logsPathSizeLabel->setText(QtConcurrent::run(
|
||||
[] { return fetchLogDirectorySize(); }));
|
||||
});
|
||||
|
||||
} // logs end
|
||||
|
||||
auto modMode = tabs.appendTab(new QVBoxLayout, "Moderation buttons");
|
||||
{
|
||||
// clang-format off
|
||||
auto label = modMode.emplace<QLabel>(
|
||||
"Moderation mode is enabled by clicking <img width='18' height='18' src=':/buttons/modModeDisabled.png'> in a channel that you moderate.<br><br>"
|
||||
"Moderation buttons can be bound to chat commands such as \"/ban {user}\", \"/timeout {user} 1000\", \"/w someusername !report {user} was bad in channel {channel}\" or any other custom text commands.<br>"
|
||||
"For deleting messages use /delete {msg-id}.");
|
||||
label->setWordWrap(true);
|
||||
label->setStyleSheet("color: #bbb");
|
||||
// clang-format on
|
||||
|
||||
// auto form = modMode.emplace<QFormLayout>();
|
||||
// {
|
||||
// form->addRow("Action on timed out messages
|
||||
// (unimplemented):",
|
||||
// this->createComboBox({"Disable", "Hide"},
|
||||
// getSettings()->timeoutAction));
|
||||
// }
|
||||
|
||||
EditableModelView *view =
|
||||
modMode
|
||||
.emplace<EditableModelView>(
|
||||
app->moderationActions->createModel(nullptr))
|
||||
.getElement();
|
||||
|
||||
view->setTitles({"Actions"});
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
QHeaderView::Fixed);
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
0, QHeaderView::Stretch);
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
getApp()->moderationActions->items.appendItem(
|
||||
ModerationAction("/timeout {user} 300"));
|
||||
});
|
||||
|
||||
/*auto taggedUsers = tabs.appendTab(new QVBoxLayout, "Tagged users");
|
||||
{
|
||||
EditableModelView *view = *taggedUsers.emplace<EditableModelView>(
|
||||
app->taggedUsers->createModel(nullptr));
|
||||
|
||||
view->setTitles({"Name"});
|
||||
view->getTableView()->horizontalHeader()->setStretchLastSection(true);
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
getApp()->taggedUsers->users.appendItem(
|
||||
TaggedUser(ProviderId::Twitch, "example", "xD"));
|
||||
});
|
||||
}*/
|
||||
}
|
||||
|
||||
// ---- misc
|
||||
this->itemsChangedTimer_.setSingleShot(true);
|
||||
}
|
||||
|
||||
void ModerationPage::selectModerationActions()
|
||||
{
|
||||
this->tabWidget_->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
#include "ModerationPage.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "controllers/moderationactions/ModerationActionModel.hpp"
|
||||
#include "controllers/moderationactions/ModerationActions.hpp"
|
||||
#include "controllers/taggedusers/TaggedUsersController.hpp"
|
||||
#include "controllers/taggedusers/TaggedUsersModel.hpp"
|
||||
#include "singletons/Logging.hpp"
|
||||
#include "singletons/Paths.hpp"
|
||||
#include "util/Helpers.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "widgets/helper/EditableModelView.hpp"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QFormLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QListView>
|
||||
#include <QPushButton>
|
||||
#include <QTableView>
|
||||
#include <QTextEdit>
|
||||
#include <QVBoxLayout>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
qint64 dirSize(QString dirPath)
|
||||
{
|
||||
qint64 size = 0;
|
||||
QDir dir(dirPath);
|
||||
// calculate total size of current directories' files
|
||||
QDir::Filters fileFilters = QDir::Files | QDir::System | QDir::Hidden;
|
||||
for (QString filePath : dir.entryList(fileFilters))
|
||||
{
|
||||
QFileInfo fi(dir, filePath);
|
||||
size += fi.size();
|
||||
}
|
||||
// add size of child directories recursively
|
||||
QDir::Filters dirFilters =
|
||||
QDir::Dirs | QDir::NoDotAndDotDot | QDir::System | QDir::Hidden;
|
||||
for (QString childDirPath : dir.entryList(dirFilters))
|
||||
size += dirSize(dirPath + QDir::separator() + childDirPath);
|
||||
return size;
|
||||
}
|
||||
|
||||
QString formatSize(qint64 size)
|
||||
{
|
||||
QStringList units = {"Bytes", "KB", "MB", "GB", "TB", "PB"};
|
||||
int i;
|
||||
double outputSize = size;
|
||||
for (i = 0; i < units.size() - 1; i++)
|
||||
{
|
||||
if (outputSize < 1024)
|
||||
break;
|
||||
outputSize = outputSize / 1024;
|
||||
}
|
||||
return QString("%0 %1").arg(outputSize, 0, 'f', 2).arg(units[i]);
|
||||
}
|
||||
|
||||
QString fetchLogDirectorySize()
|
||||
{
|
||||
QString logPathDirectory = getSettings()->logPath.getValue().isEmpty()
|
||||
? getPaths()->messageLogDirectory
|
||||
: getSettings()->logPath;
|
||||
|
||||
qint64 logsSize = dirSize(logPathDirectory);
|
||||
QString logsSizeLabel = "Your logs currently take up ";
|
||||
logsSizeLabel += formatSize(logsSize);
|
||||
logsSizeLabel += " of space";
|
||||
return logsSizeLabel;
|
||||
}
|
||||
|
||||
ModerationPage::ModerationPage()
|
||||
: SettingsPage("Moderation", ":/settings/moderation.svg")
|
||||
{
|
||||
auto app = getApp();
|
||||
LayoutCreator<ModerationPage> layoutCreator(this);
|
||||
|
||||
auto tabs = layoutCreator.emplace<QTabWidget>();
|
||||
this->tabWidget_ = tabs.getElement();
|
||||
|
||||
auto logs = tabs.appendTab(new QVBoxLayout, "Logs");
|
||||
{
|
||||
logs.append(this->createCheckBox("Enable logging",
|
||||
getSettings()->enableLogging));
|
||||
auto logsPathLabel = logs.emplace<QLabel>();
|
||||
|
||||
// Logs (copied from LoggingMananger)
|
||||
getSettings()->logPath.connect([logsPathLabel](const QString &logPath,
|
||||
auto) mutable {
|
||||
QString pathOriginal =
|
||||
logPath.isEmpty() ? getPaths()->messageLogDirectory : logPath;
|
||||
|
||||
QString pathShortened =
|
||||
"Logs are saved at <a href=\"file:///" + pathOriginal +
|
||||
"\"><span style=\"color: white;\">" +
|
||||
shortenString(pathOriginal, 50) + "</span></a>";
|
||||
|
||||
logsPathLabel->setText(pathShortened);
|
||||
logsPathLabel->setToolTip(pathOriginal);
|
||||
});
|
||||
|
||||
logsPathLabel->setTextFormat(Qt::RichText);
|
||||
logsPathLabel->setTextInteractionFlags(Qt::TextBrowserInteraction |
|
||||
Qt::LinksAccessibleByKeyboard);
|
||||
logsPathLabel->setOpenExternalLinks(true);
|
||||
|
||||
auto buttons = logs.emplace<QHBoxLayout>().withoutMargin();
|
||||
|
||||
// Select and Reset
|
||||
auto selectDir = buttons.emplace<QPushButton>("Select log directory ");
|
||||
auto resetDir = buttons.emplace<QPushButton>("Reset");
|
||||
|
||||
getSettings()->logPath.connect(
|
||||
[element = resetDir.getElement()](const QString &path) {
|
||||
element->setEnabled(!path.isEmpty());
|
||||
});
|
||||
|
||||
buttons->addStretch();
|
||||
logs->addStretch(1);
|
||||
|
||||
// Show how big (size-wise) the logs are
|
||||
auto logsPathSizeLabel = logs.emplace<QLabel>();
|
||||
logsPathSizeLabel->setText(
|
||||
QtConcurrent::run([] { return fetchLogDirectorySize(); }));
|
||||
|
||||
// Select event
|
||||
QObject::connect(
|
||||
selectDir.getElement(), &QPushButton::clicked, this,
|
||||
[this, logsPathSizeLabel]() mutable {
|
||||
auto dirName = QFileDialog::getExistingDirectory(this);
|
||||
|
||||
getSettings()->logPath = dirName;
|
||||
|
||||
// Refresh: Show how big (size-wise) the logs are
|
||||
logsPathSizeLabel->setText(
|
||||
QtConcurrent::run([] { return fetchLogDirectorySize(); }));
|
||||
});
|
||||
|
||||
buttons->addSpacing(16);
|
||||
|
||||
// Reset custom logpath
|
||||
QObject::connect(resetDir.getElement(), &QPushButton::clicked, this,
|
||||
[logsPathSizeLabel]() mutable {
|
||||
getSettings()->logPath = "";
|
||||
|
||||
// Refresh: Show how big (size-wise) the logs are
|
||||
logsPathSizeLabel->setText(QtConcurrent::run(
|
||||
[] { return fetchLogDirectorySize(); }));
|
||||
});
|
||||
|
||||
} // logs end
|
||||
|
||||
auto modMode = tabs.appendTab(new QVBoxLayout, "Moderation buttons");
|
||||
{
|
||||
// clang-format off
|
||||
auto label = modMode.emplace<QLabel>(
|
||||
"Moderation mode is enabled by clicking <img width='18' height='18' src=':/buttons/modModeDisabled.png'> in a channel that you moderate.<br><br>"
|
||||
"Moderation buttons can be bound to chat commands such as \"/ban {user}\", \"/timeout {user} 1000\", \"/w someusername !report {user} was bad in channel {channel}\" or any other custom text commands.<br>"
|
||||
"For deleting messages use /delete {msg-id}.");
|
||||
label->setWordWrap(true);
|
||||
label->setStyleSheet("color: #bbb");
|
||||
// clang-format on
|
||||
|
||||
// auto form = modMode.emplace<QFormLayout>();
|
||||
// {
|
||||
// form->addRow("Action on timed out messages
|
||||
// (unimplemented):",
|
||||
// this->createComboBox({"Disable", "Hide"},
|
||||
// getSettings()->timeoutAction));
|
||||
// }
|
||||
|
||||
EditableModelView *view =
|
||||
modMode
|
||||
.emplace<EditableModelView>(
|
||||
app->moderationActions->createModel(nullptr))
|
||||
.getElement();
|
||||
|
||||
view->setTitles({"Actions"});
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
QHeaderView::Fixed);
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
0, QHeaderView::Stretch);
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
getApp()->moderationActions->items.appendItem(
|
||||
ModerationAction("/timeout {user} 300"));
|
||||
});
|
||||
|
||||
/*auto taggedUsers = tabs.appendTab(new QVBoxLayout, "Tagged users");
|
||||
{
|
||||
EditableModelView *view = *taggedUsers.emplace<EditableModelView>(
|
||||
app->taggedUsers->createModel(nullptr));
|
||||
|
||||
view->setTitles({"Name"});
|
||||
view->getTableView()->horizontalHeader()->setStretchLastSection(true);
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
getApp()->taggedUsers->users.appendItem(
|
||||
TaggedUser(ProviderId::Twitch, "example", "xD"));
|
||||
});
|
||||
}*/
|
||||
}
|
||||
|
||||
// ---- misc
|
||||
this->itemsChangedTimer_.setSingleShot(true);
|
||||
}
|
||||
|
||||
void ModerationPage::selectModerationActions()
|
||||
{
|
||||
this->tabWidget_->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
class QTabWidget;
|
||||
class QPushButton;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class ModerationPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
ModerationPage();
|
||||
|
||||
void selectModerationActions();
|
||||
|
||||
private:
|
||||
QTimer itemsChangedTimer_;
|
||||
QTabWidget *tabWidget_{};
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
#pragma once
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
class QTabWidget;
|
||||
class QPushButton;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class ModerationPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
ModerationPage();
|
||||
|
||||
void selectModerationActions();
|
||||
|
||||
private:
|
||||
QTimer itemsChangedTimer_;
|
||||
QTabWidget *tabWidget_{};
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,176 +1,176 @@
|
||||
#include "SettingsPage.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "singletons/WindowManager.hpp"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QPainter>
|
||||
#include <util/FunctionEventFilter.hpp>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
bool filterItemsRec(QObject *object, const QString &query)
|
||||
{
|
||||
bool any{};
|
||||
|
||||
for (auto &&child : object->children())
|
||||
{
|
||||
auto setOpacity = [&](auto *widget, bool condition) {
|
||||
any |= condition;
|
||||
widget->greyedOut = !condition;
|
||||
widget->update();
|
||||
};
|
||||
|
||||
if (auto x = dynamic_cast<SCheckBox *>(child); x)
|
||||
{
|
||||
setOpacity(x, x->text().contains(query, Qt::CaseInsensitive));
|
||||
}
|
||||
else if (auto x = dynamic_cast<SLabel *>(child); x)
|
||||
{
|
||||
setOpacity(x, x->text().contains(query, Qt::CaseInsensitive));
|
||||
}
|
||||
else if (auto x = dynamic_cast<SComboBox *>(child); x)
|
||||
{
|
||||
setOpacity(x, [=]() {
|
||||
for (int i = 0; i < x->count(); i++)
|
||||
{
|
||||
if (x->itemText(i).contains(query, Qt::CaseInsensitive))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}());
|
||||
}
|
||||
else if (auto x = dynamic_cast<QTabWidget *>(child); x)
|
||||
{
|
||||
for (int i = 0; i < x->count(); i++)
|
||||
{
|
||||
bool tabAny{};
|
||||
|
||||
if (x->tabText(i).contains(query, Qt::CaseInsensitive))
|
||||
{
|
||||
tabAny = true;
|
||||
}
|
||||
auto widget = x->widget(i);
|
||||
tabAny |= filterItemsRec(widget, query);
|
||||
|
||||
any |= tabAny;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
any |= filterItemsRec(child, query);
|
||||
}
|
||||
}
|
||||
return any;
|
||||
}
|
||||
|
||||
SettingsPage::SettingsPage(const QString &name, const QString &iconResource)
|
||||
: name_(name)
|
||||
, iconResource_(iconResource)
|
||||
{
|
||||
}
|
||||
|
||||
bool SettingsPage::filterElements(const QString &query)
|
||||
{
|
||||
return filterItemsRec(this, query) || query.isEmpty() ||
|
||||
this->name_.contains(query, Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
const QString &SettingsPage::getName()
|
||||
{
|
||||
return this->name_;
|
||||
}
|
||||
|
||||
const QString &SettingsPage::getIconResource()
|
||||
{
|
||||
return this->iconResource_;
|
||||
}
|
||||
|
||||
SettingsDialogTab *SettingsPage::tab() const
|
||||
{
|
||||
return this->tab_;
|
||||
}
|
||||
|
||||
void SettingsPage::setTab(SettingsDialogTab *tab)
|
||||
{
|
||||
this->tab_ = tab;
|
||||
}
|
||||
|
||||
void SettingsPage::cancel()
|
||||
{
|
||||
this->onCancel_.invoke();
|
||||
}
|
||||
|
||||
QCheckBox *SettingsPage::createCheckBox(
|
||||
const QString &text, pajlada::Settings::Setting<bool> &setting)
|
||||
{
|
||||
QCheckBox *checkbox = new SCheckBox(text);
|
||||
|
||||
// update when setting changes
|
||||
setting.connect(
|
||||
[checkbox](const bool &value, auto) {
|
||||
checkbox->setChecked(value); //
|
||||
},
|
||||
this->managedConnections_);
|
||||
|
||||
// update setting on toggle
|
||||
QObject::connect(checkbox, &QCheckBox::toggled, this,
|
||||
[&setting](bool state) {
|
||||
setting = state;
|
||||
getApp()->windows->forceLayoutChannelViews();
|
||||
});
|
||||
|
||||
return checkbox;
|
||||
}
|
||||
|
||||
QComboBox *SettingsPage::createComboBox(
|
||||
const QStringList &items, pajlada::Settings::Setting<QString> &setting)
|
||||
{
|
||||
QComboBox *combo = new SComboBox();
|
||||
|
||||
// update setting on toogle
|
||||
combo->addItems(items);
|
||||
|
||||
// update when setting changes
|
||||
setting.connect(
|
||||
[combo](const QString &value, auto) { combo->setCurrentText(value); },
|
||||
this->managedConnections_);
|
||||
|
||||
QObject::connect(
|
||||
combo, &QComboBox::currentTextChanged,
|
||||
[&setting](const QString &newValue) { setting = newValue; });
|
||||
|
||||
return combo;
|
||||
}
|
||||
|
||||
QLineEdit *SettingsPage::createLineEdit(
|
||||
pajlada::Settings::Setting<QString> &setting)
|
||||
{
|
||||
QLineEdit *edit = new QLineEdit();
|
||||
|
||||
edit->setText(setting);
|
||||
|
||||
// update when setting changes
|
||||
QObject::connect(
|
||||
edit, &QLineEdit::textChanged,
|
||||
[&setting](const QString &newValue) { setting = newValue; });
|
||||
|
||||
return edit;
|
||||
}
|
||||
|
||||
QSpinBox *SettingsPage::createSpinBox(pajlada::Settings::Setting<int> &setting,
|
||||
int min, int max)
|
||||
{
|
||||
QSpinBox *w = new QSpinBox;
|
||||
|
||||
w->setMinimum(min);
|
||||
w->setMaximum(max);
|
||||
|
||||
setting.connect([w](const int &value, auto) { w->setValue(value); });
|
||||
QObject::connect(w, QOverload<int>::of(&QSpinBox::valueChanged),
|
||||
[&setting](int value) { setting.setValue(value); });
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
#include "SettingsPage.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "singletons/WindowManager.hpp"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QPainter>
|
||||
#include <util/FunctionEventFilter.hpp>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
bool filterItemsRec(QObject *object, const QString &query)
|
||||
{
|
||||
bool any{};
|
||||
|
||||
for (auto &&child : object->children())
|
||||
{
|
||||
auto setOpacity = [&](auto *widget, bool condition) {
|
||||
any |= condition;
|
||||
widget->greyedOut = !condition;
|
||||
widget->update();
|
||||
};
|
||||
|
||||
if (auto x = dynamic_cast<SCheckBox *>(child); x)
|
||||
{
|
||||
setOpacity(x, x->text().contains(query, Qt::CaseInsensitive));
|
||||
}
|
||||
else if (auto x = dynamic_cast<SLabel *>(child); x)
|
||||
{
|
||||
setOpacity(x, x->text().contains(query, Qt::CaseInsensitive));
|
||||
}
|
||||
else if (auto x = dynamic_cast<SComboBox *>(child); x)
|
||||
{
|
||||
setOpacity(x, [=]() {
|
||||
for (int i = 0; i < x->count(); i++)
|
||||
{
|
||||
if (x->itemText(i).contains(query, Qt::CaseInsensitive))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}());
|
||||
}
|
||||
else if (auto x = dynamic_cast<QTabWidget *>(child); x)
|
||||
{
|
||||
for (int i = 0; i < x->count(); i++)
|
||||
{
|
||||
bool tabAny{};
|
||||
|
||||
if (x->tabText(i).contains(query, Qt::CaseInsensitive))
|
||||
{
|
||||
tabAny = true;
|
||||
}
|
||||
auto widget = x->widget(i);
|
||||
tabAny |= filterItemsRec(widget, query);
|
||||
|
||||
any |= tabAny;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
any |= filterItemsRec(child, query);
|
||||
}
|
||||
}
|
||||
return any;
|
||||
}
|
||||
|
||||
SettingsPage::SettingsPage(const QString &name, const QString &iconResource)
|
||||
: name_(name)
|
||||
, iconResource_(iconResource)
|
||||
{
|
||||
}
|
||||
|
||||
bool SettingsPage::filterElements(const QString &query)
|
||||
{
|
||||
return filterItemsRec(this, query) || query.isEmpty() ||
|
||||
this->name_.contains(query, Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
const QString &SettingsPage::getName()
|
||||
{
|
||||
return this->name_;
|
||||
}
|
||||
|
||||
const QString &SettingsPage::getIconResource()
|
||||
{
|
||||
return this->iconResource_;
|
||||
}
|
||||
|
||||
SettingsDialogTab *SettingsPage::tab() const
|
||||
{
|
||||
return this->tab_;
|
||||
}
|
||||
|
||||
void SettingsPage::setTab(SettingsDialogTab *tab)
|
||||
{
|
||||
this->tab_ = tab;
|
||||
}
|
||||
|
||||
void SettingsPage::cancel()
|
||||
{
|
||||
this->onCancel_.invoke();
|
||||
}
|
||||
|
||||
QCheckBox *SettingsPage::createCheckBox(
|
||||
const QString &text, pajlada::Settings::Setting<bool> &setting)
|
||||
{
|
||||
QCheckBox *checkbox = new SCheckBox(text);
|
||||
|
||||
// update when setting changes
|
||||
setting.connect(
|
||||
[checkbox](const bool &value, auto) {
|
||||
checkbox->setChecked(value); //
|
||||
},
|
||||
this->managedConnections_);
|
||||
|
||||
// update setting on toggle
|
||||
QObject::connect(checkbox, &QCheckBox::toggled, this,
|
||||
[&setting](bool state) {
|
||||
setting = state;
|
||||
getApp()->windows->forceLayoutChannelViews();
|
||||
});
|
||||
|
||||
return checkbox;
|
||||
}
|
||||
|
||||
QComboBox *SettingsPage::createComboBox(
|
||||
const QStringList &items, pajlada::Settings::Setting<QString> &setting)
|
||||
{
|
||||
QComboBox *combo = new SComboBox();
|
||||
|
||||
// update setting on toogle
|
||||
combo->addItems(items);
|
||||
|
||||
// update when setting changes
|
||||
setting.connect(
|
||||
[combo](const QString &value, auto) { combo->setCurrentText(value); },
|
||||
this->managedConnections_);
|
||||
|
||||
QObject::connect(
|
||||
combo, &QComboBox::currentTextChanged,
|
||||
[&setting](const QString &newValue) { setting = newValue; });
|
||||
|
||||
return combo;
|
||||
}
|
||||
|
||||
QLineEdit *SettingsPage::createLineEdit(
|
||||
pajlada::Settings::Setting<QString> &setting)
|
||||
{
|
||||
QLineEdit *edit = new QLineEdit();
|
||||
|
||||
edit->setText(setting);
|
||||
|
||||
// update when setting changes
|
||||
QObject::connect(
|
||||
edit, &QLineEdit::textChanged,
|
||||
[&setting](const QString &newValue) { setting = newValue; });
|
||||
|
||||
return edit;
|
||||
}
|
||||
|
||||
QSpinBox *SettingsPage::createSpinBox(pajlada::Settings::Setting<int> &setting,
|
||||
int min, int max)
|
||||
{
|
||||
QSpinBox *w = new QSpinBox;
|
||||
|
||||
w->setMinimum(min);
|
||||
w->setMaximum(max);
|
||||
|
||||
setting.connect([w](const int &value, auto) { w->setValue(value); });
|
||||
QObject::connect(w, QOverload<int>::of(&QSpinBox::valueChanged),
|
||||
[&setting](int value) { setting.setValue(value); });
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,84 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QLineEdit>
|
||||
#include <QSpinBox>
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
|
||||
#include "singletons/Settings.hpp"
|
||||
|
||||
#define SETTINGS_PAGE_WIDGET_BOILERPLATE(type, parent) \
|
||||
class type : public parent \
|
||||
{ \
|
||||
using parent::parent; \
|
||||
\
|
||||
public: \
|
||||
bool greyedOut{}; \
|
||||
\
|
||||
protected: \
|
||||
void paintEvent(QPaintEvent *e) override \
|
||||
{ \
|
||||
parent::paintEvent(e); \
|
||||
\
|
||||
if (this->greyedOut) \
|
||||
{ \
|
||||
QPainter painter(this); \
|
||||
QColor color = QColor("#222222"); \
|
||||
color.setAlphaF(0.7); \
|
||||
painter.fillRect(this->rect(), color); \
|
||||
} \
|
||||
} \
|
||||
};
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
// S* widgets are the same as their Q* counterparts,
|
||||
// but they can be greyed out and will be if you search.
|
||||
SETTINGS_PAGE_WIDGET_BOILERPLATE(SCheckBox, QCheckBox)
|
||||
SETTINGS_PAGE_WIDGET_BOILERPLATE(SLabel, QLabel)
|
||||
SETTINGS_PAGE_WIDGET_BOILERPLATE(SComboBox, QComboBox)
|
||||
SETTINGS_PAGE_WIDGET_BOILERPLATE(SPushButton, QPushButton)
|
||||
|
||||
class SettingsDialogTab;
|
||||
|
||||
class SettingsPage : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SettingsPage(const QString &name, const QString &iconResource);
|
||||
|
||||
const QString &getName();
|
||||
const QString &getIconResource();
|
||||
|
||||
virtual bool filterElements(const QString &query);
|
||||
|
||||
SettingsDialogTab *tab() const;
|
||||
void setTab(SettingsDialogTab *tab);
|
||||
|
||||
void cancel();
|
||||
|
||||
QCheckBox *createCheckBox(const QString &text,
|
||||
pajlada::Settings::Setting<bool> &setting);
|
||||
QComboBox *createComboBox(const QStringList &items,
|
||||
pajlada::Settings::Setting<QString> &setting);
|
||||
QLineEdit *createLineEdit(pajlada::Settings::Setting<QString> &setting);
|
||||
QSpinBox *createSpinBox(pajlada::Settings::Setting<int> &setting,
|
||||
int min = 0, int max = 2500);
|
||||
|
||||
virtual void onShow()
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
QString name_;
|
||||
QString iconResource_;
|
||||
|
||||
SettingsDialogTab *tab_;
|
||||
|
||||
pajlada::Signals::NoArgSignal onCancel_;
|
||||
std::vector<pajlada::Signals::ScopedConnection> managedConnections_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
#pragma once
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QLineEdit>
|
||||
#include <QSpinBox>
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
|
||||
#include "singletons/Settings.hpp"
|
||||
|
||||
#define SETTINGS_PAGE_WIDGET_BOILERPLATE(type, parent) \
|
||||
class type : public parent \
|
||||
{ \
|
||||
using parent::parent; \
|
||||
\
|
||||
public: \
|
||||
bool greyedOut{}; \
|
||||
\
|
||||
protected: \
|
||||
void paintEvent(QPaintEvent *e) override \
|
||||
{ \
|
||||
parent::paintEvent(e); \
|
||||
\
|
||||
if (this->greyedOut) \
|
||||
{ \
|
||||
QPainter painter(this); \
|
||||
QColor color = QColor("#222222"); \
|
||||
color.setAlphaF(0.7); \
|
||||
painter.fillRect(this->rect(), color); \
|
||||
} \
|
||||
} \
|
||||
};
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
// S* widgets are the same as their Q* counterparts,
|
||||
// but they can be greyed out and will be if you search.
|
||||
SETTINGS_PAGE_WIDGET_BOILERPLATE(SCheckBox, QCheckBox)
|
||||
SETTINGS_PAGE_WIDGET_BOILERPLATE(SLabel, QLabel)
|
||||
SETTINGS_PAGE_WIDGET_BOILERPLATE(SComboBox, QComboBox)
|
||||
SETTINGS_PAGE_WIDGET_BOILERPLATE(SPushButton, QPushButton)
|
||||
|
||||
class SettingsDialogTab;
|
||||
|
||||
class SettingsPage : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SettingsPage(const QString &name, const QString &iconResource);
|
||||
|
||||
const QString &getName();
|
||||
const QString &getIconResource();
|
||||
|
||||
virtual bool filterElements(const QString &query);
|
||||
|
||||
SettingsDialogTab *tab() const;
|
||||
void setTab(SettingsDialogTab *tab);
|
||||
|
||||
void cancel();
|
||||
|
||||
QCheckBox *createCheckBox(const QString &text,
|
||||
pajlada::Settings::Setting<bool> &setting);
|
||||
QComboBox *createComboBox(const QStringList &items,
|
||||
pajlada::Settings::Setting<QString> &setting);
|
||||
QLineEdit *createLineEdit(pajlada::Settings::Setting<QString> &setting);
|
||||
QSpinBox *createSpinBox(pajlada::Settings::Setting<int> &setting,
|
||||
int min = 0, int max = 2500);
|
||||
|
||||
virtual void onShow()
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
QString name_;
|
||||
QString iconResource_;
|
||||
|
||||
SettingsDialogTab *tab_;
|
||||
|
||||
pajlada::Signals::NoArgSignal onCancel_;
|
||||
std::vector<pajlada::Signals::ScopedConnection> managedConnections_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
Reference in New Issue
Block a user