diff --git a/Config/Config.qml b/Config/Config.qml new file mode 100644 index 0000000..8d0109f --- /dev/null +++ b/Config/Config.qml @@ -0,0 +1,18 @@ + + FileView { + id: watcher + path: root.configPath + + watchChanges: true + + onFileChanged: reload() + + onAdapterUpdated: writeAdapter() + + JsonAdapter { + id: adapter + + property string gifFolder: Quickshell.shellDir + "/Gifs" + property real maxScaling: 1 + } + } diff --git a/Config/Pets.qml b/Config/Pets.qml new file mode 100644 index 0000000..7eb883b --- /dev/null +++ b/Config/Pets.qml @@ -0,0 +1,38 @@ + + FileView { + id: watcher + path: configPath + + property string name: gifItem.fileBaseName + ".json" + property string configDir: Quickshell.env("HOME") + "/.config/I-DeskPet/" + property string configPath: configDir + name + + onLoaded: { + if ( gifSaved.zIndex === -1 ) gifSaved.zIndex = gifItem.index + gifItem.x = gifSaved.positionX + gifItem.y = gifSaved.positionY + gifItem.loaded = true + } + + onLoadFailed: { + gifSaved.zIndex = gifItem.index + writeAdapter() + gifItem.loaded = true + } + + watchChanges: true + + onFileChanged: reload() + + onAdapterUpdated: writeAdapter() + + JsonAdapter { + id: gifSaved + + property real scaling: 1 + property int positionX: 0 + property int positionY: 0 + property int zIndex: -1 + } + } + } diff --git a/General.qml b/General.qml new file mode 100644 index 0000000..2856121 --- /dev/null +++ b/General.qml @@ -0,0 +1,38 @@ + + FileView { + id: watcher + path: configPath + + property string name: gifItem.fileBaseName + ".json" + property string configDir: Quickshell.env("HOME") + "/.config/I-DeskPet/" + property string configPath: configDir + name + + onLoaded: { + if ( gifSaved.zIndex === -1 ) gifSaved.zIndex = gifItem.index + gifItem.x = gifSaved.positionX + gifItem.y = gifSaved.positionY + gifItem.loaded = true + } + + onLoadFailed: { + gifSaved.zIndex = gifItem.index + writeAdapter() + gifItem.loaded = true + } + + watchChanges: true + + onFileChanged: reload() + + onAdapterUpdated: writeAdapter() + + JsonAdapter { + id: gifSaved + + property real scaling: 1 + property int positionX: 0 + property int positionY: 0 + property int zIndex: -1 + } + } +} diff --git a/Modules/ConfigLoader.qml b/Modules/ConfigLoader.qml index 6be19d5..395cce1 100644 --- a/Modules/ConfigLoader.qml +++ b/Modules/ConfigLoader.qml @@ -7,49 +7,50 @@ import Quickshell Singleton { id: root - property alias gifFolder: adapter.gifFolder - property alias maxScaling: adapter.maxScaling property string configDir: Quickshell.env("HOME") + "/.config/I-DeskPet" property string configPath: configDir + "/config.json" + property alias gifFolder: adapter.gifFolder + property alias maxScaling: adapter.maxScale Process { id: dirCheck - running: true - command: [ "test", "-d", root.configDir ] - onExited: function( exitCode ) { - if ( exitCode !== 0 ) { - console.log( "creating dir" ) - dirCreate.running = true + command: ["test", "-d", root.configDir] + running: true + + onExited: function (exitCode) { + if (exitCode !== 0) { + console.log("creating dir"); + dirCreate.running = true; } - } - } + } + } Process { id: dirCreate - running: false - command: [ "mkdir", "-p", root.configDir ] - onExited: function(): void { - console.log( "Created config directory:", root.configDir ) + command: ["mkdir", "-p", root.configDir] + running: false + + onExited: function (): void { + console.log("Created config directory:", root.configDir); } } FileView { id: watcher - path: root.configPath + path: root.configPath watchChanges: true - onFileChanged: reload() - onAdapterUpdated: writeAdapter() + onFileChanged: reload() JsonAdapter { id: adapter - property string gifFolder: Quickshell.shellDir + "/Gifs" - property real maxScaling: 1 + property string gifFolder: Quickshell.shellDir + "/Gifs" + property real maxScale: 1 } } } diff --git a/Modules/GetGifs.qml b/Modules/GetGifs.qml index 64fb61d..2814d00 100644 --- a/Modules/GetGifs.qml +++ b/Modules/GetGifs.qml @@ -3,15 +3,16 @@ import Qt.labs.folderlistmodel Item { id: root - required property string gifFolder - property alias gifsModel: folderModel property alias count: folderModel.count + required property string gifFolder + property alias gifsModel: folderModel FolderListModel { id: folderModel + folder: "file://" + root.gifFolder - nameFilters: [ "*.gif" ] + nameFilters: ["*.gif"] showDirs: false showHidden: false sortField: FolderListModel.Name diff --git a/Modules/GifsLoader.qml b/Modules/GifsLoader.qml index c86849e..af4c56d 100644 --- a/Modules/GifsLoader.qml +++ b/Modules/GifsLoader.qml @@ -7,78 +7,82 @@ import Qt.labs.folderlistmodel import qs.Modules Repeater { - id: gifRepeater - required property FolderListModel gifsModel + id: gifRepeater - model: gifsModel - Item { + required property FolderListModel gifsModel + + model: gifsModel + + Item { id: gifItem - required property url fileUrl required property string fileBaseName + required property url fileUrl + property alias hovered: mouse.containsMouse required property int index property bool loaded: false - property alias hovered: mouse.containsMouse property alias zIndex: gifSaved.zIndex - z: gifSaved.zIndex + height: Math.floor(gif.sourceSize.height / gifSaved.scaling) visible: gifItem.loaded - onXChanged: if ( gifItem.loaded ) gifSaved.positionX = gifItem.x - onYChanged: if ( gifItem.loaded ) gifSaved.positionY = gifItem.y - width: Math.floor( gif.sourceSize.width / gifSaved.scaling ) - height: Math.floor( gif.sourceSize.height / gifSaved.scaling ) + width: Math.floor(gif.sourceSize.width / gifSaved.scaling) + z: gifSaved.zIndex - AnimatedImage { - id: gif - source: gifItem.fileUrl - fillMode: Image.PreserveAspectFit - anchors.fill: parent - } + onXChanged: if (gifItem.loaded) + gifSaved.positionX = gifItem.x + onYChanged: if (gifItem.loaded) + gifSaved.positionY = gifItem.y + + AnimatedImage { + id: gif + + anchors.fill: parent + fillMode: Image.PreserveAspectFit + source: gifItem.fileUrl + } Mouse { id: mouse - onWheel: (wheel)=> { - gifSaved.scaling = Math.max( ConfigLoader.maxScaling, ( gifSaved.scaling + 0.1 * ( wheel.angleDelta.y / 120 ) ) ) - } - + onDoubleClicked: gifSaved.scaling = 1 + onWheel: wheel => { + gifSaved.scaling = Math.max(ConfigLoader.maxScaling, (gifSaved.scaling + 0.1 * (wheel.angleDelta.y / 120))); + } } FileView { id: watcher - path: configPath - property string name: gifItem.fileBaseName + ".json" property string configDir: Quickshell.env("HOME") + "/.config/I-DeskPet/" property string configPath: configDir + name + property string name: gifItem.fileBaseName + ".json" - onLoaded: { - if ( gifSaved.zIndex === -1 ) gifSaved.zIndex = gifItem.index - gifItem.x = gifSaved.positionX - gifItem.y = gifSaved.positionY - gifItem.loaded = true - } - - onLoadFailed: { - gifSaved.zIndex = gifItem.index - writeAdapter() - gifItem.loaded = true - } - + path: configPath watchChanges: true - onFileChanged: reload() - onAdapterUpdated: writeAdapter() + onFileChanged: reload() + onLoadFailed: { + gifSaved.zIndex = gifItem.index; + writeAdapter(); + gifItem.loaded = true; + } + onLoaded: { + if (gifSaved.zIndex === -1) + gifSaved.zIndex = gifItem.index; + gifItem.x = gifSaved.positionX; + gifItem.y = gifSaved.positionY; + gifItem.loaded = true; + } JsonAdapter { id: gifSaved - property real scaling: 1 property int positionX: 0 property int positionY: 0 + property real scaling: 1 property int zIndex: -1 } } - } + } } diff --git a/Modules/Mouse.qml b/Modules/Mouse.qml index 39d5ad8..4b37b16 100644 --- a/Modules/Mouse.qml +++ b/Modules/Mouse.qml @@ -1,13 +1,13 @@ import QtQuick MouseArea { - anchors.fill: parent - acceptedButtons: Qt.LeftButton - hoverEnabled: true - drag.target: parent - drag.axis: Drag.XAndYAxis - drag.minimumX: 0 - drag.maximumX: Screen.width - parent.width - drag.minimumY: 0 - drag.maximumY: Screen.height - parent.height + acceptedButtons: Qt.LeftButton + anchors.fill: parent + drag.axis: Drag.XAndYAxis + drag.maximumX: Screen.width - parent.width + drag.maximumY: Screen.height - parent.height + drag.minimumX: 0 + drag.minimumY: 0 + drag.target: parent + hoverEnabled: true } diff --git a/shell.qml b/shell.qml index de78f62..194523b 100644 --- a/shell.qml +++ b/shell.qml @@ -1,167 +1,183 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import Quickshell.Wayland -import Quickshell.Hyprland -import qs.Modules - -PanelWindow { - id: mainWindow - WlrLayershell.namespace: "I-DeskPet" - WlrLayershell.layer: WlrLayer.Overlay - WlrLayershell.exclusionMode: ExclusionMode.Ignore - surfaceFormat.opaque: false - color: "transparent" - - property bool onTop: true - property list repeaterItems: [] - - anchors { - left: true - bottom: true - right: true - top: true - } - - margins { - left: 0 - bottom: 0 - right: 0 - top: 0 - } - - GetGifs { - id: getGifs - gifFolder: ConfigLoader.gifFolder - } +pragma ComponentBehavior: Bound - GifsLoader { - id: gifLoader - gifsModel: getGifs.gifsModel - onItemAdded: function( index, item ) { - mainWindow.repeaterItems = Array.from( { length: gifLoader.count }, (_, i) => gifLoader.itemAt(i) ).filter( v => v !== null ) +import QtQuick +import Quickshell +import Quickshell.Io +import Quickshell.Wayland +import Quickshell.Hyprland +import qs.Modules + +PanelWindow { + id: mainWindow + + property var noMove: Region { + } + property bool onTop: true + property var petMove: Region { + id: pets + + height: Screen.height + intersection: Intersection.Xor + regions: maskVariants.instances + width: Screen.width + } + property list repeaterItems: [] + property bool setMask: true + + function petRegion(itemObject) { + let newregion = regionComponent.createObject(pets, { + "item": itemObject + }); + pets.regions.push(newregion); + } + + WlrLayershell.exclusionMode: ExclusionMode.Ignore + WlrLayershell.layer: WlrLayer.Overlay + WlrLayershell.namespace: "I-DeskPet" + color: "transparent" + surfaceFormat.opaque: false + + mask: Region { + height: Screen.height + intersection: Intersection.Xor + regions: maskVariants.instances + width: Screen.width + } + + anchors { + bottom: true + left: true + right: true + top: true + } + + margins { + bottom: 0 + left: 0 + right: 0 + top: 0 + } + + GetGifs { + id: getGifs + + gifFolder: ConfigLoader.gifFolder + } + + GifsLoader { + id: gifLoader + + gifsModel: getGifs.gifsModel + + onItemAdded: function (index, item) { + mainWindow.repeaterItems = Array.from({ + length: gifLoader.count + }, (_, i) => gifLoader.itemAt(i)).filter(v => v !== null); } - onItemRemoved: function( index, item ) { - mainWindow.repeaterItems = Array.from( { length: gifLoader.count }, (_, i) => gifLoader.itemAt(i) ).filter( v => v !== null ) + onItemRemoved: function (index, item) { + mainWindow.repeaterItems = Array.from({ + length: gifLoader.count + }, (_, i) => gifLoader.itemAt(i)).filter(v => v !== null); } - } - - Variants { - id: maskVariants - - model: [ ...mainWindow.repeaterItems ] - - Region { - required property Item modelData - - Component.onCompleted: { - console.log(modelData) - } - - x: modelData.x - y: modelData.y - width: modelData.width - height: modelData.height - intersection: Intersection.Subtract - } - } - - function petRegion( itemObject ) { - let newregion = regionComponent.createObject( pets, { "item": itemObject }) - pets.regions.push( newregion ) - } - - Component { - id: regionComponent - Region { } - } - - mask: Region { - width: Screen.width - height: Screen.height - intersection: Intersection.Xor - regions: maskVariants.instances - } - - property var petMove: Region { id: pets - width: Screen.width - height: Screen.height - intersection: Intersection.Xor - regions: maskVariants.instances - } - - property var noMove: Region {} - - property bool setMask: true - - GlobalShortcut { - appid: "I-DeskPet" - name: "toggle-Layer" - onPressed: { - if (!mainWindow.onTop) { - mainWindow.WlrLayershell.layer = WlrLayer.Overlay - mainWindow.onTop = true - } else { - mainWindow.WlrLayershell.layer = WlrLayer.Bottom - mainWindow.onTop = false - } - } - } - - GlobalShortcut { - appid: "I-DeskPet" - name: "toggle-Region" - onPressed: { - if ( !mainWindow.setMask ) { - mainWindow.mask = mainWindow.petMove - mainWindow.setMask = true - } else { - mainWindow.mask = mainWindow.noMove - mainWindow.setMask = false - } - } - } + } - GlobalShortcut { - appid: "I-DeskPet" - name: "cycle-zIndex" - onPressed: { - let items = mainWindow.repeaterItems - if ( items.length < 2 ) return + Variants { + id: maskVariants - // Find the hovered GIF - let hovered = null - for ( let i = 0; i < items.length; i++ ) { - if ( items[i].hovered ) { - hovered = items[i] - break - } - } - if ( !hovered ) return + model: [...mainWindow.repeaterItems] - let currentZ = hovered.zIndex - let maxZ = items.length - 1 + Region { + required property Item modelData - if ( currentZ >= maxZ ) { - // Already on top, wrap to bottom: shift everyone else up by 1 - for ( let i = 0; i < items.length; i++ ) { - if ( items[i] !== hovered ) { - items[i].zIndex += 1 - } - } - hovered.zIndex = 0 - } else { - // Swap with the item directly above - for ( let i = 0; i < items.length; i++ ) { - if ( items[i] !== hovered && items[i].zIndex === currentZ + 1 ) { - items[i].zIndex = currentZ - break - } - } - hovered.zIndex = currentZ + 1 - } - } - } + height: modelData.height + intersection: Intersection.Subtract + width: modelData.width + x: modelData.x + y: modelData.y + + Component.onCompleted: { + console.log(modelData); + } + } + } + + Component { + id: regionComponent + + Region { + } + } + + GlobalShortcut { + appid: "I-DeskPet" + name: "toggle-Layer" + + onPressed: { + if (!mainWindow.onTop) { + mainWindow.WlrLayershell.layer = WlrLayer.Overlay; + mainWindow.onTop = true; + } else { + mainWindow.WlrLayershell.layer = WlrLayer.Bottom; + mainWindow.onTop = false; + } + } + } + + GlobalShortcut { + appid: "I-DeskPet" + name: "toggle-Region" + + onPressed: { + if (!mainWindow.setMask) { + mainWindow.mask = mainWindow.petMove; + mainWindow.setMask = true; + } else { + mainWindow.mask = mainWindow.noMove; + mainWindow.setMask = false; + } + } + } + + GlobalShortcut { + appid: "I-DeskPet" + name: "cycle-zIndex" + + onPressed: { + let items = mainWindow.repeaterItems; + if (items.length < 2) + return; + + // Find the hovered GIF + let hovered = null; + for (let i = 0; i < items.length; i++) { + if (items[i].hovered) { + hovered = items[i]; + break; + } + } + if (!hovered) + return; + let currentZ = hovered.zIndex; + let maxZ = items.length - 1; + + if (currentZ >= maxZ) { + // Already on top, wrap to bottom: shift everyone else up by 1 + for (let i = 0; i < items.length; i++) { + if (items[i] !== hovered) { + items[i].zIndex += 1; + } + } + hovered.zIndex = 0; + } else { + // Swap with the item directly above + for (let i = 0; i < items.length; i++) { + if (items[i] !== hovered && items[i].zIndex === currentZ + 1) { + items[i].zIndex = currentZ; + break; + } + } + hovered.zIndex = currentZ + 1; + } + } + } }