diff --git a/quickshell/Modals/DankLauncherV2/SpotlightLauncherContent.qml b/quickshell/Modals/DankLauncherV2/SpotlightLauncherContent.qml index add822aab..7a27f5de0 100644 --- a/quickshell/Modals/DankLauncherV2/SpotlightLauncherContent.qml +++ b/quickshell/Modals/DankLauncherV2/SpotlightLauncherContent.qml @@ -1,7 +1,6 @@ pragma ComponentBehavior: Bound import QtQuick -import Quickshell import qs.Common import qs.Services import qs.Widgets @@ -319,13 +318,13 @@ FocusScope { Rectangle { anchors.fill: parent radius: height / 2 - color: categoryChip.isSelected ? Theme.primary : chipArea.containsMouse ? Theme.surfaceHover : Theme.surfaceVariantAlpha + color: chipColor.value - Behavior on color { - ColorAnimation { - duration: root._fastDuration - easing.type: Theme.standardEasing - } + DankColorAnimation { + id: chipColor + to: categoryChip.isSelected ? Theme.primary : chipArea.containsMouse ? Theme.surfaceHover : Theme.surfaceVariantAlpha + duration: root._fastDuration + easingType: Theme.standardEasing } StyledText { diff --git a/quickshell/Modals/Greeter/GreeterModal.qml b/quickshell/Modals/Greeter/GreeterModal.qml index 4a2222aec..b2469c5e8 100644 --- a/quickshell/Modals/Greeter/GreeterModal.qml +++ b/quickshell/Modals/Greeter/GreeterModal.qml @@ -191,21 +191,21 @@ FloatingWindow { width: isActive ? dotSize * 3 : dotSize height: dotSize radius: dotSize / 2 - color: isActive ? Theme.primary : Theme.surfaceTextAlpha + color: dotColor.value anchors.verticalCenter: parent.verticalCenter + DankColorAnimation { + id: dotColor + to: isActive ? Theme.primary : Theme.surfaceTextAlpha + duration: Theme.shortDuration + } + Behavior on width { NumberAnimation { duration: Theme.shortDuration easing.type: Theme.emphasizedEasing } } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } } } } diff --git a/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml b/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml index c9d705b61..e470a4bdc 100644 --- a/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml +++ b/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml @@ -1283,10 +1283,15 @@ Item { readonly property color requestedColor: isActive ? activeColor : isUrgent ? urgentColor : isPlaceholder ? Theme.surfaceTextLight : isHovered ? Theme.withAlpha(unfocusedColor, 0.7) : isOccupied ? occupiedColor : unfocusedColor - property color displayColor: requestedColor property bool colorAnimationReady: false - onRequestedColorChanged: Qt.callLater(() => delegateRoot.displayColor = delegateRoot.requestedColor) + readonly property color displayColor: pillColor.value + + DankColorAnimation { + id: pillColor + to: delegateRoot.requestedColor + animated: delegateRoot.colorAnimationReady + } Item { id: dragHandler @@ -1560,14 +1565,6 @@ Item { } } - Behavior on color { - enabled: delegateRoot.colorAnimationReady - ColorAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - Behavior on border.width { NumberAnimation { duration: Theme.mediumDuration diff --git a/quickshell/Modules/Settings/DankDashTab.qml b/quickshell/Modules/Settings/DankDashTab.qml index cb97da8df..43cec0a12 100644 --- a/quickshell/Modules/Settings/DankDashTab.qml +++ b/quickshell/Modules/Settings/DankDashTab.qml @@ -424,26 +424,22 @@ Item { id: surface anchors.fill: parent radius: rowItem.dragging ? Theme.cornerRadius + 6 : Theme.cornerRadius - color: { - if (rowItem.dragging) - return Theme.secondaryContainer; - const base = Theme.surfaceContainer; - return Theme.withAlpha(base, rowItem.isEnabled ? 0.7 : 0.4); - } + color: surfaceColor.value border.width: rowItem.dragging ? 2 : 1 border.color: rowItem.dragging ? Theme.primary : Theme.outlineHeavy + DankColorAnimation { + id: surfaceColor + to: rowItem.dragging ? Theme.secondaryContainer : Theme.withAlpha(Theme.surfaceContainer, rowItem.isEnabled ? 0.7 : 0.4) + duration: Theme.shortDuration + } + Behavior on radius { NumberAnimation { duration: Theme.shortDuration easing.type: Easing.OutCubic } } - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } Behavior on border.color { ColorAnimation { duration: Theme.shortDuration diff --git a/quickshell/Modules/Settings/WidgetsTabSection.qml b/quickshell/Modules/Settings/WidgetsTabSection.qml index 4956ff255..b60a88b4c 100644 --- a/quickshell/Modules/Settings/WidgetsTabSection.qml +++ b/quickshell/Modules/Settings/WidgetsTabSection.qml @@ -279,7 +279,7 @@ Column { scale: delegateItem.dragging ? 1.02 : 1.0 transformOrigin: Item.Center radius: delegateItem.dragging ? Theme.cornerRadius + 6 : Theme.cornerRadius - color: delegateItem.dragging ? Theme.secondaryContainer : Theme.withAlpha(Theme.surfaceContainer, modelData.enabled ? 0.7 : 0.4) + color: itemColor.value border.color: delegateItem.dragging ? Theme.primary : Theme.outlineHeavy border.width: delegateItem.dragging ? 2 : 1 @@ -295,10 +295,10 @@ Column { easing.type: Easing.OutCubic } } - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } + DankColorAnimation { + id: itemColor + to: delegateItem.dragging ? Theme.secondaryContainer : Theme.withAlpha(Theme.surfaceContainer, modelData.enabled ? 0.7 : 0.4) + duration: Theme.shortDuration } Behavior on border.color { ColorAnimation { diff --git a/quickshell/Widgets/DankButton.qml b/quickshell/Widgets/DankButton.qml index 4f978d873..4eb8b77b2 100644 --- a/quickshell/Widgets/DankButton.qml +++ b/quickshell/Widgets/DankButton.qml @@ -44,7 +44,7 @@ Rectangle { return Theme.withAlpha(root.textColor, 0.20); if (hovered) return Theme.withAlpha(root.textColor, 0.12); - return "transparent"; + return Theme.withAlpha(root.textColor, 0); } Behavior on color { diff --git a/quickshell/Widgets/DankColorAnimation.qml b/quickshell/Widgets/DankColorAnimation.qml new file mode 100644 index 000000000..479fe18f6 --- /dev/null +++ b/quickshell/Widgets/DankColorAnimation.qml @@ -0,0 +1,62 @@ +import QtQuick +import qs.Common + +// Premultiplied-alpha color tween: bind `to`, read `value`. Plain +// ColorAnimation lerps raw RGBA and flashes when the endpoints differ +// in both color and alpha (translucent <-> opaque). +QtObject { + id: root + + property color to + property bool animated: true + property int duration: Theme.mediumDuration + property int easingType: Theme.emphasizedEasing + + property color _from: to + property color _target: to + property real _mix: 1 + property bool _ready: false + + readonly property color value: { + const from = _from; + const target = _target; + const alpha = from.a + (target.a - from.a) * _mix; + if (alpha <= 0) + return Qt.rgba(target.r, target.g, target.b, 0); + const mix = (a, b) => (a * from.a + (b * target.a - a * from.a) * _mix) / alpha; + return Qt.rgba(mix(from.r, target.r), mix(from.g, target.g), mix(from.b, target.b), alpha); + } + + readonly property NumberAnimation _anim: NumberAnimation { + target: root + property: "_mix" + from: 0 + to: 1 + duration: root.duration + easing.type: root.easingType + } + + onToChanged: { + if (!_ready || !animated) { + _anim.stop(); + _from = to; + _target = to; + _mix = 1; + return; + } + if (Qt.colorEqual(to, _target)) + return; + const current = value; + _anim.stop(); + _from = current; + _target = to; + _mix = 0; + _anim.restart(); + } + + Component.onCompleted: { + _from = to; + _target = to; + _ready = true; + } +}