This commit is contained in:
Bloxx12 2025-05-06 09:38:56 +02:00
commit b750421f65
Signed by: faukah
SSH key fingerprint: SHA256:Uj2AXqvtdCA4hn5Hq0ZonhIAyUqI1q4w2sMG3Z1TH7E
6 changed files with 435 additions and 34 deletions

103
AudioPopup.qml Normal file
View file

@ -0,0 +1,103 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import QtQuick.Layouts
import Quickshell.Wayland
import Quickshell.Services.Pipewire
Singleton {
id: audioPopup
property bool popupOpen: true
property var volume: sink.ready ? audioPopup.sink.audio.volume : 0
property var visible: volume
property PwNode sink: Pipewire.defaultAudioSink
// bind the node so we can read its properties
PwObjectTracker {
objects: [audioPopup.sink]
}
Timer {
id: timer
interval: 3000
running: false
repeat: false
onTriggered: audioPopup.visible = false
}
LazyLoader {
id: loader
activeAsync: audioPopup.popupOpen
PanelWindow {
id: popup
width: 400
height: 30
visible: true
// Give the window an empty click mask so all clicks pass through it.
mask: Region {}
// Use the wlroots specific layer property to ensure it displays over
// fullscreen windows.
WlrLayershell.layer: WlrLayer.Overlay
color: "transparent"
anchors {
bottom: true
}
margins {
bottom: 250
}
Rectangle {
id: rect
Layout.fillWidth: true
anchors.verticalCenter: parent.verticalCenter
color: "white"
height: parent.height
width: parent.width
radius: 5
opacity: 0
anchors {
left: parent.left
}
Behavior on width {
NumberAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
Rectangle {
color: "black"
height: 20
radius: height / 2
anchors {
left: parent.left
}
topLeftRadius: 0
bottomLeftRadius: 0
anchors.verticalCenter: parent.verticalCenter
width: parent.width * audioPopup.sink.audio.volume
}
}
}
}
function init() {
}
}

View file

@ -29,9 +29,10 @@ PanelWindow {
WorkspaceWidget { WorkspaceWidget {
bar: root bar: root
wsBaseIndex: root.screen.name == "DP-2" ? 11 : 1
}
SysTray {
bar: root
} }
// SysTray {
// bar: root
// }
} }
} }

View file

@ -1,9 +1,10 @@
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import Quickshell
Rectangle { Rectangle {
width: parent.width width: parent.width
height: width height: width * 1.5
border.color: "black" border.color: "black"
border.width: 1 border.width: 1
radius: 5 radius: 5
@ -15,12 +16,17 @@ Rectangle {
anchors.centerIn: parent anchors.centerIn: parent
SystemClock {
id: clock
precision: SystemClock.Seconds
}
Text { Text {
id: text id: text
anchors.centerIn: parent anchors.centerIn: parent
property var date: Date() property var date: Date()
text: Qt.formatDateTime(date, "hh\nmm") text: Qt.formatDateTime(clock.date, "hh\nmm\nss")
font.family: "Iosevka NF" font.family: "Iosevka NF"
font.weight: Font.ExtraBold font.weight: Font.ExtraBold
@ -29,11 +35,4 @@ Rectangle {
color: "black" color: "black"
} }
} }
Timer {
interval: 1000 * 60
running: true
repeat: true
onTriggered: text.date = new Date()
}
} }

View file

