mirror-chatterino2/src/widgets/settingspages/GeneralPage.cpp

513 lines
18 KiB
C++
Raw Normal View History

2018-10-31 19:45:51 +01:00
#include "GeneralPage.hpp"
#include <QFontDialog>
#include <QLabel>
#include <QScrollArea>
#include "Application.hpp"
#include "singletons/Fonts.hpp"
2018-11-25 15:02:48 +01:00
#include "singletons/Paths.hpp"
2018-10-31 19:45:51 +01:00
#include "singletons/Theme.hpp"
#include "singletons/WindowManager.hpp"
2018-10-31 19:45:51 +01:00
#include "util/FuzzyConvert.hpp"
#include "util/Helpers.hpp"
2019-08-26 13:18:23 +02:00
#include "widgets/BaseWindow.hpp"
2018-10-31 19:45:51 +01:00
#include "widgets/helper/Line.hpp"
#define CHROME_EXTENSION_LINK \
"https://chrome.google.com/webstore/detail/chatterino-native-host/" \
"glknmaideaikkmemifbfkhnomoknepka"
#define FIREFOX_EXTENSION_LINK \
"https://addons.mozilla.org/en-US/firefox/addon/chatterino-native-host/"
2019-09-02 10:52:35 +02:00
#define addTitle addTitle
2018-10-31 19:45:51 +01:00
namespace chatterino {
TitleLabel *SettingsLayout::addTitle(const QString &title)
{
auto label = new TitleLabel(title + ":");
if (this->count() == 0)
label->setStyleSheet("margin-top: 0");
2018-10-31 19:45:51 +01:00
this->addWidget(label);
// groups
this->groups_.push_back(Group{title, label, {}});
2018-10-31 19:45:51 +01:00
return label;
}
QCheckBox *SettingsLayout::addCheckbox(const QString &text,
2019-08-26 13:18:23 +02:00
BoolSetting &setting, bool inverse)
2018-10-31 19:45:51 +01:00
{
auto check = new QCheckBox(text);
// update when setting changes
setting.connect(
2019-08-26 13:18:23 +02:00
[inverse, check](const bool &value, auto) {
check->setChecked(inverse ^ value);
},
2018-10-31 19:45:51 +01:00
this->managedConnections_);
// update setting on toggle
2019-08-26 13:18:23 +02:00
QObject::connect(
check, &QCheckBox::toggled, this,
[&setting, inverse](bool state) { setting = inverse ^ state; });
2018-10-31 19:45:51 +01:00
this->addWidget(check);
// groups
this->groups_.back().widgets.push_back({check, {text}});
2018-10-31 19:45:51 +01:00
return check;
}
2018-10-31 20:57:29 +01:00
ComboBox *SettingsLayout::addDropdown(const QString &text,
const QStringList &list)
2018-10-31 19:45:51 +01:00
{
auto layout = new QHBoxLayout;
2018-10-31 20:57:29 +01:00
auto combo = new ComboBox;
combo->setFocusPolicy(Qt::StrongFocus);
2018-10-31 19:45:51 +01:00
combo->addItems(list);
auto label = new QLabel(text + ":");
layout->addWidget(label);
2018-10-31 19:45:51 +01:00
layout->addStretch(1);
layout->addWidget(combo);
this->addLayout(layout);
// groups
this->groups_.back().widgets.push_back({combo, {text}});
this->groups_.back().widgets.push_back({label, {text}});
2018-10-31 19:45:51 +01:00
return combo;
}
2018-10-31 20:57:29 +01:00
ComboBox *SettingsLayout::addDropdown(
2018-10-31 19:45:51 +01:00
const QString &text, const QStringList &items,
2018-10-31 21:13:01 +01:00
pajlada::Settings::Setting<QString> &setting, bool editable)
2018-10-31 19:45:51 +01:00
{
auto combo = this->addDropdown(text, items);
2018-10-31 21:13:01 +01:00
if (editable)
combo->setEditable(true);
2018-10-31 19:45:51 +01:00
// 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;
getApp()->windows->forceLayoutChannelViews();
});
return combo;
}
DescriptionLabel *SettingsLayout::addDescription(const QString &text)
{
auto label = new DescriptionLabel(text);
label->setTextInteractionFlags(Qt::TextBrowserInteraction |
Qt::LinksAccessibleByKeyboard);
label->setOpenExternalLinks(true);
label->setWordWrap(true);
this->addWidget(label);
// groups
this->groups_.back().widgets.push_back({label, {text}});
2018-10-31 19:45:51 +01:00
return label;
}
void SettingsLayout::addSeperator()
{
this->addWidget(new Line(false));
}
2019-09-02 16:39:21 +02:00
bool SettingsLayout::filterElements(const QString &query)
{
2019-09-02 16:39:21 +02:00
bool any{};
for (auto &&group : this->groups_)
{
2019-09-02 19:00:17 +02:00
// if a description in a group matches `query` then show the entire group
bool descriptionMatches{};
for (auto &&widget : group.widgets)
{
if (auto x = dynamic_cast<DescriptionLabel *>(widget.element); x)
{
if (x->text().contains(query, Qt::CaseInsensitive))
{
descriptionMatches = true;
break;
}
}
}
// if group name matches then all should be visible
2019-09-02 19:00:17 +02:00
if (group.name.contains(query, Qt::CaseInsensitive) ||
descriptionMatches)
{
for (auto &&widget : group.widgets)
widget.element->show();
group.title->show();
2019-09-02 19:00:17 +02:00
any = true;
}
// check if any match
else
{
2019-09-02 16:39:21 +02:00
auto groupAny = false;
for (auto &&widget : group.widgets)
{
for (auto &&keyword : widget.keywords)
{
if (keyword.contains(query, Qt::CaseInsensitive))
{
widget.element->show();
2019-09-02 16:39:21 +02:00
groupAny = true;
}
else
{
widget.element->hide();
}
}
}
2019-09-02 16:39:21 +02:00
group.title->setVisible(groupAny);
2019-09-02 19:00:17 +02:00
any |= groupAny;
}
}
2019-09-02 16:39:21 +02:00
return any;
}
2018-10-31 19:45:51 +01:00
GeneralPage::GeneralPage()
: SettingsPage("General", ":/settings/about.svg")
{
auto y = new QVBoxLayout;
auto scroll = new QScrollArea;
scroll->setWidgetResizable(true);
y->addWidget(scroll);
auto x = new QHBoxLayout;
auto layout = new SettingsLayout;
this->settingsLayout_ = layout;
2018-10-31 19:45:51 +01:00
x->addLayout(layout, 0);
x->addStretch(1);
auto z = new QFrame;
z->setLayout(x);
scroll->setWidget(z);
this->setLayout(y);
this->initLayout(*layout);
layout->addStretch(1);
this->initExtra();
}
2019-09-02 16:39:21 +02:00
bool GeneralPage::filterElements(const QString &query)
{
if (this->settingsLayout_)
2019-09-02 16:39:21 +02:00
return this->settingsLayout_->filterElements(query) ||
2019-09-02 19:00:17 +02:00
this->name_.contains(query, Qt::CaseInsensitive) ||
query.isEmpty();
2019-09-02 16:39:21 +02:00
else
return false;
}
2018-10-31 19:45:51 +01:00
void GeneralPage::initLayout(SettingsLayout &layout)
{
auto &s = *getSettings();
2019-08-26 13:18:23 +02:00
layout.addTitle("Interface");
2018-10-31 19:45:51 +01:00
layout.addDropdown("Theme", {"White", "Light", "Dark", "Black"},
getApp()->themes->themeName);
layout.addDropdown<QString>(
2018-10-31 19:45:51 +01:00
"Font", {"Segoe UI", "Arial", "Choose..."},
getApp()->fonts->chatFontFamily, [](auto val) { return val; },
2018-10-31 19:45:51 +01:00
[this](auto args) { return this->getFont(args); });
layout.addDropdown<int>(
"Font size", {"9pt", "10pt", "12pt", "14pt", "16pt", "20pt"},
getApp()->fonts->chatFontSize,
[](auto val) { return QString::number(val) + "pt"; },
[](auto args) { return fuzzyToInt(args.value, 10); });
2018-11-25 21:14:42 +01:00
layout.addDropdown<float>(
2018-10-31 19:45:51 +01:00
"UI Scale",
{"0.5x", "0.6x", "0.7x", "0.8x", "0.9x", "Default", "1.2x", "1.4x",
"1.6x", "1.8x", "2x", "2.33x", "2.66x", "3x", "3.5x", "4x"},
2018-11-25 21:14:42 +01:00
s.uiScale,
[](auto val) {
if (val == 1)
return QString("Default");
else
return QString::number(val) + "x";
},
[](auto args) { return fuzzyToFloat(args.value, 1.f); });
2019-08-26 13:18:23 +02:00
layout.addCheckbox("Show tab close button", s.showTabCloseButton);
2018-10-31 19:45:51 +01:00
layout.addCheckbox("Always on top", s.windowTopMost);
#ifdef USEWINSDK
layout.addCheckbox("Start with Windows", s.autorun);
#endif
2018-10-31 19:45:51 +01:00
2019-08-26 13:18:23 +02:00
layout.addTitle("Chat");
2018-10-31 19:45:51 +01:00
layout.addDropdown<float>(
"Mouse scroll speed", {"0.5x", "0.75x", "Default", "1.5x", "2x"},
s.mouseScrollMultiplier,
[](auto val) {
if (val == 1)
return QString("Default");
else
return QString::number(val) + "x";
},
[](auto args) { return fuzzyToFloat(args.value, 1.f); });
layout.addCheckbox("Smooth scrolling", s.enableSmoothScrolling);
2019-08-26 13:18:23 +02:00
layout.addCheckbox("Smooth scrolling on new messages",
2018-10-31 19:45:51 +01:00
s.enableSmoothScrollingNewMessages);
2019-08-26 13:18:23 +02:00
layout.addCheckbox("Pause on hover", s.pauseChatOnHover);
layout.addCheckbox("Show input when it's empty", s.showEmptyInput);
layout.addCheckbox("Show message length while typing", s.showMessageLength);
if (!BaseWindow::supportsCustomWindowFrame())
{
layout.addCheckbox("Show preferences button (ctrl+p to show)",
s.hidePreferencesButton, true);
layout.addCheckbox("Show user button", s.hideUserButton, true);
}
2018-10-31 19:45:51 +01:00
layout.addTitle("Messages");
2019-08-26 13:18:23 +02:00
layout.addCheckbox("Seperate with lines", s.separateMessages);
layout.addCheckbox("Alternate background color", s.alternateMessages);
// layout.addCheckbox("Mark last message you read");
// layout.addDropdown("Last read message style", {"Default"});
layout.addCheckbox("Show deleted messages", s.hideModerated, true);
layout.addDropdown<QString>(
"Timestamps", {"Disable", "h:mm", "hh:mm", "h:mm a", "hh:mm a"},
s.timestampFormat,
[](auto val) {
return getSettings()->showTimestamps.getValue()
? val
: QString("Disable");
},
[](auto args) {
getSettings()->showTimestamps.setValue(args.index != 0);
return args.index == 0 ? getSettings()->timestampFormat.getValue()
: args.value;
});
2018-10-31 19:45:51 +01:00
layout.addDropdown<int>(
"Collapse messages",
{"Never", "After 2 lines", "After 3 lines", "After 4 lines",
"After 5 lines"},
2018-10-31 19:45:51 +01:00
s.collpseMessagesMinLines,
[](auto val) {
return val ? QString("After ") + QString::number(val) + " lines"
: QString("Never");
},
[](auto args) { return fuzzyToInt(args.value, 0); });
2019-08-26 13:18:23 +02:00
layout.addDropdown<int>(
2019-08-26 13:29:04 +02:00
"Stack timeouts", {"Stack", "Stack until timeout", "Don't stack"},
2019-08-26 13:18:23 +02:00
s.timeoutStackStyle, [](int index) { return index; },
[](auto args) { return args.index; }, false);
2018-10-31 19:45:51 +01:00
layout.addTitle("Emotes");
2019-08-26 13:18:23 +02:00
layout.addCheckbox("Enable", s.enableEmoteImages);
layout.addCheckbox("Animate", s.animateEmotes);
layout.addCheckbox("Animate only when Chatterino is focused",
s.animationsWhenFocused);
2018-10-31 19:45:51 +01:00
layout.addDropdown<float>(
2019-08-26 13:18:23 +02:00
"Size", {"0.5x", "0.75x", "Default", "1.25x", "1.5x", "2x"},
2018-10-31 19:45:51 +01:00
s.emoteScale,
[](auto val) {
if (val == 1)
return QString("Default");
else
return QString::number(val) + "x";
},
[](auto args) { return fuzzyToFloat(args.value, 1.f); });
2019-09-02 10:52:35 +02:00
layout.addDropdown<int>(
"Preview on hover", {"Don't show", "Always show", "Hold shift"},
s.emotesTooltipPreview, [](int index) { return index; },
[](auto args) { return args.index; }, false);
2018-10-31 19:45:51 +01:00
layout.addDropdown("Emoji set",
{"EmojiOne 2", "EmojiOne 3", "Twitter", "Facebook",
"Apple", "Google", "Messenger"},
s.emojiSet);
2018-10-31 19:45:51 +01:00
2019-08-26 13:22:44 +02:00
layout.addTitle("Visible badges");
2019-08-26 13:18:23 +02:00
layout.addCheckbox("Authority (staff, admin)",
2018-10-31 19:45:51 +01:00
getSettings()->showBadgesGlobalAuthority);
2019-08-26 13:18:23 +02:00
layout.addCheckbox("Channel (broadcaster, moderator)",
2018-10-31 19:45:51 +01:00
getSettings()->showBadgesChannelAuthority);
2019-08-26 13:18:23 +02:00
layout.addCheckbox("Subscriber ", getSettings()->showBadgesSubscription);
layout.addCheckbox("Vanity (prime, bits, subgifter)",
2018-10-31 19:45:51 +01:00
getSettings()->showBadgesVanity);
2019-08-26 13:18:23 +02:00
layout.addCheckbox("Chatterino", getSettings()->showBadgesChatterino);
2018-10-31 19:45:51 +01:00
2019-08-26 13:22:44 +02:00
layout.addTitle("Chat title");
2019-09-02 12:29:18 +02:00
layout.addDescription("In live channels show:");
2019-08-26 13:18:23 +02:00
layout.addCheckbox("Uptime", s.headerUptime);
layout.addCheckbox("Viewer count", s.headerViewerCount);
layout.addCheckbox("Category", s.headerGame);
layout.addCheckbox("Title", s.headerStreamTitle);
2018-10-31 19:45:51 +01:00
2019-09-02 10:52:01 +02:00
layout.addTitle("Beta");
2019-09-02 12:29:18 +02:00
layout.addDescription(
"You can receive updates earlier by ticking the box below. Report "
"issues <a href='https://chatterino.com/link/issues'>here</a>.");
2019-09-02 10:52:01 +02:00
layout.addCheckbox("Receive beta updates", s.betaUpdates);
2019-09-02 10:52:35 +02:00
#ifdef Q_OS_WIN
layout.addTitle("Browser Integration");
layout.addDescription("The browser extension replaces the default "
"Twitch.tv chat with chatterino.");
layout.addDescription(
createNamedLink(CHROME_EXTENSION_LINK, "Download for Google Chrome"));
layout.addDescription(
createNamedLink(FIREFOX_EXTENSION_LINK, "Download for Firefox"));
#endif
2019-08-26 13:22:44 +02:00
layout.addTitle("Miscellaneous");
2019-08-26 13:18:23 +02:00
2019-09-13 19:26:52 +02:00
#ifdef Q_OS_LINUX
if (!getPaths()->isPortable())
{
layout.addCheckbox(
"Use libsecret/KWallet/Gnome keychain to secure passwords",
s.useKeyring);
}
#endif
2019-09-02 10:52:35 +02:00
layout.addCheckbox("Show moderation messages", s.hideModerationActions,
true);
layout.addCheckbox("Random username color for users who never set a color",
s.colorizeNicknames);
2019-08-21 01:08:15 +02:00
layout.addCheckbox("Mention users with a comma (User,)",
s.mentionUsersWithComma);
2018-10-31 19:45:51 +01:00
layout.addCheckbox("Show joined users (< 1000 chatters)", s.showJoins);
layout.addCheckbox("Show parted users (< 1000 chatters)", s.showParts);
2019-08-26 13:18:23 +02:00
layout.addCheckbox("Lowercase domains (anti-phisching)",
s.lowercaseDomains);
2018-10-31 19:45:51 +01:00
layout.addCheckbox("Bold @usernames", s.boldUsernames);
layout.addDropdown<float>(
"Username font weight", {"50", "Default", "75", "100"}, s.boldScale,
[](auto val) {
if (val == 63)
return QString("Default");
else
return QString::number(val);
},
[](auto args) { return fuzzyToFloat(args.value, 63.f); });
2018-10-31 19:45:51 +01:00
layout.addCheckbox("Show link info when hovering", s.linkInfoTooltip);
2019-08-26 13:29:04 +02:00
layout.addCheckbox("Double click to open links and other elements in chat",
s.linksDoubleClickOnly);
2018-10-31 19:45:51 +01:00
layout.addCheckbox("Unshorten links", s.unshortLinks);
layout.addCheckbox("Show live indicator in tabs", s.showTabLive);
layout.addCheckbox(
"Only search for emote autocompletion at the start of emote names",
s.prefixOnlyEmoteCompletion);
2018-10-31 21:23:19 +01:00
layout.addCheckbox("Show twitch whispers inline", s.inlineWhispers);
layout.addCheckbox("Highlight received inline whispers",
s.highlightInlineWhispers);
layout.addCheckbox("Load message history on connect",
s.loadTwitchMessageHistoryOnConnect);
2018-10-31 21:23:19 +01:00
layout.addCheckbox("Show unhandled irc messages",
s.showUnhandledIrcMessages);
2019-09-03 12:46:22 +02:00
layout.addTitle("Cache");
layout.addDescription(
"Files that are used often (such as emotes) are saved to disk to "
"reduce bandwidth usage and tho speed up loading.");
auto cachePathLabel = layout.addDescription("placeholder :D");
getSettings()->cachePath.connect([cachePathLabel](const auto &,
auto) mutable {
QString newPath = getPaths()->cacheDirectory();
QString pathShortened = "Cache saved at <a href=\"file:///" + newPath +
"\"><span style=\"color: white;\">" +
shortenString(newPath, 50) + "</span></a>";
cachePathLabel->setText(pathShortened);
cachePathLabel->setToolTip(newPath);
});
// Choose and reset buttons
{
auto box = new QHBoxLayout;
2019-09-03 12:46:22 +02:00
box->addWidget(layout.makeButton("Choose cache path", [this]() {
getSettings()->cachePath = QFileDialog::getExistingDirectory(this);
}));
box->addWidget(layout.makeButton(
"Reset", []() { getSettings()->cachePath = ""; }));
box->addStretch(1);
layout.addLayout(box);
}
2019-09-03 12:46:22 +02:00
2019-09-02 10:52:35 +02:00
layout.addTitle("AppData");
layout.addDescription("All local files like settings and cache files are "
"store in this directory.");
layout.addButton("Open AppData directory", [] {
QDesktopServices::openUrl(getPaths()->rootAppDataDirectory);
});
2018-10-31 19:45:51 +01:00
2019-09-02 09:44:25 +02:00
// invisible element for width
auto inv = new BaseWidget(this);
inv->setScaleIndependantWidth(500);
layout.addWidget(inv);
}
2018-10-31 19:45:51 +01:00
void GeneralPage::initExtra()
{
/// update cache path
if (this->cachePath_)
2018-10-31 19:45:51 +01:00
{
getSettings()->cachePath.connect(
[cachePath = this->cachePath_](const auto &, auto) mutable {
2018-10-31 19:45:51 +01:00
QString newPath = getPaths()->cacheDirectory();
QString pathShortened = "Current location: <a href=\"file:///" +
newPath + "\">" +
shortenString(newPath, 50) + "</a>";
cachePath->setText(pathShortened);
cachePath->setToolTip(newPath);
});
}
}
QString GeneralPage::getFont(const DropdownArgs &args) const
2018-10-31 19:45:51 +01:00
{
if (args.combobox->currentIndex() == args.combobox->count() - 1)
{
args.combobox->setCurrentIndex(0);
args.combobox->setEditText("Choosing...");
QFontDialog dialog(getApp()->fonts->getFont(FontStyle::ChatMedium, 1.));
dialog.setWindowFlag(Qt::WindowStaysOnTopHint);
auto ok = bool();
auto font = dialog.getFont(&ok);
if (ok)
return font.family();
2018-10-31 19:45:51 +01:00
else
return args.combobox->itemText(0);
2018-10-31 19:45:51 +01:00
}
return args.value;
2018-10-31 19:45:51 +01:00
}
} // namespace chatterino