62 Commits

Author SHA1 Message Date
Inorishio ce1a48639f Clean up 2026-03-23 13:43:30 +01:00
Inorishio 4d19cfe87d Merge branch 'Main' of https://github.com/InoriShio/I-DeskPet into Main 2026-03-23 13:24:09 +01:00
Inorishio cd5eb171c8 binary 2026-03-23 13:21:31 +01:00
InoriShio 0ff5c32c51 Add files via upload 2026-03-19 15:29:32 +01:00
Inorishio 7e3109f758 zach's nutty qmlformat 2026-02-25 23:01:52 +01:00
Inorishio f5a0b763d5 Edit read.md 2026-02-16 13:25:42 +01:00
Inorishio 4f813a2de7 Edit read.md 2026-02-16 13:25:03 +01:00
Inorishio 7784cfd99b Edit read.md 2026-02-16 13:23:06 +01:00
Inorishio 7e5b5ffed5 Finished. 2026-02-16 12:40:29 +01:00
Inorishio 3f969d9447 It's poppin' 2026-02-14 18:24:01 +01:00
Inorishio b68c139d8d before it goes to .... 2026-02-14 17:20:10 +01:00
Inorishio 175c3463f7 screenYposGae 2026-02-12 19:46:25 +01:00
Inorishio d446be5fbd xy 2026-02-12 19:27:51 +01:00
Inorishio e31ff0aa27 can't be working on this at work lmao 2026-02-11 12:00:12 +01:00
Inorishio a0b552e796 Fileview 2026-02-09 23:45:59 +01:00
Inorishio b9a590be69 edits 2026-02-09 22:33:24 +01:00
Inorishio 16642e7d02 Read.md 2025-12-04 22:57:28 +01:00
Inorishio b8d825843d Read.md 2025-12-04 22:54:45 +01:00
Inorishio 62027782a7 Read.md 2025-12-04 22:52:41 +01:00
Inorishio 7d8037a82c Fix / move bug 2025-12-04 19:39:45 +01:00
Inorishio cf55c79855 Zach: I know everything about your life 2025-12-03 23:22:59 +01:00
InoriShio e9fab71e9d Merge pull request #2 from Zacharias-Brohn/Repeater
Zachjittery pog
2025-12-03 15:57:31 +00:00
Zacharias-Brohn 5318d3897b fixes 2025-12-03 15:33:29 +01:00
Inorishio 8967e3a1f5 Claude pog? 2025-12-03 13:53:58 +01:00
Inorishio 089a5f7a49 finished update 2025-11-09 02:37:11 +01:00
Inorishio 4acc1556b2 More pets 2025-11-04 08:02:03 +01:00
Inorishio 9dd1a5430d repeater 2025-10-30 14:39:51 +01:00
Inorishio dbcde131aa MOVEMENT 2025-10-27 00:14:05 +01:00
Inorishio 2f8a3e98a5 REGIONS 2025-10-26 22:28:03 +01:00
Inorishio 03adbbd38f REGIONS 2025-10-23 00:47:29 +02:00
Inorishio bdccb9e0aa read me 2025-10-22 22:32:56 +02:00
Inorishio 010643ee23 Click through it... 2025-10-22 22:06:14 +02:00
Inorishio 7fa9f85856 clean up 2025-10-21 22:48:57 +02:00
Inorishio 1a39b63b20 clean up 2025-10-21 22:29:38 +02:00
Inorishio da07682764 Evernight & Caelestia 2025-10-20 10:53:55 +02:00
Inorishio b20768f64c Git 2025-10-19 23:35:08 +02:00
Inorishio 2663d706b8 Git 2025-10-19 23:34:47 +02:00
Inorishio c57e90d65e Git 2025-10-19 23:34:16 +02:00
Inorishio cbd67c3c34 Git ignore 2025-10-15 22:46:31 +02:00
Inorishio 09d5484f52 Git ignore 2025-10-15 22:44:57 +02:00
Inorishio fc737d6edc Update text 2025-10-15 16:01:50 +02:00
Inorishio 7c67b41a7b Update text 2025-10-15 15:54:16 +02:00
Inorishio 2b16c6a612 Update text 2025-10-15 15:52:36 +02:00
Inorishio c6277a4a2a Update text 2025-10-15 15:21:36 +02:00
Inorishio ab2b3ce0a8 Update text 2025-10-15 15:21:09 +02:00
Inorishio 1d70410331 Update text 2025-10-15 15:20:28 +02:00
Inorishio 49c49e2e90 Update text 2025-10-15 15:17:09 +02:00
Inorishio 5dad7c0769 Update text 2025-10-15 14:45:16 +02:00
Inorishio 319a8ce00f Update text 2025-10-15 14:44:10 +02:00
Inorishio 74692b2b97 Update text 2025-10-15 14:29:47 +02:00
Inorishio 35522f5c3c Update text 2025-10-15 14:09:07 +02:00
Inorishio 5d0272b9bd Read me 2025-10-15 00:52:30 +02:00
Inorishio f2ac47cd88 Read me 2025-10-15 00:52:08 +02:00
Inorishio e7f2e43e52 Read me 2025-10-15 00:51:29 +02:00
Inorishio 0718d25887 Read me 2025-10-15 00:47:27 +02:00
Inorishio 52bc58da18 Read me 2025-10-15 00:43:23 +02:00
Inorishio 6911476077 Read me 2025-10-15 00:41:46 +02:00
Inorishio 270a7c0e4e Read me 2025-10-15 00:39:00 +02:00
Inorishio ae32389764 Read me 2025-10-15 00:27:34 +02:00
Inorishio 89962477c0 Read me 2025-10-15 00:26:21 +02:00
Inorishio ca365460af FUNCTIONS SU-.. 2025-10-15 00:23:11 +02:00
Inorishio e7cebf3092 expansion 2025-10-14 16:05:58 +02:00
10 changed files with 415 additions and 45 deletions
+4
View File
@@ -0,0 +1,4 @@
# Generated by Cargo
# will have compiled files and executables
debug
target
Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 298 KiB