@ -1,34 +1,311 @@
pragma Singleton pragma Singleton
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Controls
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import Quickshell.Wayland import Quickshell.Wayland
import Quickshell.Widgets import Quickshell.Widgets
import Quickshell.Services.SystemTray
Singleton { Singleton {
PersistentProperties { id: launcher
id: persist property bool launcherOpen: false
property bool launcherOpen: false
}
IpcHandler { IpcHandler {
target: "launcher" target: "launcher"
function open(): void { function open(): void {
persist.launcherOpen = true; launcher.launcherOpen = true;
} }
function close(): void { function close(): void {
persist.launcherOpen = false; launcher.launcherOpen = false;
} }
function toggle(): void { function toggle(): void {
persist.launcherOpen = !persist.launcherOpen; launcher.launcherOpen = !launcher.launcherOpen;
} }
} }
LazyLoader {
id: loader
activeAsync: launcher.launcherOpen
PanelWindow {
width: 450
height: 7 + searchContainer.implicitHeight + list.topMargin * 2 + list.delegateHeight * 10
color: "transparent"
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
WlrLayershell.namespace: "shell:launcher"
Rectangle {
height: 7 + searchContainer.implicitHeight + list.topMargin + list.bottomMargin + Math.min(list.contentHeight, list.delegateHeight * 10)
Behavior on height {
NumberAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
width: 450
color: "white"
radius: 5
border.color: "black"
border.width: 1
ColumnLayout {
anchors.fill: parent
anchors.margins: 7
anchors.bottomMargin: 0
spacing: 0
Rectangle {
id: searchContainer
Layout.fillWidth: true
implicitHeight: searchbox.implicitHeight + 10
color: "#30c0ffff"
radius: 3
border.color: "#50ffffff"
RowLayout {
id: searchbox
anchors.fill: parent
anchors.margins: 5
IconImage {
implicitSize: parent.height
source: "root:icons/magnifying-glass.svg"
}
TextInput {
id: search
Layout.fillWidth: true
color: "black"
focus: true
Keys.forwardTo: [list]
Keys.onEscapePressed: launcher.launcherOpen = false
Keys.onPressed: event => {
if (event.modifiers & Qt.ControlModifier) {
if (event.key == Qt.Key_J) {
list.currentIndex = list.currentIndex == list.count - 1 ? 0 : list.currentIndex + 1;
event.accepted = true;
} else if (event.key == Qt.Key_K) {
list.currentIndex = list.currentIndex == 0 ? list.count - 1 : list.currentIndex - 1;
event.accepted = true;
}
}
}
onAccepted: {
if (list.currentItem) {
list.currentItem.clicked(null);
}
}
onTextChanged: {
list.currentIndex = 0;
}
}
}
}
ListView {
id: list
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
cacheBuffer: 0 // works around QTBUG-131106
//reuseItems: true
model: ScriptModel {
values: DesktopEntries.applications.values.map(object => {
const stxt = search.text.toLowerCase();
const ntxt = object.name.toLowerCase();
let si = 0;
let ni = 0;
let matches = [];
let startMatch = -1;
for (let si = 0; si != stxt.length; ++si) {
const sc = stxt[si];
while (true) {
// Drop any entries with letters that don't exist in order
if (ni == ntxt.length)
return null;
const nc = ntxt[ni++];
if (nc == sc) {
if (startMatch == -1)
startMatch = ni;
break;
} else {
if (startMatch != -1) {
matches.push({
index: startMatch,
length: ni - startMatch
});
startMatch = -1;
}
}
}
}
if (startMatch != -1) {
matches.push({
index: startMatch,
length: ni - startMatch + 1
});
}
return {
object: object,
matches: matches
};
}).filter(entry => entry !== null).sort((a, b) => {
let ai = 0;
let bi = 0;
let s = 0;
while (ai != a.matches.length && bi != b.matches.length) {
const am = a.matches[ai];
const bm = b.matches[bi];
s = bm.length - am.length;
if (s != 0)
return s;
s = am.index - bm.index;
if (s != 0)
return s;
++ai;
++bi;
}
s = a.matches.length - b.matches.length;
if (s != 0)
return s;
s = a.object.name.length - b.object.name.length;
if (s != 0)
return s;
return a.object.name.localeCompare(b.object.name);
}).map(entry => entry.object)
onValuesChanged: list.currentIndex = 0
}
topMargin: 7
bottomMargin: list.count == 0 ? 0 : 7
add: Transition {
NumberAnimation {
property: "opacity"
from: 0
to: 1
duration: 100
}
}
displaced: Transition {
NumberAnimation {
property: "y"
duration: 200
easing.type: Easing.OutCubic
}
NumberAnimation {
property: "opacity"
to: 1
duration: 100
}
}
move: Transition {
NumberAnimation {
property: "y"
duration: 200
easing.type: Easing.OutCubic
}
NumberAnimation {
property: "opacity"
to: 1
duration: 100
}
}
remove: Transition {
NumberAnimation {
property: "y"
duration: 200
easing.type: Easing.OutCubic
}
NumberAnimation {
property: "opacity"
to: 0
duration: 100
}
}
highlight: Rectangle {
radius: 5
color: "green"
border.color: "#30ffffff"
border.width: 1
}
keyNavigationEnabled: true
keyNavigationWraps: true
highlightMoveVelocity: -1
highlightMoveDuration: 100
preferredHighlightBegin: list.topMargin
preferredHighlightEnd: list.height - list.bottomMargin
highlightRangeMode: ListView.ApplyRange
snapMode: ListView.SnapToItem
readonly property real delegateHeight: 44
delegate: MouseArea {
required property DesktopEntry modelData
implicitHeight: list.delegateHeight
implicitWidth: ListView.view.width
onClicked: {
modelData.execute();
launcher.launcherOpen = false;
}
RowLayout {
id: delegateLayout
anchors {
verticalCenter: parent.verticalCenter
left: parent.left
leftMargin: 5
}
IconImage {
Layout.alignment: Qt.AlignVCenter
asynchronous: true
implicitSize: 30
source: Quickshell.iconPath(modelData.icon)
}
Text {
text: modelData.name
color: "black"
Layout.alignment: Qt.AlignVCenter
}
}
}
}
}
}
}
}
function init() {
}
} }

View file

@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Effects import QtQuick.Effects
import QtQuick.Controls
import Quickshell import Quickshell
import Quickshell.Services.SystemTray import Quickshell.Services.SystemTray
@ -10,14 +11,11 @@ Rectangle {
id: root id: root
required property var bar required property var bar
Column { anchors.horizontalCenter: parent.horizontalCenter
id: column
spacing: 5
anchors { ColumnLayout {
fill: parent id: column
margins: 5 spacing: 35
}
Repeater { Repeater {
model: SystemTray.items model: SystemTray.items
@ -27,8 +25,29 @@ Rectangle {
required property SystemTrayItem modelData required property SystemTrayItem modelData
implicitHeight: width Item {
height: 30
width: 30
anchors.horizontalCenter: parent.horizontalCenter
Image {
source: item.modelData.icon
anchors.fill: parent
MouseArea {
anchors.fill: parent
onClicked: function (mouse) {
if (mouse.button === Qt.LeftButton) {
item.modelData.activate();
}
if (mouse.button === Qt.RightButton) {
if (item.modelData.hasMenu) {
}
}
}
}
}
}
} }
} }
} }

View file

@ -1,11 +1,15 @@
pragma ComponentBehavior: Bound
import Quickshell import Quickshell
import Quickshell.Io
import QtQuick import QtQuick
import QtQuick.Layouts
ShellRoot { ShellRoot {
id: shellroot id: shellroot
Component.onCompleted: [Launcher.init(), AudioPopup.init()]
ReloadPopup {}
Variants { Variants {
model: Quickshell.screens model: Quickshell.screens
@ -15,8 +19,6 @@ ShellRoot {
Bar { Bar {
screen: modelData screen: modelData
} }
ReloadPopup {}
} }
} }
} }