First iteration of vertical bar
This commit is contained in:
parent
25ba27cbdd
commit
4f5acb7114
7 changed files with 744 additions and 128 deletions
|
|
@ -263,7 +263,7 @@ Singleton {
|
||||||
|
|
||||||
// bar
|
// bar
|
||||||
property JsonObject bar: JsonObject {
|
property JsonObject bar: JsonObject {
|
||||||
property string position: "top" // "top" or "bottom"
|
property string position: "top" // "top", "bottom", "left", or "right"
|
||||||
property real backgroundOpacity: 1.0
|
property real backgroundOpacity: 1.0
|
||||||
property list<string> monitors: []
|
property list<string> monitors: []
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,14 +34,15 @@ Variants {
|
||||||
|
|
||||||
WlrLayershell.namespace: "noctalia-bar"
|
WlrLayershell.namespace: "noctalia-bar"
|
||||||
|
|
||||||
implicitHeight: Math.round(Style.barHeight * scaling)
|
implicitHeight: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? screen.height : Math.round(Style.barHeight * scaling)
|
||||||
|
implicitWidth: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? Math.round(Style.barHeight * scaling) : screen.width
|
||||||
color: Color.transparent
|
color: Color.transparent
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
top: Settings.data.bar.position === "top"
|
top: Settings.data.bar.position === "top" || Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
||||||
bottom: Settings.data.bar.position === "bottom"
|
bottom: Settings.data.bar.position === "bottom" || Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
||||||
left: true
|
left: Settings.data.bar.position === "left" || Settings.data.bar.position === "top" || Settings.data.bar.position === "bottom"
|
||||||
right: true
|
right: Settings.data.bar.position === "right" || Settings.data.bar.position === "top" || Settings.data.bar.position === "bottom"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Floating bar margins - only apply when floating is enabled
|
// Floating bar margins - only apply when floating is enabled
|
||||||
|
|
@ -67,91 +68,197 @@ Variants {
|
||||||
radius: Settings.data.bar.floating ? Settings.data.bar.rounding : 0
|
radius: Settings.data.bar.floating ? Settings.data.bar.rounding : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------
|
// For vertical bars, use a single column layout
|
||||||
// Left Section - Dynamic Widgets
|
Loader {
|
||||||
Row {
|
id: verticalBarLayout
|
||||||
id: leftSection
|
anchors.fill: parent
|
||||||
objectName: "leftSection"
|
visible: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
||||||
|
sourceComponent: verticalBarComponent
|
||||||
|
}
|
||||||
|
|
||||||
height: parent.height
|
// For horizontal bars, use the original three-section layout
|
||||||
anchors.left: parent.left
|
Loader {
|
||||||
anchors.leftMargin: Style.marginS * scaling
|
id: horizontalBarLayout
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.fill: parent
|
||||||
spacing: Style.marginS * scaling
|
visible: Settings.data.bar.position === "top" || Settings.data.bar.position === "bottom"
|
||||||
|
sourceComponent: horizontalBarComponent
|
||||||
|
}
|
||||||
|
|
||||||
Repeater {
|
// Main layout components
|
||||||
model: Settings.data.bar.widgets.left
|
Component {
|
||||||
delegate: NWidgetLoader {
|
id: verticalBarComponent
|
||||||
widgetId: (modelData.id !== undefined ? modelData.id : "")
|
Item {
|
||||||
widgetProps: {
|
anchors.fill: parent
|
||||||
"screen": root.modelData || null,
|
|
||||||
"scaling": ScalingService.getScreenScale(screen),
|
// Top section (left widgets)
|
||||||
"widgetId": modelData.id,
|
Column {
|
||||||
"section": parent.objectName.replace("Section", "").toLowerCase(),
|
spacing: Style.marginS * root.scaling
|
||||||
"sectionWidgetIndex": index,
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
"sectionWidgetsCount": Settings.data.bar.widgets.left.length
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: Style.marginM * root.scaling
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: Settings.data.bar.widgets.left
|
||||||
|
delegate: NWidgetLoader {
|
||||||
|
widgetId: (modelData.id !== undefined ? modelData.id : "")
|
||||||
|
widgetProps: {
|
||||||
|
"screen": root.modelData || null,
|
||||||
|
"scaling": ScalingService.getScreenScale(screen),
|
||||||
|
"widgetId": modelData.id,
|
||||||
|
"section": "left",
|
||||||
|
"sectionWidgetIndex": index,
|
||||||
|
"sectionWidgetsCount": Settings.data.bar.widgets.left.length,
|
||||||
|
"barPosition": Settings.data.bar.position
|
||||||
|
}
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Center section (center widgets)
|
||||||
|
Column {
|
||||||
|
spacing: Style.marginS * root.scaling
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: Settings.data.bar.widgets.center
|
||||||
|
delegate: NWidgetLoader {
|
||||||
|
widgetId: (modelData.id !== undefined ? modelData.id : "")
|
||||||
|
widgetProps: {
|
||||||
|
"screen": root.modelData || null,
|
||||||
|
"scaling": ScalingService.getScreenScale(screen),
|
||||||
|
"widgetId": modelData.id,
|
||||||
|
"section": "center",
|
||||||
|
"sectionWidgetIndex": index,
|
||||||
|
"sectionWidgetsCount": Settings.data.bar.widgets.center.length,
|
||||||
|
"barPosition": Settings.data.bar.position
|
||||||
|
}
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom section (right widgets)
|
||||||
|
Column {
|
||||||
|
spacing: Style.marginS * root.scaling
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: Style.marginM * root.scaling
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: Settings.data.bar.widgets.right
|
||||||
|
delegate: NWidgetLoader {
|
||||||
|
widgetId: (modelData.id !== undefined ? modelData.id : "")
|
||||||
|
widgetProps: {
|
||||||
|
"screen": root.modelData || null,
|
||||||
|
"scaling": ScalingService.getScreenScale(screen),
|
||||||
|
"widgetId": modelData.id,
|
||||||
|
"section": "right",
|
||||||
|
"sectionWidgetIndex": index,
|
||||||
|
"sectionWidgetsCount": Settings.data.bar.widgets.right.length,
|
||||||
|
"barPosition": Settings.data.bar.position
|
||||||
|
}
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------
|
Component {
|
||||||
// Center Section - Dynamic Widgets
|
id: horizontalBarComponent
|
||||||
Row {
|
Row {
|
||||||
id: centerSection
|
anchors.fill: parent
|
||||||
objectName: "centerSection"
|
|
||||||
|
// Left Section
|
||||||
height: parent.height
|
Row {
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
id: leftSection
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
objectName: "leftSection"
|
||||||
spacing: Style.marginS * scaling
|
height: parent.height
|
||||||
|
anchors.left: parent.left
|
||||||
Repeater {
|
anchors.leftMargin: Style.marginS * root.scaling
|
||||||
model: Settings.data.bar.widgets.center
|
|
||||||
delegate: NWidgetLoader {
|
|
||||||
widgetId: (modelData.id !== undefined ? modelData.id : "")
|
|
||||||
widgetProps: {
|
|
||||||
"screen": root.modelData || null,
|
|
||||||
"scaling": ScalingService.getScreenScale(screen),
|
|
||||||
"widgetId": modelData.id,
|
|
||||||
"section": parent.objectName.replace("Section", "").toLowerCase(),
|
|
||||||
"sectionWidgetIndex": index,
|
|
||||||
"sectionWidgetsCount": Settings.data.bar.widgets.center.length
|
|
||||||
}
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Style.marginS * root.scaling
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: Settings.data.bar.widgets.left
|
||||||
|
delegate: NWidgetLoader {
|
||||||
|
widgetId: (modelData.id !== undefined ? modelData.id : "")
|
||||||
|
widgetProps: {
|
||||||
|
"screen": root.modelData || null,
|
||||||
|
"scaling": ScalingService.getScreenScale(screen),
|
||||||
|
"widgetId": modelData.id,
|
||||||
|
"section": "left",
|
||||||
|
"sectionWidgetIndex": index,
|
||||||
|
"sectionWidgetsCount": Settings.data.bar.widgets.left.length,
|
||||||
|
"barPosition": Settings.data.bar.position
|
||||||
|
}
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Center Section
|
||||||
|
Row {
|
||||||
|
id: centerSection
|
||||||
|
objectName: "centerSection"
|
||||||
|
height: parent.height
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Style.marginS * root.scaling
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: Settings.data.bar.widgets.center
|
||||||
|
delegate: NWidgetLoader {
|
||||||
|
widgetId: (modelData.id !== undefined ? modelData.id : "")
|
||||||
|
widgetProps: {
|
||||||
|
"screen": root.modelData || null,
|
||||||
|
"scaling": ScalingService.getScreenScale(screen),
|
||||||
|
"widgetId": modelData.id,
|
||||||
|
"section": "center",
|
||||||
|
"sectionWidgetIndex": index,
|
||||||
|
"sectionWidgetsCount": Settings.data.bar.widgets.center.length,
|
||||||
|
"barPosition": Settings.data.bar.position
|
||||||
|
}
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right Section
|
||||||
|
Row {
|
||||||
|
id: rightSection
|
||||||
|
objectName: "rightSection"
|
||||||
|
height: parent.height
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Style.marginS * root.scaling
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Style.marginS * root.scaling
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: Settings.data.bar.widgets.right
|
||||||
|
delegate: NWidgetLoader {
|
||||||
|
widgetId: (modelData.id !== undefined ? modelData.id : "")
|
||||||
|
widgetProps: {
|
||||||
|
"screen": root.modelData || null,
|
||||||
|
"scaling": ScalingService.getScreenScale(screen),
|
||||||
|
"widgetId": modelData.id,
|
||||||
|
"section": "right",
|
||||||
|
"sectionWidgetIndex": index,
|
||||||
|
"sectionWidgetsCount": Settings.data.bar.widgets.right.length,
|
||||||
|
"barPosition": Settings.data.bar.position
|
||||||
|
}
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------
|
|
||||||
// Right Section - Dynamic Widgets
|
|
||||||
Row {
|
|
||||||
id: rightSection
|
|
||||||
objectName: "rightSection"
|
|
||||||
|
|
||||||
height: parent.height
|
|
||||||
anchors.right: bar.right
|
|
||||||
anchors.rightMargin: Style.marginS * scaling
|
|
||||||
anchors.verticalCenter: bar.verticalCenter
|
|
||||||
spacing: Style.marginS * scaling
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: Settings.data.bar.widgets.right
|
|
||||||
delegate: NWidgetLoader {
|
|
||||||
widgetId: (modelData.id !== undefined ? modelData.id : "")
|
|
||||||
widgetProps: {
|
|
||||||
"screen": root.modelData || null,
|
|
||||||
"scaling": ScalingService.getScreenScale(screen),
|
|
||||||
"widgetId": modelData.id,
|
|
||||||
"section": parent.objectName.replace("Section", "").toLowerCase(),
|
|
||||||
"sectionWidgetIndex": index,
|
|
||||||
"sectionWidgetsCount": Settings.data.bar.widgets.right.length
|
|
||||||
}
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import qs.Commons
|
||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
RowLayout {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
property ShellScreen screen
|
property ShellScreen screen
|
||||||
property real scaling: 1.0
|
property real scaling: 1.0
|
||||||
|
|
@ -18,6 +18,7 @@ RowLayout {
|
||||||
property string section: ""
|
property string section: ""
|
||||||
property int sectionWidgetIndex: -1
|
property int sectionWidgetIndex: -1
|
||||||
property int sectionWidgetsCount: 0
|
property int sectionWidgetsCount: 0
|
||||||
|
property string barPosition: "top"
|
||||||
|
|
||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
|
|
@ -36,6 +37,9 @@ RowLayout {
|
||||||
readonly property real minWidth: Math.max(1, screen.width * 0.06)
|
readonly property real minWidth: Math.max(1, screen.width * 0.06)
|
||||||
readonly property real maxWidth: minWidth * 2
|
readonly property real maxWidth: minWidth * 2
|
||||||
|
|
||||||
|
implicitHeight: (barPosition === "left" || barPosition === "right") ? calculatedVerticalHeight() : Math.round(Style.barHeight * scaling)
|
||||||
|
implicitWidth: (barPosition === "left" || barPosition === "right") ? Math.round(Style.capsuleHeight * scaling) : calculatedHorizontalWidth()
|
||||||
|
|
||||||
function getTitle() {
|
function getTitle() {
|
||||||
try {
|
try {
|
||||||
return CompositorService.focusedWindowTitle !== "(No active window)" ? CompositorService.focusedWindowTitle : ""
|
return CompositorService.focusedWindowTitle !== "(No active window)" ? CompositorService.focusedWindowTitle : ""
|
||||||
|
|
@ -45,10 +49,25 @@ RowLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
|
||||||
spacing: Style.marginS * scaling
|
|
||||||
visible: getTitle() !== ""
|
visible: getTitle() !== ""
|
||||||
|
|
||||||
|
function calculatedVerticalHeight() {
|
||||||
|
let total = Math.round(Style.capsuleHeight * scaling)
|
||||||
|
if (showIcon) {
|
||||||
|
total += Style.fontSizeL * scaling * 1.2 + Style.marginS * scaling
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculatedHorizontalWidth() {
|
||||||
|
let total = Style.marginM * 2 * scaling // padding
|
||||||
|
if (showIcon) {
|
||||||
|
total += Style.fontSizeL * scaling * 1.2 + Style.marginS * scaling
|
||||||
|
}
|
||||||
|
total += Math.min(fullTitleMetrics.contentWidth, minWidth * scaling)
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
function getAppIcon() {
|
function getAppIcon() {
|
||||||
try {
|
try {
|
||||||
// Try CompositorService first
|
// Try CompositorService first
|
||||||
|
|
@ -102,8 +121,9 @@ RowLayout {
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: windowTitleRect
|
id: windowTitleRect
|
||||||
visible: root.visible
|
visible: root.visible
|
||||||
Layout.preferredWidth: contentLayout.implicitWidth + Style.marginM * 2 * scaling
|
anchors.centerIn: parent
|
||||||
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
|
width: (barPosition === "left" || barPosition === "right") ? Math.round(60 * scaling) : parent.width
|
||||||
|
height: (barPosition === "left" || barPosition === "right") ? parent.height : Math.round(Style.capsuleHeight * scaling)
|
||||||
radius: Math.round(Style.radiusM * scaling)
|
radius: Math.round(Style.radiusM * scaling)
|
||||||
color: Color.mSurfaceVariant
|
color: Color.mSurfaceVariant
|
||||||
|
|
||||||
|
|
@ -114,10 +134,12 @@ RowLayout {
|
||||||
anchors.rightMargin: Style.marginS * scaling
|
anchors.rightMargin: Style.marginS * scaling
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
|
// Horizontal layout for top/bottom bars
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: contentLayout
|
id: horizontalLayout
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Style.marginS * scaling
|
spacing: Style.marginS * scaling
|
||||||
|
visible: barPosition === "top" || barPosition === "bottom"
|
||||||
|
|
||||||
// Window icon
|
// Window icon
|
||||||
Item {
|
Item {
|
||||||
|
|
@ -176,12 +198,66 @@ RowLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Vertical layout for left/right bars - icon only
|
||||||
|
Item {
|
||||||
|
id: verticalLayout
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: parent.width - Style.marginM * scaling * 2
|
||||||
|
height: parent.height - Style.marginM * scaling * 2
|
||||||
|
visible: barPosition === "left" || barPosition === "right"
|
||||||
|
|
||||||
|
// Window icon
|
||||||
|
Item {
|
||||||
|
width: Style.fontSizeL * scaling * 1.2
|
||||||
|
height: Style.fontSizeL * scaling * 1.2
|
||||||
|
anchors.centerIn: parent
|
||||||
|
visible: getTitle() !== "" && showIcon
|
||||||
|
|
||||||
|
IconImage {
|
||||||
|
id: windowIconVertical
|
||||||
|
anchors.fill: parent
|
||||||
|
source: getAppIcon()
|
||||||
|
asynchronous: true
|
||||||
|
smooth: true
|
||||||
|
visible: source !== ""
|
||||||
|
|
||||||
|
// Handle loading errors gracefully
|
||||||
|
onStatusChanged: {
|
||||||
|
if (status === Image.Error) {
|
||||||
|
Logger.warn("ActiveWindow", "Failed to load icon:", source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Mouse area for hover detection
|
// Mouse area for hover detection
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: mouseArea
|
id: mouseArea
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onEntered: {
|
||||||
|
if (barPosition === "left" || barPosition === "right") {
|
||||||
|
tooltip.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onExited: {
|
||||||
|
if (barPosition === "left" || barPosition === "right") {
|
||||||
|
tooltip.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hover tooltip with full title (only for vertical bars)
|
||||||
|
NTooltip {
|
||||||
|
id: tooltip
|
||||||
|
target: verticalLayout
|
||||||
|
text: getTitle()
|
||||||
|
positionLeft: barPosition === "right"
|
||||||
|
positionRight: barPosition === "left"
|
||||||
|
delay: 500
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -191,6 +267,7 @@ RowLayout {
|
||||||
function onActiveWindowChanged() {
|
function onActiveWindowChanged() {
|
||||||
try {
|
try {
|
||||||
windowIcon.source = Qt.binding(getAppIcon)
|
windowIcon.source = Qt.binding(getAppIcon)
|
||||||
|
windowIconVertical.source = Qt.binding(getAppIcon)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Logger.warn("ActiveWindow", "Error in onActiveWindowChanged:", e)
|
Logger.warn("ActiveWindow", "Error in onActiveWindowChanged:", e)
|
||||||
}
|
}
|
||||||
|
|
@ -198,6 +275,7 @@ RowLayout {
|
||||||
function onWindowListChanged() {
|
function onWindowListChanged() {
|
||||||
try {
|
try {
|
||||||
windowIcon.source = Qt.binding(getAppIcon)
|
windowIcon.source = Qt.binding(getAppIcon)
|
||||||
|
windowIconVertical.source = Qt.binding(getAppIcon)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Logger.warn("ActiveWindow", "Error in onWindowListChanged:", e)
|
Logger.warn("ActiveWindow", "Error in onWindowListChanged:", e)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import qs.Commons
|
||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
RowLayout {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property ShellScreen screen
|
property ShellScreen screen
|
||||||
|
|
@ -16,6 +16,7 @@ RowLayout {
|
||||||
property string section: ""
|
property string section: ""
|
||||||
property int sectionWidgetIndex: -1
|
property int sectionWidgetIndex: -1
|
||||||
property int sectionWidgetsCount: 0
|
property int sectionWidgetsCount: 0
|
||||||
|
property string barPosition: "top"
|
||||||
|
|
||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
|
|
@ -35,22 +36,60 @@ RowLayout {
|
||||||
readonly property bool showNetworkStats: (widgetSettings.showNetworkStats !== undefined) ? widgetSettings.showNetworkStats : widgetMetadata.showNetworkStats
|
readonly property bool showNetworkStats: (widgetSettings.showNetworkStats !== undefined) ? widgetSettings.showNetworkStats : widgetMetadata.showNetworkStats
|
||||||
readonly property bool showDiskUsage: (widgetSettings.showDiskUsage !== undefined) ? widgetSettings.showDiskUsage : widgetMetadata.showDiskUsage
|
readonly property bool showDiskUsage: (widgetSettings.showDiskUsage !== undefined) ? widgetSettings.showDiskUsage : widgetMetadata.showDiskUsage
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
implicitHeight: (barPosition === "left" || barPosition === "right") ? calculatedVerticalHeight() : Math.round(Style.barHeight * scaling)
|
||||||
spacing: Style.marginS * scaling
|
implicitWidth: (barPosition === "left" || barPosition === "right") ? Math.round(Style.capsuleHeight * scaling) : calculatedHorizontalWidth()
|
||||||
|
|
||||||
|
function calculatedVerticalHeight() {
|
||||||
|
let total = 0
|
||||||
|
let visibleCount = 0
|
||||||
|
|
||||||
|
if (showCpuUsage) visibleCount++
|
||||||
|
if (showCpuTemp) visibleCount++
|
||||||
|
if (showMemoryUsage) visibleCount++
|
||||||
|
if (showNetworkStats) visibleCount += 2 // download + upload
|
||||||
|
if (showDiskUsage) visibleCount++
|
||||||
|
|
||||||
|
total = visibleCount * Math.round(Style.capsuleHeight * scaling)
|
||||||
|
total += Math.max(visibleCount - 1, 0) * Style.marginS * scaling
|
||||||
|
total += Style.marginM * scaling * 2 // padding
|
||||||
|
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculatedHorizontalWidth() {
|
||||||
|
let total = 0
|
||||||
|
let visibleCount = 0
|
||||||
|
|
||||||
|
if (showCpuUsage) visibleCount++
|
||||||
|
if (showCpuTemp) visibleCount++
|
||||||
|
if (showMemoryUsage) visibleCount++
|
||||||
|
if (showNetworkStats) visibleCount += 2 // download + upload
|
||||||
|
if (showDiskUsage) visibleCount++
|
||||||
|
|
||||||
|
// Estimate width per component (icon + text + spacing)
|
||||||
|
total = visibleCount * Math.round(60 * scaling) // rough estimate
|
||||||
|
total += Math.max(visibleCount - 1, 0) * Style.marginS * scaling
|
||||||
|
total += Style.marginM * scaling * 2 // padding
|
||||||
|
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
|
id: backgroundContainer
|
||||||
Layout.preferredWidth: mainLayout.implicitWidth + Style.marginM * scaling * 2
|
anchors.centerIn: parent
|
||||||
Layout.alignment: Qt.AlignVCenter
|
width: (barPosition === "left" || barPosition === "right") ? Math.round(Style.capsuleHeight * scaling) : parent.width
|
||||||
|
height: (barPosition === "left" || barPosition === "right") ? parent.height : Math.round(Style.capsuleHeight * scaling)
|
||||||
radius: Math.round(Style.radiusM * scaling)
|
radius: Math.round(Style.radiusM * scaling)
|
||||||
color: Color.mSurfaceVariant
|
color: Color.mSurfaceVariant
|
||||||
|
|
||||||
|
// Horizontal layout for top/bottom bars
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: mainLayout
|
id: horizontalLayout
|
||||||
anchors.centerIn: parent // Better centering than margins
|
anchors.centerIn: parent
|
||||||
width: parent.width - Style.marginM * scaling * 2
|
width: parent.width - Style.marginM * scaling * 2
|
||||||
|
height: parent.height - Style.marginM * scaling * 2
|
||||||
spacing: Style.marginS * scaling
|
spacing: Style.marginS * scaling
|
||||||
|
visible: false // Temporarily hide horizontal layout for debugging
|
||||||
|
|
||||||
// CPU Usage Component
|
// CPU Usage Component
|
||||||
Item {
|
Item {
|
||||||
|
|
@ -233,5 +272,196 @@ RowLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Vertical layout for left/right bars
|
||||||
|
ColumnLayout {
|
||||||
|
id: verticalLayout
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: Math.round(32 * scaling)
|
||||||
|
height: parent.height - Style.marginM * scaling * 2
|
||||||
|
spacing: Style.marginS * scaling
|
||||||
|
visible: true // Temporarily show vertical layout for debugging
|
||||||
|
|
||||||
|
// CPU Usage Component
|
||||||
|
Item {
|
||||||
|
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
|
||||||
|
Layout.preferredWidth: Math.round(32 * scaling)
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
visible: showCpuUsage
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: cpuUsageRowVertical
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Style.marginXXS * scaling
|
||||||
|
|
||||||
|
NIcon {
|
||||||
|
icon: "cpu-usage"
|
||||||
|
font.pointSize: Style.fontSizeS * scaling
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
NText {
|
||||||
|
text: `${SystemStatService.cpuUsage}%`
|
||||||
|
font.family: Settings.data.ui.fontFixed
|
||||||
|
font.pointSize: Style.fontSizeXXS * scaling * 0.8
|
||||||
|
font.weight: Style.fontWeightMedium
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
color: Color.mPrimary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CPU Temperature Component
|
||||||
|
Item {
|
||||||
|
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
|
||||||
|
Layout.preferredWidth: Math.round(32 * scaling)
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
visible: showCpuTemp
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: cpuTempRowVertical
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Style.marginXXS * scaling
|
||||||
|
|
||||||
|
NIcon {
|
||||||
|
icon: "cpu-temperature"
|
||||||
|
// Fire is so tall, we need to make it smaller
|
||||||
|
font.pointSize: Style.fontSizeXS * scaling
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
NText {
|
||||||
|
text: `${SystemStatService.cpuTemp}°C`
|
||||||
|
font.family: Settings.data.ui.fontFixed
|
||||||
|
font.pointSize: Style.fontSizeXXS * scaling * 0.8
|
||||||
|
font.weight: Style.fontWeightMedium
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
color: Color.mPrimary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory Usage Component
|
||||||
|
Item {
|
||||||
|
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
|
||||||
|
Layout.preferredWidth: Math.round(32 * scaling)
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
visible: showMemoryUsage
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: memoryUsageRowVertical
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Style.marginXXS * scaling
|
||||||
|
|
||||||
|
NIcon {
|
||||||
|
icon: "memory"
|
||||||
|
font.pointSize: Style.fontSizeS * scaling
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
NText {
|
||||||
|
text: showMemoryAsPercent ? `${SystemStatService.memPercent}%` : `${SystemStatService.memGb}G`
|
||||||
|
font.family: Settings.data.ui.fontFixed
|
||||||
|
font.pointSize: Style.fontSizeXXS * scaling * 0.8
|
||||||
|
font.weight: Style.fontWeightMedium
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
color: Color.mPrimary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Network Download Speed Component
|
||||||
|
Item {
|
||||||
|
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
|
||||||
|
Layout.preferredWidth: Math.round(32 * scaling)
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
visible: showNetworkStats
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: networkDownloadRowVertical
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Style.marginXXS * scaling
|
||||||
|
|
||||||
|
NIcon {
|
||||||
|
icon: "download-speed"
|
||||||
|
font.pointSize: Style.fontSizeS * scaling
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
NText {
|
||||||
|
text: SystemStatService.formatSpeed(SystemStatService.rxSpeed)
|
||||||
|
font.family: Settings.data.ui.fontFixed
|
||||||
|
font.pointSize: Style.fontSizeXXS * scaling * 0.8
|
||||||
|
font.weight: Style.fontWeightMedium
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
color: Color.mPrimary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Network Upload Speed Component
|
||||||
|
Item {
|
||||||
|
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
|
||||||
|
Layout.preferredWidth: Math.round(32 * scaling)
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
visible: showNetworkStats
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: networkUploadRowVertical
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Style.marginXXS * scaling
|
||||||
|
|
||||||
|
NIcon {
|
||||||
|
icon: "upload-speed"
|
||||||
|
font.pointSize: Style.fontSizeS * scaling
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
NText {
|
||||||
|
text: SystemStatService.formatSpeed(SystemStatService.txSpeed)
|
||||||
|
font.family: Settings.data.ui.fontFixed
|
||||||
|
font.pointSize: Style.fontSizeXXS * scaling * 0.8
|
||||||
|
font.weight: Style.fontWeightMedium
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
color: Color.mPrimary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disk Usage Component (primary drive)
|
||||||
|
Item {
|
||||||
|
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
|
||||||
|
Layout.preferredWidth: Math.round(32 * scaling)
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
visible: showDiskUsage
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: diskUsageRowVertical
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Style.marginXXS * scaling
|
||||||
|
|
||||||
|
NIcon {
|
||||||
|
icon: "storage"
|
||||||
|
font.pointSize: Style.fontSizeS * scaling
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
NText {
|
||||||
|
text: `${SystemStatService.diskPercent}%`
|
||||||
|
font.family: Settings.data.ui.fontFixed
|
||||||
|
font.pointSize: Style.fontSizeXXS * scaling * 0.8
|
||||||
|
font.weight: Style.fontWeightMedium
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
color: Color.mPrimary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ Item {
|
||||||
property string section: ""
|
property string section: ""
|
||||||
property int sectionWidgetIndex: -1
|
property int sectionWidgetIndex: -1
|
||||||
property int sectionWidgetsCount: 0
|
property int sectionWidgetsCount: 0
|
||||||
|
property string barPosition: "top"
|
||||||
|
|
||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
|
|
@ -47,17 +48,8 @@ Item {
|
||||||
|
|
||||||
signal workspaceChanged(int workspaceId, color accentColor)
|
signal workspaceChanged(int workspaceId, color accentColor)
|
||||||
|
|
||||||
implicitHeight: Math.round(Style.barHeight * scaling)
|
implicitHeight: (barPosition === "left" || barPosition === "right") ? calculatedVerticalHeight() : Math.round(Style.barHeight * scaling)
|
||||||
implicitWidth: {
|
implicitWidth: (barPosition === "left" || barPosition === "right") ? Math.round(Style.barHeight * scaling) : calculatedHorizontalWidth()
|
||||||
let total = 0
|
|
||||||
for (var i = 0; i < localWorkspaces.count; i++) {
|
|
||||||
const ws = localWorkspaces.get(i)
|
|
||||||
total += calculatedWsWidth(ws)
|
|
||||||
}
|
|
||||||
total += Math.max(localWorkspaces.count - 1, 0) * spacingBetweenPills
|
|
||||||
total += horizontalPadding * 2
|
|
||||||
return total
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculatedWsWidth(ws) {
|
function calculatedWsWidth(ws) {
|
||||||
if (ws.isFocused)
|
if (ws.isFocused)
|
||||||
|
|
@ -68,6 +60,37 @@ Item {
|
||||||
return Math.round(20 * scaling)
|
return Math.round(20 * scaling)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function calculatedWsHeight(ws) {
|
||||||
|
if (ws.isFocused)
|
||||||
|
return Math.round(44 * scaling)
|
||||||
|
else if (ws.isActive)
|
||||||
|
return Math.round(28 * scaling)
|
||||||
|
else
|
||||||
|
return Math.round(20 * scaling)
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculatedVerticalHeight() {
|
||||||
|
let total = 0
|
||||||
|
for (var i = 0; i < localWorkspaces.count; i++) {
|
||||||
|
const ws = localWorkspaces.get(i)
|
||||||
|
total += calculatedWsHeight(ws)
|
||||||
|
}
|
||||||
|
total += Math.max(localWorkspaces.count - 1, 0) * spacingBetweenPills
|
||||||
|
total += horizontalPadding * 2
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculatedHorizontalWidth() {
|
||||||
|
let total = 0
|
||||||
|
for (var i = 0; i < localWorkspaces.count; i++) {
|
||||||
|
const ws = localWorkspaces.get(i)
|
||||||
|
total += calculatedWsWidth(ws)
|
||||||
|
}
|
||||||
|
total += Math.max(localWorkspaces.count - 1, 0) * spacingBetweenPills
|
||||||
|
total += horizontalPadding * 2
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
refreshWorkspaces()
|
refreshWorkspaces()
|
||||||
}
|
}
|
||||||
|
|
@ -99,7 +122,8 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
workspaceRepeater.model = localWorkspaces
|
workspaceRepeaterHorizontal.model = localWorkspaces
|
||||||
|
workspaceRepeaterVertical.model = localWorkspaces
|
||||||
updateWorkspaceFocus()
|
updateWorkspaceFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -148,9 +172,8 @@ Item {
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: workspaceBackground
|
id: workspaceBackground
|
||||||
width: parent.width
|
width: (barPosition === "left" || barPosition === "right") ? Math.round(Style.capsuleHeight * scaling) : parent.width
|
||||||
|
height: (barPosition === "left" || barPosition === "right") ? parent.height : Math.round(Style.capsuleHeight * scaling)
|
||||||
height: Math.round(Style.capsuleHeight * scaling)
|
|
||||||
radius: Math.round(Style.radiusM * scaling)
|
radius: Math.round(Style.radiusM * scaling)
|
||||||
color: Color.mSurfaceVariant
|
color: Color.mSurfaceVariant
|
||||||
|
|
||||||
|
|
@ -158,14 +181,17 @@ Item {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Horizontal layout for top/bottom bars
|
||||||
Row {
|
Row {
|
||||||
id: pillRow
|
id: pillRow
|
||||||
spacing: spacingBetweenPills
|
spacing: spacingBetweenPills
|
||||||
anchors.verticalCenter: workspaceBackground.verticalCenter
|
anchors.verticalCenter: workspaceBackground.verticalCenter
|
||||||
width: root.width - horizontalPadding * 2
|
width: root.width - horizontalPadding * 2
|
||||||
x: horizontalPadding
|
x: horizontalPadding
|
||||||
|
visible: barPosition === "top" || barPosition === "bottom"
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
id: workspaceRepeater
|
id: workspaceRepeaterHorizontal
|
||||||
model: localWorkspaces
|
model: localWorkspaces
|
||||||
Item {
|
Item {
|
||||||
id: workspacePillContainer
|
id: workspacePillContainer
|
||||||
|
|
@ -299,4 +325,149 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Vertical layout for left/right bars
|
||||||
|
Column {
|
||||||
|
id: pillColumn
|
||||||
|
spacing: spacingBetweenPills
|
||||||
|
anchors.horizontalCenter: workspaceBackground.horizontalCenter
|
||||||
|
height: root.height - horizontalPadding * 2
|
||||||
|
y: horizontalPadding
|
||||||
|
visible: barPosition === "left" || barPosition === "right"
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: workspaceRepeaterVertical
|
||||||
|
model: localWorkspaces
|
||||||
|
Item {
|
||||||
|
id: workspacePillContainerVertical
|
||||||
|
width: (labelMode !== "none") ? Math.round(18 * scaling) : Math.round(14 * scaling)
|
||||||
|
height: root.calculatedWsHeight(model)
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: pillVertical
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
active: (labelMode !== "none")
|
||||||
|
sourceComponent: Component {
|
||||||
|
Text {
|
||||||
|
x: (pillVertical.width - width) / 2
|
||||||
|
y: (pillVertical.height - height) / 2 + (height - contentHeight) / 2
|
||||||
|
text: {
|
||||||
|
if (labelMode === "name" && model.name && model.name.length > 0) {
|
||||||
|
return model.name.substring(0, 2)
|
||||||
|
} else {
|
||||||
|
return model.idx.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
font.pointSize: model.isFocused ? Style.fontSizeXS * scaling : Style.fontSizeXXS * scaling
|
||||||
|
font.capitalization: Font.AllUppercase
|
||||||
|
font.family: Settings.data.ui.fontFixed
|
||||||
|
font.weight: Style.fontWeightBold
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
color: {
|
||||||
|
if (model.isFocused)
|
||||||
|
return Color.mOnPrimary
|
||||||
|
if (model.isUrgent)
|
||||||
|
return Color.mOnError
|
||||||
|
if (model.isActive || model.isOccupied)
|
||||||
|
return Color.mOnSecondary
|
||||||
|
|
||||||
|
return Color.mOnSurface
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
radius: width * 0.5
|
||||||
|
color: {
|
||||||
|
if (model.isFocused)
|
||||||
|
return Color.mPrimary
|
||||||
|
if (model.isUrgent)
|
||||||
|
return Color.mError
|
||||||
|
if (model.isActive || model.isOccupied)
|
||||||
|
return Color.mSecondary
|
||||||
|
|
||||||
|
return Color.mOutline
|
||||||
|
}
|
||||||
|
scale: model.isFocused ? 1.0 : 0.9
|
||||||
|
z: 0
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: pillMouseAreaVertical
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
WorkspaceService.switchToWorkspace(model.idx)
|
||||||
|
}
|
||||||
|
hoverEnabled: true
|
||||||
|
}
|
||||||
|
// Material 3-inspired smooth animation for width, height, scale, color, opacity, and radius
|
||||||
|
Behavior on width {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Style.animationNormal
|
||||||
|
easing.type: Easing.OutBack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on height {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Style.animationNormal
|
||||||
|
easing.type: Easing.OutBack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Style.animationNormal
|
||||||
|
easing.type: Easing.OutBack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Style.animationFast
|
||||||
|
easing.type: Easing.InOutCubic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Style.animationFast
|
||||||
|
easing.type: Easing.InOutCubic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on radius {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Style.animationNormal
|
||||||
|
easing.type: Easing.OutBack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on width {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Style.animationNormal
|
||||||
|
easing.type: Easing.OutBack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on height {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Style.animationNormal
|
||||||
|
easing.type: Easing.OutBack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Burst effect overlay for focused pill (smaller outline)
|
||||||
|
Rectangle {
|
||||||
|
id: pillBurstVertical
|
||||||
|
anchors.centerIn: workspacePillContainerVertical
|
||||||
|
width: workspacePillContainerVertical.width + 18 * root.masterProgress * scale
|
||||||
|
height: workspacePillContainerVertical.height + 18 * root.masterProgress * scale
|
||||||
|
radius: width / 2
|
||||||
|
color: Color.transparent
|
||||||
|
border.color: root.effectColor
|
||||||
|
border.width: Math.max(1, Math.round((2 + 6 * (1.0 - root.masterProgress)) * scaling))
|
||||||
|
opacity: root.effectsActive && model.isFocused ? (1.0 - root.masterProgress) * 0.7 : 0
|
||||||
|
visible: root.effectsActive && model.isFocused
|
||||||
|
z: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,14 @@ ColumnLayout {
|
||||||
key: "bottom"
|
key: "bottom"
|
||||||
name: "Bottom"
|
name: "Bottom"
|
||||||
}
|
}
|
||||||
|
ListElement {
|
||||||
|
key: "left"
|
||||||
|
name: "Left"
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
key: "right"
|
||||||
|
name: "Right"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
currentKey: Settings.data.bar.position
|
currentKey: Settings.data.bar.position
|
||||||
onSelected: key => Settings.data.bar.position = key
|
onSelected: key => Settings.data.bar.position = key
|
||||||
|
|
|
||||||
60
flake.nix
60
flake.nix
|
|
@ -1,6 +1,5 @@
|
||||||
{
|
{
|
||||||
description =
|
description = "Noctalia shell - a Wayland desktop shell built with Quickshell";
|
||||||
"Noctalia shell - a Wayland desktop shell built with Quickshell";
|
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
|
|
@ -12,13 +11,22 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, systems, quickshell, ... }:
|
outputs =
|
||||||
let eachSystem = nixpkgs.lib.genAttrs (import systems);
|
{
|
||||||
in {
|
self,
|
||||||
formatter =
|
nixpkgs,
|
||||||
eachSystem (system: nixpkgs.legacyPackages.${system}.alejandra);
|
systems,
|
||||||
|
quickshell,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
eachSystem = nixpkgs.lib.genAttrs (import systems);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.alejandra);
|
||||||
|
|
||||||
packages = eachSystem (system:
|
packages = eachSystem (
|
||||||
|
system:
|
||||||
let
|
let
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
qs = quickshell.packages.${system}.default.override {
|
qs = quickshell.packages.${system}.default.override {
|
||||||
|
|
@ -26,7 +34,8 @@
|
||||||
withI3 = false;
|
withI3 = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
runtimeDeps = with pkgs;
|
runtimeDeps =
|
||||||
|
with pkgs;
|
||||||
[
|
[
|
||||||
bash
|
bash
|
||||||
bluez
|
bluez
|
||||||
|
|
@ -41,21 +50,34 @@
|
||||||
matugen
|
matugen
|
||||||
networkmanager
|
networkmanager
|
||||||
wl-clipboard
|
wl-clipboard
|
||||||
] ++ lib.optionals (pkgs.stdenv.hostPlatform.isx86_64)
|
]
|
||||||
[ gpu-screen-recorder ];
|
++ lib.optionals (pkgs.stdenv.hostPlatform.isx86_64) [
|
||||||
|
gpu-screen-recorder
|
||||||
|
];
|
||||||
|
|
||||||
fontconfig = pkgs.makeFontsConf {
|
fontconfig = pkgs.makeFontsConf {
|
||||||
fontDirectories = [ pkgs.roboto pkgs.inter-nerdfont ];
|
fontDirectories = [
|
||||||
|
pkgs.roboto
|
||||||
|
pkgs.inter-nerdfont
|
||||||
|
];
|
||||||
};
|
};
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
default = pkgs.stdenv.mkDerivation {
|
default = pkgs.stdenv.mkDerivation {
|
||||||
pname = "noctalia-shell";
|
pname = "noctalia-shell";
|
||||||
version = self.rev or self.dirtyRev or "dirty";
|
version = self.rev or self.dirtyRev or "dirty";
|
||||||
src = ./.;
|
src = ./.;
|
||||||
|
|
||||||
nativeBuildInputs =
|
nativeBuildInputs = [
|
||||||
[ pkgs.gcc pkgs.makeWrapper pkgs.qt6.wrapQtAppsHook ];
|
pkgs.gcc
|
||||||
buildInputs = [ qs pkgs.xkeyboard_config pkgs.qt6.qtbase ];
|
pkgs.makeWrapper
|
||||||
|
pkgs.qt6.wrapQtAppsHook
|
||||||
|
];
|
||||||
|
buildInputs = [
|
||||||
|
qs
|
||||||
|
pkgs.xkeyboard-config
|
||||||
|
pkgs.qt6.qtbase
|
||||||
|
];
|
||||||
propagatedBuildInputs = runtimeDeps;
|
propagatedBuildInputs = runtimeDeps;
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
|
|
@ -69,14 +91,14 @@
|
||||||
'';
|
'';
|
||||||
|
|
||||||
meta = {
|
meta = {
|
||||||
description =
|
description = "A sleek and minimal desktop shell thoughtfully crafted for Wayland, built with Quickshell.";
|
||||||
"A sleek and minimal desktop shell thoughtfully crafted for Wayland, built with Quickshell.";
|
|
||||||
homepage = "https://github.com/noctalia-dev/noctalia-shell";
|
homepage = "https://github.com/noctalia-dev/noctalia-shell";
|
||||||
license = pkgs.lib.licenses.mit;
|
license = pkgs.lib.licenses.mit;
|
||||||
mainProgram = "noctalia-shell";
|
mainProgram = "noctalia-shell";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
defaultPackage = eachSystem (system: self.packages.${system}.default);
|
defaultPackage = eachSystem (system: self.packages.${system}.default);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue