progress
This commit is contained in:
parent
35524b5e6e
commit
b750421f65
6 changed files with 435 additions and 34 deletions
103
AudioPopup.qml
Normal file
103
AudioPopup.qml
Normal 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() {
|
||||||
|
}
|
||||||
|
}
|
7
Bar.qml
7
Bar.qml
|
@ -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
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
297
Launcher.qml
297
Launcher.qml
|
@ -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() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
35
SysTray.qml
35
SysTray.qml
|
@ -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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
shell.qml
10
shell.qml
|
@ -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 {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue