Compare commits

..

No commits in common. "0fd3c78fb035f10e0ec5bf353d9a7ddba95b8f82" and "c5067c4e7ffabf719c204ba4137bd11ba14aa68d" have entirely different histories.

13 changed files with 896 additions and 726 deletions

View file

@ -1,6 +1,7 @@
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import "." as M
M.BarSection {
@ -11,8 +12,9 @@ M.BarSection {
tooltip: ""
property int percent: 0
property bool _panelHovered: false
property bool _osdActive: false
readonly property bool _showPanel: root._hovered || hoverPanel.panelHovered || _osdActive
readonly property bool _showPanel: root._hovered || _panelHovered || _osdActive
onPercentChanged: if (percent > 0)
_flashPanel()
@ -95,13 +97,103 @@ M.BarSection {
onWheel: event => root.adjust(event.angleDelta.y)
}
M.HoverPanel {
id: hoverPanel
showPanel: root._showPanel
anchorX: root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0)
accentColor: root.accentColor
panelNamespace: "nova-backlight"
contentWidth: 200
PanelWindow {
id: panel
screen: QsWindow.window?.screen ?? null
visible: _winVisible
color: "transparent"
property bool _winVisible: false
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.exclusiveZone: 0
WlrLayershell.namespace: "nova-backlight"
anchors.top: true
anchors.left: true
margins.top: 0
margins.left: Math.max(0, Math.min(Math.round(root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0) - implicitWidth / 2), (panel.screen?.width ?? 1920) - implicitWidth))
implicitWidth: panelContent.width
implicitHeight: panelContent.height
Connections {
target: root
function on_ShowPanelChanged() {
if (root._showPanel) {
panel._winVisible = true;
hideAnim.stop();
showAnim.start();
} else {
showAnim.stop();
hideAnim.start();
}
}
}
ParallelAnimation {
id: showAnim
NumberAnimation {
target: panelContent
property: "opacity"
to: 1
duration: 120
easing.type: Easing.OutCubic
}
NumberAnimation {
target: panelContent
property: "y"
to: 0
duration: 150
easing.type: Easing.OutCubic
}
}
ParallelAnimation {
id: hideAnim
NumberAnimation {
target: panelContent
property: "opacity"
to: 0
duration: 150
easing.type: Easing.InCubic
}
NumberAnimation {
target: panelContent
property: "y"
to: -panelContent.height
duration: 150
easing.type: Easing.InCubic
}
onFinished: panel._winVisible = false
}
HoverHandler {
onHoveredChanged: root._panelHovered = hovered
}
Rectangle {
x: panelContent.x
y: panelContent.y
width: panelContent.width
height: panelContent.height
color: M.Theme.base01
opacity: panelContent.opacity * Math.max(M.Theme.barOpacity, 0.85)
topLeftRadius: 0
topRightRadius: 0
bottomLeftRadius: M.Theme.radius
bottomRightRadius: M.Theme.radius
border.color: root.accentColor
border.width: 1
}
Column {
id: panelContent
width: 200
opacity: 0
y: -height
Item {
width: parent.width
@ -175,3 +267,4 @@ M.BarSection {
}
}
}
}

View file

@ -101,10 +101,10 @@ M.BarSection {
}
}
LazyLoader {
Loader {
id: menuLoader
active: false
M.BluetoothMenu {
sourceComponent: M.BluetoothMenu {
accentColor: root.accentColor
screen: root.bar.screen
anchorX: root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0)

View file

@ -83,9 +83,16 @@ PanelWindow {
opacity: 0
y: -height
M.PopupBackground {
Rectangle {
anchors.fill: parent
accentColor: M.FlyoutState.accentColor
color: M.Theme.base01
opacity: Math.max(M.Theme.barOpacity, 0.85)
topLeftRadius: 0
topRightRadius: 0
bottomLeftRadius: M.Theme.radius
bottomRightRadius: M.Theme.radius
border.color: M.FlyoutState.accentColor
border.width: 1
}
Text {

View file

@ -1,115 +0,0 @@
import QtQuick
import Quickshell
import Quickshell.Wayland
import "." as M
// Shared hover/OSD panel PanelWindow slides down from the bar on hover or
// external trigger. Parent module computes showPanel and reads panelHovered.
PanelWindow {
id: root
required property bool showPanel
required property real anchorX
required property color accentColor
property string panelNamespace: "nova-panel"
property real contentWidth: 220
property bool animateHeight: false
property bool panelHovered: false
default property alias content: panelContent.children
screen: QsWindow.window?.screen ?? null
visible: _winVisible
color: "transparent"
property bool _winVisible: false
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.exclusiveZone: 0
WlrLayershell.namespace: root.panelNamespace
anchors.top: true
anchors.left: true
margins.top: 0
margins.left: Math.max(0, Math.min(Math.round(anchorX - implicitWidth / 2), (screen?.width ?? 1920) - implicitWidth))
implicitWidth: panelContent.width
implicitHeight: panelContent.height
Behavior on implicitHeight {
enabled: root.animateHeight
NumberAnimation {
duration: 100
easing.type: Easing.OutCubic
}
}
onShowPanelChanged: {
if (showPanel) {
_winVisible = true;
hideAnim.stop();
showAnim.start();
} else {
showAnim.stop();
hideAnim.start();
}
}
ParallelAnimation {
id: showAnim
NumberAnimation {
target: panelContent
property: "opacity"
to: 1
duration: 120
easing.type: Easing.OutCubic
}
NumberAnimation {
target: panelContent
property: "y"
to: 0
duration: 150
easing.type: Easing.OutCubic
}
}
ParallelAnimation {
id: hideAnim
NumberAnimation {
target: panelContent
property: "opacity"
to: 0
duration: 150
easing.type: Easing.InCubic
}
NumberAnimation {
target: panelContent
property: "y"
to: -panelContent.height
duration: 150
easing.type: Easing.InCubic
}
onFinished: root._winVisible = false
}
HoverHandler {
onHoveredChanged: root.panelHovered = hovered
}
M.PopupBackground {
x: panelContent.x
y: panelContent.y
width: panelContent.width
height: panelContent.height
opacity: panelContent.opacity * Math.max(M.Theme.barOpacity, 0.85)
accentColor: root.accentColor
}
Column {
id: panelContent
width: root.contentWidth
opacity: 0
y: -height
}
}

View file

@ -1,6 +1,7 @@
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Services.Mpris
import "." as M
@ -57,8 +58,9 @@ M.BarSection {
required property var bar
property bool _panelHovered: false
property bool _pinned: false
readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered
readonly property bool _anyHover: root._hovered || _panelHovered
readonly property bool _showPanel: _anyHover || _pinned
on_AnyHoverChanged: {
@ -95,14 +97,112 @@ M.BarSection {
}
}
M.HoverPanel {
id: hoverPanel
showPanel: root._showPanel
anchorX: root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0)
accentColor: root.accentColor
panelNamespace: "nova-mpris"
contentWidth: 280
animateHeight: true
PanelWindow {
id: panel
screen: QsWindow.window?.screen ?? null
visible: _winVisible
color: "transparent"
property bool _winVisible: false
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.exclusiveZone: 0
WlrLayershell.namespace: "nova-mpris"
anchors.top: true
anchors.left: true
margins.top: 0
margins.left: Math.max(0, Math.min(Math.round(root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0) - implicitWidth / 2), (panel.screen?.width ?? 1920) - implicitWidth))
implicitWidth: panelContent.width
implicitHeight: panelContent.height
Behavior on implicitHeight {
NumberAnimation {
duration: 100
easing.type: Easing.OutCubic
}
}
Connections {
target: root
function on_ShowPanelChanged() {
if (root._showPanel) {
panel._winVisible = true;
hideAnim.stop();
showAnim.start();
} else {
showAnim.stop();
hideAnim.start();
}
}
}
ParallelAnimation {
id: showAnim
NumberAnimation {
target: panelContent
property: "opacity"
to: 1
duration: 120
easing.type: Easing.OutCubic
}
NumberAnimation {
target: panelContent
property: "y"
to: 0
duration: 150
easing.type: Easing.OutCubic
}
}
ParallelAnimation {
id: hideAnim
NumberAnimation {
target: panelContent
property: "opacity"
to: 0
duration: 150
easing.type: Easing.InCubic
}
NumberAnimation {
target: panelContent
property: "y"
to: -panelContent.height
duration: 150
easing.type: Easing.InCubic
}
onFinished: panel._winVisible = false
}
HoverHandler {
onHoveredChanged: root._panelHovered = hovered
}
Rectangle {
x: panelContent.x
y: panelContent.y
width: panelContent.width
height: panelContent.height
color: M.Theme.base01
opacity: panelContent.opacity * Math.max(M.Theme.barOpacity, 0.85)
topLeftRadius: 0
topRightRadius: 0
bottomLeftRadius: M.Theme.radius
bottomRightRadius: M.Theme.radius
border.color: root.accentColor
border.width: 1
}
Column {
id: panelContent
width: 280
opacity: 0
y: -height
topPadding: 4
bottomPadding: 4
spacing: 2
// Album art
Item {
@ -385,3 +485,4 @@ M.BarSection {
}
}
}
}

View file

@ -121,10 +121,10 @@ M.BarSection {
}
}
LazyLoader {
Loader {
id: menuLoader
active: false
M.NetworkMenu {
sourceComponent: M.NetworkMenu {
accentColor: root.accentColor
screen: root.bar.screen
anchorX: root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0)

View file

@ -77,10 +77,10 @@ M.BarSection {
onTapped: M.NotifService.toggleDnd()
}
LazyLoader {
Loader {
id: centerLoader
active: false
M.NotifCenter {
sourceComponent: M.NotifCenter {
accentColor: root.accentColor
screen: root.bar.screen
anchorX: root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0)

View file

@ -1,15 +0,0 @@
import QtQuick
import "." as M
Rectangle {
property color accentColor: M.Theme.base05
color: M.Theme.base01
opacity: Math.max(M.Theme.barOpacity, 0.85)
topLeftRadius: 0
topRightRadius: 0
bottomLeftRadius: M.Theme.radius
bottomRightRadius: M.Theme.radius
border.color: accentColor
border.width: 1
}

View file

@ -56,9 +56,16 @@ PanelWindow {
anchors.fill: parent
}
M.PopupBackground {
Rectangle {
anchors.fill: parent
accentColor: root.accentColor
color: M.Theme.base01
opacity: Math.max(M.Theme.barOpacity, 0.85)
topLeftRadius: 0
topRightRadius: 0
bottomLeftRadius: M.Theme.radius
bottomRightRadius: M.Theme.radius
border.color: root.accentColor
border.width: 1
}
Column {

View file

@ -23,11 +23,11 @@ M.BarIcon {
}
}
LazyLoader {
Loader {
id: menuLoader
active: false
M.PowerMenu {
accentColor: root.accentColor
sourceComponent: M.PowerMenu {
accentColor: parent?.accentColor ?? root.color
screen: root.bar.screen
anchorX: root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0)
onDismissed: menuLoader.active = false

View file

@ -105,10 +105,10 @@ RowLayout {
}
// Per-icon context menu window, created on demand
LazyLoader {
Loader {
id: menuLoader
active: false
M.TrayMenu {
sourceComponent: M.TrayMenu {
accentColor: root.parent?.accentColor ?? M.Theme.base05
handle: iconItem.modelData.menu
screen: root.bar.screen

View file

@ -1,5 +1,6 @@
import QtQuick
import Quickshell
import Quickshell.Wayland
import Quickshell.Services.Pipewire
import "." as M
@ -39,13 +40,11 @@ M.BarSection {
}
property bool _expanded: false
property bool _panelHovered: false
property bool _osdActive: false
readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered
readonly property bool _anyHover: root._hovered || _panelHovered
readonly property bool _showPanel: _anyHover || _expanded || _osdActive
on_ShowPanelChanged: if (!_showPanel)
_expanded = false
onVolumeChanged: _flashPanel()
onMutedChanged: _flashPanel()
@ -105,13 +104,107 @@ M.BarSection {
}
// Unified volume panel hover shows slider, click expands to show devices
M.HoverPanel {
id: hoverPanel
showPanel: root._showPanel
anchorX: root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0)
accentColor: root.accentColor
panelNamespace: "nova-volume"
contentWidth: 220
PanelWindow {
id: panel
screen: QsWindow.window?.screen ?? null
visible: _winVisible
color: "transparent"
property bool _winVisible: false
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.exclusiveZone: 0
WlrLayershell.namespace: "nova-volume"
anchors.top: true
anchors.left: true
margins.top: 0
margins.left: Math.max(0, Math.min(Math.round(root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0) - implicitWidth / 2), (panel.screen?.width ?? 1920) - implicitWidth))
implicitWidth: panelContent.width
implicitHeight: panelContent.height
// Show/hide logic
Connections {
target: root
function on_ShowPanelChanged() {
if (root._showPanel) {
panel._winVisible = true;
hideAnim.stop();
showAnim.start();
} else {
root._expanded = false;
showAnim.stop();
hideAnim.start();
}
}
}
ParallelAnimation {
id: showAnim
NumberAnimation {
target: panelContent
property: "opacity"
to: 1
duration: 120
easing.type: Easing.OutCubic
}
NumberAnimation {
target: panelContent
property: "y"
to: 0
duration: 150
easing.type: Easing.OutCubic
}
}
ParallelAnimation {
id: hideAnim
NumberAnimation {
target: panelContent
property: "opacity"
to: 0
duration: 150
easing.type: Easing.InCubic
}
NumberAnimation {
target: panelContent
property: "y"
to: -panelContent.height
duration: 150
easing.type: Easing.InCubic
}
onFinished: panel._winVisible = false
}
// Keep panel open when mouse is over it
HoverHandler {
onHoveredChanged: root._panelHovered = hovered
// Click inside panel doesn't dismiss
}
Rectangle {
x: panelContent.x
y: panelContent.y
width: panelContent.width
height: panelContent.height
color: M.Theme.base01
opacity: panelContent.opacity * Math.max(M.Theme.barOpacity, 0.85)
topLeftRadius: 0
topRightRadius: 0
bottomLeftRadius: M.Theme.radius
bottomRightRadius: M.Theme.radius
border.color: root.accentColor
border.width: 1
}
Column {
id: panelContent
width: 220
opacity: 0
y: -height
// Compact: slider row
Item {
@ -422,3 +515,4 @@ M.BarSection {
}
}
}
}

View file

@ -13,8 +13,6 @@ Volume 1.0 Volume.qml
Tray 1.0 Tray.qml
TrayMenu 1.0 TrayMenu.qml
PopupPanel 1.0 PopupPanel.qml
PopupBackground 1.0 PopupBackground.qml
HoverPanel 1.0 HoverPanel.qml
PowerMenu 1.0 PowerMenu.qml
ScreenCorners 1.0 ScreenCorners.qml
ThemedIcon 1.0 ThemedIcon.qml