diff options
| author | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-07-19 22:54:58 +1000 |
|---|---|---|
| committer | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-07-19 22:54:58 +1000 |
| commit | 7c991dee0a276ab110325f6c8d1c44875d5f8526 (patch) | |
| tree | 50a6c8b788defc3107909e1b4a356bf691cd2a47 | |
| parent | launcher: fix (diff) | |
| download | caelestia-shell-7c991dee0a276ab110325f6c8d1c44875d5f8526.tar.gz caelestia-shell-7c991dee0a276ab110325f6c8d1c44875d5f8526.tar.bz2 caelestia-shell-7c991dee0a276ab110325f6c8d1c44875d5f8526.zip | |
internal: file dialog part 1
| -rw-r--r-- | widgets/filedialog/FileDialog.qml | 40 | ||||
| -rw-r--r-- | widgets/filedialog/FolderContents.qml | 122 | ||||
| -rw-r--r-- | widgets/filedialog/HeaderBar.qml | 128 | ||||
| -rw-r--r-- | widgets/filedialog/Sizes.qml | 7 |
4 files changed, 297 insertions, 0 deletions
diff --git a/widgets/filedialog/FileDialog.qml b/widgets/filedialog/FileDialog.qml new file mode 100644 index 0000000..915c09c --- /dev/null +++ b/widgets/filedialog/FileDialog.qml @@ -0,0 +1,40 @@ +import qs.services +import qs.config +import Quickshell +import QtQuick.Layouts + +FloatingWindow { + id: root + + property list<string> cwd: ["Home", "Downloads"] + + implicitWidth: 1000 + implicitHeight: 600 + color: Colours.palette.m3surface + + RowLayout { + anchors.fill: parent + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true + + spacing: Appearance.spacing.small + + HeaderBar { + Layout.fillWidth: true + cwd: root.cwd + } + + FolderContents { + Layout.fillWidth: true + Layout.fillHeight: true + + cwd: root.cwd + } + } + } +} diff --git a/widgets/filedialog/FolderContents.qml b/widgets/filedialog/FolderContents.qml new file mode 100644 index 0000000..c59d87f --- /dev/null +++ b/widgets/filedialog/FolderContents.qml @@ -0,0 +1,122 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.services +import qs.config +import qs.utils +import Quickshell +import Quickshell.Io +import Quickshell.Widgets +import QtQuick +import Qt.labs.folderlistmodel + +GridView { + id: root + + required property list<string> cwd + + property var mimes: ({}) + + clip: true + focus: true + Keys.onEscapePressed: root.currentIndex = -1 + + model: FolderListModel { + folder: { + let url = "file://"; + if (root.cwd[0] === "Home") + url += `${Paths.strip(Paths.home)}/${root.cwd.slice(1).join("/")}`; + else + url += root.cwd.join("/"); + return url; + } + } + + delegate: StyledRect { + id: item + + required property int index + required property string fileName + required property url fileUrl + required property string fileSuffix + required property bool fileIsDir + + readonly property real nonAnimHeight: icon.implicitHeight + name.anchors.topMargin + name.implicitHeight + Appearance.padding.normal * 2 + + implicitWidth: Sizes.itemWidth + implicitHeight: nonAnimHeight + + radius: Appearance.rounding.normal + color: root.currentItem === item ? Colours.palette.m3primary : "transparent" + z: root.currentItem === item || implicitHeight !== nonAnimHeight ? 1 : 0 + clip: true + + StateLayer { + color: root.currentItem === item ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + onDoubleClicked: console.log("double clicked", item) + + function onClicked(): void { + root.currentIndex = item.index; + } + } + + IconImage { + id: icon + + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: Appearance.spacing.normal + + asynchronous: true + implicitSize: Sizes.itemWidth - Appearance.padding.normal * 2 + source: { + const mime = root.mimes[item.fileSuffix]; + + if (mime?.startsWith("image-")) + return item.fileUrl; + + return Quickshell.iconPath(item.fileIsDir ? "inode-directory" : root.mimes[item.fileSuffix] ?? "application-x-zerosize", "image-missing"); + } + onStatusChanged: { + if (status === Image.Error) + source = Quickshell.iconPath("error"); + } + } + + StyledText { + id: name + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: icon.bottom + anchors.topMargin: Appearance.spacing.small + anchors.margins: Appearance.padding.normal + + horizontalAlignment: Text.AlignHCenter + text: item.fileName + color: root.currentItem === item ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + elide: root.currentItem === item ? Text.ElideNone : Text.ElideRight + wrapMode: root.currentItem === item ? Text.WrapAtWordBoundaryOrAnywhere : Text.NoWrap + } + + Behavior on implicitHeight { + NumberAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } + } + } + + FileView { + path: "/etc/mime.types" + onLoaded: { + root.mimes = text().split("\n").filter(l => !l.startsWith("#")).reduce((mimes, line) => { + const [type, ext] = line.split(/\s+/); + if (ext) + mimes[ext] = type.replace("/", "-"); + return mimes; + }, {}); + } + } +} diff --git a/widgets/filedialog/HeaderBar.qml b/widgets/filedialog/HeaderBar.qml new file mode 100644 index 0000000..40177a3 --- /dev/null +++ b/widgets/filedialog/HeaderBar.qml @@ -0,0 +1,128 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +RowLayout { + id: root + + required property list<string> cwd + + spacing: Appearance.spacing.small + + Item { + implicitWidth: implicitHeight + implicitHeight: upIcon.implicitHeight + Appearance.padding.small * 2 + + StateLayer { + radius: Appearance.rounding.small + + function onClicked(): void { + root.cwd.pop(); + } + } + + MaterialIcon { + id: upIcon + + anchors.centerIn: parent + text: "drive_folder_upload" + } + } + + StyledRect { + Layout.fillWidth: true + + radius: Appearance.rounding.small + color: Colours.palette.m3surfaceContainer + + implicitHeight: pathComponents.implicitHeight + pathComponents.anchors.margins * 2 + + RowLayout { + id: pathComponents + + anchors.fill: parent + anchors.margins: Appearance.padding.small + anchors.leftMargin: 0 + + spacing: Appearance.spacing.small + + Repeater { + model: root.cwd + + RowLayout { + id: folder + + required property string modelData + required property int index + + spacing: 0 + + Loader { + Layout.rightMargin: Appearance.spacing.small + active: folder.index > 0 + asynchronous: true + sourceComponent: StyledText { + text: "/" + color: Colours.palette.m3onSurfaceVariant + font.bold: true + } + } + + Item { + implicitWidth: homeIcon.implicitWidth + (homeIcon.active ? Appearance.padding.small : 0) + folderName.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: Math.max(homeIcon.implicitHeight, folderName.implicitHeight) + Appearance.padding.small * 2 + + Loader { + anchors.fill: parent + active: folder.index < root.cwd.length - 1 + asynchronous: true + sourceComponent: StateLayer { + radius: Appearance.rounding.small + + function onClicked(): void { + root.cwd = root.cwd.slice(0, folder.index); + } + } + } + + Loader { + id: homeIcon + + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: Appearance.padding.normal + + active: folder.index === 0 && folder.modelData === "Home" + asynchronous: true + sourceComponent: MaterialIcon { + text: "home" + color: root.cwd.length === 1 ? Colours.palette.m3onSurface : Colours.palette.m3onSurfaceVariant + fill: 1 + } + } + + StyledText { + id: folderName + + anchors.left: homeIcon.right + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: homeIcon.active ? Appearance.padding.small : 0 + + text: folder.modelData + color: folder.index < root.cwd.length - 1 ? Colours.palette.m3onSurfaceVariant : Colours.palette.m3onSurface + font.bold: true + } + } + } + } + + Item { + Layout.fillWidth: true + } + } + } +} diff --git a/widgets/filedialog/Sizes.qml b/widgets/filedialog/Sizes.qml new file mode 100644 index 0000000..d332ab3 --- /dev/null +++ b/widgets/filedialog/Sizes.qml @@ -0,0 +1,7 @@ +pragma Singleton + +import Quickshell + +Singleton { + property int itemWidth: 100 +} |