Refactor StreamerMode/Theme setting widgets (#6317)

This commit is contained in:
pajlada
2025-07-12 14:05:49 +02:00
committed by GitHub
parent 49aa83244c
commit 627b6d806e
8 changed files with 164 additions and 152 deletions
+1
View File
@@ -70,6 +70,7 @@
- Dev: Merged top/bottom and left/right notebook layouts. (#6215)
- Dev: Refactored `Button` and friends. (#6102, #6255, #6266, #6302, #6268)
- Dev: Made Settings & Account button on Linux/macOS SVGs. (#6267)
- Dev: Some more setting widget refactors. (#6317)
- Dev: Emoji style / set is now stored lowercase (and matched case-insensitively). Changing emoji style from this point on and then running an old version might mean you will use the Twitter emoji style by default. (#6300)
- Dev: Refactored `OnceFlag`. (#6237, #6316)
- Dev: Bumped clang-format requirement to 19. (#6236)
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#include <cstdint>
#include <optional>
#include <string_view>
namespace chatterino {
enum StreamerModeSetting : std::uint8_t {
Disabled,
Enabled,
DetectStreamingSoftware,
};
constexpr std::optional<std::string_view> qmagicenumDisplayName(
StreamerModeSetting value) noexcept
{
switch (value)
{
case Disabled:
return "Disabled";
case Enabled:
return "Enabled";
case DetectStreamingSoftware:
return "Automatic (Detect streaming software)";
}
}
} // namespace chatterino
+4 -7
View File
@@ -5,6 +5,7 @@
#include "common/LastMessageLineStyle.hpp"
#include "common/Modes.hpp"
#include "common/SignalVector.hpp"
#include "common/StreamerModeSetting.hpp"
#include "common/ThumbnailPreviewMode.hpp"
#include "common/TimeoutStackStyle.hpp"
#include "controllers/filters/FilterRecord.hpp"
@@ -84,12 +85,6 @@ enum class StreamLinkPreferredQuality : std::uint8_t {
AudioOnly,
};
enum StreamerModeSetting {
Disabled = 0,
Enabled = 1,
DetectStreamingSoftware = 2,
};
enum class TabStyle : std::uint8_t {
Normal,
Compact,
@@ -402,7 +397,9 @@ public:
// - "Always hide"
// - "Don't hide"
EnumSetting<StreamerModeSetting> enableStreamerMode = {
"/streamerMode/enabled", StreamerModeSetting::DetectStreamingSoftware};
"/streamerMode/enabled",
StreamerModeSetting::DetectStreamingSoftware,
};
BoolSetting streamerModeHideUsercardAvatars = {
"/streamerMode/hideUsercardAvatars", true};
BoolSetting streamerModeHideLinkThumbnails = {
+18 -44
View File
@@ -131,40 +131,25 @@ void GeneralPage::initLayout(GeneralPageView &layout)
available.emplace_back("System", "System");
#endif
auto addThemeDropdown = [&](auto name, auto &setting,
const auto &options,
const QString &tooltip = {}) {
return layout.addDropdown<QString>(
name, options, setting,
[](const auto *combo, const auto &themeKey) {
return combo->findData(themeKey, Qt::UserRole);
},
[](const auto &args) {
return args.combobox->itemData(args.index, Qt::UserRole)
.toString();
},
tooltip, Theme::fallbackTheme.name);
};
addThemeDropdown("Theme", themes->themeName, available);
SettingWidget::dropdown("Theme", themes->themeName, available)
->addTo(layout);
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
auto *darkDropdown = addThemeDropdown(
"Dark system theme", themes->darkSystemThemeName,
themes->availableThemes(),
"This theme is selected if your system is in a dark theme and you "
"enabled the adaptive 'System' theme.");
auto *lightDropdown = addThemeDropdown(
"Light system theme", themes->lightSystemThemeName,
themes->availableThemes(),
"This theme is selected if your system is in a light theme and you "
"enabled the adaptive 'System' theme.");
SettingWidget::dropdown("Dark system theme",
themes->darkSystemThemeName,
themes->availableThemes())
->setTooltip("This theme is selected if your system is in a dark "
"theme and you enabled the adaptive 'System' theme.")
->conditionallyEnabledBy(themes->themeName, "System")
->addTo(layout);
auto isSystem = [](const auto &s) {
return s == "System";
};
layout.enableIf(darkDropdown, themes->themeName, isSystem);
layout.enableIf(lightDropdown, themes->themeName, isSystem);
SettingWidget::dropdown("Light system theme",
themes->lightSystemThemeName,
themes->availableThemes())
->setTooltip("This theme is selected if your system is in a light "
"theme and you enabled the adaptive 'System' theme.")
->conditionallyEnabledBy(themes->themeName, "System")
->addTo(layout);
#endif
}
@@ -705,19 +690,8 @@ void GeneralPage::initLayout(GeneralPageView &layout)
"streaming software is running.\nSelect which things you want to "
"change while streaming");
ComboBox *dankDropdown =
layout.addDropdown<std::underlying_type_t<StreamerModeSetting>>(
"Enable Streamer Mode",
{"Disabled", "Enabled", "Automatic (Detect streaming software)"},
s.enableStreamerMode,
[](int value) {
return value;
},
[](DropdownArgs args) {
return static_cast<StreamerModeSetting>(args.index);
},
false);
dankDropdown->setMinimumWidth(dankDropdown->minimumSizeHint().width() + 30);
SettingWidget::dropdown("Enable Streamer Mode", s.enableStreamerMode)
->addTo(layout);
SettingWidget::checkbox("Hide usercard avatars",
s.streamerModeHideUsercardAvatars)
@@ -183,34 +183,6 @@ ComboBox *GeneralPageView::addDropdown(const QString &text,
return combo;
}
ComboBox *GeneralPageView::addDropdown(
const QString &text, const QStringList &items,
pajlada::Settings::Setting<QString> &setting, bool editable,
QString toolTipText)
{
auto *combo = this->addDropdown(text, items, toolTipText);
if (editable)
{
combo->setEditable(true);
}
// 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()->getWindows()->forceLayoutChannelViews();
});
return combo;
}
void GeneralPageView::addNavigationSpacing()
{
assert(this->navigationLayout_ != nullptr &&
@@ -134,9 +134,6 @@ public:
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 = {});
void addNavigationSpacing();
template <typename OnClick>
@@ -240,67 +237,6 @@ public:
return combo;
}
template <typename T>
ComboBox *addDropdown(
const QString &text,
const std::vector<std::pair<QString, QVariant>> &items,
pajlada::Settings::Setting<T> &setting,
std::function<boost::variant<int, QString>(ComboBox *, T)> getValue,
std::function<T(DropdownArgs)> setValue, QString toolTipText = {},
const QString &defaultValueText = {})
{
auto *combo = this->addDropdown(text, {}, std::move(toolTipText));
for (const auto &[itemText, userData] : items)
{
combo->addItem(itemText, userData);
}
if (!defaultValueText.isEmpty())
{
combo->setCurrentText(defaultValueText);
}
setting.connect(
[getValue = std::move(getValue), combo](const T &value, auto) {
auto var = getValue(combo, value);
if (var.which() == 0)
{
const auto index = boost::get<int>(var);
if (index >= 0)
{
combo->setCurrentIndex(index);
}
}
else
{
combo->setCurrentText(boost::get<QString>(var));
combo->setEditText(boost::get<QString>(var));
}
},
this->managedConnections_);
QObject::connect(
combo, QOverload<const int>::of(&QComboBox::currentIndexChanged),
[combo, &setting,
setValue = std::move(setValue)](const int newIndex) {
setting = setValue(DropdownArgs{combo->itemText(newIndex),
combo->currentIndex(), combo});
getApp()->getWindows()->forceLayoutChannelViews();
});
return combo;
}
void enableIf(QComboBox *widget, auto &setting, auto cb)
{
auto updateVisibility = [cb = std::move(cb), &setting, widget]() {
auto enabled = cb(setting.getValue());
widget->setEnabled(enabled);
};
setting.connect(updateVisibility, this->managedConnections_);
}
DescriptionLabel *addDescription(const QString &text);
void addSeparator();
+88 -9
View File
@@ -181,7 +181,7 @@ SettingWidget *SettingWidget::dropdown(const QString &label,
}
// TODO: this can probably use some other size hint/size strategy
combo->setMinimumWidth(combo->minimumSizeHint().width());
combo->setMinimumWidth(combo->minimumSizeHint().width() + 30);
widget->actionWidget = combo;
widget->label = lbl;
@@ -254,7 +254,7 @@ SettingWidget *SettingWidget::dropdown(const QString &label,
}
// TODO: this can probably use some other size hint/size strategy
combo->setMinimumWidth(combo->minimumSizeHint().width());
combo->setMinimumWidth(combo->minimumSizeHint().width() + 30);
widget->actionWidget = combo;
widget->label = lbl;
@@ -313,6 +313,72 @@ template SettingWidget *SettingWidget::dropdown<LastMessageLineStyle>(
const QString &label, EnumSetting<LastMessageLineStyle> &setting);
template SettingWidget *SettingWidget::dropdown<ThumbnailPreviewMode>(
const QString &label, EnumSetting<ThumbnailPreviewMode> &setting);
template SettingWidget *SettingWidget::dropdown<StreamerModeSetting>(
const QString &label, EnumSetting<StreamerModeSetting> &setting);
SettingWidget *SettingWidget::dropdown(
const QString &label, QStringSetting &setting,
const std::vector<std::pair<QString, QVariant>> &items)
{
auto *widget = new SettingWidget(label);
auto *lbl = new QLabel(label % ":");
auto *combo = new ComboBox;
combo->setFocusPolicy(Qt::StrongFocus);
for (const auto &[itemText, itemData] : items)
{
combo->addItem(itemText, itemData);
}
// TODO: this can probably use some other size hint/size strategy
combo->setMinimumWidth(combo->minimumSizeHint().width() + 30);
widget->actionWidget = combo;
widget->label = lbl;
widget->hLayout->addWidget(lbl);
widget->hLayout->addStretch(1);
widget->hLayout->addWidget(combo);
setting.connect(
[combo, label](const auto &value) {
std::optional<int> foundRow;
for (auto row = 0; row < combo->model()->rowCount(); ++row)
{
auto index = combo->model()->index(row, 0);
auto rowEnumValue = index.data(Qt::UserRole);
if (rowEnumValue == value)
{
foundRow = row;
break;
}
}
if (foundRow)
{
combo->setCurrentIndex(*foundRow);
}
else
{
qCWarning(chatterinoWidget)
<< "Did not find a correct combo box row for" << label
<< " with value" << value;
}
},
widget->managedConnections);
QObject::connect(combo, &QComboBox::currentTextChanged,
[label, combo, &setting](const auto &newText) {
bool ok = true;
auto stringValue = combo->currentData().toString();
setting.setValue(stringValue);
});
return widget;
}
SettingWidget *SettingWidget::colorButton(const QString &label,
QStringSetting &setting)
@@ -498,26 +564,39 @@ SettingWidget *SettingWidget::conditionallyEnabledBy(BoolSetting &setting)
return this;
}
SettingWidget *SettingWidget::conditionallyEnabledBy(
QStringSetting &setting, const QString &expectedValue)
{
setting.connect(
[this, expectedValue](const auto &value, const auto &) {
this->actionWidget->setEnabled(value == expectedValue);
},
this->managedConnections);
return this;
}
void SettingWidget::addTo(GeneralPageView &view)
{
view.pushWidget(this);
if (this->label != nullptr)
{
view.registerWidget(this->label, this->keywords, this);
}
view.registerWidget(this->actionWidget, this->keywords, this);
this->registerWidget(view);
}
void SettingWidget::addTo(GeneralPageView &view, QFormLayout *formLayout)
{
this->registerWidget(view);
formLayout->addRow(this->label, this->actionWidget);
}
void SettingWidget::registerWidget(GeneralPageView &view)
{
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
@@ -16,6 +16,8 @@
#include <functional>
#include <optional>
#include <utility>
#include <vector>
class QFormLayout;
@@ -66,14 +68,25 @@ public:
intInput(const QString &label, IntSetting &setting,
IntInputParams params);
/// Create a dropdown backed by an enum
///
/// The setting itself expects the enum name (i.e. "Foo")
template <typename T>
[[nodiscard("Must use created setting widget")]] static SettingWidget *
dropdown(const QString &label, EnumStringSetting<T> &setting);
/// Create a dropdown backed by an enum
///
/// The setting itself expects the enum value (i.e. 3)
template <typename T>
[[nodiscard("Must use created setting widget")]] static SettingWidget *
dropdown(const QString &label, EnumSetting<T> &setting);
/// Create a dropdown for a String setting that is not backed by an enum
[[nodiscard("Must use created setting widget")]] static SettingWidget *
dropdown(const QString &label, QStringSetting &setting,
const std::vector<std::pair<QString, QVariant>> &items);
[[nodiscard("Must use created setting widget")]] static SettingWidget *
colorButton(const QString &label, QStringSetting &setting);
[[nodiscard("Must use created setting widget")]] static SettingWidget *
@@ -96,13 +109,22 @@ public:
[[nodiscard("Must use created setting widget")]] SettingWidget *addKeywords(
const QStringList &newKeywords);
/// Conditionally enable the widget if the given bool setting is true
[[nodiscard("Must use created setting widget")]] SettingWidget *
conditionallyEnabledBy(BoolSetting &setting);
/// Conditionally enable the widget if the given string setting is equal to expectedValue
[[nodiscard("Must use created setting widget")]] SettingWidget *
conditionallyEnabledBy(QStringSetting &setting,
const QString &expectedValue);
void addTo(GeneralPageView &view);
void addTo(GeneralPageView &view, QFormLayout *formLayout);
private:
/// Registers this widget & its optional label to the given page view
void registerWidget(GeneralPageView &view);
QWidget *label = nullptr;
QWidget *actionWidget = nullptr;