Files
noctalia-shell/Modules/Bar/Bar.qml
T
ItsLemmy 101b27fcc7 New windowing system
Large commit that totally refactor of the way we handle the bar and
panels.

Testing should focus on Panels, Bar, Keyboard Focus, IPC calls.

Changes brief:
- One NFullScreenWindow per screen which handle it's bar and dedicated
panels.
- Added shadows
- Reintroduced dimming
- New panels animations
- Proper Z ordering
- Panels on overlay laywer is not reimplemented, if we do it then the
bar will be on the Overlay too
- Panel dragging was not reimplemented, to be discussed before
reimplementing
- Still a WIP, need to work more on shadows and polishing + debugging.
2025-11-03 00:53:02 -05:00

310 lines
11 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Wayland
import Quickshell.Services.UPower
import qs.Commons
import qs.Services
import qs.Widgets
import qs.Modules.Notification
import qs.Modules.Bar.Extras
// Bar Component
Item {
id: root
// This property will be set by NFullScreenWindow
property ShellScreen screen: null
// Expose bar region for click-through mask
readonly property var barRegion: barContentLoader.item?.children[0] || null
// Bar positioning properties
readonly property string barPosition: Settings.data.bar.position || "top"
readonly property bool barIsVertical: barPosition === "left" || barPosition === "right"
readonly property bool barFloating: Settings.data.bar.floating || false
readonly property real barMarginH: barFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0
readonly property real barMarginV: barFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0
// Fill the parent (the Loader)
anchors.fill: parent
// Register bar when screen becomes available
onScreenChanged: {
if (screen && screen.name) {
Logger.d("Bar", "Bar screen set to:", screen.name)
Logger.d("Bar", " Position:", barPosition, "Floating:", barFloating)
Logger.d("Bar", " Margins - H:", barMarginH, "V:", barMarginV)
BarService.registerBar(screen.name)
}
}
// Wait for screen to be set before loading bar content
Loader {
id: barContentLoader
anchors.fill: parent
active: root.screen !== null && root.screen !== undefined
sourceComponent: Item {
anchors.fill: parent
// Background fill with shadow
NShapedRectangle {
id: bar
// Position and size the bar based on orientation and floating margins
x: (root.barPosition === "right") ? (parent.width - Style.barHeight - root.barMarginH) : root.barMarginH
y: (root.barPosition === "bottom") ? (parent.height - Style.barHeight - root.barMarginV) : root.barMarginV
width: root.barIsVertical ? Style.barHeight : (parent.width - root.barMarginH * 2)
height: root.barIsVertical ? (parent.height - root.barMarginV * 2) : Style.barHeight
backgroundColor: Qt.alpha(Color.mSurface, Settings.data.bar.backgroundOpacity)
// Floating bar rounded corners
topLeftRadius: Settings.data.bar.floating || topLeftInverted ? Style.radiusL : 0
topRightRadius: Settings.data.bar.floating || topRightInverted ? Style.radiusL : 0
bottomLeftRadius: Settings.data.bar.floating || bottomLeftInverted ? Style.radiusL : 0
bottomRightRadius: Settings.data.bar.floating || bottomRightInverted ? Style.radiusL : 0
topLeftInverted: Settings.data.bar.outerCorners && (barPosition === "bottom" || barPosition === "right")
topLeftInvertedDirection: barIsVertical ? "horizontal" : "vertical"
topRightInverted: Settings.data.bar.outerCorners && (barPosition === "bottom" || barPosition === "left")
topRightInvertedDirection: barIsVertical ? "horizontal" : "vertical"
bottomLeftInverted: Settings.data.bar.outerCorners && (barPosition === "top" || barPosition === "right")
bottomLeftInvertedDirection: barIsVertical ? "horizontal" : "vertical"
bottomRightInverted: Settings.data.bar.outerCorners && (barPosition === "top" || barPosition === "left")
bottomRightInvertedDirection: barIsVertical ? "horizontal" : "vertical"
// No border on the bar
borderWidth: 0
// Shadow configuration
shadowEnabled: true
shadowBlur: 0.5
// Fade shadow progressively when a panel is attached to the bar to avoid visual disconnection
// shadowOpacity: {
// if (PanelService.openedPanel && PanelService.openedPanel.attachedToBar) {
// // Fade shadow out as panel opens (animationProgress goes from 0 to 1)
// return 1.0 - PanelService.openedPanel.animationProgress
// }
// return 1.0
// }
Behavior on shadowOpacity {
NumberAnimation {
duration: Style.animationFast
easing.type: Easing.OutCubic
}
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
hoverEnabled: false
preventStealing: true
onClicked: function (mouse) {
if (mouse.button === Qt.RightButton) {
// Look up for any ControlCenter button on this bar
var widget = BarService.lookupWidget("ControlCenter", root.screen.name)
// Open the panel near the button if any
PanelService.getPanel("controlCenterPanel", root.screen)?.toggle(widget)
mouse.accepted = true
}
}
}
Loader {
anchors.fill: parent
sourceComponent: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? verticalBarComponent : horizontalBarComponent
}
}
}
}
// For vertical bars
Component {
id: verticalBarComponent
Item {
anchors.fill: parent
clip: true
// Top section (left widgets)
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: Style.marginM
spacing: Style.marginS
Repeater {
model: Settings.data.bar.widgets.left
delegate: BarWidgetLoader {
required property var modelData
required property int index
widgetId: modelData.id || ""
barDensity: Settings.data.bar.density
widgetScreen: root.screen
widgetProps: ({
"widgetId": modelData.id,
"section": "left",
"sectionWidgetIndex": index,
"sectionWidgetsCount": Settings.data.bar.widgets.left.length
})
Layout.alignment: Qt.AlignHCenter
}
}
}
// Center section (center widgets)
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
spacing: Style.marginS
Repeater {
model: Settings.data.bar.widgets.center
delegate: BarWidgetLoader {
required property var modelData
required property int index
widgetId: modelData.id || ""
barDensity: Settings.data.bar.density
widgetScreen: root.screen
widgetProps: ({
"widgetId": modelData.id,
"section": "center",
"sectionWidgetIndex": index,
"sectionWidgetsCount": Settings.data.bar.widgets.center.length
})
Layout.alignment: Qt.AlignHCenter
}
}
}
// Bottom section (right widgets)
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: Style.marginM
spacing: Style.marginS
Repeater {
model: Settings.data.bar.widgets.right
delegate: BarWidgetLoader {
required property var modelData
required property int index
widgetId: modelData.id || ""
barDensity: Settings.data.bar.density
widgetScreen: root.screen
widgetProps: ({
"widgetId": modelData.id,
"section": "right",
"sectionWidgetIndex": index,
"sectionWidgetsCount": Settings.data.bar.widgets.right.length
})
Layout.alignment: Qt.AlignHCenter
}
}
}
}
}
// For horizontal bars
Component {
id: horizontalBarComponent
Item {
anchors.fill: parent
clip: true
// Left Section
RowLayout {
id: leftSection
objectName: "leftSection"
anchors.left: parent.left
anchors.leftMargin: Style.marginS
anchors.verticalCenter: parent.verticalCenter
spacing: Style.marginS
Repeater {
model: Settings.data.bar.widgets.left
delegate: BarWidgetLoader {
required property var modelData
required property int index
widgetId: modelData.id || ""
barDensity: Settings.data.bar.density
widgetScreen: root.screen
widgetProps: ({
"widgetId": modelData.id,
"section": "left",
"sectionWidgetIndex": index,
"sectionWidgetsCount": Settings.data.bar.widgets.left.length
})
Layout.alignment: Qt.AlignVCenter
}
}
}
// Center Section
RowLayout {
id: centerSection
objectName: "centerSection"
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
spacing: Style.marginS
Repeater {
model: Settings.data.bar.widgets.center
delegate: BarWidgetLoader {
required property var modelData
required property int index
widgetId: modelData.id || ""
barDensity: Settings.data.bar.density
widgetScreen: root.screen
widgetProps: ({
"widgetId": modelData.id,
"section": "center",
"sectionWidgetIndex": index,
"sectionWidgetsCount": Settings.data.bar.widgets.center.length
})
Layout.alignment: Qt.AlignVCenter
}
}
}
// Right Section
RowLayout {
id: rightSection
objectName: "rightSection"
anchors.right: parent.right
anchors.rightMargin: Style.marginS
anchors.verticalCenter: parent.verticalCenter
spacing: Style.marginS
Repeater {
model: Settings.data.bar.widgets.right
delegate: BarWidgetLoader {
required property var modelData
required property int index
widgetId: modelData.id || ""
barDensity: Settings.data.bar.density
widgetScreen: root.screen
widgetProps: ({
"widgetId": modelData.id,
"section": "right",
"sectionWidgetIndex": index,
"sectionWidgetsCount": Settings.data.bar.widgets.right.length
})
Layout.alignment: Qt.AlignVCenter
}
}
}
}
}
}