idian: Remove Utils inheritance

Updates the idian widgets to no longer inherit from the Utils class.

The multi-inheritance approach was from an earlier iteration of the
utils prior to the static methods and served as a convenience factor.
With the addition of the static methods, many of them no longer need
an actual instance of the class.
This commit is contained in:
Warchamp7
2026-09-18 15:24:10 -04:00
committed by Ryan Foster
parent d129eeb303
commit ab197847da
16 changed files with 130 additions and 129 deletions
+16 -18
View File
@@ -51,8 +51,6 @@ VolumeControl::VolumeControl(obs_source_t *source, QWidget *parent, bool vertica
contextMenu(nullptr),
QFrame(parent)
{
utils = std::make_unique<idian::Utils>(this);
uuid = obs_source_get_uuid(source);
mainLayout = new QBoxLayout(QBoxLayout::LeftToRight, this);
@@ -62,21 +60,21 @@ VolumeControl::VolumeControl(obs_source_t *source, QWidget *parent, bool vertica
categoryLabel = new QLabel("Active");
categoryLabel->setAlignment(Qt::AlignCenter);
utils->addClass(categoryLabel, "mixer-category");
utils->addClass(categoryLabel, "text-tiny");
idian::Utils::addClass(categoryLabel, "mixer-category");
idian::Utils::addClass(categoryLabel, "text-tiny");
nameButton = new VolumeName(source, this);
nameButton->setMaximumWidth(280);
utils->addClass(nameButton, "text-small");
utils->addClass(nameButton, "mixer-name");
idian::Utils::addClass(nameButton, "text-small");
idian::Utils::addClass(nameButton, "mixer-name");
muteButton = new QPushButton(this);
muteButton->setCheckable(true);
utils->addClass(muteButton, "btn-mute");
idian::Utils::addClass(muteButton, "btn-mute");
monitorButton = new QPushButton(this);
monitorButton->setCheckable(true);
utils->addClass(monitorButton, "btn-monitor");
idian::Utils::addClass(monitorButton, "btn-monitor");
volumeLabel = new QLabel(this);
volumeLabel->setIndent(0);
@@ -89,8 +87,8 @@ VolumeControl::VolumeControl(obs_source_t *source, QWidget *parent, bool vertica
sourceName = obs_source_get_name(source);
setObjectName(sourceName);
utils->applyStateStylingEventFilter(muteButton);
utils->applyStateStylingEventFilter(monitorButton);
idian::Utils::applyStateStylingEventFilter(muteButton);
idian::Utils::applyStateStylingEventFilter(monitorButton);
volumeMeter = new VolumeMeter(this, source);
@@ -641,11 +639,11 @@ void VolumeControl::updateCategoryLabel()
bool styleUnassigned = mixerStatus().has(VolumeControl::MixerStatus::Unassigned);
bool stylePreviewed = mixerStatus().has(VolumeControl::MixerStatus::Preview);
utils->toggleClass("volume-pinned", stylePinned);
utils->toggleClass("volume-inactive", styleInactive);
utils->toggleClass("volume-preview", styleInactive && stylePreviewed);
utils->toggleClass("volume-hidden", styleHidden && !stylePinned);
utils->toggleClass("volume-unassigned", styleUnassigned);
idian::Utils::toggleClass(this, "volume-pinned", stylePinned);
idian::Utils::toggleClass(this, "volume-inactive", styleInactive);
idian::Utils::toggleClass(this, "volume-preview", styleInactive && stylePreviewed);
idian::Utils::toggleClass(this, "volume-hidden", styleHidden && !stylePinned);
idian::Utils::toggleClass(this, "volume-unassigned", styleUnassigned);
categoryLabel->setText(labelText);
categoryLabel->setAlignment(Qt::AlignCenter);
@@ -803,10 +801,10 @@ void VolumeControl::processMixerState()
// Qt doesn't support overriding the QPushButton icon using pseudo state selectors like :checked
// in QSS so we set a checked class selector on the button to be used instead.
utils->toggleClass(muteButton, "checked", showAsMuted);
utils->toggleClass(monitorButton, "checked", showAsMonitored);
idian::Utils::toggleClass(muteButton, "checked", showAsMuted);
idian::Utils::toggleClass(monitorButton, "checked", showAsMonitored);
utils->toggleClass(muteButton, "mute-warning", showWarningIcon);
idian::Utils::toggleClass(muteButton, "mute-warning", showWarningIcon);
style()->polish(muteButton);
style()->polish(monitorButton);
-2
View File
@@ -66,8 +66,6 @@ public:
};
private:
std::unique_ptr<idian::Utils> utils;
OBSWeakSource weakSource_;
const char *uuid;
std::vector<OBSSignal> obsSignals;
+1 -1
View File
@@ -21,7 +21,7 @@
using idian::CheckBox;
CheckBox::CheckBox(QWidget *parent) : QCheckBox(parent), Utils(this)
CheckBox::CheckBox(QWidget *parent) : QCheckBox(parent)
{
Utils::applyStateStylingEventFilter(this);
}
+1 -1
View File
@@ -25,7 +25,7 @@
using idian::ComboBox;
ComboBox::ComboBox(QWidget *parent) : QComboBox(parent), Utils(this)
ComboBox::ComboBox(QWidget *parent) : QComboBox(parent)
{
Utils::applyStateStylingEventFilter(this);
}
+1 -1
View File
@@ -18,7 +18,7 @@
#include <Idian/InlineButton.hpp>
namespace idian {
InlineButton::InlineButton(QWidget *parent) : QPushButton(parent), Utils(this)
InlineButton::InlineButton(QWidget *parent) : QPushButton(parent)
{
Utils::applyStateStylingEventFilter(this);
}
+2 -3
View File
@@ -35,8 +35,7 @@ QColor blendColors(const QColor &color1, const QColor &color2, float ratio)
ToggleSwitch::ToggleSwitch(QWidget *parent)
: QAbstractButton(parent),
animHandle(new QPropertyAnimation(this, "xpos", this)),
animBgColor(new QPropertyAnimation(this, "blend", this)),
Utils(this)
animBgColor(new QPropertyAnimation(this, "blend", this))
{
Utils::applyStateStylingEventFilter(this);
@@ -104,7 +103,7 @@ void ToggleSwitch::updateBackgroundColor()
void ToggleSwitch::changeEvent(QEvent *event)
{
if (event->type() == QEvent::EnabledChange) {
Utils::toggleClass("disabled", !isEnabled());
Utils::toggleClass(this, "disabled", !isEnabled());
updateBackgroundColor();
}
}
+1 -1
View File
@@ -23,7 +23,7 @@
namespace idian {
class CheckBox : public QCheckBox, public Utils {
class CheckBox : public QCheckBox {
Q_OBJECT;
public:
+1 -1
View File
@@ -24,7 +24,7 @@
namespace idian {
class ComboBox : public QComboBox, public Utils {
class ComboBox : public QComboBox {
Q_OBJECT
public:
@@ -26,7 +26,7 @@ class QPixmap;
namespace idian {
class Utils;
class InlineButton : public QPushButton, public Utils {
class InlineButton : public QPushButton {
Q_OBJECT
public:
+1 -1
View File
@@ -35,7 +35,7 @@ class RowList;
class RowInfo;
// Row widget containing one or more controls
class Row : public QFrame, public Utils {
class Row : public QFrame {
Q_OBJECT
public:
@@ -23,7 +23,7 @@
#include <QLabel>
namespace idian {
StateEventFilter::StateEventFilter(idian::Utils *utils, QWidget *target) : QObject(target), target(target), utils(utils)
StateEventFilter::StateEventFilter(QWidget *target) : QObject(target), target(target)
{
QAbstractButton *button = qobject_cast<QAbstractButton *>(target);
if (button) {
@@ -45,54 +45,54 @@ bool StateEventFilter::eventFilter(QObject *obj, QEvent *event)
switch (event->type()) {
case QEvent::StyleChange:
case QEvent::ThemeChange:
utils->repolish(widget);
Utils::repolish(widget);
utils->polishChildren(widget);
Utils::polishChildren(widget);
break;
case QEvent::FocusIn:
utils->toggleClass(widget, "focus", true);
Utils::toggleClass(widget, "focus", true);
focusEvent = static_cast<QFocusEvent *>(event);
if (focusEvent->reason() != Qt::MouseFocusReason && focusEvent->reason() != Qt::PopupFocusReason) {
utils->toggleClass(widget, "keyFocus", true);
Utils::toggleClass(widget, "keyFocus", true);
} else {
utils->toggleClass(widget, "keyFocus", false);
Utils::toggleClass(widget, "keyFocus", false);
}
utils->polishChildren(widget);
Utils::polishChildren(widget);
break;
case QEvent::FocusOut:
utils->toggleClass(widget, "focus", false);
Utils::toggleClass(widget, "focus", false);
focusEvent = static_cast<QFocusEvent *>(event);
if (focusEvent->reason() != Qt::PopupFocusReason) {
utils->toggleClass(widget, "keyFocus", false);
utils->polishChildren(widget);
Utils::toggleClass(widget, "keyFocus", false);
Utils::polishChildren(widget);
}
utils->polishChildren(widget);
Utils::polishChildren(widget);
break;
case QEvent::HoverEnter:
if (widget->isEnabled()) {
utils->toggleClass(widget, "hover", true);
Utils::toggleClass(widget, "hover", true);
}
utils->polishChildren(widget);
Utils::polishChildren(widget);
break;
case QEvent::HoverLeave:
utils->toggleClass(widget, "hover", false);
Utils::toggleClass(widget, "hover", false);
utils->polishChildren(widget);
Utils::polishChildren(widget);
break;
case QEvent::EnabledChange:
utils->toggleClass(widget, "disabled", !widget->isEnabled());
Utils::toggleClass(widget, "disabled", !widget->isEnabled());
utils->polishChildren(widget);
Utils::polishChildren(widget);
break;
default:
@@ -104,10 +104,10 @@ bool StateEventFilter::eventFilter(QObject *obj, QEvent *event)
// Delay icon update
if (QLabel *label = qobject_cast<QLabel *>(widget)) {
QMetaObject::invokeMethod(
this, [this, label]() { utils->applyColorToIcon(label); }, Qt::QueuedConnection);
this, [this, label]() { Utils::applyColorToIcon(label); }, Qt::QueuedConnection);
} else if (QAbstractButton *button = qobject_cast<QAbstractButton *>(widget)) {
QMetaObject::invokeMethod(
this, [this, button]() { utils->applyColorToIcon(button); }, Qt::QueuedConnection);
this, [this, button]() { Utils::applyColorToIcon(button); }, Qt::QueuedConnection);
}
}
@@ -116,7 +116,7 @@ bool StateEventFilter::eventFilter(QObject *obj, QEvent *event)
void StateEventFilter::updateCheckedState(bool checked)
{
utils->toggleClass(target, "checked", checked);
Utils::toggleClass(target, "checked", checked);
}
} // namespace idian
@@ -27,7 +27,7 @@ class StateEventFilter : public QObject {
Q_OBJECT
public:
explicit StateEventFilter(idian::Utils *utils, QWidget *parent);
explicit StateEventFilter(QWidget *parent);
bool eventFilter(QObject *obj, QEvent *event);
@@ -35,7 +35,6 @@ public slots:
void updateCheckedState(bool checked);
private:
Utils *utils;
QWidget *target;
};
} // namespace idian
@@ -31,7 +31,7 @@
namespace idian {
class ToggleSwitch : public QAbstractButton, public Utils {
class ToggleSwitch : public QAbstractButton {
Q_OBJECT
Q_PROPERTY(int xpos MEMBER xPos WRITE setPos)
Q_PROPERTY(QColor background MEMBER backgroundInactive DESIGNABLE true)
+71 -1
View File
@@ -26,6 +26,76 @@
#include <QStyleOptionFrame>
namespace idian {
void Utils::polishChildren(QWidget *widget)
{
for (QWidget *child : widget->findChildren<QWidget *>()) {
repolish(child);
}
}
void Utils::repolish(QWidget *widget)
{
widget->style()->polish(widget);
}
void Utils::addClass(QWidget *widget, const QString &classname)
{
if (!classNameIsValid(classname)) {
return;
}
QVariant current = widget->property("class");
QStringList classList = current.toString().split(" ");
if (classList.contains(classname)) {
return;
}
classList.removeDuplicates();
classList.removeAll("");
classList.append(classname);
QString newClasses = classList.isEmpty() ? "" : classList.join(" ");
widget->setProperty("class", newClasses);
repolish(widget);
}
void Utils::removeClass(QWidget *widget, const QString &classname)
{
if (!classNameIsValid(classname)) {
return;
}
QVariant current = widget->property("class");
if (current.isNull()) {
return;
}
QStringList classList = current.toString().split(" ");
if (!classList.contains(classname, Qt::CaseSensitive)) {
return;
}
classList.removeDuplicates();
classList.removeAll("");
classList.removeAll(classname);
QString newClasses = classList.isEmpty() ? "" : classList.join(" ");
widget->setProperty("class", newClasses);
repolish(widget);
}
void Utils::toggleClass(QWidget *widget, const QString &classname, bool toggle)
{
if (toggle) {
addClass(widget, classname);
} else {
removeClass(widget, classname);
}
}
void Utils::applyColorToIcon(QAbstractButton *button)
{
if (button && !button->icon().isNull()) {
@@ -71,6 +141,6 @@ QPixmap Utils::recolorPixmap(const QPixmap &src, const QColor &color)
// Widgets can then be styled via CSS class-style rules like .hover.
void Utils::applyStateStylingEventFilter(QWidget *widget)
{
widget->installEventFilter(new StateEventFilter(this, widget));
widget->installEventFilter(new StateEventFilter(widget));
}
} // namespace idian
+9 -72
View File
@@ -27,7 +27,8 @@ class QLabel;
namespace idian {
// Helpers for OBS Idian widgets
class Utils {
class Utils : public QObject {
Q_OBJECT
static bool classNameIsValid(const QString &name)
{
@@ -37,92 +38,28 @@ class Utils {
}
public:
QWidget *parent = nullptr;
Utils(QWidget *w) { parent = w; }
Utils(QObject *parent = nullptr) {};
// Force all children widgets to repaint
void polishChildren() { polishChildren(parent); }
static void polishChildren(QWidget *widget)
{
for (QWidget *child : widget->findChildren<QWidget *>()) {
repolish(child);
}
}
static void polishChildren(QWidget *widget);
void repolish() { repolish(parent); }
static void repolish(QWidget *widget) { widget->style()->polish(widget); }
static void repolish(QWidget *widget);
// Adds a style class to the widget
void addClass(const QString &classname) { addClass(parent, classname); }
static void addClass(QWidget *widget, const QString &classname)
{
if (!classNameIsValid(classname)) {
return;
}
QVariant current = widget->property("class");
QStringList classList = current.toString().split(" ");
if (classList.contains(classname)) {
return;
}
classList.removeDuplicates();
classList.removeAll("");
classList.append(classname);
QString newClasses = classList.isEmpty() ? "" : classList.join(" ");
widget->setProperty("class", newClasses);
repolish(widget);
}
static void addClass(QWidget *widget, const QString &classname);
// Removes a style class from a widget
void removeClass(const QString &classname) { removeClass(parent, classname); }
static void removeClass(QWidget *widget, const QString &classname)
{
if (!classNameIsValid(classname)) {
return;
}
QVariant current = widget->property("class");
if (current.isNull()) {
return;
}
QStringList classList = current.toString().split(" ");
if (!classList.contains(classname, Qt::CaseSensitive)) {
return;
}
classList.removeDuplicates();
classList.removeAll("");
classList.removeAll(classname);
QString newClasses = classList.isEmpty() ? "" : classList.join(" ");
widget->setProperty("class", newClasses);
repolish(widget);
}
static void removeClass(QWidget *widget, const QString &classname);
// Forces the addition or removal of a style class from a widget
void toggleClass(const QString &classname, bool toggle) { toggleClass(parent, classname, toggle); }
static void toggleClass(QWidget *widget, const QString &classname, bool toggle)
{
if (toggle) {
addClass(widget, classname);
} else {
removeClass(widget, classname);
}
}
static void toggleClass(QWidget *widget, const QString &classname, bool toggle);
static void applyColorToIcon(QAbstractButton *button);
static void applyColorToIcon(QLabel *label);
static QPixmap recolorPixmap(const QPixmap &src, const QColor &color);
void applyStateStylingEventFilter(QWidget *widget);
static void applyStateStylingEventFilter(QWidget *widget);
};
} // namespace idian
+3 -3
View File
@@ -27,7 +27,7 @@
#include <Idian/moc_Row.cpp>
namespace idian {
Row::Row(QWidget *parent) : QFrame(parent), Utils(this)
Row::Row(QWidget *parent) : QFrame(parent)
{
rowLayout = new QHBoxLayout(this);
rowLayout->setContentsMargins(0, 0, 0, 0);
@@ -49,7 +49,7 @@ void Row::setBuddy(QWidget *widget)
void Row::setChangeCursor(bool change)
{
changeCursor = change;
Utils::toggleClass("cursor-pointer", change);
Utils::toggleClass(this, "cursor-pointer", change);
}
void Row::enterEvent(QEnterEvent *event)
@@ -98,7 +98,7 @@ void Row::connectBuddyWidget(QWidget *widget)
{
setAttribute(Qt::WA_Hover, true);
setFocusPolicy(Qt::StrongFocus);
applyStateStylingEventFilter(this);
Utils::applyStateStylingEventFilter(this);
// If element is a ToggleSwitch and checkable, forward clicks to the widget
ToggleSwitch *obsToggle = qobject_cast<ToggleSwitch *>(widget);