From baa3c2a773ee462ac6bab298b9dfd4f6cdf3d351 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 9 Nov 2025 12:58:48 +0100 Subject: [PATCH] overlay: add kurukuru --- .../quickshell/ii/modules/common/Config.qml | 4 + .../ii/modules/common/Directories.qml | 2 + .../ii/modules/common/Persistent.qml | 24 +++-- .../ii/modules/ii/overlay/OverlayContext.qml | 7 +- .../overlay/OverlayWidgetDelegateChooser.qml | 4 +- .../ii/overlay/StyledOverlayWidget.qml | 6 +- .../overlay/floatingImage/FloatingImage.qml | 95 +++++++++++++++++++ .../ii/modules/settings/InterfaceConfig.qml | 15 +++ 8 files changed, 142 insertions(+), 15 deletions(-) create mode 100644 dots/.config/quickshell/ii/modules/ii/overlay/floatingImage/FloatingImage.qml diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml index 0ceb7dd1b..b6247237f 100644 --- a/dots/.config/quickshell/ii/modules/common/Config.qml +++ b/dots/.config/quickshell/ii/modules/common/Config.qml @@ -381,6 +381,10 @@ Singleton { property bool openingZoomAnimation: true property bool darkenScreen: true property real clickthroughOpacity: 0.7 + property JsonObject floatingImage: JsonObject { + property string imageSource: "https://cdn.discordapp.com/attachments/961693710968557598/1369635662390759434/image.gif?ex=6911cb1c&is=6910799c&hm=4450244066c0a7a6e5d2bdd195f47388eb5e7f9dd53d3931e99ad9642c638a00&" + property real scale: 0.5 + } } property JsonObject overview: JsonObject { diff --git a/dots/.config/quickshell/ii/modules/common/Directories.qml b/dots/.config/quickshell/ii/modules/common/Directories.qml index 59f3dab53..8e70506d3 100644 --- a/dots/.config/quickshell/ii/modules/common/Directories.qml +++ b/dots/.config/quickshell/ii/modules/common/Directories.qml @@ -24,6 +24,7 @@ Singleton { property string scriptPath: Quickshell.shellPath("scripts") property string favicons: FileUtils.trimFileProtocol(`${Directories.cache}/media/favicons`) property string coverArt: FileUtils.trimFileProtocol(`${Directories.cache}/media/coverart`) + property string tempImages: "/tmp/quickshell/media/images" property string booruPreviews: FileUtils.trimFileProtocol(`${Directories.cache}/media/boorus`) property string booruDownloads: FileUtils.trimFileProtocol(Directories.pictures + "/homework") property string booruDownloadsNsfw: FileUtils.trimFileProtocol(Directories.pictures + "/homework/🌶️") @@ -52,5 +53,6 @@ Singleton { Quickshell.execDetached(["bash", "-c", `rm -rf '${latexOutput}'; mkdir -p '${latexOutput}'`]) Quickshell.execDetached(["bash", "-c", `rm -rf '${cliphistDecode}'; mkdir -p '${cliphistDecode}'`]) Quickshell.execDetached(["mkdir", "-p", `${aiChats}`]) + Quickshell.execDetached(["rm", "-rf", `${tempImages}`]) } } diff --git a/dots/.config/quickshell/ii/modules/common/Persistent.qml b/dots/.config/quickshell/ii/modules/common/Persistent.qml index 171f150e6..212fc34b9 100644 --- a/dots/.config/quickshell/ii/modules/common/Persistent.qml +++ b/dots/.config/quickshell/ii/modules/common/Persistent.qml @@ -89,6 +89,22 @@ Singleton { property real width: 250 property real height: 100 } + property JsonObject floatingImage: JsonObject { + property bool pinned: false + property bool clickthrough: false + property real x: 1650 + property real y: 390 + property real width: 0 + property real height: 0 + } + property JsonObject fpsLimiter: JsonObject { + property bool pinned: false + property bool clickthrough: false + property real x: 1570 + property real y: 615 + property real width: 280 + property real height: 80 + } property JsonObject recorder: JsonObject { property bool pinned: false property bool clickthrough: false @@ -115,14 +131,6 @@ Singleton { property real height: 600 property int tabIndex: 0 } - property JsonObject fpsLimiter: JsonObject { - property bool pinned: false - property bool clickthrough: false - property real x: 1576 - property real y: 630 - property real width: 280 - property real height: 80 - } } property JsonObject timer: JsonObject { diff --git a/dots/.config/quickshell/ii/modules/ii/overlay/OverlayContext.qml b/dots/.config/quickshell/ii/modules/ii/overlay/OverlayContext.qml index b228deda6..15e1ef91b 100644 --- a/dots/.config/quickshell/ii/modules/ii/overlay/OverlayContext.qml +++ b/dots/.config/quickshell/ii/modules/ii/overlay/OverlayContext.qml @@ -6,11 +6,12 @@ Singleton { id: root readonly property list availableWidgets: [ - { identifier: "recorder", materialSymbol: "screen_record" }, - { identifier: "volumeMixer", materialSymbol: "volume_up" }, { identifier: "crosshair", materialSymbol: "point_scan" }, { identifier: "fpsLimiter", materialSymbol: "animation" }, - { identifier: "resources", materialSymbol: "browse_activity" } + { identifier: "floatingImage", materialSymbol: "imagesmode" }, + { identifier: "recorder", materialSymbol: "screen_record" }, + { identifier: "resources", materialSymbol: "browse_activity" }, + { identifier: "volumeMixer", materialSymbol: "volume_up" }, ] readonly property bool hasPinnedWidgets: root.pinnedWidgetIdentifiers.length > 0 diff --git a/dots/.config/quickshell/ii/modules/ii/overlay/OverlayWidgetDelegateChooser.qml b/dots/.config/quickshell/ii/modules/ii/overlay/OverlayWidgetDelegateChooser.qml index d69c76719..6e4bc6522 100644 --- a/dots/.config/quickshell/ii/modules/ii/overlay/OverlayWidgetDelegateChooser.qml +++ b/dots/.config/quickshell/ii/modules/ii/overlay/OverlayWidgetDelegateChooser.qml @@ -11,14 +11,16 @@ import qs.modules.ii.overlay.volumeMixer import qs.modules.ii.overlay.fpsLimiter import qs.modules.ii.overlay.recorder import qs.modules.ii.overlay.resources +import qs.modules.ii.overlay.floatingImage DelegateChooser { id: root role: "identifier" DelegateChoice { roleValue: "crosshair"; Crosshair {} } - DelegateChoice { roleValue: "volumeMixer"; VolumeMixer {} } + DelegateChoice { roleValue: "floatingImage"; FloatingImage {} } DelegateChoice { roleValue: "fpsLimiter"; FpsLimiter {} } DelegateChoice { roleValue: "recorder"; Recorder {} } DelegateChoice { roleValue: "resources"; Resources {} } + DelegateChoice { roleValue: "volumeMixer"; VolumeMixer {} } } diff --git a/dots/.config/quickshell/ii/modules/ii/overlay/StyledOverlayWidget.qml b/dots/.config/quickshell/ii/modules/ii/overlay/StyledOverlayWidget.qml index 9e13ca934..949cd2380 100644 --- a/dots/.config/quickshell/ii/modules/ii/overlay/StyledOverlayWidget.qml +++ b/dots/.config/quickshell/ii/modules/ii/overlay/StyledOverlayWidget.qml @@ -33,8 +33,8 @@ AbstractOverlayWidget { property string title: identifier.replace(/([A-Z])/g, " $1").replace(/^./, function(str){ return str.toUpperCase(); }) property var persistentStateEntry: Persistent.states.overlay[identifier] property real radius: Appearance.rounding.windowRounding - property real minimumWidth: 250 - property real minimumHeight: 100 + property real minimumWidth: contentItem.implicitWidth + property real minimumHeight: contentItem.implicitHeight property real resizeMargin: 8 property real padding: 6 property real contentRadius: radius - padding @@ -238,8 +238,8 @@ AbstractOverlayWidget { } StyledText { - text: root.title Layout.fillWidth: true + text: root.title elide: Text.ElideRight } diff --git a/dots/.config/quickshell/ii/modules/ii/overlay/floatingImage/FloatingImage.qml b/dots/.config/quickshell/ii/modules/ii/overlay/floatingImage/FloatingImage.qml new file mode 100644 index 000000000..86ffd54ff --- /dev/null +++ b/dots/.config/quickshell/ii/modules/ii/overlay/floatingImage/FloatingImage.qml @@ -0,0 +1,95 @@ +import QtQuick +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import Quickshell +import qs.modules.common +import qs.modules.common.functions +import qs.modules.common.utils +import qs.modules.ii.overlay + +StyledOverlayWidget { + id: root + showClickabilityButton: false + resizable: false + + property string imageSource: Config.options.overlay.floatingImage.imageSource + property real scaleFactor: Config.options.overlay.floatingImage.scale + property int imageWidth: 0 + property int imageHeight: 0 + + // Override to always save 0 size + function savePosition(xPos = root.x, yPos = root.y, width = 0, height = 0) { + persistentStateEntry.x = Math.round(xPos); + persistentStateEntry.y = Math.round(yPos); + persistentStateEntry.width = 0 + persistentStateEntry.height = 0 + } + + onImageSourceChanged: { + imageDownloader.running = false; + imageDownloader.sourceUrl = root.imageSource; + imageDownloader.filePath = Qt.resolvedUrl(Directories.tempImages + "/" + Qt.md5(root.imageSource)) + imageDownloader.running = true; + } + onScaleFactorChanged: { + setSize(); + } + + function setSize() { + bg.implicitWidth = root.imageWidth * root.scaleFactor; + bg.implicitHeight = root.imageHeight * root.scaleFactor; + } + + contentItem: OverlayBackground { + id: bg + color: ColorUtils.transparentize(Appearance.m3colors.m3surfaceContainer, root.actuallyPinned ? 1 : 0) + radius: root.contentRadius + + WheelHandler { + onWheel: (event) => { + if (event.angleDelta.y < 0) { + Config.options.overlay.floatingImage.scale = Math.max(0.1, Config.options.overlay.floatingImage.scale - 0.1); + } + else if (event.angleDelta.y > 0) { + Config.options.overlay.floatingImage.scale = Math.min(5.0, Config.options.overlay.floatingImage.scale + 0.1); + } + } + acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad + } + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Rectangle { + width: bg.width + height: bg.height + radius: bg.radius + } + } + + AnimatedImage { + id: animatedImage + anchors.centerIn: parent + width: root.imageWidth * root.scaleFactor + height: root.imageHeight * root.scaleFactor + sourceSize.width: width + sourceSize.height: height + + playing: visible + asynchronous: true + source: "" + + ImageDownloaderProcess { + id: imageDownloader + filePath: Qt.resolvedUrl(Directories.tempImages + "/" + Qt.md5(root.imageSource)) + sourceUrl: root.imageSource + + onDone: (path, width, height) => { + root.imageWidth = width; + root.imageHeight = height; + root.setSize(); + animatedImage.source = path; + } + } + } + } +} diff --git a/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml b/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml index c57406a7f..738578585 100644 --- a/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml +++ b/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml @@ -328,6 +328,21 @@ ContentPage { } } + ContentSection { + icon: "point_scan" + title: Translation.tr("Overlay: Floating Image") + + MaterialTextArea { + Layout.fillWidth: true + placeholderText: Translation.tr("Image source") + text: Config.options.overlay.floatingImage.imageSource + wrapMode: TextEdit.Wrap + onTextChanged: { + Config.options.overlay.floatingImage.imageSource = text; + } + } + } + ContentSection { icon: "screenshot_frame_2" title: Translation.tr("Region selector (screen snipping/Google Lens)")