This commit is contained in:
Zacharias-Brohn
2025-12-07 02:16:33 +01:00
parent ef3791b0d4
commit 0f3f4a981f
12 changed files with 1173 additions and 183 deletions
+134 -128
View File
@@ -9,147 +9,153 @@ import qs.Helpers
import qs.Daemons
RowLayout {
id: root
anchors.fill: parent
id: root
anchors.fill: parent
readonly property int vPadding: 6
required property Wrapper popouts
required property PanelWindow bar
readonly property int vPadding: 6
required property Wrapper popouts
required property PanelWindow bar
function checkPopout(x: real): void {
const ch = childAt(x, height / 2) as WrappedLoader;
function checkPopout(x: real): void {
const ch = childAt(x, height / 2) as WrappedLoader;
if (!ch) {
popouts.hasCurrent = false;
return;
}
if (!ch) {
popouts.hasCurrent = false;
return;
}
const id = ch.id;
const top = ch.x;
const item = ch.item;
const itemWidth = item.implicitWidth;
const id = ch.id;
const top = ch.x;
const item = ch.item;
const itemWidth = item.implicitWidth;
if (id === "audio" && Config.barConfig.popouts.audio) {
popouts.currentName = "audio";
popouts.currentCenter = Qt.binding( () => item.mapToItem(root, itemWidth / 2, 0 ).x );
popouts.hasCurrent = true;
} else if ( id === "resources" && Config.barConfig.popouts.resources ) {
popouts.currentName = "resources";
popouts.currentCenter = Qt.binding( () => item.mapToItem( root, itemWidth / 2, 0 ).x );
popouts.hasCurrent = true;
} else if ( id === "tray" && Config.barConfig.popouts.tray ) {
const index = Math.floor((( x - top ) / item.implicitWidth ) * item.items.count );
const trayItem = item.items.itemAt( index );
if ( trayItem ) {
popouts.currentName = `traymenu${ index }`;
popouts.currentCenter = Qt.binding( () => trayItem.mapToItem( root, trayItem.implicitWidth / 2, 0 ).x );
popouts.hasCurrent = true;
} else {
popouts.hasCurrent = false;
}
}
}
if (id === "audio" && Config.barConfig.popouts.audio) {
popouts.currentName = "audio";
popouts.currentCenter = Qt.binding( () => item.mapToItem(root, itemWidth / 2, 0 ).x );
popouts.hasCurrent = true;
} else if ( id === "resources" && Config.barConfig.popouts.resources ) {
popouts.currentName = "resources";
popouts.currentCenter = Qt.binding( () => item.mapToItem( root, itemWidth / 2, 0 ).x );
popouts.hasCurrent = true;
} else if ( id === "tray" && Config.barConfig.popouts.tray ) {
const index = Math.floor((( x - top ) / item.implicitWidth ) * item.items.count );
const trayItem = item.items.itemAt( index );
if ( trayItem ) {
popouts.currentName = `traymenu${ index }`;
popouts.currentCenter = Qt.binding( () => trayItem.mapToItem( root, trayItem.implicitWidth / 2, 0 ).x );
popouts.hasCurrent = true;
} else {
popouts.hasCurrent = false;
}
} else if ( id === "clock" && Config.barConfig.popouts.clock ) {
Calendar.displayYear = new Date().getFullYear();
Calendar.displayMonth = new Date().getMonth();
popouts.currentName = "calendar";
popouts.currentCenter = Qt.binding( () => item.mapToItem( root, itemWidth / 2, 0 ).x );
popouts.hasCurrent = true;
}
}
Repeater {
id: repeater
model: Config.barConfig.entries
Repeater {
id: repeater
model: Config.barConfig.entries
DelegateChooser {
role: "id"
DelegateChooser {
role: "id"
DelegateChoice {
roleValue: "spacer"
delegate: WrappedLoader {
Layout.fillWidth: true
}
}
DelegateChoice {
roleValue: "workspaces"
delegate: WrappedLoader {
sourceComponent: Workspaces {
bar: root.bar
}
}
}
DelegateChoice {
roleValue: "audio"
delegate: WrappedLoader {
sourceComponent: AudioWidget {}
}
}
DelegateChoice {
roleValue: "tray"
delegate: WrappedLoader {
sourceComponent: TrayWidget {
bar: root.bar
}
}
}
DelegateChoice {
roleValue: "resources"
delegate: WrappedLoader {
sourceComponent: Resources {}
}
}
DelegateChoice {
roleValue: "updates"
delegate: WrappedLoader {
sourceComponent: UpdatesWidget {}
}
}
DelegateChoice {
roleValue: "notifBell"
delegate: WrappedLoader {
sourceComponent: NotifBell {}
}
}
DelegateChoice {
roleValue: "clock"
delegate: WrappedLoader {
sourceComponent: Clock {}
}
}
DelegateChoice {
roleValue: "activeWindow"
delegate: WrappedLoader {
sourceComponent: WindowTitle {}
}
}
}
}
DelegateChoice {
roleValue: "spacer"
delegate: WrappedLoader {
Layout.fillWidth: true
}
}
DelegateChoice {
roleValue: "workspaces"
delegate: WrappedLoader {
sourceComponent: Workspaces {
bar: root.bar
}
}
}
DelegateChoice {
roleValue: "audio"
delegate: WrappedLoader {
sourceComponent: AudioWidget {}
}
}
DelegateChoice {
roleValue: "tray"
delegate: WrappedLoader {
sourceComponent: TrayWidget {
bar: root.bar
}
}
}
DelegateChoice {
roleValue: "resources"
delegate: WrappedLoader {
sourceComponent: Resources {}
}
}
DelegateChoice {
roleValue: "updates"
delegate: WrappedLoader {
sourceComponent: UpdatesWidget {}
}
}
DelegateChoice {
roleValue: "notifBell"
delegate: WrappedLoader {
sourceComponent: NotifBell {}
}
}
DelegateChoice {
roleValue: "clock"
delegate: WrappedLoader {
sourceComponent: Clock {}
}
}
DelegateChoice {
roleValue: "activeWindow"
delegate: WrappedLoader {
sourceComponent: WindowTitle {}
}
}
}
}
component WrappedLoader: Loader {
required property bool enabled
required property string id
required property int index
component WrappedLoader: Loader {
required property bool enabled
required property string id
required property int index
Layout.alignment: Qt.AlignVCenter
Layout.fillHeight: true
Layout.alignment: Qt.AlignVCenter
Layout.fillHeight: true
function findFirstEnabled(): Item {
const count = repeater.count;
for (let i = 0; i < count; i++) {
const item = repeater.itemAt(i);
if (item?.enabled)
return item;
}
return null;
}
function findFirstEnabled(): Item {
const count = repeater.count;
for (let i = 0; i < count; i++) {
const item = repeater.itemAt(i);
if (item?.enabled)
return item;
}
return null;
}
function findLastEnabled(): Item {
for (let i = repeater.count - 1; i >= 0; i--) {
const item = repeater.itemAt(i);
if (item?.enabled)
return item;
}
return null;
}
function findLastEnabled(): Item {
for (let i = repeater.count - 1; i >= 0; i--) {
const item = repeater.itemAt(i);
if (item?.enabled)
return item;
}
return null;
}
Layout.leftMargin: findFirstEnabled() === this ? root.vPadding : 0
Layout.rightMargin: findLastEnabled() === this ? root.vPadding : 0
Layout.leftMargin: findFirstEnabled() === this ? root.vPadding : 0
Layout.rightMargin: findLastEnabled() === this ? root.vPadding : 0
visible: enabled
active: enabled
}
visible: enabled
active: enabled
}
}
+73
View File
@@ -0,0 +1,73 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Helpers
RowLayout {
spacing: 12
Rectangle {
Layout.preferredWidth: 40
Layout.preferredHeight: 40
color: "transparent"
radius: 1000
CustomText {
text: "◀"
font.pointSize: 12
color: DynamicColors.palette.m3onSurface
anchors.centerIn: parent
}
StateLayer {
onClicked: {
if (Calendar.displayMonth === 0) {
Calendar.displayMonth = 11;
Calendar.displayYear -= 1;
} else {
Calendar.displayMonth -= 1;
}
}
}
}
CustomText {
text: new Date(Calendar.displayYear, Calendar.displayMonth, 1).toLocaleDateString(
Qt.locale(),
"MMMM yyyy"
)
font.weight: 600
font.pointSize: 14
color: DynamicColors.palette.m3onSurface
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
}
Rectangle {
Layout.preferredWidth: 40
Layout.preferredHeight: 40
color: "transparent"
radius: 1000
CustomText {
text: "▶"
font.pointSize: 12
color: DynamicColors.palette.m3onSurface
anchors.centerIn: parent
}
StateLayer {
onClicked: {
if (Calendar.displayMonth === 11) {
Calendar.displayMonth = 0;
Calendar.displayYear += 1;
} else {
Calendar.displayMonth += 1;
}
}
}
}
}
+77
View File
@@ -0,0 +1,77 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Helpers
Item {
id: root
required property Item wrapper
implicitWidth: layout.childrenRect.width + layout.anchors.margins * 2
implicitHeight: layout.childrenRect.height + layout.anchors.margins * 2
ColumnLayout {
id: layout
anchors.centerIn: parent
anchors.margins: 16
spacing: 16
// Header with month/year and navigation
CalendarHeader {
Layout.fillWidth: true
Layout.preferredHeight: childrenRect.height
}
// Calendar grid
RowLayout {
Layout.fillWidth: true
Layout.preferredHeight: childrenRect.height
spacing: 12
ColumnLayout {
Layout.alignment: Qt.AlignTop
Layout.preferredHeight: childrenRect.height
Layout.preferredWidth: weekNumberColumn.width
spacing: 8
Item {
Layout.preferredHeight: dayOfWeekRow.height
}
WeekNumberColumn {
id: weekNumberColumn
Layout.alignment: Qt.AlignTop
Layout.preferredHeight: weekNumbers.values.length * 44
}
}
ColumnLayout {
Layout.alignment: Qt.AlignTop
Layout.fillWidth: true
Layout.preferredHeight: childrenRect.height
spacing: 8
DayOfWeekRow {
id: dayOfWeekRow
locale: Qt.locale()
Layout.fillWidth: true
Layout.preferredHeight: 30
}
MonthGrid {
locale: Qt.locale()
wrapper: root.wrapper
Layout.preferredWidth: childrenRect.width
Layout.preferredHeight: childrenRect.height
}
}
}
}
}
+45
View File
@@ -0,0 +1,45 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Helpers
RowLayout {
id: root
required property var locale
spacing: 4
Repeater {
model: 7
Item {
required property int index
Layout.fillWidth: true
Layout.preferredHeight: 30
readonly property string dayName: {
// Get the day name for this column
const dayIndex = (index + Calendar.weekStartDay) % 7;
return root.locale.dayName(dayIndex, Locale.ShortFormat);
}
CustomText {
anchors.centerIn: parent
text: parent.dayName
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: DynamicColors.palette.m3onSurfaceVariant
opacity: 0.8
font.weight: 500
font.pointSize: 11
}
}
}
}
+117
View File
@@ -0,0 +1,117 @@
pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Helpers
GridLayout {
id: root
required property var locale
required property Item wrapper
columns: 7
rowSpacing: 4
columnSpacing: 4
uniformCellWidths: true
uniformCellHeights: true
component Anim: NumberAnimation {
target: root
duration: MaterialEasing.expressiveEffectsTime
easing.bezierCurve: MaterialEasing.expressiveEffects
}
Repeater {
id: repeater
model: ScriptModel {
values: Calendar.getWeeksForMonth(Calendar.displayMonth, Calendar.displayYear)
Behavior on values {
SequentialAnimation {
id: switchAnim
ParallelAnimation {
Anim {
property: "opacity"
from: 1.0
to: 0.0
}
Anim {
property: "scale"
from: 1.0
to: 0.8
}
}
PropertyAction {}
ParallelAnimation {
Anim {
property: "opacity"
from: 0.0
to: 1.0
}
Anim {
property: "scale"
from: 0.8
to: 1.0
}
}
}
}
}
Rectangle {
required property var modelData
required property int index
Layout.preferredWidth: 40
Layout.preferredHeight: width
radius: 1000
color: {
if (modelData.isToday) {
console.log(width);
return DynamicColors.palette.m3primaryContainer;
}
return "transparent";
}
Behavior on color {
ColorAnimation { duration: 200 }
}
CustomText {
anchors.centerIn: parent
text: parent.modelData.day.toString()
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
opacity: parent.modelData.isCurrentMonth ? 1.0 : 0.4
color: {
if (parent.modelData.isToday) {
return DynamicColors.palette.m3onPrimaryContainer;
}
return DynamicColors.palette.m3onSurface;
}
Behavior on color {
ColorAnimation { duration: 200 }
}
Behavior on opacity {
NumberAnimation { duration: 200 }
}
}
StateLayer {
color: DynamicColors.palette.m3onSurface
onClicked: {
console.log(`Selected date: ${parent.modelData.day}/${parent.modelData.month + 1}/${parent.modelData.year}`);
}
}
}
}
}
+45
View File
@@ -0,0 +1,45 @@
pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Helpers
ColumnLayout {
id: root
spacing: 4
readonly property var weekNumbers: Calendar.getWeekNumbers(Calendar.displayMonth, Calendar.displayYear)
Repeater {
model: ScriptModel {
values: root.weekNumbers
}
Item {
id: weekItem
Layout.preferredHeight: 40
Layout.preferredWidth: 20
Layout.alignment: Qt.AlignHCenter
required property int index
required property var modelData
CustomText {
id: weekText
anchors.centerIn: parent
text: weekItem.modelData
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: DynamicColors.palette.m3onSurfaceVariant
opacity: 0.5
font.pointSize: 10
}
}
}
}
+8
View File
@@ -4,6 +4,7 @@ import Quickshell
import Quickshell.Services.SystemTray
import QtQuick
import qs.Config
import qs.Modules.Calendar
Item {
id: root
@@ -69,6 +70,13 @@ Item {
}
}
}
Popout {
name: "calendar"
sourceComponent: CalendarPopup {
wrapper: root.wrapper
}
}
}
component Popout: Loader {
+2 -6
View File
@@ -62,7 +62,6 @@ WlSessionLockSurface {
onTextChanged: text = ""
}
ScreencopyView {
id: background
@@ -84,14 +83,11 @@ WlSessionLockSurface {
}
}
Image {
CachingImage {
id: backgroundImage
anchors.fill: parent
asynchronous: false
cache: false
source: WallpaperPath.currentWallpaperPath
sourceSize.width: root.screen.width
sourceSize.height: root.screen.height
path: WallpaperPath.currentWallpaperPath
visible: Config.lock.useWallpaper
Component.onCompleted: {