mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
101b27fcc7
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.
310 lines
11 KiB
QML
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
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|