adds overview, removes old stuff
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
// WallpaperPopup.qml - A popup for browsing and setting wallpapers from /usr/share/wallpapers
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
required property var screen
|
||||
|
||||
property bool logicalOpen: GlobalStates.popups.active === "wallpaper"
|
||||
property bool _keepVisible: false
|
||||
visible: logicalOpen || _keepVisible
|
||||
|
||||
onLogicalOpenChanged: {
|
||||
if (logicalOpen) {
|
||||
closeTimer.stop()
|
||||
_keepVisible = false
|
||||
if (wallpaperModel.count === 0) scanProc.running = true
|
||||
openY.start()
|
||||
openOpacity.start()
|
||||
focusTimer.start()
|
||||
} else {
|
||||
_keepVisible = true
|
||||
closeY.start()
|
||||
closeOpacity.start()
|
||||
closeTimer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
Timer { id: closeTimer; interval: 280; onTriggered: root._keepVisible = false }
|
||||
Timer { id: focusTimer; interval: 50; onTriggered: grid.forceActiveFocus() }
|
||||
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.namespace: "quickshell-popup-wallpaper"
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
||||
anchors { top: true; left: true; right: true; bottom: true }
|
||||
color: Qt.rgba(0, 0, 0, 0)
|
||||
|
||||
MouseArea { anchors.fill: parent; onClicked: GlobalStates.popups.close() }
|
||||
|
||||
NumberAnimation { id: openY; target: box; property: "y"; to: 1; duration: 250; easing.type: Easing.OutCubic }
|
||||
NumberAnimation { id: closeY; target: box; property: "y"; to: -340; duration: 200; easing.type: Easing.InCubic }
|
||||
NumberAnimation { id: openOpacity; target: box; property: "opacity"; to: Theme.popupOpacity; duration: 200 }
|
||||
NumberAnimation { id: closeOpacity; target: box; property: "opacity"; to: 0.0; duration: 200 }
|
||||
|
||||
// ── Named-pipe IPC ────────────────────────────────────────
|
||||
// Trigger from Hyprland keybind: echo 1 > /tmp/qs-wallpaper-ipc
|
||||
// Trigger from another QML popup: Exec.run(["bash", "-c", "echo 1 > /tmp/qs-wallpaper-ipc"])
|
||||
Process {
|
||||
id: ipcReader
|
||||
running: true
|
||||
command: ["bash", "-c",
|
||||
"rm -f /tmp/qs-wallpaper-ipc && " +
|
||||
"mkfifo /tmp/qs-wallpaper-ipc && " +
|
||||
"while true; do cat /tmp/qs-wallpaper-ipc; done"]
|
||||
stdout: SplitParser {
|
||||
onRead: () => GlobalStates.popups.toggle("wallpaper", 0)
|
||||
}
|
||||
onExited: running = true
|
||||
}
|
||||
|
||||
// ── Wallpaper scanner ─────────────────────────────────────
|
||||
ListModel { id: wallpaperModel }
|
||||
|
||||
Process {
|
||||
id: scanProc
|
||||
running: false
|
||||
command: ["bash", "-c",
|
||||
"find /usr/share/wallpapers -type f " +
|
||||
"\\( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.webp' \\) " +
|
||||
"| sort"]
|
||||
stdout: SplitParser {
|
||||
onRead: (line) => {
|
||||
var p = line.trim()
|
||||
if (p) wallpaperModel.append({ path: p })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process { id: setProc; running: false }
|
||||
|
||||
// ── Popup box ─────────────────────────────────────────────
|
||||
Rectangle {
|
||||
id: box
|
||||
|
||||
// anchorX = 0 → centered; anchorX > 0 → centered under widget
|
||||
x: {
|
||||
var ax = GlobalStates.popups.anchorX
|
||||
var cx = ax > 0 ? ax - width / 2 : parent.width / 2 - width / 2
|
||||
return Math.max(4, Math.min(parent.width - width - 4, cx))
|
||||
}
|
||||
y: -340
|
||||
opacity: 0.0
|
||||
|
||||
width: 324
|
||||
height: 500
|
||||
|
||||
color: Theme.popupBackground
|
||||
radius: Theme.radius * 2
|
||||
clip: true
|
||||
border.color: Theme.popupBorderColor
|
||||
border.width: Theme.popupBorderWidth
|
||||
|
||||
MouseArea { anchors.fill: parent }
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
visible: wallpaperModel.count === 0
|
||||
text: "Scanning..."
|
||||
font { family: Theme.fontSans; pixelSize: Theme.fontSize }
|
||||
color: Theme.pillText
|
||||
opacity: 0.5
|
||||
}
|
||||
|
||||
GridView {
|
||||
id: grid
|
||||
anchors { fill: parent; margins: 8 }
|
||||
clip: true
|
||||
cellWidth: Math.floor(width / 2)
|
||||
cellHeight: 104
|
||||
focus: true
|
||||
keyNavigationEnabled: true
|
||||
currentIndex: 0
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
var item = wallpaperModel.get(grid.currentIndex)
|
||||
if (item) {
|
||||
setProc.command = ["waypaper", "--wallpaper", item.path]
|
||||
setProc.running = true
|
||||
GlobalStates.popups.close()
|
||||
}
|
||||
}
|
||||
Keys.onEscapePressed: GlobalStates.popups.close()
|
||||
|
||||
model: wallpaperModel
|
||||
|
||||
highlight: Rectangle {
|
||||
z: 2
|
||||
radius: Theme.radius + 1
|
||||
color: "transparent"
|
||||
border.color: Theme.accent ?? "#cba6f7"
|
||||
border.width: 2
|
||||
}
|
||||
highlightFollowsCurrentItem: true
|
||||
highlightMoveDuration: 80
|
||||
|
||||
delegate: Item {
|
||||
required property string path
|
||||
required property int index
|
||||
|
||||
width: grid.cellWidth - 4
|
||||
height: 100
|
||||
|
||||
Rectangle {
|
||||
anchors { fill: parent; margins: 2 }
|
||||
radius: Theme.radius
|
||||
color: "black"
|
||||
clip: true
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: "file://" + path
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
sourceSize: Qt.size(152, 96)
|
||||
smooth: true
|
||||
asynchronous: true
|
||||
opacity: status === Image.Ready ? 1.0 : 0.0
|
||||
Behavior on opacity { NumberAnimation { duration: 150 } }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.radius
|
||||
color: hover.containsMouse ? Qt.rgba(1, 1, 1, 0.2) : "transparent"
|
||||
Behavior on color { ColorAnimation { duration: 100 } }
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: hover
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
grid.currentIndex = index
|
||||
setProc.command = ["waypaper", "--wallpaper", path]
|
||||
setProc.running = true
|
||||
GlobalStates.popups.close()
|
||||
}
|
||||
onEntered: grid.currentIndex = index
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user