Просмотр исходного кода

frontend: Create event filter for widget state styles

Warchamp7 3 месяцев назад
Родитель
Сommit
802cf6bd90

+ 24 - 28
frontend/data/themes/Yami.obt

@@ -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;
 }
 

+ 5 - 0
frontend/data/themes/Yami_Acri.ovt

@@ -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);
+}

+ 30 - 0
frontend/data/themes/Yami_Light.ovt

@@ -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);
+}

+ 3 - 0
shared/qt/idian/CMakeLists.txt

@@ -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

+ 4 - 1
shared/qt/idian/components/CheckBox.cpp

@@ -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);
+}

+ 4 - 1
shared/qt/idian/components/ComboBox.cpp

@@ -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()
 {

+ 2 - 0
shared/qt/idian/components/ToggleSwitch.cpp

@@ -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;

+ 0 - 13
shared/qt/idian/include/Idian/CheckBox.hpp

@@ -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

+ 0 - 12
shared/qt/idian/include/Idian/ComboBox.hpp

@@ -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

+ 7 - 37
shared/qt/idian/include/Idian/Row.hpp

@@ -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;
 };

+ 78 - 0
shared/qt/idian/include/Idian/StateEventFilter.cpp

@@ -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

+ 25 - 0
shared/qt/idian/include/Idian/StateEventFilter.hpp

@@ -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

+ 0 - 12
shared/qt/idian/include/Idian/ToggleSwitch.hpp

@@ -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);
 

+ 10 - 0
shared/qt/idian/include/Idian/Utils.cpp

@@ -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

+ 9 - 19
shared/qt/idian/include/Idian/Utils.hpp

@@ -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

+ 7 - 7
shared/qt/idian/widgets/Row.cpp

@@ -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);