progress
This commit is contained in:
parent
1a27b905bf
commit
334bca71fe
17 changed files with 733 additions and 117 deletions
|
@ -6,11 +6,9 @@ import Quickshell
|
|||
import "../../config"
|
||||
import "components"
|
||||
|
||||
Rectangle {
|
||||
Item {
|
||||
id: root
|
||||
|
||||
color: Config.bar.colors.bar
|
||||
|
||||
required property ShellScreen screen
|
||||
|
||||
anchors {
|
||||
|
@ -48,10 +46,5 @@ Rectangle {
|
|||
screen: root.screen
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.screen.name
|
||||
color: "green"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,22 +13,23 @@ Rectangle {
|
|||
|
||||
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
|
||||
|
||||
property bool _: log()
|
||||
function log() {
|
||||
console.debug("Screen name: " + screen.name);
|
||||
console.debug("Found the following workspaces:");
|
||||
for (let i = 0; i < workspaces.length; i++) {
|
||||
console.debug("Workspace " + workspaces[i].id + " On screen " + workspaces[i].output + " With name: " + workspaces[i].name);
|
||||
// console.debug(workspaces[i].output);
|
||||
}
|
||||
return true;
|
||||
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
|
||||
|
||||
|
@ -96,8 +97,13 @@ Rectangle {
|
|||
border.color: Config.catppuccin.mantle
|
||||
border.width: 0
|
||||
color: Config.catppuccin.blue
|
||||
// visible: wsItem.isCorrectScreen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
Niri.workspaces.forEach(workspace => {
|
||||
root.workspaceAdded(workspace);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
|
9
modules/drawers/Backgrounds.qml
Normal file
9
modules/drawers/Backgrounds.qml
Normal file
|
@ -0,0 +1,9 @@
|
|||
import Quickshell
|
||||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
|
||||
import "../notifications" as Notifications
|
||||
|
||||
Rectangle {
|
||||
required property Item bar
|
||||
}
|
|
@ -7,7 +7,7 @@ import "../../config"
|
|||
Item {
|
||||
id: root
|
||||
|
||||
required property Rectangle bar
|
||||
required property Item bar
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
|
|
|
@ -7,9 +7,11 @@ import QtQuick
|
|||
import QtQuick.Effects
|
||||
|
||||
import "../bar"
|
||||
import "../volume"
|
||||
import "../notifications"
|
||||
|
||||
// import "../../services"
|
||||
import "../../services"
|
||||
import "../../config"
|
||||
|
||||
Variants {
|
||||
model: Quickshell.screens
|
||||
|
@ -35,13 +37,22 @@ Variants {
|
|||
// 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: 8
|
||||
width: win.width - bar.implicitWidth
|
||||
height: win.height - 8
|
||||
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 {
|
||||
|
@ -60,6 +71,10 @@ Variants {
|
|||
Border {
|
||||
bar: bar
|
||||
}
|
||||
|
||||
Backgrounds {
|
||||
bar: bar
|
||||
}
|
||||
}
|
||||
|
||||
MultiEffect {
|
||||
|
@ -73,45 +88,18 @@ Variants {
|
|||
id: bar
|
||||
screen: scope.modelData
|
||||
}
|
||||
Item {
|
||||
id: notifs
|
||||
|
||||
readonly property list<Notif> list: []
|
||||
readonly property list<Notif> popups: list.filter(n => n.popup)
|
||||
VolumeSlider {
|
||||
id: volume
|
||||
isInRightPanel: hover.isInRightPanel
|
||||
screen: scope.modelData
|
||||
}
|
||||
|
||||
NotificationServer {
|
||||
id: server
|
||||
|
||||
keepOnReload: false
|
||||
|
||||
onNotification: notif => {
|
||||
notif.tracked = true;
|
||||
console.log("Got notification: " + notif.body);
|
||||
|
||||
root.list.push(notifComp.createObject(root, {
|
||||
popup: true,
|
||||
notification: notif,
|
||||
body: notif.body,
|
||||
appName: notif.appName
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: notifComp
|
||||
|
||||
Notif {}
|
||||
}
|
||||
Hover {
|
||||
id: hover
|
||||
screen: scope.modelData
|
||||
bar: bar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component Notif: QtObject {
|
||||
property bool popup
|
||||
readonly property date time: new Date()
|
||||
|
||||
required property Notification notification
|
||||
readonly property string body: notification.body
|
||||
readonly property string appName: notification.appName
|
||||
}
|
||||
}
|
||||
|
|
319
modules/launcher/Launcher.qml
Normal file
319
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() {
|
||||
}
|
||||
}
|
41
modules/volume/VolumeSlider.qml
Normal file
41
modules/volume/VolumeSlider.qml
Normal file
|
@ -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
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue