quickshell: init config
This commit is contained in:
parent
cbb594395a
commit
5e9c4e8e4c
20 changed files with 1650 additions and 0 deletions
103
modules/style/quickshell/shell/AudioPopup.qml
Normal file
103
modules/style/quickshell/shell/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() {
|
||||||
|
}
|
||||||
|
}
|
46
modules/style/quickshell/shell/ClockWidget.qml
Normal file
46
modules/style/quickshell/shell/ClockWidget.qml
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
|
||||||
|
|
||||||
|
width: text.width
|
||||||
|
implicitHeight: text.height
|
||||||
|
// border.color: "black"
|
||||||
|
border.width: 2
|
||||||
|
radius: 0
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
Behavior on implicitHeight {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 100
|
||||||
|
easing.type: Easing.OutCubic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: text.height
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
SystemClock {
|
||||||
|
id: clock
|
||||||
|
precision: SystemClock.Seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: text
|
||||||
|
anchors.centerIn: parent
|
||||||
|
property var date: Date()
|
||||||
|
|
||||||
|
text: Qt.formatDateTime(clock.date, "hh mm")
|
||||||
|
|
||||||
|
font.family: "ComicShannsMono Nerd Font Mono"
|
||||||
|
font.weight: Font.ExtraBold
|
||||||
|
font.pointSize: 12
|
||||||
|
|
||||||
|
color: "black"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
310
modules/style/quickshell/shell/Launcher.qml
Normal file
310
modules/style/quickshell/shell/Launcher.qml
Normal file
|
@ -0,0 +1,310 @@
|
||||||
|
pragma Singleton
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import Quickshell.Widgets
|
||||||
|
|
||||||
|
import "./config"
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: launcher
|
||||||
|
property bool launcherOpen: false
|
||||||
|
|
||||||
|
IpcHandler {
|
||||||
|
target: "launcher"
|
||||||
|
|
||||||
|
function open(): void {
|
||||||
|
launcher.launcherOpen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function close(): void {
|
||||||
|
launcher.launcherOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle(): void {
|
||||||
|
launcher.launcherOpen = !launcher.launcherOpen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyLoader {
|
||||||
|
id: loader
|
||||||
|
activeAsync: launcher.launcherOpen
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
implicitWidth: 450
|
||||||
|
implicitHeight: 7 + searchContainer.implicitHeight + list.topMargin * 2 + list.delegateHeight * 10
|
||||||
|
color: "transparent"
|
||||||
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
||||||
|
|
||||||
|
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: Config.catppuccin.base
|
||||||
|
radius: 5
|
||||||
|
border.color: Config.catppuccin.mantle
|
||||||
|
border.width: 2
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 7
|
||||||
|
anchors.bottomMargin: 0
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: searchContainer
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitHeight: searchbox.implicitHeight + 10
|
||||||
|
color: Config.catppuccin.base
|
||||||
|
radius: 3
|
||||||
|
border.color: Config.catppuccin.mantle
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: searchbox
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 5
|
||||||
|
|
||||||
|
TextInput {
|
||||||
|
id: search
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: Config.catppuccin.text
|
||||||
|
font.pointSize: 13
|
||||||
|
|
||||||
|
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: "transparent"
|
||||||
|
border.color: Config.catppuccin.lavender
|
||||||
|
border.width: 2
|
||||||
|
}
|
||||||
|
keyNavigationEnabled: true
|
||||||
|
keyNavigationWraps: true
|
||||||
|
highlightMoveVelocity: -1
|
||||||
|
highlightMoveDuration: 50
|
||||||
|
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: Config.catppuccin.text
|
||||||
|
font.family: "JetBrainsMono Nerd Font Mono"
|
||||||
|
font.pointSize: 13
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function init() {
|
||||||
|
}
|
||||||
|
}
|
127
modules/style/quickshell/shell/ReloadPopup.qml
Normal file
127
modules/style/quickshell/shell/ReloadPopup.qml
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
|
||||||
|
Scope {
|
||||||
|
id: root
|
||||||
|
property bool failed
|
||||||
|
property string errorString
|
||||||
|
|
||||||
|
// Connect to the Quickshell global to listen for the reload signals.
|
||||||
|
Connections {
|
||||||
|
target: Quickshell
|
||||||
|
|
||||||
|
function onReloadCompleted() {
|
||||||
|
root.failed = false;
|
||||||
|
popupLoader.loading = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onReloadFailed(error: string) {
|
||||||
|
// Close any existing popup before making a new one.
|
||||||
|
popupLoader.active = false;
|
||||||
|
|
||||||
|
root.failed = true;
|
||||||
|
root.errorString = error;
|
||||||
|
popupLoader.loading = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep the popup in a loader because it isn't needed most of the timeand will take up
|
||||||
|
// memory that could be used for something else.
|
||||||
|
LazyLoader {
|
||||||
|
id: popupLoader
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: popup
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: true
|
||||||
|
right: true
|
||||||
|
}
|
||||||
|
|
||||||
|
margins {
|
||||||
|
top: 25
|
||||||
|
left: 25
|
||||||
|
}
|
||||||
|
|
||||||
|
width: rect.width
|
||||||
|
height: rect.height
|
||||||
|
|
||||||
|
// color blending is a bit odd as detailed in the type reference.
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: rect
|
||||||
|
color: root.failed ? "#40802020" : "#40009020"
|
||||||
|
|
||||||
|
implicitHeight: layout.implicitHeight + 50
|
||||||
|
implicitWidth: layout.implicitWidth + 30
|
||||||
|
|
||||||
|
// Fills the whole area of the rectangle, making any clicks go to it,
|
||||||
|
// which dismiss the popup.
|
||||||
|
MouseArea {
|
||||||
|
id: mouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: popupLoader.active = false
|
||||||
|
|
||||||
|
// makes the mouse area track mouse hovering, so the hide animation
|
||||||
|
// can be paused when hovering.
|
||||||
|
hoverEnabled: true
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: layout
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
topMargin: 20
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: root.failed ? "Reloaing failed." : "Reloading completed!"
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: root.errorString
|
||||||
|
color: "white"
|
||||||
|
// When visible is false, it also takes up no space.
|
||||||
|
visible: root.errorString != ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A progress bar on the bottom of the screen, showing how long until the
|
||||||
|
// popup is removed.
|
||||||
|
Rectangle {
|
||||||
|
id: bar
|
||||||
|
color: "#20ffffff"
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
height: 20
|
||||||
|
|
||||||
|
PropertyAnimation {
|
||||||
|
id: anim
|
||||||
|
target: bar
|
||||||
|
property: "width"
|
||||||
|
from: rect.width
|
||||||
|
to: 0
|
||||||
|
duration: failed ? 10000 : 800
|
||||||
|
onFinished: popupLoader.active = false
|
||||||
|
|
||||||
|
// Pause the animation when the mouse is hovering over the popup,
|
||||||
|
// so it stays onscreen while reading. This updates reactively
|
||||||
|
// when the mouse moves on and off the popup.
|
||||||
|
paused: mouseArea.containsMouse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We could set `running: true` inside the animation, but the width of the
|
||||||
|
// rectangle might not be calculated yet, due to the layout.
|
||||||
|
// In the `Component.onCompleted` event handler, all of the component's
|
||||||
|
// properties and children have been initialized.
|
||||||
|
Component.onCompleted: anim.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
modules/style/quickshell/shell/SysTray.qml
Normal file
57
modules/style/quickshell/shell/SysTray.qml
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Effects
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Services.SystemTray
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
required property var bar
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
height: column.height + 10
|
||||||
|
color: "#30c0ffff"
|
||||||
|
radius: 5
|
||||||
|
border.color: "black"
|
||||||
|
border.width: 2
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: column
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: SystemTray.items
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: item
|
||||||
|
|
||||||
|
required property SystemTrayItem modelData
|
||||||
|
|
||||||
|
height: 35
|
||||||
|
width: 35
|
||||||
|
|
||||||
|
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) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
46
modules/style/quickshell/shell/config/Config.qml
Normal file
46
modules/style/quickshell/shell/config/Config.qml
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property QtObject bar: QtObject {
|
||||||
|
readonly property int width: 50
|
||||||
|
readonly property var colors: QtObject {
|
||||||
|
readonly property color bar: "#1e1e2e"
|
||||||
|
readonly property color barOutline: "#50ffffff"
|
||||||
|
readonly property color widget: "#25ceffff"
|
||||||
|
readonly property color widgetActive: "#80ceffff"
|
||||||
|
readonly property color widgetOutline: "#40ffffff"
|
||||||
|
readonly property color widgetOutlineSeparate: "#20ffffff"
|
||||||
|
readonly property color separator: "#60ffffff"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property QtObject border: QtObject {
|
||||||
|
readonly property int thickness: 8
|
||||||
|
readonly property color color: "#1e1e2e"
|
||||||
|
readonly property int rounding: 25
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property QtObject catppuccin: QtObject {
|
||||||
|
readonly property color base: "#1e1e2e"
|
||||||
|
readonly property color mantle: "#181825"
|
||||||
|
readonly property color surface0: "#313244"
|
||||||
|
readonly property color surface1: "#45475a"
|
||||||
|
readonly property color surface2: "#585b70"
|
||||||
|
readonly property color text: "#cdd6f4"
|
||||||
|
readonly property color rosewater: "#f5e0dc"
|
||||||
|
readonly property color lavender: "#b4befe"
|
||||||
|
readonly property color red: "#f38ba8"
|
||||||
|
readonly property color peach: "#fab387"
|
||||||
|
readonly property color yellow: "#f9e2af"
|
||||||
|
readonly property color green: "#a6e3a1"
|
||||||
|
readonly property color teal: "#a6e3a1"
|
||||||
|
readonly property color blue: "#89b4fa"
|
||||||
|
readonly property color mauve: "#cba6f7"
|
||||||
|
readonly property color flamingo: "#f2cdcd"
|
||||||
|
}
|
||||||
|
}
|
50
modules/style/quickshell/shell/modules/bar/Bar.qml
Normal file
50
modules/style/quickshell/shell/modules/bar/Bar.qml
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
|
||||||
|
import "../../config"
|
||||||
|
import "components"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property ShellScreen screen
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
bottom: parent.bottom
|
||||||
|
left: parent.left
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitWidth: Config.bar.width
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: child
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
bottom: parent.bottom
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitWidth: Math.max(clock.implicitWidth, workspaces.implicitWidth)
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: 2
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
margins: 0
|
||||||
|
}
|
||||||
|
Clock {
|
||||||
|
id: clock
|
||||||
|
}
|
||||||
|
Workspaces {
|
||||||
|
id: workspaces
|
||||||
|
screen: root.screen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
|
||||||
|
import "../../../config"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
width: text.width + 5
|
||||||
|
height: text.height + 5
|
||||||
|
implicitWidth: width
|
||||||
|
border.color: Config.catppuccin.rosewater
|
||||||
|
border.width: 0
|
||||||
|
radius: 5
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: text
|
||||||
|
anchors.centerIn: parent
|
||||||
|
property var date: Date()
|
||||||
|
|
||||||
|
text: Qt.formatDateTime(clock.date, "hh mm")
|
||||||
|
|
||||||
|
font.family: "JetBrainsMono NF Mono"
|
||||||
|
font.pointSize: 15
|
||||||
|
|
||||||
|
color: Config.catppuccin.text
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemClock {
|
||||||
|
id: clock
|
||||||
|
precision: SystemClock.Seconds
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import "../../../services/niri"
|
||||||
|
import "../../../config"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property ShellScreen screen
|
||||||
|
property var workspaces: Niri.workspaces
|
||||||
|
property var wsCount: Niri.workspaces.length
|
||||||
|
property var activeWorkspace: Niri.activeWorkspace
|
||||||
|
property var activeWorkspaceIndex: Niri.activeWorkspaceIndex
|
||||||
|
|
||||||
|
property int wsItemHeight: 15
|
||||||
|
|
||||||
|
signal workspaceAdded(workspace: var)
|
||||||
|
function onWorkspaceAdded(workspace: var) {
|
||||||
|
root.workspaces.push(workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
// property bool _: log()
|
||||||
|
// function log() {
|
||||||
|
// console.log(workspaces.values);
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Works
|
||||||
|
height: 300
|
||||||
|
|
||||||
|
// Gives warning
|
||||||
|
// height: workspaces.length * root.wsItemHeight
|
||||||
|
implicitWidth: list.implicitWidth
|
||||||
|
color: "transparent"
|
||||||
|
border.color: Config.catppuccin.rosewater
|
||||||
|
border.width: 0
|
||||||
|
radius: 7
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: list
|
||||||
|
model: root.workspaces
|
||||||
|
implicitHeight: contentHeight
|
||||||
|
implicitWidth: contentItem.childrenRect.width
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
// anchors.fill: parent
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
id: wsItem
|
||||||
|
// Name of the workspace
|
||||||
|
property string name: "VOID"
|
||||||
|
// ID of the workspace
|
||||||
|
required property string id
|
||||||
|
|
||||||
|
required property string output
|
||||||
|
|
||||||
|
property bool isActive: (id - 1 == root.activeWorkspaceIndex)
|
||||||
|
|
||||||
|
property real animActive: isActive ? 1 : 0.65
|
||||||
|
Behavior on animActive {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 150
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// property bool isCorrectScreen: log()
|
||||||
|
// function log() {
|
||||||
|
// console.log("Screen name: " + root.screen.name);
|
||||||
|
// console.log(wsItem.output);
|
||||||
|
// console.log(wsItem.id);
|
||||||
|
|
||||||
|
// let isCorrect = root.screen.name == wsItem.output;
|
||||||
|
// console.log("isCorrect: ", isCorrect);
|
||||||
|
// return root.screen.name == wsItem.output;
|
||||||
|
// }
|
||||||
|
|
||||||
|
implicitHeight: root.wsItemHeight
|
||||||
|
implicitWidth: 50
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
right: parent.right
|
||||||
|
left: parent.left
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
height: wsItem.height - 5
|
||||||
|
width: parent.width * wsItem.animActive
|
||||||
|
radius: height / 2
|
||||||
|
border.color: Config.catppuccin.mantle
|
||||||
|
border.width: 0
|
||||||
|
color: Config.catppuccin.blue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
Niri.workspaces.forEach(workspace => {
|
||||||
|
root.workspaceAdded(workspace);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
import "../notifications" as Notifications
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
required property Item bar
|
||||||
|
}
|
54
modules/style/quickshell/shell/modules/drawers/Border.qml
Normal file
54
modules/style/quickshell/shell/modules/drawers/Border.qml
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Effects
|
||||||
|
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property Item bar
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: rect
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Config.border.color
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: 150
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: mask
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
layer.enabled: true
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Config.border.thickness
|
||||||
|
anchors.leftMargin: root.bar.implicitWidth
|
||||||
|
radius: Config.border.rounding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiEffect {
|
||||||
|
anchors.fill: parent
|
||||||
|
maskEnabled: true
|
||||||
|
maskInverted: true
|
||||||
|
maskSource: mask
|
||||||
|
source: rect
|
||||||
|
maskThresholdMin: 0.5
|
||||||
|
maskSpreadAtMin: 1
|
||||||
|
}
|
||||||
|
}
|
105
modules/style/quickshell/shell/modules/drawers/Drawers.qml
Normal file
105
modules/style/quickshell/shell/modules/drawers/Drawers.qml
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import Quickshell.Services.Notifications
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Effects
|
||||||
|
|
||||||
|
import "../bar"
|
||||||
|
import "../volume"
|
||||||
|
import "../notifications"
|
||||||
|
|
||||||
|
import "../../services"
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
Variants {
|
||||||
|
model: Quickshell.screens
|
||||||
|
|
||||||
|
Scope {
|
||||||
|
id: scope
|
||||||
|
required property ShellScreen modelData
|
||||||
|
|
||||||
|
Exclusions {
|
||||||
|
screen: scope.modelData
|
||||||
|
bar: bar
|
||||||
|
}
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: win
|
||||||
|
|
||||||
|
screen: scope.modelData
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||||
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||||
|
|
||||||
|
// Clickthrough mask.
|
||||||
|
// Clickable areas of the window are determined by the provided region.
|
||||||
|
mask: Region {
|
||||||
|
// Start at the bottom left; right of the bar and on top of the border
|
||||||
|
x: bar.implicitWidth
|
||||||
|
y: Config.border.thickness
|
||||||
|
|
||||||
|
// Width is the window width - the bar's width - the border thickness
|
||||||
|
width: win.width - bar.implicitWidth - Config.border.thickness
|
||||||
|
|
||||||
|
// Height is window width - the border thickness x2 —top border and bottom border.
|
||||||
|
height: win.height - Config.border.thickness * 2
|
||||||
|
|
||||||
|
// Setting the intersection mode to Xor will invert the mask and make everything in the mask region not clickable and pass through clicks inside it through the window.
|
||||||
|
intersection: Intersection.Xor
|
||||||
|
Region {
|
||||||
|
item: volume
|
||||||
|
intersection: Intersection.Subtract
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: true
|
||||||
|
bottom: true
|
||||||
|
left: true
|
||||||
|
right: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: background
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
Border {
|
||||||
|
bar: bar
|
||||||
|
}
|
||||||
|
|
||||||
|
Backgrounds {
|
||||||
|
bar: bar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiEffect {
|
||||||
|
anchors.fill: source
|
||||||
|
source: background
|
||||||
|
shadowEnabled: true
|
||||||
|
blurMax: 15
|
||||||
|
}
|
||||||
|
|
||||||
|
Bar {
|
||||||
|
id: bar
|
||||||
|
screen: scope.modelData
|
||||||
|
}
|
||||||
|
|
||||||
|
VolumeSlider {
|
||||||
|
id: volume
|
||||||
|
isInRightPanel: hover.isInRightPanel
|
||||||
|
screen: scope.modelData
|
||||||
|
}
|
||||||
|
|
||||||
|
Hover {
|
||||||
|
id: hover
|
||||||
|
screen: scope.modelData
|
||||||
|
bar: bar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
Scope {
|
||||||
|
id: root
|
||||||
|
required property ShellScreen screen
|
||||||
|
required property Item bar
|
||||||
|
|
||||||
|
ExclusionZone {
|
||||||
|
anchors.left: true
|
||||||
|
exclusiveZone: root.bar.implicitWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
ExclusionZone {
|
||||||
|
anchors.top: true
|
||||||
|
}
|
||||||
|
|
||||||
|
ExclusionZone {
|
||||||
|
anchors.right: true
|
||||||
|
}
|
||||||
|
|
||||||
|
ExclusionZone {
|
||||||
|
anchors.bottom: true
|
||||||
|
}
|
||||||
|
|
||||||
|
component ExclusionZone: PanelWindow {
|
||||||
|
screen: root.screen
|
||||||
|
color: "transparent"
|
||||||
|
exclusiveZone: Config.border.thickness
|
||||||
|
implicitHeight: Config.border.thickness
|
||||||
|
implicitWidth: Config.border.thickness
|
||||||
|
mask: Region {}
|
||||||
|
}
|
||||||
|
}
|
319
modules/style/quickshell/shell/modules/launcher/Launcher.qml
Normal file
319
modules/style/quickshell/shell/modules/launcher/Launcher.qml
Normal file
|
@ -0,0 +1,319 @@
|
||||||
|
pragma Singleton
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import Quickshell.Widgets
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: launcher
|
||||||
|
property bool launcherOpen: false
|
||||||
|
|
||||||
|
IpcHandler {
|
||||||
|
target: "launcher"
|
||||||
|
|
||||||
|
function open(): void {
|
||||||
|
launcher.launcherOpen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function close(): void {
|
||||||
|
launcher.launcherOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle(): void {
|
||||||
|
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"
|
||||||
|
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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: "#30c0afaf"
|
||||||
|
radius: 5
|
||||||
|
border.color: "black"
|
||||||
|
border.width: 2
|
||||||
|
|
||||||
|
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: "#20e0ffff"
|
||||||
|
border.color: "#30ffffff"
|
||||||
|
border.width: 1
|
||||||
|
}
|
||||||
|
keyNavigationEnabled: true
|
||||||
|
keyNavigationWraps: true
|
||||||
|
highlightMoveVelocity: -1
|
||||||
|
highlightMoveDuration: 50
|
||||||
|
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"
|
||||||
|
font.family: "ComicShannsMono Nerd Font Mono"
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function init() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import Quickshell.Services.Notifications
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import "../../config"
|
||||||
|
import "../../services"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
color: "transparent"
|
||||||
|
required property Notification.Notif modelData
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: root.modelData.summary
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import Quickshell.Services.Notifications
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Effects
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
required property bool isInRightPanel
|
||||||
|
required property ShellScreen screen
|
||||||
|
property bool isVisible
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
property bool _: log()
|
||||||
|
function log() {
|
||||||
|
console.log(hover.hovered);
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
right: parent.right
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitWidth: 60
|
||||||
|
implicitHeight: screen.height / 3
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
id: hover
|
||||||
|
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.right: parent.right
|
||||||
|
color: "green"
|
||||||
|
implicitWidth: hover.hovered | root.isInRightPanel ? 60 : 10
|
||||||
|
implicitHeight: root.screen.height / 3
|
||||||
|
}
|
||||||
|
}
|
49
modules/style/quickshell/shell/services/Hover.qml
Normal file
49
modules/style/quickshell/shell/services/Hover.qml
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import "../config"
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
|
required property ShellScreen screen
|
||||||
|
// required property Panels panels
|
||||||
|
required property Item bar
|
||||||
|
|
||||||
|
property bool showVolumeMenu: false
|
||||||
|
property bool isInRightPanel: false
|
||||||
|
|
||||||
|
// function withinPanelHeight(panel: Item, x: real, y: real): bool {
|
||||||
|
// const panelY = Config.border.thickness + panel.y;
|
||||||
|
// return y >= panelY - Config.border.rounding && y <= panelY + panel.height + Config.border.rounding;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function inLeftBorder(x: real, y: real): bool {
|
||||||
|
// return x <= Config.border.thickness;
|
||||||
|
// }
|
||||||
|
|
||||||
|
function inRightPanel(x: real, y: real): bool {
|
||||||
|
// Cursor is in middle veritcal third of screen
|
||||||
|
// Cursor is in the right border
|
||||||
|
return y >= root.screen.height / 3 && y <= (root.screen.height / 3) * 2 && x >= root.screen.width - Config.border.thickness;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update on mouse cursor movement
|
||||||
|
onPositionChanged: event => {
|
||||||
|
const x = event.x;
|
||||||
|
const y = event.y;
|
||||||
|
|
||||||
|
root.isInRightPanel = inRightPanel(x, y);
|
||||||
|
|
||||||
|
console.log("In right panel: " + root.isInRightPanel);
|
||||||
|
|
||||||
|
console.log("x:" + x + " y: " + y);
|
||||||
|
}
|
||||||
|
onContainsMouseChanged: {
|
||||||
|
if (!containsMouse) {
|
||||||
|
root.isInRightPanel = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
modules/style/quickshell/shell/services/Notification.qml
Normal file
20
modules/style/quickshell/shell/services/Notification.qml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
pragma Singleton
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import Quickshell.Services.Notifications
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides extra features not in Quickshell.Services.Notifications:
|
||||||
|
* - Persistent storage
|
||||||
|
* - Popup notifications, with timeout
|
||||||
|
* - Notification groups by app
|
||||||
|
*/
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
NotificationServer {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
94
modules/style/quickshell/shell/services/niri/Niri.qml
Normal file
94
modules/style/quickshell/shell/services/niri/Niri.qml
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
// Kind thanks to https://github.com/MapoMagpie/nixos-flakes/blob/main/home/ui/quickshell/config/Data/Niri.qml
|
||||||
|
// This file was taken from there and further modified.
|
||||||
|
|
||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
// property var data
|
||||||
|
property var workspaces: []
|
||||||
|
property var activeWorkspace: "VOID"
|
||||||
|
property var activeWorkspaceIndex: 0
|
||||||
|
property var windows: []
|
||||||
|
// property var activedWindowId: 0
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: proc
|
||||||
|
command: ["niri", "msg", "-j", "event-stream"]
|
||||||
|
|
||||||
|
running: true
|
||||||
|
stdout: SplitParser {
|
||||||
|
onRead: data => {
|
||||||
|
var event = JSON.parse(data);
|
||||||
|
let workspaces = [];
|
||||||
|
if (event.WorkspacesChanged) {
|
||||||
|
root.workspaces = event.WorkspacesChanged.workspaces;
|
||||||
|
root.workspaces = root.workspaces.sort((a, b) => a.id - b.id);
|
||||||
|
root.activeWorkspaceIndex = root.workspaces.findIndex(w => w.is_focused);
|
||||||
|
if (root.activeWorkspaceIndex < 0) {
|
||||||
|
root.activeWorkspaceIndex = 0;
|
||||||
|
}
|
||||||
|
root.activeWorkspace = root.workspaces[root.activeWorkspaceIndex].name;
|
||||||
|
}
|
||||||
|
if (event.WindowsChanged) {
|
||||||
|
root.windows = [...event.WindowsChanged.windows].sort((a, b) => a.id - b.id);
|
||||||
|
}
|
||||||
|
if (event.WindowOpenedOrChanged) {
|
||||||
|
const window = event.WindowOpenedOrChanged.window;
|
||||||
|
const index = root.windows.findIndex(w => w.id === window.id);
|
||||||
|
// console.log("window opened or changed: ", index, ", win id: ", window.id);
|
||||||
|
if (index >= 0) {
|
||||||
|
// console.log("replace window, old: ", root.windows[index].id, ", new: ", window.id);
|
||||||
|
root.windows[index] = window;
|
||||||
|
} else {
|
||||||
|
// console.log("push window, new: ", window.id);
|
||||||
|
root.windows.push(window);
|
||||||
|
}
|
||||||
|
root.windows = [...root.windows.sort((a, b) => a.id - b.id)];
|
||||||
|
}
|
||||||
|
if (event.WindowClosed) {
|
||||||
|
const index = root.windows.findIndex(w => w.id === event.WindowClosed.id);
|
||||||
|
// console.log("window closed: ", index, ", win id: ", event.WindowClosed.id);
|
||||||
|
if (index >= 0) {
|
||||||
|
root.windows.splice(index, 1);
|
||||||
|
}
|
||||||
|
root.windows = [...root.windows.sort((a, b) => a.id - b.id)];
|
||||||
|
}
|
||||||
|
if (event.WorkspaceActivated) {
|
||||||
|
root.activeWorkspaceIndex = root.workspaces.findIndex(w => w.id === event.WorkspaceActivated.id);
|
||||||
|
if (root.activeWorkspaceIndex < 0) {
|
||||||
|
root.activeWorkspaceIndex = 0;
|
||||||
|
}
|
||||||
|
root.activeWorkspace = root.workspaces[root.activeWorkspaceIndex].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// component Workspace: QtObject {
|
||||||
|
// required property int id
|
||||||
|
// property int idx
|
||||||
|
// property string name: "VOID"
|
||||||
|
// required property string output
|
||||||
|
// property bool is_active
|
||||||
|
// property bool is_focused
|
||||||
|
// property int active_window_id
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// {
|
||||||
|
// "workspaces": [
|
||||||
|
// {
|
||||||
|
// "id": 5,
|
||||||
|
// "idx": 4,
|
||||||
|
// "name": "GAME",
|
||||||
|
// "output": "DP-3",
|
||||||
|
// "is_active": false,
|
||||||
|
// "is_focused": false,
|
||||||
|
// "active_window_id": null
|
||||||
|
// },
|
||||||
|
// ]
|
||||||
|
// }
|
|
@ -0,0 +1,21 @@
|
||||||
|
//@ pragma Env QS_NO_RELOAD_POPUP=1
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
import "modules"
|
||||||
|
import "modules/drawers"
|
||||||
|
import "services"
|
||||||
|
|
||||||
|
// import "modules/background"
|
||||||
|
|
||||||
|
ShellRoot {
|
||||||
|
id: shellroot
|
||||||
|
|
||||||
|
Component.onCompleted: [Launcher.init()]
|
||||||
|
|
||||||
|
Drawers {}
|
||||||
|
// Background {}Popup
|
||||||
|
//
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue