frontend: Create event filter for widget state styles

This commit is contained in:
Warchamp7
2025-10-15 14:11:22 -04:00
committed by Ryan Foster
parent d1db882817
commit 802cf6bd90
16 changed files with 208 additions and 130 deletions

View File

@@ -1760,7 +1760,6 @@ QTableView::indicator:unchecked {
QCheckBox::indicator:unchecked:hover,
QGroupBox::indicator:unchecked:hover,
QTableView::indicator:unchecked:hover {
border: none;
image: url(theme:Yami/checkbox_unchecked_focus.svg);
}
@@ -2321,11 +2320,11 @@ idian--ToggleSwitch {
border: var(--highlight_width) solid transparent;
}
idian--ToggleSwitch:hover {
idian--ToggleSwitch.hover {
border-color: var(--grey4);
}
idian--ToggleSwitch:checked:hover {
idian--ToggleSwitch.checked.hover {
border-color: var(--white1);
}
@@ -2333,13 +2332,13 @@ idian--ToggleSwitch.keyFocus {
border-color: var(--highlight_color);
}
idian--Row idian--ToggleSwitch:hover,
idian--Row idian--ToggleSwitch.hover,
idian--Row.hover > idian--ToggleSwitch.row-buddy {
border-color: var(--grey1);
}
idian--Row idian--ToggleSwitch:checked:hover,
idian--Row.hover idian--ToggleSwitch.row-buddy:checked {
idian--Row idian--ToggleSwitch.hover.checked,
idian--Row.hover > idian--ToggleSwitch.checked.row-buddy {
border-color: var(--white1);
}
@@ -2358,7 +2357,7 @@ idian--Row QComboBox:focus {
border-color: transparent;
}
idian--Row QComboBox:hover {
idian--Row QComboBox.hover {
border-color: var(--grey1);
}
@@ -2383,7 +2382,7 @@ idian--Row QComboBox QAbstractItemView::item {
padding: var(--padding_base) var(--padding_large);
}
idian--Row QComboBox QAbstractItemView::item:hover,
idian--Row QComboBox QAbstractItemView.hover::item,
idian--Row QComboBox QAbstractItemView::item:selected {
background-color: var(--list_item_bg_selected);
padding: var(--padding_base) var(--padding_large);
@@ -2406,32 +2405,30 @@ idian--Row idian--CheckBox {
outline: none;
}
idian--Row idian--CheckBox::indicator,
idian--Row idian--CheckBox::indicator:unchecked:hover {
idian--CheckBox::indicator {
border: var(--highlight_width) solid transparent;
border-radius: var(--border_radius);
}
idian--Row.hover > idian--CheckBox.row-buddy::indicator,
idian--Row > idian--CheckBox::indicator:unchecked:hover,
idian--Row > idian--CheckBox::indicator:hover {
border-color: var(--grey1);
}
idian--Row.hover > idian--CheckBox.row-buddy::indicator:unchecked,
idian--CheckBox.keyFocus::indicator:unchecked {
idian--CheckBox.keyFocus::indicator,
idian--Row.hover > idian--CheckBox.row-buddy::indicator {
image: url(theme:Yami/checkbox_unchecked_focus.svg);
}
idian--Row idian--CheckBox.keyFocus::indicator,
idian--Row.hover > idian--CheckBox::indicator {
idian--CheckBox.keyFocus.checked::indicator,
idian--Row.hover > idian--CheckBox.row-buddy.checked::indicator {
image: url(theme:Yami/checkbox_checked_focus.svg);
}
idian--Row idian--CheckBox.keyFocus::indicator,
idian--Row idian--CheckBox.keyFocus::indicator:unchecked,
idian--Row idian--CheckBox.keyFocus::indicator:hover,
idian--Row idian--CheckBox.keyFocus::indicator:unchecked:hover {
idian--CheckBox.hover::indicator,
idian--CheckBox.checked.hover::indicator,
idian--Row.hover > idian--CheckBox.row-buddy::indicator
idian--Row.hover > idian--CheckBox.row-buddy.checked::indicator {
border-color: var(--grey1);
}
idian--CheckBox.keyFocus::indicator,
idian--CheckBox.keyFocus.checked::indicator {
border-color: var(--highlight_color);
}
@@ -2503,16 +2500,15 @@ idian--RowFrame.hover .btn-frame {
background: var(--grey4);
}
idian--RowFrame.hover idian--Row,
idian--RowFrame.hover idian--Row.hover {
idian--RowFrame.hover idian--Row {
background: var(--grey4);
border: 2px solid var(--grey1);
border: var(--highlight_width) solid var(--grey1);
border-right: none;
}
idian--RowFrame.hover .row-buddy {
background: var(--grey4);
border: 2px solid var(--grey1);
border: var(--highlight_width) solid var(--grey1);
border-left: none;
}

View File

@@ -229,3 +229,8 @@ QCalendarWidget QToolButton:pressed {
QCalendarWidget QSpinBox {
background-color: var(--primary_dark);
}
idian--ToggleSwitch {
qproperty-background_checked: var(--button_bg);
qproperty-background_checked_hover: var(--primary_light);
}

View File

@@ -324,3 +324,33 @@ QCalendarWidget #qt_calendar_prevmonth {
QCalendarWidget #qt_calendar_nextmonth {
qproperty-icon: url(theme:Light/right.svg);
}
/* Idian Widgets */
idian--ToggleSwitch {
qproperty-background: var(--grey8);
qproperty-background_hover: var(--grey7);
qproperty-background_checked: var(--primary);
qproperty-background_checked_hover: var(--primary_light);
}
idian--Row QComboBox::down-arrow {
image: url(theme:Light/collapse.svg);
}
idian--CheckBox.keyFocus::indicator,
idian--Row.hover > idian--CheckBox.row-buddy::indicator {
image: url(theme:Light/checkbox_unchecked_focus.svg);
}
idian--CheckBox.keyFocus.checked::indicator,
idian--Row.hover > idian--CheckBox.row-buddy.checked::indicator {
image: url(theme:Light/checkbox_checked_focus.svg);
}
idian--ExpandButton::indicator {
image: url(theme:Light/down.svg);
}
idian--ExpandButton::indicator:checked {
image: url(theme:Light/up.svg);
}

View File

@@ -22,7 +22,10 @@ target_sources(
include/Idian/Row.hpp
include/Idian/SpinBox.hpp
include/Idian/ToggleSwitch.hpp
include/Idian/Utils.cpp
include/Idian/Utils.hpp
include/Idian/StateEventFilter.cpp
include/Idian/StateEventFilter.hpp
widgets/Group.cpp
widgets/PropertiesList.cpp
widgets/Row.cpp

View File

@@ -21,4 +21,7 @@
using idian::CheckBox;
CheckBox::CheckBox(QWidget *parent) : QCheckBox(parent), Utils(this) {}
CheckBox::CheckBox(QWidget *parent) : QCheckBox(parent), Utils(this)
{
Utils::applyStateStylingEventFilter(this);
}

View File

@@ -25,7 +25,10 @@
using idian::ComboBox;
ComboBox::ComboBox(QWidget *parent) : QComboBox(parent), Utils(this) {}
ComboBox::ComboBox(QWidget *parent) : QComboBox(parent), Utils(this)
{
Utils::applyStateStylingEventFilter(this);
}
void ComboBox::showPopup()
{

View File

@@ -38,6 +38,8 @@ ToggleSwitch::ToggleSwitch(QWidget *parent)
animBgColor(new QPropertyAnimation(this, "blend", this)),
Utils(this)
{
Utils::applyStateStylingEventFilter(this);
offPos = rect().width() / 2 - 18;
onPos = rect().width() / 2 + 18;
xPos = offPos;

View File

@@ -28,19 +28,6 @@ class CheckBox : public QCheckBox, public Utils {
public:
CheckBox(QWidget *parent = nullptr);
protected:
void focusInEvent(QFocusEvent *e) override
{
Utils::showKeyFocused(e);
QAbstractButton::focusInEvent(e);
}
void focusOutEvent(QFocusEvent *e) override
{
Utils::hideKeyFocused(e);
QAbstractButton::focusOutEvent(e);
}
};
} // namespace idian

View File

@@ -41,18 +41,6 @@ protected:
void hidePopup() override;
void mousePressEvent(QMouseEvent *event) override;
void focusInEvent(QFocusEvent *e) override
{
Utils::showKeyFocused(e);
QComboBox::focusInEvent(e);
}
void focusOutEvent(QFocusEvent *e) override
{
Utils::hideKeyFocused(e);
QComboBox::focusOutEvent(e);
}
};
} // namespace idian

View File

@@ -39,7 +39,13 @@ class GenericRow : public QFrame, public Utils {
Q_OBJECT
public:
GenericRow(QWidget *parent = nullptr) : QFrame(parent), Utils(this) { setAccessibleName(""); };
GenericRow(QWidget *parent = nullptr) : QFrame(parent), Utils(this)
{
setAttribute(Qt::WA_Hover, true);
applyStateStylingEventFilter(this);
setAccessibleName("");
};
virtual void setTitle(const QString &title) = 0;
virtual void setDescription(const QString &description) = 0;
@@ -84,18 +90,6 @@ protected:
void keyReleaseEvent(QKeyEvent *) override;
bool hasDescription() const { return descriptionLabel != nullptr; }
void focusInEvent(QFocusEvent *event) override
{
Utils::showKeyFocused(event);
QFrame::focusInEvent(event);
}
void focusOutEvent(QFocusEvent *event) override
{
Utils::hideKeyFocused(event);
QFrame::focusOutEvent(event);
}
private:
QGridLayout *layout;
@@ -127,18 +121,6 @@ protected:
explicit ExpandButton(QWidget *parent = nullptr);
void paintEvent(QPaintEvent *) override;
void focusInEvent(QFocusEvent *event) override
{
Utils::showKeyFocused(event);
QAbstractButton::focusInEvent(event);
}
void focusOutEvent(QFocusEvent *event) override
{
Utils::hideKeyFocused(event);
QAbstractButton::focusOutEvent(event);
}
};
class RowFrame : protected QFrame, protected Utils {
@@ -153,18 +135,6 @@ protected:
void enterEvent(QEnterEvent *) override;
void leaveEvent(QEvent *) override;
void focusInEvent(QFocusEvent *event) override
{
Utils::showKeyFocused(event);
QWidget::focusInEvent(event);
}
void focusOutEvent(QFocusEvent *event) override
{
Utils::hideKeyFocused(event);
QWidget::focusOutEvent(event);
}
private:
friend class CollapsibleRow;
};

View File

@@ -0,0 +1,78 @@
#include <Idian/StateEventFilter.hpp>
#include <Idian/Utils.hpp>
#include <QAbstractButton>
#include <QLabel>
namespace idian {
StateEventFilter::StateEventFilter(idian::Utils *utils, QWidget *target) : QObject(target), target(target), utils(utils)
{
QAbstractButton *button = qobject_cast<QAbstractButton *>(target);
if (button) {
connect(button, &QAbstractButton::toggled, this, &StateEventFilter::updateCheckedState);
}
}
bool StateEventFilter::eventFilter(QObject *obj, QEvent *event)
{
if (!obj->isWidgetType()) {
return QObject::eventFilter(obj, event);
}
QWidget *widget = qobject_cast<QWidget *>(obj);
QFocusEvent *focusEvent = nullptr;
switch (event->type()) {
case QEvent::FocusIn:
utils->toggleClass(widget, "focus", true);
focusEvent = static_cast<QFocusEvent *>(event);
if (focusEvent->reason() != Qt::MouseFocusReason && focusEvent->reason() != Qt::PopupFocusReason) {
utils->toggleClass(widget, "keyFocus", true);
} else {
utils->toggleClass(widget, "keyFocus", false);
}
utils->polishChildren(widget);
break;
case QEvent::FocusOut:
utils->toggleClass(widget, "focus", false);
focusEvent = static_cast<QFocusEvent *>(event);
if (focusEvent->reason() != Qt::PopupFocusReason) {
utils->toggleClass(widget, "keyFocus", false);
utils->polishChildren(widget);
}
break;
case QEvent::MouseButtonPress:
break;
case QEvent::HoverEnter:
if (widget->isEnabled()) {
utils->toggleClass(widget, "hover", true);
}
utils->polishChildren(widget);
break;
case QEvent::HoverLeave:
utils->toggleClass(widget, "hover", false);
utils->polishChildren(widget);
break;
case QEvent::EnabledChange:
bool widgetEnabled = widget->isEnabled();
utils->toggleClass(widget, "disabled", !widgetEnabled);
utils->polishChildren(widget);
break;
}
return QObject::eventFilter(obj, event);
}
void StateEventFilter::updateCheckedState(bool checked)
{
utils->toggleClass(target, "checked", checked);
}
} // namespace idian

View File

@@ -0,0 +1,25 @@
#pragma once
#include <Idian/Utils.hpp>
#include <QWidget>
#include <QAbstractbutton>
#include <QStyleOptionButton>
namespace idian {
class StateEventFilter : public QObject {
Q_OBJECT
public:
explicit StateEventFilter(idian::Utils *utils, QWidget *parent);
bool eventFilter(QObject *obj, QEvent *event);
public slots:
void updateCheckedState(bool checked);
private:
Utils *utils;
QWidget *target;
};
} // namespace idian

View File

@@ -82,18 +82,6 @@ protected:
void keyReleaseEvent(QKeyEvent *) override;
void mouseReleaseEvent(QMouseEvent *) override;
void focusInEvent(QFocusEvent *e) override
{
Utils::showKeyFocused(e);
QAbstractButton::focusInEvent(e);
}
void focusOutEvent(QFocusEvent *e) override
{
Utils::hideKeyFocused(e);
QAbstractButton::focusOutEvent(e);
}
private slots:
void onClicked(bool checked);

View File

@@ -0,0 +1,10 @@
#include <Idian/Utils.hpp>
#include <Idian/StateEventFilter.hpp>
namespace idian {
void Utils::applyStateStylingEventFilter(QWidget *widget)
{
widget->installEventFilter(new StateEventFilter(this, widget));
}
} // namespace idian

View File

@@ -18,6 +18,7 @@
#pragma once
#include <QFocusEvent>
#include <QPainter>
#include <QRegularExpression>
#include <QStyle>
#include <QWidget>
@@ -39,23 +40,6 @@ public:
Utils(QWidget *w) { parent = w; }
// Set a custom property whenever the widget has keyboard focus specifically
void showKeyFocused(QFocusEvent *e)
{
if (e->reason() != Qt::MouseFocusReason && e->reason() != Qt::PopupFocusReason) {
addClass("keyFocus");
} else {
removeClass("keyFocus");
}
}
void hideKeyFocused(QFocusEvent *e)
{
if (e->reason() != Qt::PopupFocusReason) {
removeClass("keyFocus");
}
}
// Force all children widgets to repaint
void polishChildren() { polishChildren(parent); }
@@ -91,9 +75,11 @@ public:
}
classList.removeDuplicates();
classList.removeAll("");
classList.append(classname);
widget->setProperty("class", classList.join(" "));
QString newClasses = classList.isEmpty() ? "" : classList.join(" ");
widget->setProperty("class", newClasses);
repolish(widget);
}
@@ -118,9 +104,11 @@ public:
}
classList.removeDuplicates();
classList.removeAll("");
classList.removeAll(classname);
widget->setProperty("class", classList.join(" "));
QString newClasses = classList.isEmpty() ? "" : classList.join(" ");
widget->setProperty("class", newClasses);
repolish(widget);
}
@@ -136,6 +124,8 @@ public:
removeClass(widget, classname);
}
}
void applyStateStylingEventFilter(QWidget *widget);
};
} // namespace idian

View File

@@ -157,8 +157,6 @@ void Row::enterEvent(QEnterEvent *event)
setCursor(Qt::PointingHandCursor);
}
Utils::addClass("hover");
if (buddyWidget)
Utils::repolish(buddyWidget);
@@ -171,8 +169,6 @@ void Row::enterEvent(QEnterEvent *event)
void Row::leaveEvent(QEvent *event)
{
Utils::removeClass("hover");
if (buddyWidget)
Utils::repolish(buddyWidget);
@@ -236,6 +232,7 @@ void Row::connectBuddyWidget(QWidget *widget)
// Button for expanding a collapsible ActionRow
ExpandButton::ExpandButton(QWidget *parent) : QAbstractButton(parent), Utils(this)
{
Utils::applyStateStylingEventFilter(this);
setCheckable(true);
}
@@ -358,13 +355,17 @@ void CollapsibleRow::addRow(GenericRow *actionRow)
propertyList->addRow(actionRow);
}
RowFrame::RowFrame(QWidget *parent) : QFrame(parent), Utils(this) {}
RowFrame::RowFrame(QWidget *parent) : QFrame(parent), Utils(this)
{
setAttribute(Qt::WA_Hover, true);
Utils::applyStateStylingEventFilter(this);
}
void RowFrame::enterEvent(QEnterEvent *event)
{
setCursor(Qt::PointingHandCursor);
Utils::addClass("hover");
Utils::polishChildren();
QWidget::enterEvent(event);
@@ -372,7 +373,6 @@ void RowFrame::enterEvent(QEnterEvent *event)
void RowFrame::leaveEvent(QEvent *event)
{
Utils::removeClass("hover");
Utils::polishChildren();
QWidget::leaveEvent(event);