Add settings tooltips (#3437)

Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
Adam Davies 2022-10-30 07:06:38 -05:00 committed by GitHub
parent ff684fc7ed
commit fa93d63383
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 116 additions and 40 deletions

View file

@ -68,6 +68,7 @@
- Minor: Migrated /uniquechat and /r9kbeta to Helix API. (#4057) - Minor: Migrated /uniquechat and /r9kbeta to Helix API. (#4057)
- Minor: Migrated /uniquechatoff and /r9kbetaoff to Helix API. (#4057) - Minor: Migrated /uniquechatoff and /r9kbetaoff to Helix API. (#4057)
- Minor: Make menus and placeholders display appropriate custom key combos. (#4045) - Minor: Make menus and placeholders display appropriate custom key combos. (#4045)
- Minor: Add settings tooltips. (#3437)
- Bugfix: Connection to Twitch PubSub now recovers more reliably. (#3643, #3716) - Bugfix: Connection to Twitch PubSub now recovers more reliably. (#3643, #3716)
- Bugfix: Fixed `Smooth scrolling on new messages` setting sometimes hiding messages. (#4028) - Bugfix: Fixed `Smooth scrolling on new messages` setting sometimes hiding messages. (#4028)
- Bugfix: Fixed a crash that can occur when closing and quickly reopening a split, then running a command. (#3852) - Bugfix: Fixed a crash that can occur when closing and quickly reopening a split, then running a command. (#3852)

View file

@ -191,9 +191,11 @@ void GeneralPage::initLayout(GeneralPageView &layout)
layout.addCheckbox("Show message reply button", s.showReplyButton); layout.addCheckbox("Show message reply button", s.showReplyButton);
layout.addCheckbox("Show tab close button", s.showTabCloseButton); layout.addCheckbox("Show tab close button", s.showTabCloseButton);
layout.addCheckbox("Always on top", s.windowTopMost); layout.addCheckbox("Always on top", s.windowTopMost, false,
"Always keep Chatterino as the top window.");
#ifdef USEWINSDK #ifdef USEWINSDK
layout.addCheckbox("Start with Windows", s.autorun); layout.addCheckbox("Start with Windows", s.autorun, false,
"Start Chatterino when your computer starts.");
#endif #endif
if (!BaseWindow::supportsCustomWindowFrame()) if (!BaseWindow::supportsCustomWindowFrame())
{ {
@ -253,17 +255,19 @@ void GeneralPage::initLayout(GeneralPageView &layout)
layout.addCheckbox("Smooth scrolling", s.enableSmoothScrolling); layout.addCheckbox("Smooth scrolling", s.enableSmoothScrolling);
layout.addCheckbox("Smooth scrolling on new messages", layout.addCheckbox("Smooth scrolling on new messages",
s.enableSmoothScrollingNewMessages); s.enableSmoothScrollingNewMessages);
layout.addCheckbox("Show input when it's empty", s.showEmptyInput); layout.addCheckbox("Show input when it's empty", s.showEmptyInput, false,
"Show the chat box even when there is nothing typed.");
layout.addCheckbox("Show message length while typing", s.showMessageLength); layout.addCheckbox("Show message length while typing", s.showMessageLength);
layout.addCheckbox("Allow sending duplicate messages", layout.addCheckbox(
s.allowDuplicateMessages); "Allow sending duplicate messages", s.allowDuplicateMessages, false,
"Allow a single message to be repeatedly sent without any changes.");
layout.addTitle("Messages"); layout.addTitle("Messages");
layout.addCheckbox("Separate with lines", s.separateMessages); layout.addCheckbox("Separate with lines", s.separateMessages);
layout.addCheckbox("Alternate background color", s.alternateMessages); layout.addCheckbox("Alternate background color", s.alternateMessages);
layout.addCheckbox("Show deleted messages", s.hideModerated, true); layout.addCheckbox("Show deleted messages", s.hideModerated, true);
layout.addDropdown<QString>( layout.addDropdown<QString>(
"Timestamp format (a = am/pm, zzz = milliseconds)", "Timestamp format",
{"Disable", "h:mm", "hh:mm", "h:mm a", "hh:mm a", "h:mm:ss", "hh:mm:ss", {"Disable", "h:mm", "hh:mm", "h:mm a", "hh:mm a", "h:mm:ss", "hh:mm:ss",
"h:mm:ss a", "hh:mm:ss a", "h:mm:ss.zzz", "h:mm:ss.zzz a", "h:mm:ss a", "hh:mm:ss a", "h:mm:ss.zzz", "h:mm:ss.zzz a",
"hh:mm:ss.zzz", "hh:mm:ss.zzz a"}, "hh:mm:ss.zzz", "hh:mm:ss.zzz a"},
@ -278,7 +282,8 @@ void GeneralPage::initLayout(GeneralPageView &layout)
return args.index == 0 ? getSettings()->timestampFormat.getValue() return args.index == 0 ? getSettings()->timestampFormat.getValue()
: args.value; : args.value;
}); },
true, "a = am/pm, zzz = milliseconds");
layout.addDropdown<int>( layout.addDropdown<int>(
"Limit message height", "Limit message height",
{"Never", "2 lines", "3 lines", "4 lines", "5 lines"}, {"Never", "2 lines", "3 lines", "4 lines", "5 lines"},
@ -367,7 +372,7 @@ void GeneralPage::initLayout(GeneralPageView &layout)
[](auto args) { [](auto args) {
return args.index; return args.index;
}, },
false); false, "Show emote name, provider, and author on hover.");
layout.addDropdown("Emoji style", layout.addDropdown("Emoji style",
{ {
"Twitter", "Twitter",
@ -404,7 +409,8 @@ void GeneralPage::initLayout(GeneralPageView &layout)
dankDropdown->setMinimumWidth(dankDropdown->minimumSizeHint().width() + 30); dankDropdown->setMinimumWidth(dankDropdown->minimumSizeHint().width() + 30);
layout.addCheckbox("Hide usercard avatars", layout.addCheckbox("Hide usercard avatars",
s.streamerModeHideUsercardAvatars); s.streamerModeHideUsercardAvatars, false,
"Prevent potentially explicit avatars from showing.");
layout.addCheckbox("Hide link thumbnails", layout.addCheckbox("Hide link thumbnails",
s.streamerModeHideLinkThumbnails); s.streamerModeHideLinkThumbnails);
layout.addCheckbox( layout.addCheckbox(
@ -644,16 +650,19 @@ void GeneralPage::initLayout(GeneralPageView &layout)
}); });
layout.addSubtitle("Visible badges"); layout.addSubtitle("Visible badges");
layout.addCheckbox("Authority (staff, admin)", s.showBadgesGlobalAuthority); layout.addCheckbox("Authority", s.showBadgesGlobalAuthority, false,
"e.g., staff, admin");
layout.addCheckbox("Predictions", s.showBadgesPredictions); layout.addCheckbox("Predictions", s.showBadgesPredictions);
layout.addCheckbox("Channel (broadcaster, moderator)", layout.addCheckbox("Channel", s.showBadgesChannelAuthority, false,
s.showBadgesChannelAuthority); "e.g., broadcaster, moderator");
layout.addCheckbox("Subscriber ", s.showBadgesSubscription); layout.addCheckbox("Subscriber ", s.showBadgesSubscription);
layout.addCheckbox("Vanity (prime, bits, subgifter)", s.showBadgesVanity); layout.addCheckbox("Vanity", s.showBadgesVanity, false,
"e.g., prime, bits, sub gifter");
layout.addCheckbox("Chatterino", s.showBadgesChatterino); layout.addCheckbox("Chatterino", s.showBadgesChatterino);
layout.addCheckbox("FrankerFaceZ (Bot, FFZ Supporter, FFZ Developer)", layout.addCheckbox("FrankerFaceZ", s.showBadgesFfz, false,
s.showBadgesFfz); "e.g., Bot, FFZ supporter, FFZ developer");
layout.addCheckbox("7TV", s.showBadgesSevenTV); layout.addCheckbox("7TV", s.showBadgesSevenTV, false,
"Badges for 7TV admins, developers, and supporters");
layout.addSeperator(); layout.addSeperator();
layout.addCheckbox("Use custom FrankerFaceZ moderator badges", layout.addCheckbox("Use custom FrankerFaceZ moderator badges",
s.useCustomFfzModeratorBadges); s.useCustomFfzModeratorBadges);
@ -679,8 +688,9 @@ void GeneralPage::initLayout(GeneralPageView &layout)
} }
#endif #endif
layout.addCheckbox("Show moderation messages", s.hideModerationActions, layout.addCheckbox(
true); "Show moderation messages", s.hideModerationActions, true,
"Show messages for timeouts, bans, and other moderator actions.");
layout.addCheckbox("Show deletions of single messages", layout.addCheckbox("Show deletions of single messages",
s.hideDeletionActions, true); s.hideDeletionActions, true);
layout.addCheckbox("Colorize users without color set (gray names)", layout.addCheckbox("Colorize users without color set (gray names)",
@ -694,11 +704,15 @@ void GeneralPage::initLayout(GeneralPageView &layout)
layout.addCheckbox( layout.addCheckbox(
"Automatically close reply thread popup when it loses focus", "Automatically close reply thread popup when it loses focus",
s.autoCloseThreadPopup); s.autoCloseThreadPopup);
layout.addCheckbox("Lowercase domains (anti-phishing)", s.lowercaseDomains); layout.addCheckbox("Lowercase domains (anti-phishing)", s.lowercaseDomains,
false,
"Make all clickable links lowercase to deter "
"phishing attempts.");
layout.addCheckbox("Bold @usernames", s.boldUsernames); layout.addCheckbox("Bold @usernames", s.boldUsernames);
layout.addCheckbox("Color @usernames", s.colorUsernames); layout.addCheckbox("Color @usernames", s.colorUsernames);
layout.addCheckbox("Try to find usernames without @ prefix", layout.addCheckbox("Try to find usernames without @ prefix",
s.findAllUsernames); s.findAllUsernames, false,
"Find mentions of users in chat without the @ prefix.");
layout.addCheckbox("Show username autocompletion popup menu", layout.addCheckbox("Show username autocompletion popup menu",
s.showUsernameCompletionMenu); s.showUsernameCompletionMenu);
const QStringList usernameDisplayModes = {"Username", "Localized name", const QStringList usernameDisplayModes = {"Username", "Localized name",
@ -734,11 +748,16 @@ void GeneralPage::initLayout(GeneralPageView &layout)
layout.addCheckbox( layout.addCheckbox(
"Only search for emote autocompletion at the start of emote names", "Only search for emote autocompletion at the start of emote names",
s.prefixOnlyEmoteCompletion); s.prefixOnlyEmoteCompletion, false,
"When disabled, emote tab-completion will complete based on any part "
"of the name."
"\ne.g., sheffy -> DatSheffy");
layout.addCheckbox("Only search for username autocompletion with an @", layout.addCheckbox("Only search for username autocompletion with an @",
s.userCompletionOnlyWithAt); s.userCompletionOnlyWithAt);
layout.addCheckbox("Show Twitch whispers inline", s.inlineWhispers); layout.addCheckbox("Show Twitch whispers inline", s.inlineWhispers, false,
"Show whispers as messages in all splits instead "
"of just /whispers.");
layout.addCheckbox("Highlight received inline whispers", layout.addCheckbox("Highlight received inline whispers",
s.highlightInlineWhispers); s.highlightInlineWhispers);
layout.addCheckbox("Load message history on connect", layout.addCheckbox("Load message history on connect",
@ -760,8 +779,10 @@ void GeneralPage::initLayout(GeneralPageView &layout)
[](auto args) { [](auto args) {
return args.index; return args.index;
}, },
false); false, "Combine consecutive timeout messages into a single message.");
layout.addCheckbox("Combine multiple bit tips into one", s.stackBits); layout.addCheckbox("Combine multiple bit tips into one", s.stackBits, false,
"Combine consecutive cheermotes (sent in a single "
"message) into one cheermote.");
layout.addCheckbox("Messages in /mentions highlights tab", layout.addCheckbox("Messages in /mentions highlights tab",
s.highlightMentions); s.highlightMentions);
layout.addCheckbox("Strip leading mention in replies", s.stripReplyMention); layout.addCheckbox("Strip leading mention in replies", s.stripReplyMention);

View file

@ -1,13 +1,33 @@
#include "GeneralPageView.hpp" #include "widgets/settingspages/GeneralPageView.hpp"
#include <QScrollBar>
#include "Application.hpp" #include "Application.hpp"
#include "singletons/Settings.hpp"
#include "singletons/WindowManager.hpp" #include "singletons/WindowManager.hpp"
#include "util/LayoutHelper.hpp" #include "util/LayoutHelper.hpp"
#include "util/RapidJsonSerializeQString.hpp"
#include "widgets/dialogs/ColorPickerDialog.hpp" #include "widgets/dialogs/ColorPickerDialog.hpp"
#include "widgets/helper/ColorButton.hpp" #include "widgets/helper/ColorButton.hpp"
#include "widgets/helper/Line.hpp" #include "widgets/helper/Line.hpp"
#include <QRegularExpression>
#include <QScrollBar>
namespace {
constexpr int MAX_TOOLTIP_LINE_LENGTH = 50;
const auto MAX_TOOLTIP_LINE_LENGTH_PATTERN =
QStringLiteral(R"(.{%1}\S*\K(\s+))").arg(MAX_TOOLTIP_LINE_LENGTH);
const QRegularExpression MAX_TOOLTIP_LINE_LENGTH_REGEX(
MAX_TOOLTIP_LINE_LENGTH_PATTERN);
const auto TOOLTIP_STYLE_SHEET = QStringLiteral(R"(QToolTip {
padding: 2px;
background-color: #333333;
border: 1px solid #545454;
}
)");
} // namespace
namespace chatterino { namespace chatterino {
GeneralPageView::GeneralPageView(QWidget *parent) GeneralPageView::GeneralPageView(QWidget *parent)
@ -86,9 +106,11 @@ SubtitleLabel *GeneralPageView::addSubtitle(const QString &title)
} }
QCheckBox *GeneralPageView::addCheckbox(const QString &text, QCheckBox *GeneralPageView::addCheckbox(const QString &text,
BoolSetting &setting, bool inverse) BoolSetting &setting, bool inverse,
QString toolTipText)
{ {
auto check = new QCheckBox(text); auto check = new QCheckBox(text);
this->addToolTip(*check, toolTipText);
// update when setting changes // update when setting changes
setting.connect( setting.connect(
@ -112,7 +134,8 @@ QCheckBox *GeneralPageView::addCheckbox(const QString &text,
} }
ComboBox *GeneralPageView::addDropdown(const QString &text, ComboBox *GeneralPageView::addDropdown(const QString &text,
const QStringList &list) const QStringList &list,
QString toolTipText)
{ {
auto layout = new QHBoxLayout; auto layout = new QHBoxLayout;
auto combo = new ComboBox; auto combo = new ComboBox;
@ -124,6 +147,7 @@ ComboBox *GeneralPageView::addDropdown(const QString &text,
layout->addStretch(1); layout->addStretch(1);
layout->addWidget(combo); layout->addWidget(combo);
this->addToolTip(*label, toolTipText);
this->addLayout(layout); this->addLayout(layout);
// groups // groups
@ -135,9 +159,10 @@ ComboBox *GeneralPageView::addDropdown(const QString &text,
ComboBox *GeneralPageView::addDropdown( ComboBox *GeneralPageView::addDropdown(
const QString &text, const QStringList &items, const QString &text, const QStringList &items,
pajlada::Settings::Setting<QString> &setting, bool editable) pajlada::Settings::Setting<QString> &setting, bool editable,
QString toolTipText)
{ {
auto combo = this->addDropdown(text, items); auto combo = this->addDropdown(text, items, toolTipText);
if (editable) if (editable)
combo->setEditable(true); combo->setEditable(true);
@ -160,15 +185,19 @@ ComboBox *GeneralPageView::addDropdown(
ColorButton *GeneralPageView::addColorButton( ColorButton *GeneralPageView::addColorButton(
const QString &text, const QColor &color, const QString &text, const QColor &color,
pajlada::Settings::Setting<QString> &setting) pajlada::Settings::Setting<QString> &setting, QString toolTipText)
{ {
auto colorButton = new ColorButton(color); auto colorButton = new ColorButton(color);
auto layout = new QHBoxLayout(); auto layout = new QHBoxLayout();
auto label = new QLabel(text + ":"); auto label = new QLabel(text + ":");
layout->addWidget(label); layout->addWidget(label);
layout->addStretch(1); layout->addStretch(1);
layout->addWidget(colorButton); layout->addWidget(colorButton);
this->addToolTip(*label, toolTipText);
this->addLayout(layout); this->addLayout(layout);
QObject::connect( QObject::connect(
colorButton, &ColorButton::clicked, [this, &setting, colorButton]() { colorButton, &ColorButton::clicked, [this, &setting, colorButton]() {
auto dialog = new ColorPickerDialog(QColor(setting), this); auto dialog = new ColorPickerDialog(QColor(setting), this);
@ -190,11 +219,13 @@ ColorButton *GeneralPageView::addColorButton(
} }
QSpinBox *GeneralPageView::addIntInput(const QString &text, IntSetting &setting, QSpinBox *GeneralPageView::addIntInput(const QString &text, IntSetting &setting,
int min, int max, int step) int min, int max, int step,
QString toolTipText)
{ {
auto layout = new QHBoxLayout; auto layout = new QHBoxLayout;
auto label = new QLabel(text + ":"); auto label = new QLabel(text + ":");
this->addToolTip(*label, toolTipText);
auto input = new QSpinBox; auto input = new QSpinBox;
input->setMinimum(min); input->setMinimum(min);
@ -362,4 +393,23 @@ void GeneralPageView::updateNavigationHighlighting()
} }
} }
void GeneralPageView::addToolTip(QWidget &widget, QString text) const
{
if (text.isEmpty())
{
return;
}
if (text.length() > MAX_TOOLTIP_LINE_LENGTH)
{
// match MAX_TOOLTIP_LINE_LENGTH characters, any remaining
// non-space, and then capture the following space for
// replacement with newline
text.replace(MAX_TOOLTIP_LINE_LENGTH_REGEX, "\n");
}
widget.setToolTip(text);
widget.setStyleSheet(TOOLTIP_STYLE_SHEET);
}
} // namespace chatterino } // namespace chatterino

View file

@ -99,15 +99,17 @@ public:
SubtitleLabel *addSubtitle(const QString &text); SubtitleLabel *addSubtitle(const QString &text);
/// @param inverse Inverses true to false and vice versa /// @param inverse Inverses true to false and vice versa
QCheckBox *addCheckbox(const QString &text, BoolSetting &setting, QCheckBox *addCheckbox(const QString &text, BoolSetting &setting,
bool inverse = false); bool inverse = false, QString toolTipText = {});
ComboBox *addDropdown(const QString &text, const QStringList &items); ComboBox *addDropdown(const QString &text, const QStringList &items,
QString toolTipText = {});
ComboBox *addDropdown(const QString &text, const QStringList &items, ComboBox *addDropdown(const QString &text, const QStringList &items,
pajlada::Settings::Setting<QString> &setting, pajlada::Settings::Setting<QString> &setting,
bool editable = false); bool editable = false, QString toolTipText = {});
ColorButton *addColorButton(const QString &text, const QColor &color, ColorButton *addColorButton(const QString &text, const QColor &color,
pajlada::Settings::Setting<QString> &setting); pajlada::Settings::Setting<QString> &setting,
QString toolTipText = {});
QSpinBox *addIntInput(const QString &text, IntSetting &setting, int min, QSpinBox *addIntInput(const QString &text, IntSetting &setting, int min,
int max, int step); int max, int step, QString toolTipText = {});
void addNavigationSpacing(); void addNavigationSpacing();
template <typename OnClick> template <typename OnClick>
@ -135,7 +137,8 @@ public:
const QString &text, const QStringList &items, const QString &text, const QStringList &items,
pajlada::Settings::Setting<T> &setting, pajlada::Settings::Setting<T> &setting,
std::function<boost::variant<int, QString>(T)> getValue, std::function<boost::variant<int, QString>(T)> getValue,
std::function<T(DropdownArgs)> setValue, bool editable = true) std::function<T(DropdownArgs)> setValue, bool editable = true,
QString toolTipText = {})
{ {
auto items2 = items; auto items2 = items;
auto selected = getValue(setting.getValue()); auto selected = getValue(setting.getValue());
@ -147,7 +150,7 @@ public:
items2.insert(0, boost::get<QString>(selected)); items2.insert(0, boost::get<QString>(selected));
} }
auto combo = this->addDropdown(text, items2); auto combo = this->addDropdown(text, items2, toolTipText);
if (editable) if (editable)
combo->setEditable(true); combo->setEditable(true);
@ -200,6 +203,7 @@ protected:
private: private:
void updateNavigationHighlighting(); void updateNavigationHighlighting();
void addToolTip(QWidget &widget, QString text) const;
struct Widget { struct Widget {
QWidget *element; QWidget *element;