+56
View File
@@ -0,0 +1,56 @@
pragma Singleton
import QtQuick
import Quickshell.Io
import Quickshell
Singleton {
id: root
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
command: ["test", "-d", root.configDir]
running: true
onExited: function (exitCode) {
if (exitCode !== 0) {
console.log("creating dir");
dirCreate.running = true;
}
}
}
Process {
id: dirCreate
command: ["mkdir", "-p", root.configDir]
running: false
onExited: function (): void {
console.log("Created config directory:", root.configDir);
}
}
FileView {
id: watcher
path: root.configPath
watchChanges: true
onAdapterUpdated: writeAdapter()
onFileChanged: reload()
JsonAdapter {
id: adapter
property string gifFolder: Quickshell.shellDir + "/Gifs"
property real maxScale: 1
}
}
}
+20
View File
@@ -0,0 +1,20 @@
import QtQuick
import Qt.labs.folderlistmodel
Item {
id: root
property alias count: folderModel.count
required property string gifFolder
property alias gifsModel: folderModel
FolderListModel {
id: folderModel
folder: "file://" + root.gifFolder
nameFilters: ["*.gif"]
showDirs: false
showHidden: false
sortField: FolderListModel.Name
}
}
+88
View File
@@ -0,0 +1,88 @@
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
import Qt.labs.folderlistmodel
import qs.Modules
Repeater {
id: gifRepeater
required property FolderListModel gifsModel
model: gifsModel
Item {
id: gifItem
required property string fileBaseName
required property url fileUrl
property alias hovered: mouse.containsMouse
required property int index
property bool loaded: false
property alias zIndex: gifSaved.zIndex
height: Math.floor(gif.sourceSize.height / gifSaved.scaling)
visible: gifItem.loaded
width: Math.floor(gif.sourceSize.width / gifSaved.scaling)
z: gifSaved.zIndex
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
onDoubleClicked: gifSaved.scaling = 1
onWheel: wheel => {
gifSaved.scaling = Math.max(ConfigLoader.maxScaling, (gifSaved.scaling + 0.1 * (wheel.angleDelta.y / 120)));
}
}
FileView {
id: watcher
property string configDir: Quickshell.env("HOME") + "/.config/I-DeskPet/"
property string configPath: configDir + name
property string name: gifItem.fileBaseName + ".json"
path: configPath
watchChanges: true
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 int positionX: 0
property int positionY: 0
property real scaling: 1
property int zIndex: -1
}
}
}
}
+13
View File
@@ -0,0 +1,13 @@
import QtQuick
MouseArea {
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
}
+63 -1
View File
@@ -1 +1,63 @@
### Pet March (Evernight) <div align="Center">
<h3> Pet March (Evernight) </h3>
<p>My selfmade desktop pet using QT </p>
<img src=./Assets/Evernight.gif style="margin: 0px 30px 0px 0px;" />
</div>
## Feature list
- [x] Hyprland keybind support
- [x] Toggle layer ontop/bottom
- [x] Toggle active mouse area
- [x] Dynamic path + live update
- [x] Supports multiple gifs
- [x] User config options
- [x] Evernight base gif img
# Config
Configuration is found at:
```zsh
~/.config/I-DeskPet
```
Options:
- gifFolder
- maxScaling
Example for config.json:
```json
{
"gifFolder": "/home/inorishio/Pictures/Pets",
"maxScaling": 1
}
```
# Hyprland keybinds
Toggle click through
```zsh
bind = CTRL, mouse:274, global, I-DeskPet:toggle-Region
```
Toggle between having your gif on your background vs foreground
```zsh
bind = SHIFT, mouse:274, global, I-DeskPet:toggle-Layer
```
Keybind for cycling through gif layering.
Hover over which gif you want to cycle it's layer for and use the keybind.
```zsh
bind = $mainMod, Z, global, I-DeskPet:cycle-zIndex
```
# Other keybinds
- Double click = Reset gif size to original
- Scroll = Scales the gif up and or down
Executable → Regular
+154 -27
View File
@@ -1,56 +1,183 @@
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Io
import Quickshell.Wayland import Quickshell.Wayland
//import qs.Gifs import Quickshell.Hyprland
import qs.Modules
PanelWindow { PanelWindow {
id: mainWindow id: mainWindow
WlrLayershell.layer: WlrLayer.Top
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<Item> 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" color: "transparent"
surfaceFormat.opaque: false
mask: Region {
height: Screen.height
intersection: Intersection.Xor
regions: maskVariants.instances
width: Screen.width
}
anchors { anchors {
bottom: true bottom: true
left: true left: true
right: true
top: true
} }
surfaceFormat.opaque: false
implicitWidth: 320
implicitHeight: 293
margins { margins {
bottom: 0
left: 0 left: 0
bottom: 5 right: 0
top: 0
} }
property bool onTop: true GetGifs {
id: getGifs
function toggleLayer() { gifFolder: ConfigLoader.gifFolder
if (onTop) { }
WlrLayershell.layer = WlrLayer.Bottom
onTop = false 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);
}
}
Variants {
id: maskVariants
model: [...mainWindow.repeaterItems]
Region {
required property Item modelData
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 { } else {
WlrLayershell.layer = WlrLayer.Top mainWindow.WlrLayershell.layer = WlrLayer.Bottom;
onTop = true mainWindow.onTop = false;
}
} }
} }
Rectangle { GlobalShortcut {
anchors.fill: parent appid: "I-DeskPet"
color: "transparent" name: "toggle-Region"
id: petContainer onPressed: {
AnimatedImage { if (!mainWindow.setMask) {
anchors.fill: parent mainWindow.mask = mainWindow.petMove;
source: "Gifs/evernight.gif" mainWindow.setMask = true;
fillMode: Image.PreserveAspectFit } else {
mainWindow.mask = mainWindow.noMove;
mainWindow.setMask = false;
}
}
} }
MouseArea { GlobalShortcut {
anchors.fill: parent appid: "I-DeskPet"
acceptedButtons: Qt.MiddleButton name: "cycle-zIndex"
onClicked: (mouse) => {
if (mouse.button === Qt.MiddleButton) { onPressed: {
mainWindow.toggleLayer() 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;
}
} }
} }
} }