diff --git a/modules/Flyout.qml b/modules/Flyout.qml
index 78810ef..fe0f9ac 100644
--- a/modules/Flyout.qml
+++ b/modules/Flyout.qml
@@ -8,9 +8,23 @@ PanelWindow {
required property var screen
- visible: M.FlyoutState.visible && M.FlyoutState.screen === root.screen
+ visible: _winVisible
color: "transparent"
+ property bool _winVisible: false
+ property bool _shown: M.FlyoutState.visible && M.FlyoutState.screen === root.screen
+
+ on_ShownChanged: {
+ if (_shown) {
+ _winVisible = true;
+ hideAnim.stop();
+ showAnim.start();
+ } else {
+ showAnim.stop();
+ hideAnim.start();
+ }
+ }
+
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.exclusiveZone: 0
WlrLayershell.namespace: "nova-flyout"
@@ -18,32 +32,54 @@ PanelWindow {
anchors.top: true
anchors.left: true
- // Flush below bar, centered on hovered item
margins.top: 0
- margins.left: Math.max(0, Math.min(Math.round(M.FlyoutState.itemX - implicitWidth / 2), screen.width - implicitWidth))
+ margins.left: Math.max(0, Math.min(
+ Math.round(M.FlyoutState.itemX - implicitWidth / 2),
+ screen.width - implicitWidth
+ ))
implicitWidth: label.implicitWidth + M.Theme.barPadding * 2
implicitHeight: label.implicitHeight + M.Theme.barPadding * 2
- // Background matching bar style — square top corners so it looks
- // flush / attached to the bar above, rounded bottom corners only
- Rectangle {
- anchors.fill: parent
- color: M.Theme.base00
- opacity: Math.max(M.Theme.barOpacity, 0.85)
- topLeftRadius: 0
- topRightRadius: 0
- bottomLeftRadius: M.Theme.radius
- bottomRightRadius: M.Theme.radius
+ ParallelAnimation {
+ id: showAnim
+ NumberAnimation { target: content; property: "opacity"; to: 1; duration: 120; easing.type: Easing.OutCubic }
+ NumberAnimation { target: content; property: "y"; to: 0; duration: 150; easing.type: Easing.OutCubic }
}
- Text {
- id: label
- anchors.centerIn: parent
- text: M.FlyoutState.text.replace(/\n/g, "
")
- textFormat: Text.RichText
- color: M.Theme.base05
- font.pixelSize: M.Theme.fontSize
- font.family: M.Theme.fontFamily
+ ParallelAnimation {
+ id: hideAnim
+ NumberAnimation { target: content; property: "opacity"; to: 0; duration: 150; easing.type: Easing.InCubic }
+ NumberAnimation { target: content; property: "y"; to: -content.height; duration: 150; easing.type: Easing.InCubic }
+ onFinished: root._winVisible = false
+ }
+
+ Item {
+ id: content
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: root.implicitHeight
+ opacity: 0
+ y: -height
+
+ Rectangle {
+ anchors.fill: parent
+ color: M.Theme.base00
+ opacity: Math.max(M.Theme.barOpacity, 0.85)
+ topLeftRadius: 0
+ topRightRadius: 0
+ bottomLeftRadius: M.Theme.radius
+ bottomRightRadius: M.Theme.radius
+ }
+
+ Text {
+ id: label
+ anchors.centerIn: parent
+ text: M.FlyoutState.text.replace(/\n/g, "
")
+ textFormat: Text.RichText
+ color: M.Theme.base05
+ font.pixelSize: M.Theme.fontSize
+ font.family: M.Theme.fontFamily
+ }
}
}
diff --git a/modules/Osd.qml b/modules/Osd.qml
index 9e7a47a..49ee87d 100644
--- a/modules/Osd.qml
+++ b/modules/Osd.qml
@@ -4,16 +4,28 @@ import Quickshell.Wayland
import "." as M
// OSD overlay — slides out from the bar, centered on screen.
-// Attached to the bar (square top corners, flush below it).
PanelWindow {
id: root
required property var screen
- // Stay visible while animating out
- visible: M.OsdState.visible || hideAnim.running
+ visible: _winVisible
color: "transparent"
+ property bool _winVisible: false
+ property bool _shown: M.OsdState.visible
+
+ on_ShownChanged: {
+ if (_shown) {
+ _winVisible = true;
+ hideAnim.stop();
+ showAnim.start();
+ } else {
+ showAnim.stop();
+ hideAnim.start();
+ }
+ }
+
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.exclusiveZone: 0
WlrLayershell.namespace: "nova-osd"
@@ -28,18 +40,6 @@ PanelWindow {
implicitWidth: 200
implicitHeight: 48
- // Slide + fade animation state
- property bool _shown: M.OsdState.visible
- on_ShownChanged: {
- if (_shown) {
- hideAnim.stop();
- showAnim.start();
- } else {
- showAnim.stop();
- hideAnim.start();
- }
- }
-
ParallelAnimation {
id: showAnim
NumberAnimation { target: content; property: "opacity"; to: 1; duration: 150; easing.type: Easing.OutCubic }
@@ -50,6 +50,7 @@ PanelWindow {
id: hideAnim
NumberAnimation { target: content; property: "opacity"; to: 0; duration: 250; easing.type: Easing.InCubic }
NumberAnimation { target: content; property: "y"; to: -content.height; duration: 250; easing.type: Easing.InCubic }
+ onFinished: root._winVisible = false
}
Item {
@@ -60,7 +61,6 @@ PanelWindow {
opacity: 0
y: -height
- // Background — flush with bar above
Rectangle {
anchors.fill: parent
color: M.Theme.base00
@@ -75,7 +75,6 @@ PanelWindow {
anchors.centerIn: parent
spacing: 10
- // Icon
Text {
text: M.OsdState.icon
color: M.Theme.base0D
@@ -84,7 +83,6 @@ PanelWindow {
anchors.verticalCenter: parent.verticalCenter
}
- // Progress bar
Item {
width: 120
height: 6
@@ -108,7 +106,6 @@ PanelWindow {
}
}
- // Percentage
Text {
text: Math.round(M.OsdState.value * 100) + "%"
color: M.Theme.base05