desktop icons

This commit is contained in:
Zacharias-Brohn
2026-03-12 14:45:20 +01:00
parent 851b78f0ff
commit 9e9708ed12
11 changed files with 561 additions and 156 deletions
+95 -63
View File
@@ -6,17 +6,18 @@ import Quickshell.Hyprland
import qs.Components
import qs.Config
import qs.Paths
import qs.Helpers
Item {
id: root
anchors.fill: parent
z: 998
visible: false
property real menuX: 0
property real menuY: 0
MouseArea {
anchors.fill: parent
onClicked: root.close()
@@ -25,39 +26,46 @@ Item {
CustomClippingRect {
id: popupBackground
readonly property real padding: 4
x: root.menuX
y: root.menuY
color: DynamicColors.tPalette.m3surface
radius: Appearance.rounding.normal
implicitWidth: menuLayout.implicitWidth + padding * 2
implicitHeight: menuLayout.implicitHeight + padding * 2
Behavior on opacity { Anim {} }
opacity: root.visible ? 1 : 0
ColumnLayout {
id: menuLayout
anchors.fill: parent
anchors.margins: popupBackground.padding
anchors.centerIn: parent
spacing: 0
StateLayer {
Layout.fillWidth: true
contentItem: RowLayout {
CustomRect {
Layout.preferredWidth: 200
radius: popupBackground.radius - popupBackground.padding
implicitHeight: openTerminalRow.implicitHeight + Appearance.padding.small * 2
RowLayout {
id: openTerminalRow
spacing: 8
anchors.fill: parent
anchors.margins: 12
anchors.leftMargin: Appearance.padding.smaller
MaterialIcon { text: "terminal"; font.pointSize: 20 }
CustomText { text: "Open terminal"; Layout.fillWidth: true }
}
onClicked: {
Quickshell.execDetached([Config.general.apps.terminal, "--working-directory", FileUtils.trimFileProtocol(Paths.desktop)])
root.close()
StateLayer {
anchors.fill: parent
onClicked: {
Quickshell.execDetached([Config.general.apps.terminal, "--working-directory", FileUtils.trimFileProtocol(Paths.desktop)])
root.close()
}
}
}
@@ -69,81 +77,105 @@ Item {
Layout.bottomMargin: 4
}
StateLayer {
CustomRect {
Layout.fillWidth: true
contentItem: RowLayout {
radius: popupBackground.radius - popupBackground.padding
implicitHeight: settingsRow.implicitHeight + Appearance.padding.small * 2
RowLayout {
id: settingsRow
spacing: 8
anchors.fill: parent
anchors.margins: 12
anchors.leftMargin: Appearance.padding.smaller
MaterialIcon { text: "settings"; font.pointSize: 20 }
CustomText { text: "Sleex settings"; Layout.fillWidth: true }
CustomText { text: "ZShell settings"; Layout.fillWidth: true }
}
onClicked: {
Quickshell.execDetached(["qs", "-p", "/usr/share/sleex/settings.qml"])
root.close()
StateLayer {
anchors.fill: parent
onClicked: {
Quickshell.execDetached(["qs", "-p", "/usr/share/sleex/settings.qml"])
root.close()
}
}
}
CustomRect {
Layout.fillWidth: true
implicitHeight: 1
color: Appearance.m3colors.m3outlineVariant
color: DynamicColors.palette.m3outlineVariant
Layout.topMargin: 4
Layout.bottomMargin: 4
}
StateLayer {
CustomRect {
Layout.fillWidth: true
contentItem: RowLayout {
radius: popupBackground.radius - popupBackground.padding
implicitHeight: logoutRow.implicitHeight + Appearance.padding.small * 2
RowLayout {
id: logoutRow
spacing: 8
anchors.fill: parent
anchors.margins: 12
anchors.leftMargin: Appearance.padding.smaller
MaterialIcon { text: "logout"; font.pointSize: 20 }
CustomText { text: "Logout"; Layout.fillWidth: true }
}
onClicked: {
Hyprland.dispatch("global quickshell:sessionOpen")
root.close()
}
}
CustomRect {
Layout.fillWidth: true
implicitHeight: 1
color: Appearance.m3colors.m3outlineVariant
Layout.topMargin: 4
Layout.bottomMargin: 4
}
StateLayer {
Layout.fillWidth: true
contentItem: RowLayout {
spacing: 8
StateLayer {
anchors.fill: parent
anchors.margins: 12
MaterialIcon { text: Config.options.background.showDesktopIcons ? "visibility_off" : "visibility"; font.pointSize: 20 }
CustomText { text: Config.options.background.showDesktopIcons ? "Hide icons" : "Show icons"; Layout.fillWidth: true }
}
onClicked: {
Config.options.background.showDesktopIcons = !Config.options.background.showDesktopIcons
root.close()
onClicked: {
Hyprland.dispatch("global quickshell:sessionOpen")
root.close()
}
}
}
// CustomRect {
// Layout.fillWidth: true
// implicitHeight: 1
// color: DynamicColors.palette.m3outlineVariant
// Layout.topMargin: 4
// Layout.bottomMargin: 4
// }
//
// CustomRect {
// Layout.fillWidth: true
// radius: popupBackground.radius - popupBackground.padding
// implicitHeight: desktopIconsRow.implicitHeight + Appearance.padding.small * 2
//
// RowLayout {
// id: desktopIconsRow
// spacing: 8
// anchors.fill: parent
// anchors.leftMargin: Appearance.padding.smaller
//
// MaterialIcon { text: Config.options.background.showDesktopIcons ? "visibility_off" : "visibility"; font.pointSize: 20 }
// CustomText { text: Config.options.background.showDesktopIcons ? "Hide icons" : "Show icons"; Layout.fillWidth: true }
// }
//
// StateLayer {
// anchors.fill: parent
//
// onClicked: {
// Config.options.background.showDesktopIcons = !Config.options.background.showDesktopIcons
// root.close()
// }
// }
// }
}
}
function openAt(mouseX, mouseY, parentW, parentH) {
menuX = Math.min(mouseX, parentW - popupBackground.implicitWidth)
menuY = Math.min(mouseY, parentH - popupBackground.implicitHeight)
menuX = Math.floor(Math.min(mouseX, parentW - popupBackground.implicitWidth))
menuY = Math.floor(Math.min(mouseY, parentH - popupBackground.implicitHeight))
visible = true
}
function close() {
visible = false
}
+116 -77
View File
@@ -23,73 +23,87 @@ Item {
property real menuX: 0
property real menuY: 0
MouseArea {
anchors.fill: parent
onClicked: contextMenu.close()
}
CustomClippingRect {
id: popupBackground
readonly property real padding: 4
readonly property real padding: Appearance.padding.small
x: contextMenu.menuX
y: contextMenu.menuY
color: DynamicColors.tPalette.m3surface
radius: Appearance.rounding.normal
implicitWidth: menuLayout.implicitWidth + padding * 2
implicitHeight: menuLayout.implicitHeight + padding * 2
Behavior on opacity { Anim {} }
opacity: contextMenu.visible ? 1 : 0
ColumnLayout {
id: menuLayout
anchors.fill: parent
anchors.margins: popupBackground.padding
anchors.centerIn: parent
spacing: 0
StateLayer {
Layout.fillWidth: true
contentItem: RowLayout {
CustomRect {
Layout.preferredWidth: 160
radius: popupBackground.radius - popupBackground.padding
implicitHeight: openRow.implicitHeight + Appearance.padding.small * 2
RowLayout {
id: openRow
spacing: 8
anchors.fill: parent
anchors.margins: 12
anchors.leftMargin: Appearance.padding.smaller
MaterialIcon { text: "open_in_new"; font.pointSize: 20 }
CustomText { text: "Open"; Layout.fillWidth: true }
}
onClicked: {
for (let i = 0; i < contextMenu.targetPaths.length; i++) {
let p = contextMenu.targetPaths[i];
if (p === contextMenu.targetFilePath) {
if (p.endsWith(".desktop") && contextMenu.targetAppEntry) contextMenu.targetAppEntry.execute()
else contextMenu.openFileRequested(p, contextMenu.targetIsDir)
} else {
Quickshell.execDetached(["xdg-open", p])
StateLayer {
anchors.fill: parent
onClicked: {
for (let i = 0; i < contextMenu.targetPaths.length; i++) {
let p = contextMenu.targetPaths[i];
if (p === contextMenu.targetFilePath) {
if (p.endsWith(".desktop") && contextMenu.targetAppEntry) contextMenu.targetAppEntry.execute()
else contextMenu.openFileRequested(p, contextMenu.targetIsDir)
} else {
Quickshell.execDetached(["xdg-open", p])
}
}
contextMenu.close()
}
contextMenu.close()
}
}
StateLayer {
CustomRect {
Layout.fillWidth: true
contentItem: RowLayout {
radius: popupBackground.radius - popupBackground.padding
implicitHeight: openWithRow.implicitHeight + Appearance.padding.small * 2
RowLayout {
id: openWithRow
spacing: 8
anchors.fill: parent
anchors.margins: 12
anchors.leftMargin: Appearance.padding.smaller
MaterialIcon { text: contextMenu.targetIsDir ? "terminal" : "apps"; font.pointSize: 20 }
CustomText { text: contextMenu.targetIsDir ? "Open in terminal" : "Open with..."; Layout.fillWidth: true }
}
onClicked: {
Quickshell.execDetached(["xdg-open", contextMenu.targetFilePath])
contextMenu.close()
StateLayer {
anchors.fill: parent
onClicked: {
if (contextMenu.targetIsDir) {
Quickshell.execDetached([Config.general.apps.terminal, "--working-directory", contextMenu.targetFilePath])
} else {
Quickshell.execDetached(["xdg-open", contextMenu.targetFilePath])
}
contextMenu.close()
}
}
}
@@ -101,92 +115,117 @@ Item {
Layout.bottomMargin: 4
}
StateLayer {
CustomRect {
Layout.fillWidth: true
contentItem: RowLayout {
radius: popupBackground.radius - popupBackground.padding
implicitHeight: copyPathRow.implicitHeight + Appearance.padding.small * 2
RowLayout {
id: copyPathRow
spacing: 8
anchors.fill: parent
anchors.margins: 12
anchors.leftMargin: Appearance.padding.smaller
MaterialIcon { text: "content_copy"; font.pointSize: 20 }
CustomText { text: "Copy path"; Layout.fillWidth: true }
}
onClicked: {
Quickshell.execDetached(["wl-copy", contextMenu.targetPaths.join("\n")])
contextMenu.close()
StateLayer {
anchors.fill: parent
onClicked: {
Quickshell.execDetached(["wl-copy", contextMenu.targetPaths.join("\n")])
contextMenu.close()
}
}
}
StateLayer {
CustomRect {
Layout.fillWidth: true
visible: contextMenu.targetPaths.length === 1
contentItem: RowLayout {
radius: popupBackground.radius - popupBackground.padding
implicitHeight: renameRow.implicitHeight + Appearance.padding.small * 2
RowLayout {
id: renameRow
spacing: 8
anchors.fill: parent
anchors.margins: 12
anchors.leftMargin: Appearance.padding.smaller
MaterialIcon { text: "edit"; font.pointSize: 20 }
CustomText { text: "Rename"; Layout.fillWidth: true }
}
onClicked: {
contextMenu.renameRequested(contextMenu.targetFilePath)
contextMenu.close()
StateLayer {
anchors.fill: parent
onClicked: {
contextMenu.renameRequested(contextMenu.targetFilePath)
contextMenu.close()
}
}
}
Rectangle {
Layout.fillWidth: true
implicitHeight: 1
color: Appearance.m3colors.m3outlineVariant
color: DynamicColors.palette.m3outlineVariant
Layout.topMargin: 4
Layout.bottomMargin: 4
}
StateLayer {
id: deleteButton
CustomRect {
Layout.fillWidth: true
colBackgroundHover: Appearance.colors.colError
contentItem: RowLayout {
radius: popupBackground.radius - popupBackground.padding
implicitHeight: deleteRow.implicitHeight + Appearance.padding.small * 2
RowLayout {
id: deleteRow
spacing: 8
anchors.fill: parent
anchors.margins: 12
anchors.leftMargin: Appearance.padding.smaller
MaterialIcon {
text: "delete";
font.pointSize: 20;
color: deleteButton.hovered ? Appearance.colors.colOnError : Appearance.colors.colError
text: "delete"
font.pointSize: 20
color: deleteButton.hovered ? DynamicColors.palette.m3onError : DynamicColors.palette.m3error
}
CustomText {
text: "Move to trash";
Layout.fillWidth: true;
color: deleteButton.hovered ? Appearance.colors.colOnError : Appearance.colors.colError
text: "Move to trash"
Layout.fillWidth: true
color: deleteButton.hovered ? DynamicColors.palette.m3onError : DynamicColors.palette.m3error
}
}
onClicked: {
let cmd = ["gio", "trash"].concat(contextMenu.targetPaths)
Quickshell.execDetached(cmd)
contextMenu.close()
StateLayer {
id: deleteButton
anchors.fill: parent
color: DynamicColors.tPalette.m3error
onClicked: {
let cmd = ["gio", "trash"].concat(contextMenu.targetPaths)
Quickshell.execDetached(cmd)
contextMenu.close()
}
}
}
}
}
function openAt(mouseX, mouseY, path, isDir, appEnt, parentW, parentH, selectionArray) {
targetFilePath = path
targetIsDir = isDir
targetAppEntry = appEnt
targetPaths = (selectionArray && selectionArray.length > 0) ? selectionArray : [path]
menuX = Math.min(mouseX, parentW - popupBackground.implicitWidth)
menuY = Math.min(mouseY, parentH - popupBackground.implicitHeight)
menuX = Math.floor(Math.min(mouseX, parentW - popupBackground.implicitWidth))
menuY = Math.floor(Math.min(mouseY, parentH - popupBackground.implicitHeight))
visible = true
}
function close() {
visible = false
}
+2 -1
View File
@@ -15,6 +15,7 @@ Item {
property int gridX: model.gridX
property int gridY: model.gridY
property bool isSnapping: snapAnimX.running || snapAnimY.running
property bool lassoActive
property string resolvedIcon: {
if (fileName.endsWith(".desktop")) {
if (appEntry && appEntry.icon && appEntry.icon !== "")
@@ -214,7 +215,7 @@ Item {
acceptedButtons: Qt.LeftButton | Qt.RightButton
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
cursorShape: root.lassoActive ? undefined : Qt.PointingHandCursor
drag.target: dragContainer
hoverEnabled: true
+57 -13
View File
@@ -2,6 +2,8 @@ import QtQuick
import Quickshell
import qs.Modules
import qs.Helpers
import qs.Config
import qs.Components
import qs.Paths
import ZShell.Services
@@ -15,6 +17,7 @@ Item {
property string editingFilePath: ""
property real groupDragX: 0
property real groupDragY: 0
property bool lassoActive: false
property var selectedIcons: []
property real startX: 0
property real startY: 0
@@ -54,7 +57,6 @@ Item {
root.groupDragY = 0;
}
anchors.fill: parent
focus: true
Keys.onPressed: event => {
@@ -68,15 +70,55 @@ Item {
Component.onCompleted: loadDirectory(FileUtils.trimFileProtocol(Paths.desktop))
}
Rectangle {
CustomRect {
id: lasso
border.color: Appearance.colors.colPrimary
function hideLasso() {
fadeIn.stop();
fadeOut.start();
root.lassoActive = false;
}
function showLasso() {
root.lassoActive = true;
fadeOut.stop();
visible = true;
fadeIn.start();
}
border.color: DynamicColors.palette.m3primary
border.width: 1
color: DynamicColors.tPalette.m3primary
opacity: 0
radius: Appearance.rounding.small
visible: false
z: 99
NumberAnimation {
id: fadeIn
duration: 120
from: 0
property: "opacity"
target: lasso
to: 1
}
SequentialAnimation {
id: fadeOut
NumberAnimation {
duration: 120
from: lasso.opacity
property: "opacity"
target: lasso
to: 0
}
ScriptAction {
script: lasso.visible = false
}
}
}
MouseArea {
@@ -85,10 +127,10 @@ Item {
onPositionChanged: mouse => {
if (lasso.visible) {
lasso.x = Math.min(mouse.x, root.startX);
lasso.y = Math.min(mouse.y, root.startY);
lasso.width = Math.abs(mouse.x - root.startX);
lasso.height = Math.abs(mouse.y - root.startY);
lasso.x = Math.floor(Math.min(mouse.x, root.startX));
lasso.y = Math.floor(Math.min(mouse.y, root.startY));
lasso.width = Math.floor(Math.abs(mouse.x - root.startX));
lasso.height = Math.floor(Math.abs(mouse.y - root.startY));
let minCol = Math.floor((lasso.x - gridArea.x) / cellWidth);
let maxCol = Math.floor((lasso.x + lasso.width - gridArea.x) / cellWidth);
@@ -115,17 +157,17 @@ Item {
} else {
bgContextMenu.close();
root.selectedIcons = [];
root.startX = mouse.x;
root.startY = mouse.y;
lasso.x = mouse.x;
lasso.y = mouse.y;
root.startX = Math.floor(mouse.x);
root.startY = Math.floor(mouse.y);
lasso.x = Math.floor(mouse.x);
lasso.y = Math.floor(mouse.y);
lasso.width = 0;
lasso.height = 0;
lasso.visible = true;
lasso.showLasso();
}
}
onReleased: {
lasso.visible = false;
lasso.hideLasso();
}
}
@@ -142,6 +184,8 @@ Item {
delegate: DesktopIconDelegate {
property int itemIndex: index
lassoActive: root.lassoActive
}
}
}