forked from Shinonome/dots-hyprland
102 lines
4.6 KiB
QML
102 lines
4.6 KiB
QML
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
import qs
|
|
import qs.modules.common
|
|
import qs.modules.common.functions
|
|
import qs.modules.common.widgets.widgetCanvas
|
|
|
|
AbstractWidget {
|
|
id: root
|
|
|
|
required property string configEntryName
|
|
required property int screenWidth
|
|
required property int screenHeight
|
|
required property int scaledScreenWidth
|
|
required property int scaledScreenHeight
|
|
required property real wallpaperScale
|
|
property bool visibleWhenLocked: false
|
|
property var configEntry: Config.options.background.widgets[configEntryName]
|
|
property string placementStrategy: configEntry.placementStrategy
|
|
property real targetX: Math.max(0, Math.min(configEntry.x, scaledScreenWidth - width))
|
|
property real targetY : Math.max(0, Math.min(configEntry.y, scaledScreenHeight - height))
|
|
x: targetX
|
|
y: targetY
|
|
visible: opacity > 0
|
|
opacity: (GlobalStates.screenLocked && !visibleWhenLocked) ? 0 : 1
|
|
Behavior on opacity {
|
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
|
}
|
|
scale: (draggable && containsPress) ? 1.05 : 1
|
|
Behavior on scale {
|
|
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
|
|
}
|
|
|
|
draggable: placementStrategy === "free"
|
|
onReleased: {
|
|
root.targetX = root.x;
|
|
root.targetY = root.y;
|
|
configEntry.x = root.targetX;
|
|
configEntry.y = root.targetY;
|
|
}
|
|
|
|
property bool needsColText: false
|
|
property color dominantColor: Appearance.colors.colPrimary
|
|
property bool dominantColorIsDark: dominantColor.hslLightness < 0.5
|
|
property color colText: {
|
|
const onNormalBackground = (GlobalStates.screenLocked && Config.options.lock.blur.enable)
|
|
const adaptiveColor = ColorUtils.colorWithLightness(Appearance.colors.colPrimary, (dominantColorIsDark ? 0.8 : 0.12))
|
|
return onNormalBackground ? Appearance.colors.colOnLayer0 : adaptiveColor;
|
|
}
|
|
|
|
property bool wallpaperIsVideo: Config.options.background.wallpaperPath.endsWith(".mp4") || Config.options.background.wallpaperPath.endsWith(".webm") || Config.options.background.wallpaperPath.endsWith(".mkv") || Config.options.background.wallpaperPath.endsWith(".avi") || Config.options.background.wallpaperPath.endsWith(".mov")
|
|
property string wallpaperPath: wallpaperIsVideo ? Config.options.background.thumbnailPath : Config.options.background.wallpaperPath
|
|
|
|
onWallpaperPathChanged: refreshPlacementIfNeeded()
|
|
onPlacementStrategyChanged: refreshPlacementIfNeeded()
|
|
Connections {
|
|
target: Config
|
|
function onReadyChanged() { refreshPlacementIfNeeded() }
|
|
}
|
|
function refreshPlacementIfNeeded() {
|
|
if (!Config.ready || (root.placementStrategy === "free" && root.needsColText)) return;
|
|
leastBusyRegionProc.wallpaperPath = root.wallpaperPath;
|
|
leastBusyRegionProc.running = false;
|
|
leastBusyRegionProc.running = true;
|
|
}
|
|
Process {
|
|
id: leastBusyRegionProc
|
|
property string wallpaperPath: root.wallpaperPath
|
|
// TODO: make these less arbitrary
|
|
property int contentWidth: 300
|
|
property int contentHeight: 300
|
|
property int horizontalPadding: 200
|
|
property int verticalPadding: 200
|
|
command: [Quickshell.shellPath("scripts/images/least-busy-region-venv.sh") // Comments to force the formatter to break lines
|
|
, "--screen-width", Math.round(root.scaledScreenWidth) //
|
|
, "--screen-height", Math.round(root.scaledScreenHeight) //
|
|
, "--width", contentWidth //
|
|
, "--height", contentHeight //
|
|
, "--horizontal-padding", horizontalPadding //
|
|
, "--vertical-padding", verticalPadding //
|
|
, wallpaperPath //
|
|
, ...(root.placementStrategy === "mostBusy" ? ["--busiest"] : [])
|
|
// "--visual-output",
|
|
]
|
|
stdout: StdioCollector {
|
|
id: leastBusyRegionOutputCollector
|
|
onStreamFinished: {
|
|
const output = leastBusyRegionOutputCollector.text;
|
|
// console.log("[Background] Least busy region output:", output)
|
|
if (output.length === 0) return;
|
|
const parsedContent = JSON.parse(output);
|
|
root.dominantColor = parsedContent.dominant_color || Appearance.colors.colPrimary;
|
|
if (root.placementStrategy === "free") return;
|
|
root.targetX = parsedContent.center_x * root.wallpaperScale - root.width / 2;
|
|
root.targetY = parsedContent.center_y * root.wallpaperScale - root.height / 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|