refactor: use some more SettingWidget & restyle external tools page (#6023)
This commit is contained in:
@@ -51,6 +51,7 @@
|
||||
- Dev: Fixed duplicate CMake configure in clean builds. (#5940)
|
||||
- Dev: BTTV emotes are now loaded as WEBP. (#5957)
|
||||
- Dev: Reduced time we wait for PubSub connections to cleanly exit from 1s to 100ms. (#6019)
|
||||
- Dev: Refactored some settings styles/APIs. (#6023)
|
||||
- Dev: Added snapshot tests for EventSub. (#5965)
|
||||
- Dev: Removed dead code and some MSVC warnings. (#6024)
|
||||
|
||||
|
||||
@@ -76,6 +76,15 @@ enum class ShowModerationState : int {
|
||||
Never = 1,
|
||||
};
|
||||
|
||||
enum class StreamLinkPreferredQuality : std::uint8_t {
|
||||
Choose,
|
||||
Source,
|
||||
High,
|
||||
Medium,
|
||||
Low,
|
||||
AudioOnly,
|
||||
};
|
||||
|
||||
enum StreamerModeSetting {
|
||||
Disabled = 0,
|
||||
Enabled = 1,
|
||||
@@ -538,8 +547,10 @@ public:
|
||||
BoolSetting streamlinkUseCustomPath = {"/external/streamlink/useCustomPath",
|
||||
false};
|
||||
QStringSetting streamlinkPath = {"/external/streamlink/customPath", ""};
|
||||
QStringSetting preferredQuality = {"/external/streamlink/quality",
|
||||
"Choose"};
|
||||
EnumStringSetting<StreamLinkPreferredQuality> preferredQuality = {
|
||||
"/external/streamlink/quality",
|
||||
StreamLinkPreferredQuality::Choose,
|
||||
};
|
||||
QStringSetting streamlinkOpts = {"/external/streamlink/options", ""};
|
||||
|
||||
// Custom URI Scheme
|
||||
@@ -700,3 +711,26 @@ private:
|
||||
Settings *getSettings();
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
template <>
|
||||
constexpr magic_enum::customize::customize_t
|
||||
magic_enum::customize::enum_name<chatterino::StreamLinkPreferredQuality>(
|
||||
chatterino::StreamLinkPreferredQuality value) noexcept
|
||||
{
|
||||
using chatterino::StreamLinkPreferredQuality;
|
||||
switch (value)
|
||||
{
|
||||
case chatterino::StreamLinkPreferredQuality::Choose:
|
||||
case chatterino::StreamLinkPreferredQuality::Source:
|
||||
case chatterino::StreamLinkPreferredQuality::High:
|
||||
case chatterino::StreamLinkPreferredQuality::Medium:
|
||||
case chatterino::StreamLinkPreferredQuality::Low:
|
||||
return default_tag;
|
||||
|
||||
case chatterino::StreamLinkPreferredQuality::AudioOnly:
|
||||
return "Audio only";
|
||||
|
||||
default:
|
||||
return default_tag;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,10 +199,9 @@ void openStreamlinkForChannel(const QString &channel)
|
||||
|
||||
QString channelURL = "twitch.tv/" + channel;
|
||||
|
||||
QString preferredQuality = getSettings()->preferredQuality.getValue();
|
||||
preferredQuality = preferredQuality.toLower();
|
||||
auto preferredQuality = getSettings()->preferredQuality.getEnum();
|
||||
|
||||
if (preferredQuality == "choose")
|
||||
if (preferredQuality == StreamLinkPreferredQuality::Choose)
|
||||
{
|
||||
getStreamQualities(channelURL, [=](QStringList qualityOptions) {
|
||||
QualityPopup::showDialog(channelURL, qualityOptions);
|
||||
@@ -218,22 +217,22 @@ void openStreamlinkForChannel(const QString &channel)
|
||||
// Streamlink qualities to exclude
|
||||
QString exclude;
|
||||
|
||||
if (preferredQuality == "high")
|
||||
if (preferredQuality == StreamLinkPreferredQuality::High)
|
||||
{
|
||||
exclude = ">720p30";
|
||||
quality = "high,best";
|
||||
}
|
||||
else if (preferredQuality == "medium")
|
||||
else if (preferredQuality == StreamLinkPreferredQuality::Medium)
|
||||
{
|
||||
exclude = ">540p30";
|
||||
quality = "medium,best";
|
||||
}
|
||||
else if (preferredQuality == "low")
|
||||
else if (preferredQuality == StreamLinkPreferredQuality::Low)
|
||||
{
|
||||
exclude = ">360p30";
|
||||
quality = "low,best";
|
||||
}
|
||||
else if (preferredQuality == "audio only")
|
||||
else if (preferredQuality == StreamLinkPreferredQuality::AudioOnly)
|
||||
{
|
||||
quality = "audio,audio_only";
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "util/Helpers.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "util/RemoveScrollAreaBackground.hpp"
|
||||
#include "util/StreamLink.hpp"
|
||||
#include "widgets/settingspages/SettingWidget.hpp"
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QGroupBox>
|
||||
@@ -13,31 +12,47 @@
|
||||
namespace chatterino {
|
||||
|
||||
inline const QStringList STREAMLINK_QUALITY = {
|
||||
"Choose", "Source", "High", "Medium", "Low", "Audio only"};
|
||||
"Choose", "Source", "High", "Medium", "Low", "Audio only",
|
||||
};
|
||||
|
||||
ExternalToolsPage::ExternalToolsPage()
|
||||
: view(GeneralPageView::withoutNavigation(this))
|
||||
{
|
||||
LayoutCreator<ExternalToolsPage> layoutCreator(this);
|
||||
auto *y = new QVBoxLayout;
|
||||
auto *x = new QHBoxLayout;
|
||||
x->addWidget(this->view);
|
||||
auto *z = new QFrame;
|
||||
z->setLayout(x);
|
||||
y->addWidget(z);
|
||||
this->setLayout(y);
|
||||
|
||||
auto scroll = layoutCreator.emplace<QScrollArea>();
|
||||
auto widget = scroll.emplaceScrollAreaWidget();
|
||||
removeScrollAreaBackground(scroll.getElement(), widget.getElement());
|
||||
this->initLayout(*view);
|
||||
}
|
||||
|
||||
auto layout = widget.setLayoutType<QVBoxLayout>();
|
||||
bool ExternalToolsPage::filterElements(const QString &query)
|
||||
{
|
||||
if (this->view)
|
||||
{
|
||||
return this->view->filterElements(query) || query.isEmpty();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||
void ExternalToolsPage::initLayout(GeneralPageView &layout)
|
||||
{
|
||||
auto &s = *getSettings();
|
||||
|
||||
{
|
||||
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(
|
||||
auto *form = new QFormLayout;
|
||||
layout.addTitle("Streamlink");
|
||||
layout.addDescription("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!");
|
||||
layout.addDescription(
|
||||
formatRichNamedLink("https://streamlink.github.io/", "Website") +
|
||||
" " +
|
||||
formatRichNamedLink(
|
||||
@@ -46,115 +61,83 @@ ExternalToolsPage::ExternalToolsPage()
|
||||
" " +
|
||||
formatRichNamedLink("https://streamlink.github.io/cli.html#twitch",
|
||||
"Documentation"));
|
||||
links->setTextFormat(Qt::RichText);
|
||||
links->setTextInteractionFlags(Qt::TextBrowserInteraction |
|
||||
Qt::LinksAccessibleByKeyboard |
|
||||
Qt::LinksAccessibleByMouse);
|
||||
links->setOpenExternalLinks(true);
|
||||
|
||||
groupLayout->setWidget(0, QFormLayout::SpanningRole, description);
|
||||
groupLayout->setWidget(1, QFormLayout::SpanningRole, links);
|
||||
SettingWidget::checkbox("Use custom path (Enable if using non-standard "
|
||||
"streamlink installation path)",
|
||||
s.streamlinkUseCustomPath)
|
||||
->addTo(layout);
|
||||
|
||||
auto *customPathCb =
|
||||
this->createCheckBox("Use custom path (Enable if using "
|
||||
"non-standard streamlink installation path)",
|
||||
getSettings()->streamlinkUseCustomPath);
|
||||
groupLayout->setWidget(2, QFormLayout::SpanningRole, customPathCb);
|
||||
|
||||
auto *note = new QLabel(
|
||||
layout.addDescription(
|
||||
QStringLiteral(
|
||||
"Chatterino expects the executable to be called \"%1\".")
|
||||
.arg(STREAMLINK_BINARY_NAME));
|
||||
note->setWordWrap(true);
|
||||
note->setStyleSheet("color: #bbb");
|
||||
groupLayout->setWidget(3, QFormLayout::SpanningRole, note);
|
||||
|
||||
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));
|
||||
layout.addLayout(form);
|
||||
|
||||
getSettings()->streamlinkUseCustomPath.connect(
|
||||
[=](const auto &value, auto) {
|
||||
customPath->setEnabled(value);
|
||||
},
|
||||
this->managedConnections_);
|
||||
SettingWidget::lineEdit(
|
||||
"Custom streamlink path", s.streamlinkPath,
|
||||
"Path to folder where Streamlink executable can be found")
|
||||
->conditionallyEnabledBy(s.streamlinkUseCustomPath)
|
||||
->addTo(layout, form);
|
||||
|
||||
SettingWidget::dropdown("Preferred quality", s.preferredQuality)
|
||||
->addTo(layout, form);
|
||||
|
||||
SettingWidget::lineEdit("Additional options", s.streamlinkOpts, "")
|
||||
->addTo(layout, form);
|
||||
}
|
||||
layout->addSpacing(16);
|
||||
|
||||
{
|
||||
auto group = layout.emplace<QGroupBox>("Custom stream player");
|
||||
auto groupLayout = group.setLayoutType<QFormLayout>();
|
||||
layout.addTitle("Custom stream player");
|
||||
layout.addDescription(
|
||||
"You can open Twitch streams directly in any video player that has "
|
||||
"built-in Twitch support and has own URI Scheme.\nE.g.: IINA for "
|
||||
"macOS and Potplayer (with extension) for Windows.\n\nWith this "
|
||||
"value set, you will get the option to \"Open in custom player\" "
|
||||
"when right-clicking a channel header.");
|
||||
|
||||
auto *description = new QLabel(
|
||||
"You can open Twitch streams directly in any video player that "
|
||||
"has built-in Twitch support and has own URI Scheme.\nE.g.: "
|
||||
"IINA for macOS and Potplayer (with extension) for "
|
||||
"Windows.\n\nWith this value set, you will get the option to "
|
||||
"\"Open in custom player\" when "
|
||||
"right-clicking a channel header.");
|
||||
description->setWordWrap(true);
|
||||
description->setStyleSheet("color: #bbb");
|
||||
|
||||
groupLayout->setWidget(0, QFormLayout::SpanningRole, description);
|
||||
|
||||
auto *lineEdit = this->createLineEdit(getSettings()->customURIScheme);
|
||||
lineEdit->setPlaceholderText("custom-player-scheme://");
|
||||
groupLayout->addRow("Custom stream player URI Scheme:", lineEdit);
|
||||
SettingWidget::lineEdit("Custom stream player URI Scheme",
|
||||
s.customURIScheme, "custom-player-scheme://")
|
||||
->addTo(layout);
|
||||
}
|
||||
layout->addSpacing(16);
|
||||
|
||||
{
|
||||
auto group = layout.emplace<QGroupBox>("Image Uploader");
|
||||
auto groupLayout = group.setLayoutType<QFormLayout>();
|
||||
auto *form = new QFormLayout;
|
||||
layout.addTitle("Image Uploader");
|
||||
|
||||
auto *description = new QLabel(
|
||||
"You can set custom host for uploading images, like "
|
||||
"imgur.com or s-ul.eu.<br>Check " +
|
||||
layout.addDescription(
|
||||
"You can set custom host for uploading images, like imgur.com or "
|
||||
"s-ul.eu.<br>Check " +
|
||||
formatRichNamedLink("https://chatterino.com/help/image-uploader",
|
||||
"this guide") +
|
||||
" for help.");
|
||||
description->setWordWrap(true);
|
||||
description->setStyleSheet("color: #bbb");
|
||||
description->setTextFormat(Qt::RichText);
|
||||
description->setTextInteractionFlags(Qt::TextBrowserInteraction |
|
||||
Qt::LinksAccessibleByKeyboard |
|
||||
Qt::LinksAccessibleByMouse);
|
||||
description->setOpenExternalLinks(true);
|
||||
|
||||
groupLayout->setWidget(0, QFormLayout::SpanningRole, description);
|
||||
SettingWidget::checkbox("Enable image uploader", s.imageUploaderEnabled)
|
||||
->addTo(layout);
|
||||
|
||||
groupLayout->addRow(this->createCheckBox(
|
||||
"Enable image uploader", getSettings()->imageUploaderEnabled));
|
||||
groupLayout->addRow(
|
||||
this->createCheckBox("Ask for confirmation when uploading an image",
|
||||
getSettings()->askOnImageUpload));
|
||||
SettingWidget::checkbox("Ask for confirmation when uploading an image",
|
||||
s.askOnImageUpload)
|
||||
->addTo(layout);
|
||||
|
||||
groupLayout->addRow(
|
||||
"Request URL: ",
|
||||
this->createLineEdit(getSettings()->imageUploaderUrl));
|
||||
groupLayout->addRow(
|
||||
"Form field: ",
|
||||
this->createLineEdit(getSettings()->imageUploaderFormField));
|
||||
groupLayout->addRow(
|
||||
"Extra Headers: ",
|
||||
this->createLineEdit(getSettings()->imageUploaderHeaders));
|
||||
groupLayout->addRow(
|
||||
"Image link: ",
|
||||
this->createLineEdit(getSettings()->imageUploaderLink));
|
||||
groupLayout->addRow(
|
||||
"Deletion link: ",
|
||||
this->createLineEdit(getSettings()->imageUploaderDeletionLink));
|
||||
layout.addLayout(form);
|
||||
|
||||
SettingWidget::lineEdit("Request URL", s.imageUploaderUrl)
|
||||
->addTo(layout, form);
|
||||
|
||||
SettingWidget::lineEdit("Form field", s.imageUploaderFormField)
|
||||
->addTo(layout, form);
|
||||
|
||||
SettingWidget::lineEdit("Extra Headers", s.imageUploaderHeaders)
|
||||
->addTo(layout, form);
|
||||
|
||||
SettingWidget::lineEdit("Image link", s.imageUploaderLink)
|
||||
->addTo(layout, form);
|
||||
|
||||
SettingWidget::lineEdit("Deletion link", s.imageUploaderDeletionLink)
|
||||
->addTo(layout, form);
|
||||
}
|
||||
|
||||
layout->addStretch(1);
|
||||
layout.addStretch();
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/settingspages/GeneralPageView.hpp"
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
@@ -8,6 +9,13 @@ class ExternalToolsPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
ExternalToolsPage();
|
||||
|
||||
bool filterElements(const QString &query) override;
|
||||
|
||||
private:
|
||||
void initLayout(GeneralPageView &layout);
|
||||
|
||||
GeneralPageView *view;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -95,7 +95,7 @@ GeneralPage::GeneralPage()
|
||||
{
|
||||
auto *y = new QVBoxLayout;
|
||||
auto *x = new QHBoxLayout;
|
||||
auto *view = new GeneralPageView;
|
||||
auto *view = GeneralPageView::withNavigation(this);
|
||||
this->view_ = view;
|
||||
x->addWidget(view);
|
||||
auto *z = new QFrame;
|
||||
@@ -275,8 +275,9 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
||||
"reply to a message regardless of this setting.")
|
||||
->addTo(layout);
|
||||
|
||||
layout.addCheckbox("Show message reply button", s.showReplyButton, false,
|
||||
"Show a reply button next to every chat message");
|
||||
SettingWidget::checkbox("Show message reply button", s.showReplyButton)
|
||||
->setTooltip("Show a reply button next to every chat message")
|
||||
->addTo(layout);
|
||||
|
||||
auto removeTabSeq = getApp()->getHotkeys()->getDisplaySequence(
|
||||
HotkeyCategory::Window, "removeTab");
|
||||
@@ -309,9 +310,13 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
||||
.arg(settingsSeq.toString(
|
||||
QKeySequence::SequenceFormat::NativeText));
|
||||
}
|
||||
layout.addCheckbox("Show preferences button" + shortcut,
|
||||
s.hidePreferencesButton, true);
|
||||
layout.addCheckbox("Show user button", s.hideUserButton, true);
|
||||
|
||||
SettingWidget::inverseCheckbox("Show preferences button" + shortcut,
|
||||
s.hidePreferencesButton)
|
||||
->addTo(layout);
|
||||
|
||||
SettingWidget::inverseCheckbox("Show user button", s.hideUserButton)
|
||||
->addTo(layout);
|
||||
}
|
||||
layout.addCheckbox("Mark tabs with live channels", s.showTabLive, false,
|
||||
"Shows a red dot in the top right corner of a tab to "
|
||||
@@ -464,24 +469,34 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
||||
},
|
||||
false);
|
||||
|
||||
layout.addCheckbox(
|
||||
"Hide scrollbar thumb", s.hideScrollbarThumb, false,
|
||||
"Hiding the scrollbar thumb (the handle you can drag) will disable "
|
||||
"all mouse interaction in the scrollbar.");
|
||||
SettingWidget::checkbox("Hide scrollbar thumb", s.hideScrollbarThumb)
|
||||
->setTooltip("Hiding the scrollbar thumb (the handle you can drag) "
|
||||
"will disable all mouse interaction in the scrollbar.")
|
||||
->addKeywords({"scroll bar"})
|
||||
->addTo(layout);
|
||||
|
||||
layout.addCheckbox("Hide scrollbar highlights", s.hideScrollbarHighlights,
|
||||
false);
|
||||
SettingWidget::checkbox("Hide scrollbar highlights",
|
||||
s.hideScrollbarHighlights)
|
||||
->addKeywords({"scroll bar"})
|
||||
->addTo(layout);
|
||||
|
||||
layout.addTitle("Messages");
|
||||
layout.addCheckbox(
|
||||
"Separate with lines", s.separateMessages, false,
|
||||
"Adds a line between each message to help better tell them apart.");
|
||||
layout.addCheckbox("Alternate background color", s.alternateMessages, false,
|
||||
"Slightly change the background behind every other "
|
||||
"message to help better tell them apart.");
|
||||
layout.addCheckbox("Hide deleted messages", s.hideModerated, false,
|
||||
"When enabled, messages deleted by moderators will "
|
||||
"be hidden.");
|
||||
|
||||
SettingWidget::checkbox("Separate with lines", s.separateMessages)
|
||||
->setTooltip(
|
||||
"Adds a line between each message to help better tell them apart.")
|
||||
->addTo(layout);
|
||||
|
||||
SettingWidget::checkbox("Alternate background color", s.alternateMessages)
|
||||
->setTooltip("Slightly change the background behind every other "
|
||||
"message to help better tell them apart.")
|
||||
->addTo(layout);
|
||||
|
||||
SettingWidget::checkbox("Hide deleted messages", s.hideModerated)
|
||||
->setTooltip(
|
||||
"When enabled, messages deleted by moderators will be hidden.")
|
||||
->addTo(layout);
|
||||
|
||||
layout.addDropdown<QString>(
|
||||
"Timestamp format",
|
||||
{"Disable", "h:mm", "hh:mm", "h:mm a", "hh:mm a", "h:mm:ss", "hh:mm:ss",
|
||||
@@ -539,9 +554,8 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
||||
}
|
||||
},
|
||||
false);
|
||||
layout.addColorButton("Line color",
|
||||
QColor(getSettings()->lastMessageColor.getValue()),
|
||||
getSettings()->lastMessageColor);
|
||||
|
||||
SettingWidget::colorButton("Line color", s.lastMessageColor)->addTo(layout);
|
||||
|
||||
layout.addTitle("Emotes");
|
||||
layout.addCheckbox("Enable", s.enableEmoteImages);
|
||||
@@ -1047,11 +1061,20 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
||||
true,
|
||||
"The final scale of the messages in the overlay is computed by "
|
||||
"multiplying this zoom factor with the global zoom level.");
|
||||
layout.addIntInput(
|
||||
"Background opacity (0-255)", s.overlayBackgroundOpacity, 0, 255, 1,
|
||||
"Controls the opacity of the (possibly alternating) background behind "
|
||||
"messages. The color is set through the current theme. 255 corresponds "
|
||||
"to a fully opaque background.");
|
||||
|
||||
SettingWidget::intInput("Background opacity (0-255)",
|
||||
s.overlayBackgroundOpacity,
|
||||
{
|
||||
.min = 0,
|
||||
.max = 255,
|
||||
.singleStep = 1,
|
||||
})
|
||||
->setTooltip(
|
||||
"Controls the opacity of the (possibly alternating) background "
|
||||
"behind messages. The color is set through the current theme. 255 "
|
||||
"corresponds to a fully opaque background.")
|
||||
->addTo(layout);
|
||||
|
||||
layout.addCheckbox("Enable Shadow", s.enableOverlayShadow, false,
|
||||
"Enables a drop shadow on the overlay. This will use "
|
||||
"more processing power.");
|
||||
@@ -1059,9 +1082,10 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
||||
1,
|
||||
"Controls the opacity of the added drop shadow. 255 "
|
||||
"corresponds to a fully opaque shadow.");
|
||||
layout.addColorButton("Shadow color",
|
||||
QColor(getSettings()->overlayShadowColor.getValue()),
|
||||
getSettings()->overlayShadowColor);
|
||||
|
||||
SettingWidget::colorButton("Shadow color", s.overlayShadowColor)
|
||||
->addTo(layout);
|
||||
|
||||
layout
|
||||
.addIntInput("Shadow radius", s.overlayShadowRadius, 0, 40, 1,
|
||||
"Controls how far the shadow is spread (the blur "
|
||||
@@ -1088,15 +1112,14 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
||||
s.openLinksIncognito);
|
||||
}
|
||||
|
||||
layout.addCustomCheckbox(
|
||||
SettingWidget::customCheckbox(
|
||||
"Restart on crash (requires restart)",
|
||||
[] {
|
||||
return getApp()->getCrashHandler()->shouldRecover();
|
||||
},
|
||||
getApp()->getCrashHandler()->shouldRecover(),
|
||||
[](bool on) {
|
||||
return getApp()->getCrashHandler()->saveShouldRecover(on);
|
||||
},
|
||||
"When possible, restart Chatterino if the program crashes");
|
||||
getApp()->getCrashHandler()->saveShouldRecover(on);
|
||||
})
|
||||
->setTooltip("When possible, restart Chatterino if the program crashes")
|
||||
->addTo(layout);
|
||||
|
||||
#if defined(Q_OS_LINUX) && !defined(NO_QTKEYCHAIN)
|
||||
if (!getApp()->getPaths().isPortable())
|
||||
@@ -1107,13 +1130,18 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
||||
}
|
||||
#endif
|
||||
|
||||
layout.addCheckbox(
|
||||
"Show moderation messages", s.hideModerationActions, true,
|
||||
"Show messages for timeouts, bans, and other moderator actions.");
|
||||
layout.addCheckbox("Show deletions of single messages",
|
||||
s.hideDeletionActions, true,
|
||||
"Show when a single message is deleted.\ne.g. A message "
|
||||
"from TreuKS was deleted: abc");
|
||||
SettingWidget::inverseCheckbox("Show moderation messages",
|
||||
s.hideModerationActions)
|
||||
->setTooltip(
|
||||
"Show messages for timeouts, bans, and other moderator actions.")
|
||||
->addTo(layout);
|
||||
|
||||
SettingWidget::inverseCheckbox("Show deletions of single messages",
|
||||
s.hideDeletionActions)
|
||||
->setTooltip("Show when a single message is deleted.\ne.g. A message "
|
||||
"from TreuKS was deleted: abc")
|
||||
->addTo(layout);
|
||||
|
||||
layout.addCheckbox(
|
||||
"Colorize users without color set (gray names)", s.colorizeNicknames,
|
||||
false,
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#include "widgets/settingspages/GeneralPageView.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "common/QLogging.hpp"
|
||||
#include "util/LayoutHelper.hpp"
|
||||
#include "util/RapidJsonSerializeQString.hpp"
|
||||
#include "widgets/dialogs/ColorPickerDialog.hpp"
|
||||
#include "widgets/helper/color/ColorButton.hpp"
|
||||
#include "widgets/helper/Line.hpp"
|
||||
#include "widgets/settingspages/SettingWidget.hpp"
|
||||
|
||||
@@ -25,30 +24,55 @@ namespace chatterino {
|
||||
|
||||
GeneralPageView::GeneralPageView(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, contentScrollArea_(new QScrollArea)
|
||||
, contentLayout_(new QVBoxLayout)
|
||||
{
|
||||
auto *scrollArea = this->contentScrollArea_ =
|
||||
makeScrollArea(this->contentLayout_ = new QVBoxLayout);
|
||||
scrollArea->setObjectName("generalSettingsScrollContent");
|
||||
|
||||
auto *navigation =
|
||||
wrapLayout(this->navigationLayout_ = makeLayout<QVBoxLayout>({}));
|
||||
navigation->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum);
|
||||
this->navigationLayout_->setAlignment(Qt::AlignTop);
|
||||
this->navigationLayout_->addSpacing(6);
|
||||
|
||||
this->setLayout(makeLayout<QHBoxLayout>(
|
||||
{scrollArea, new QSpacerItem(16, 1), navigation}));
|
||||
|
||||
QObject::connect(scrollArea->verticalScrollBar(), &QScrollBar::valueChanged,
|
||||
this, [this] {
|
||||
this->updateNavigationHighlighting();
|
||||
});
|
||||
auto *contentWidget = new QWidget;
|
||||
contentWidget->setLayout(this->contentLayout_);
|
||||
this->contentScrollArea_->setWidget(contentWidget);
|
||||
this->contentScrollArea_->setObjectName("generalSettingsScrollContent");
|
||||
this->contentScrollArea_->setWidgetResizable(true);
|
||||
}
|
||||
|
||||
void GeneralPageView::addWidget(QWidget *widget, QStringList keywords)
|
||||
GeneralPageView *GeneralPageView::withoutNavigation(QWidget *parent)
|
||||
{
|
||||
auto *view = new GeneralPageView(parent);
|
||||
|
||||
view->setLayout(makeLayout<QHBoxLayout>({
|
||||
view->contentScrollArea_,
|
||||
}));
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
GeneralPageView *GeneralPageView::withNavigation(QWidget *parent)
|
||||
{
|
||||
auto *view = new GeneralPageView(parent);
|
||||
|
||||
auto *navigation =
|
||||
wrapLayout(view->navigationLayout_ = makeLayout<QVBoxLayout>({}));
|
||||
navigation->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum);
|
||||
view->navigationLayout_->setAlignment(Qt::AlignTop);
|
||||
view->navigationLayout_->addSpacing(6);
|
||||
|
||||
view->setLayout(makeLayout<QHBoxLayout>({
|
||||
view->contentScrollArea_,
|
||||
new QSpacerItem(16, 1),
|
||||
navigation,
|
||||
}));
|
||||
|
||||
QObject::connect(view->contentScrollArea_->verticalScrollBar(),
|
||||
&QScrollBar::valueChanged, view, [view] {
|
||||
view->updateNavigationHighlighting();
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
void GeneralPageView::addWidget(QWidget *widget, const QStringList &keywords)
|
||||
{
|
||||
this->contentLayout_->addWidget(widget);
|
||||
if (!keywords.isEmpty())
|
||||
if (!this->groups_.empty())
|
||||
{
|
||||
this->groups_.back().widgets.push_back({
|
||||
.element = widget,
|
||||
@@ -57,6 +81,25 @@ void GeneralPageView::addWidget(QWidget *widget, QStringList keywords)
|
||||
}
|
||||
}
|
||||
|
||||
void GeneralPageView::registerWidget(QWidget *widget,
|
||||
const QStringList &keywords,
|
||||
QWidget *parentElement)
|
||||
{
|
||||
if (!this->groups_.empty())
|
||||
{
|
||||
this->groups_.back().widgets.push_back({
|
||||
.element = widget,
|
||||
.keywords = keywords,
|
||||
.parentElement = parentElement,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void GeneralPageView::pushWidget(QWidget *widget)
|
||||
{
|
||||
this->contentLayout_->addWidget(widget);
|
||||
}
|
||||
|
||||
void GeneralPageView::addLayout(QLayout *layout)
|
||||
{
|
||||
this->contentLayout_->addLayout(layout);
|
||||
@@ -79,14 +122,21 @@ TitleLabel *GeneralPageView::addTitle(const QString &title)
|
||||
auto *label = new TitleLabel(title + ":");
|
||||
this->addWidget(label);
|
||||
|
||||
// navigation item
|
||||
auto *navLabel = new NavigationLabel(title);
|
||||
navLabel->setCursor(Qt::PointingHandCursor);
|
||||
this->navigationLayout_->addWidget(navLabel);
|
||||
NavigationLabel *navLabel = nullptr;
|
||||
|
||||
QObject::connect(navLabel, &NavigationLabel::leftMouseUp, label, [=, this] {
|
||||
this->contentScrollArea_->verticalScrollBar()->setValue(label->y());
|
||||
});
|
||||
// navigation item
|
||||
if (this->navigationLayout_ != nullptr)
|
||||
{
|
||||
navLabel = new NavigationLabel(title);
|
||||
navLabel->setCursor(Qt::PointingHandCursor);
|
||||
this->navigationLayout_->addWidget(navLabel);
|
||||
|
||||
QObject::connect(
|
||||
navLabel, &NavigationLabel::leftMouseUp, label, [this, label] {
|
||||
this->contentScrollArea_->verticalScrollBar()->setValue(
|
||||
label->y());
|
||||
});
|
||||
}
|
||||
|
||||
// groups
|
||||
this->groups_.push_back(Group{title, label, navLabel, nullptr, {}});
|
||||
@@ -113,6 +163,12 @@ QCheckBox *GeneralPageView::addCheckbox(const QString &text,
|
||||
BoolSetting &setting, bool inverse,
|
||||
QString toolTipText)
|
||||
{
|
||||
if (inverse)
|
||||
{
|
||||
qCWarning(chatterinoWidget)
|
||||
<< "use SettingWidget::inverseCheckbox instead";
|
||||
}
|
||||
|
||||
auto *check = new QCheckBox(text);
|
||||
this->addToolTip(*check, toolTipText);
|
||||
|
||||
@@ -137,28 +193,6 @@ QCheckBox *GeneralPageView::addCheckbox(const QString &text,
|
||||
return check;
|
||||
}
|
||||
|
||||
QCheckBox *GeneralPageView::addCustomCheckbox(const QString &text,
|
||||
const std::function<bool()> &load,
|
||||
std::function<void(bool)> save,
|
||||
const QString &toolTipText)
|
||||
{
|
||||
auto *check = new QCheckBox(text);
|
||||
this->addToolTip(*check, toolTipText);
|
||||
|
||||
check->setChecked(load());
|
||||
|
||||
QObject::connect(check, &QCheckBox::toggled, this,
|
||||
[save = std::move(save)](bool state) {
|
||||
save(state);
|
||||
});
|
||||
|
||||
this->addWidget(check);
|
||||
|
||||
this->groups_.back().widgets.push_back({check, {text}});
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
ComboBox *GeneralPageView::addDropdown(const QString &text,
|
||||
const QStringList &list,
|
||||
QString toolTipText)
|
||||
@@ -211,43 +245,6 @@ ComboBox *GeneralPageView::addDropdown(
|
||||
return combo;
|
||||
}
|
||||
|
||||
ColorButton *GeneralPageView::addColorButton(
|
||||
const QString &text, const QColor &color,
|
||||
pajlada::Settings::Setting<QString> &setting, QString toolTipText)
|
||||
{
|
||||
auto *colorButton = new ColorButton(color);
|
||||
auto *layout = new QHBoxLayout();
|
||||
auto *label = new QLabel(text + ":");
|
||||
|
||||
layout->addWidget(label);
|
||||
layout->addStretch(1);
|
||||
layout->addWidget(colorButton);
|
||||
|
||||
this->addToolTip(*label, toolTipText);
|
||||
this->addLayout(layout);
|
||||
|
||||
QObject::connect(
|
||||
colorButton, &ColorButton::clicked, [this, &setting, colorButton]() {
|
||||
auto *dialog = new ColorPickerDialog(QColor(setting), this);
|
||||
// colorButton & setting are never deleted and the signal is deleted
|
||||
// once the dialog is closed
|
||||
QObject::connect(dialog, &ColorPickerDialog::colorConfirmed, this,
|
||||
[&setting, colorButton](auto selected) {
|
||||
if (selected.isValid())
|
||||
{
|
||||
setting = selected.name(QColor::HexArgb);
|
||||
colorButton->setColor(selected);
|
||||
}
|
||||
});
|
||||
dialog->show();
|
||||
});
|
||||
|
||||
this->groups_.back().widgets.push_back({label, {text}});
|
||||
this->groups_.back().widgets.push_back({colorButton, {text}});
|
||||
|
||||
return colorButton;
|
||||
}
|
||||
|
||||
QSpinBox *GeneralPageView::addIntInput(const QString &text, IntSetting &setting,
|
||||
int min, int max, int step,
|
||||
QString toolTipText)
|
||||
@@ -289,6 +286,9 @@ QSpinBox *GeneralPageView::addIntInput(const QString &text, IntSetting &setting,
|
||||
|
||||
void GeneralPageView::addNavigationSpacing()
|
||||
{
|
||||
assert(this->navigationLayout_ != nullptr &&
|
||||
"addNavigationSpacing used without navigation");
|
||||
|
||||
this->navigationLayout_->addSpacing(24);
|
||||
}
|
||||
|
||||
@@ -341,10 +341,17 @@ bool GeneralPageView::filterElements(const QString &query)
|
||||
for (auto &&widget : group.widgets)
|
||||
{
|
||||
widget.element->show();
|
||||
if (widget.parentElement != nullptr)
|
||||
{
|
||||
widget.parentElement->show();
|
||||
}
|
||||
}
|
||||
|
||||
group.title->show();
|
||||
group.navigationLink->show();
|
||||
if (group.navigationLink != nullptr)
|
||||
{
|
||||
group.navigationLink->show();
|
||||
}
|
||||
any = true;
|
||||
}
|
||||
// check if any match
|
||||
@@ -383,11 +390,19 @@ bool GeneralPageView::filterElements(const QString &query)
|
||||
{
|
||||
currentSubtitleVisible = true;
|
||||
widget.element->show();
|
||||
if (widget.parentElement != nullptr)
|
||||
{
|
||||
widget.parentElement->show();
|
||||
}
|
||||
groupAny = true;
|
||||
break;
|
||||
}
|
||||
|
||||
widget.element->hide();
|
||||
if (widget.parentElement != nullptr)
|
||||
{
|
||||
widget.parentElement->hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,7 +417,10 @@ bool GeneralPageView::filterElements(const QString &query)
|
||||
}
|
||||
|
||||
group.title->setVisible(groupAny);
|
||||
group.navigationLink->setVisible(groupAny);
|
||||
if (group.navigationLink != nullptr)
|
||||
{
|
||||
group.navigationLink->setVisible(groupAny);
|
||||
}
|
||||
any |= groupAny;
|
||||
}
|
||||
}
|
||||
@@ -412,6 +430,11 @@ bool GeneralPageView::filterElements(const QString &query)
|
||||
|
||||
void GeneralPageView::updateNavigationHighlighting()
|
||||
{
|
||||
if (this->navigationLayout_ == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto scrollY = this->contentScrollArea_->verticalScrollBar()->value();
|
||||
auto first = true;
|
||||
|
||||
|
||||
@@ -91,11 +91,22 @@ struct DropdownArgs {
|
||||
class GeneralPageView : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GeneralPageView(QWidget *parent = nullptr);
|
||||
|
||||
void addWidget(QWidget *widget, QStringList keywords = {});
|
||||
public:
|
||||
static GeneralPageView *withNavigation(QWidget *parent);
|
||||
static GeneralPageView *withoutNavigation(QWidget *parent);
|
||||
|
||||
void addWidget(QWidget *widget, const QStringList &keywords = {});
|
||||
|
||||
/// Register the widget with the given keywords.
|
||||
/// This assumes that the widget is being held by a layout that has been added previously
|
||||
void registerWidget(QWidget *widget, const QStringList &keywords,
|
||||
QWidget *parentElement);
|
||||
|
||||
/// Pushes the widget into the current layout
|
||||
void pushWidget(QWidget *widget);
|
||||
|
||||
void addLayout(QLayout *layout);
|
||||
void addStretch();
|
||||
|
||||
@@ -104,19 +115,12 @@ public:
|
||||
/// @param inverse Inverses true to false and vice versa
|
||||
QCheckBox *addCheckbox(const QString &text, BoolSetting &setting,
|
||||
bool inverse = false, QString toolTipText = {});
|
||||
QCheckBox *addCustomCheckbox(const QString &text,
|
||||
const std::function<bool()> &load,
|
||||
std::function<void(bool)> save,
|
||||
const QString &toolTipText = {});
|
||||
|
||||
ComboBox *addDropdown(const QString &text, const QStringList &items,
|
||||
QString toolTipText = {});
|
||||
ComboBox *addDropdown(const QString &text, const QStringList &items,
|
||||
pajlada::Settings::Setting<QString> &setting,
|
||||
bool editable = false, QString toolTipText = {});
|
||||
ColorButton *addColorButton(const QString &text, const QColor &color,
|
||||
pajlada::Settings::Setting<QString> &setting,
|
||||
QString toolTipText = {});
|
||||
QSpinBox *addIntInput(const QString &text, IntSetting &setting, int min,
|
||||
int max, int step, QString toolTipText = {});
|
||||
void addNavigationSpacing();
|
||||
@@ -299,8 +303,13 @@ private:
|
||||
void addToolTip(QWidget &widget, QString text) const;
|
||||
|
||||
struct Widget {
|
||||
QWidget *element;
|
||||
/// The element of the register widget
|
||||
/// This can point to the label of the widget, or the action widget (e.g. the spinbox)
|
||||
QWidget *element{};
|
||||
QStringList keywords;
|
||||
|
||||
/// The optional parent element of the widget (usually pointing at a SettingWidget)
|
||||
QWidget *parentElement{};
|
||||
};
|
||||
|
||||
struct Group {
|
||||
@@ -311,9 +320,9 @@ private:
|
||||
std::vector<Widget> widgets;
|
||||
};
|
||||
|
||||
QScrollArea *contentScrollArea_;
|
||||
QVBoxLayout *contentLayout_;
|
||||
QVBoxLayout *navigationLayout_;
|
||||
QScrollArea *contentScrollArea_ = nullptr;
|
||||
QVBoxLayout *contentLayout_ = nullptr;
|
||||
QVBoxLayout *navigationLayout_ = nullptr;
|
||||
|
||||
std::vector<Group> groups_;
|
||||
pajlada::Signals::SignalHolder managedConnections_;
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
#include "widgets/settingspages/SettingWidget.hpp"
|
||||
|
||||
#include "util/RapidJsonSerializeQString.hpp" // IWYU pragma: keep
|
||||
#include "widgets/dialogs/ColorPickerDialog.hpp"
|
||||
#include "widgets/helper/color/ColorButton.hpp"
|
||||
#include "widgets/settingspages/GeneralPageView.hpp"
|
||||
|
||||
#include <QBoxLayout>
|
||||
#include <QCheckBox>
|
||||
#include <QFormLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -86,6 +91,145 @@ SettingWidget *SettingWidget::inverseCheckbox(const QString &label,
|
||||
return widget;
|
||||
}
|
||||
|
||||
SettingWidget *SettingWidget::customCheckbox(
|
||||
const QString &label, bool initialValue,
|
||||
const std::function<void(bool)> &save)
|
||||
{
|
||||
auto *widget = new SettingWidget(label);
|
||||
|
||||
auto *check = new QCheckBox(label);
|
||||
|
||||
widget->hLayout->addWidget(check);
|
||||
|
||||
check->setChecked(initialValue);
|
||||
|
||||
QObject::connect(check, &QCheckBox::toggled, widget, save);
|
||||
|
||||
widget->actionWidget = check;
|
||||
widget->label = check;
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
SettingWidget *SettingWidget::intInput(const QString &label,
|
||||
IntSetting &setting,
|
||||
IntInputParams params)
|
||||
{
|
||||
auto *widget = new SettingWidget(label);
|
||||
|
||||
auto *lbl = new QLabel(label + ":");
|
||||
|
||||
auto *input = new QSpinBox;
|
||||
if (params.min.has_value())
|
||||
{
|
||||
input->setMinimum(params.min.value());
|
||||
}
|
||||
if (params.max.has_value())
|
||||
{
|
||||
input->setMaximum(params.max.value());
|
||||
}
|
||||
if (params.singleStep.has_value())
|
||||
{
|
||||
input->setSingleStep(params.singleStep.value());
|
||||
}
|
||||
|
||||
widget->hLayout->addWidget(lbl);
|
||||
widget->hLayout->addStretch(1);
|
||||
widget->hLayout->addWidget(input);
|
||||
|
||||
// update when setting changes
|
||||
setting.connect(
|
||||
[input](const int &value, const auto &) {
|
||||
input->setValue(value);
|
||||
},
|
||||
widget->managedConnections);
|
||||
|
||||
// update setting on value changed
|
||||
QObject::connect(input, QOverload<int>::of(&QSpinBox::valueChanged), widget,
|
||||
[&setting](int newValue) {
|
||||
setting = newValue;
|
||||
});
|
||||
|
||||
widget->actionWidget = input;
|
||||
widget->label = lbl;
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
SettingWidget *SettingWidget::colorButton(const QString &label,
|
||||
QStringSetting &setting)
|
||||
{
|
||||
QColor color(setting.getValue());
|
||||
auto *widget = new SettingWidget(label);
|
||||
|
||||
auto *lbl = new QLabel(label + ":");
|
||||
|
||||
auto *colorButton = new ColorButton(color);
|
||||
|
||||
widget->hLayout->addWidget(lbl);
|
||||
widget->hLayout->addStretch(1);
|
||||
widget->hLayout->addWidget(colorButton);
|
||||
|
||||
// update when setting changes
|
||||
setting.connect(
|
||||
[colorButton](const QString &value, const auto &) {
|
||||
colorButton->setColor(QColor(value));
|
||||
},
|
||||
widget->managedConnections);
|
||||
|
||||
QObject::connect(colorButton, &ColorButton::clicked, [widget, &setting]() {
|
||||
auto *dialog = new ColorPickerDialog(QColor(setting), widget);
|
||||
// colorButton & setting are never deleted and the signal is deleted
|
||||
// once the dialog is closed
|
||||
QObject::connect(
|
||||
dialog, &ColorPickerDialog::colorConfirmed, widget,
|
||||
[&setting](auto selected) {
|
||||
if (selected.isValid())
|
||||
{
|
||||
setting.setValue(selected.name(QColor::HexArgb));
|
||||
}
|
||||
});
|
||||
dialog->show();
|
||||
});
|
||||
|
||||
widget->actionWidget = colorButton;
|
||||
widget->label = lbl;
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
SettingWidget *SettingWidget::lineEdit(const QString &label,
|
||||
QStringSetting &setting,
|
||||
const QString &placeholderText)
|
||||
{
|
||||
QColor color(setting.getValue());
|
||||
auto *widget = new SettingWidget(label);
|
||||
|
||||
auto *lbl = new QLabel(label + ":");
|
||||
|
||||
auto *edit = new QLineEdit;
|
||||
edit->setText(setting);
|
||||
if (!placeholderText.isEmpty())
|
||||
{
|
||||
edit->setPlaceholderText(placeholderText);
|
||||
}
|
||||
|
||||
widget->hLayout->addWidget(lbl);
|
||||
// widget->hLayout->addStretch(1);
|
||||
widget->hLayout->addWidget(edit);
|
||||
|
||||
// update when setting changes
|
||||
QObject::connect(edit, &QLineEdit::textChanged,
|
||||
[&setting](const QString &newValue) {
|
||||
setting = newValue;
|
||||
});
|
||||
|
||||
widget->actionWidget = edit;
|
||||
widget->label = lbl;
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
SettingWidget *SettingWidget::setTooltip(QString tooltip)
|
||||
{
|
||||
assert(!tooltip.isEmpty());
|
||||
@@ -136,9 +280,37 @@ SettingWidget *SettingWidget::addKeywords(const QStringList &newKeywords)
|
||||
return this;
|
||||
}
|
||||
|
||||
SettingWidget *SettingWidget::conditionallyEnabledBy(BoolSetting &setting)
|
||||
{
|
||||
setting.connect(
|
||||
[this](const auto &value, const auto &) {
|
||||
this->actionWidget->setEnabled(value);
|
||||
},
|
||||
this->managedConnections);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void SettingWidget::addTo(GeneralPageView &view)
|
||||
{
|
||||
view.addWidget(this, this->keywords);
|
||||
view.pushWidget(this);
|
||||
|
||||
if (this->label != nullptr)
|
||||
{
|
||||
view.registerWidget(this->label, this->keywords, this);
|
||||
}
|
||||
view.registerWidget(this->actionWidget, this->keywords, this);
|
||||
}
|
||||
|
||||
void SettingWidget::addTo(GeneralPageView &view, QFormLayout *formLayout)
|
||||
{
|
||||
if (this->label != nullptr)
|
||||
{
|
||||
view.registerWidget(this->label, this->keywords, this);
|
||||
}
|
||||
view.registerWidget(this->actionWidget, this->keywords, this);
|
||||
|
||||
formLayout->addRow(this->label, this->actionWidget);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <QtContainerFwd>
|
||||
#include <QWidget>
|
||||
|
||||
class QFormLayout;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class GeneralPageView;
|
||||
@@ -26,6 +28,12 @@ class SettingWidget : QWidget
|
||||
explicit SettingWidget(const QString &mainKeyword);
|
||||
|
||||
public:
|
||||
struct IntInputParams {
|
||||
std::optional<int> min;
|
||||
std::optional<int> max;
|
||||
std::optional<int> singleStep;
|
||||
};
|
||||
|
||||
~SettingWidget() override = default;
|
||||
SettingWidget &operator=(const SettingWidget &) = delete;
|
||||
SettingWidget &operator=(SettingWidget &&) = delete;
|
||||
@@ -35,6 +43,13 @@ public:
|
||||
static SettingWidget *checkbox(const QString &label, BoolSetting &setting);
|
||||
static SettingWidget *inverseCheckbox(const QString &label,
|
||||
BoolSetting &setting);
|
||||
static SettingWidget *customCheckbox(const QString &label,
|
||||
bool initialValue,
|
||||
const std::function<void(bool)> &save);
|
||||
|
||||
static SettingWidget *intInput(const QString &label, IntSetting &setting,
|
||||
IntInputParams params);
|
||||
|
||||
template <typename T>
|
||||
static SettingWidget *dropdown(const QString &label,
|
||||
EnumStringSetting<T> &setting)
|
||||
@@ -81,6 +96,11 @@ public:
|
||||
|
||||
return widget;
|
||||
}
|
||||
static SettingWidget *colorButton(const QString &label,
|
||||
QStringSetting &setting);
|
||||
static SettingWidget *lineEdit(const QString &label,
|
||||
QStringSetting &setting,
|
||||
const QString &placeholderText = {});
|
||||
|
||||
SettingWidget *setTooltip(QString tooltip);
|
||||
SettingWidget *setDescription(const QString &text);
|
||||
@@ -90,7 +110,10 @@ public:
|
||||
/// All text from the tooltip, description, and label are already keywords
|
||||
SettingWidget *addKeywords(const QStringList &newKeywords);
|
||||
|
||||
SettingWidget *conditionallyEnabledBy(BoolSetting &setting);
|
||||
|
||||
void addTo(GeneralPageView &view);
|
||||
void addTo(GeneralPageView &view, QFormLayout *formLayout);
|
||||
|
||||
private:
|
||||
QWidget *label = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user