select part of wallpaper to show
Format (JS/TS) / format (pull_request) Failing after 7s
Lint (JS/TS) / lint (pull_request) Failing after 12s
Lint (Python) / lint (pull_request) Failing after 20s
Lint (Rust) / lint (pull_request) Failing after 1m40s

This commit is contained in:
2026-05-19 15:38:59 +02:00
parent b20767c702
commit b6ad180b6a
5 changed files with 109 additions and 96 deletions
+7 -7
View File
@@ -29,13 +29,13 @@ SettingsPage {
step: 50
}
// Separator {
// }
//
// WallpaperCropper {
// Layout.fillWidth: true
// Layout.preferredHeight: 300
// }
Separator {
}
WallpaperCropper {
Layout.fillWidth: true
Layout.preferredHeight: 600
}
}
SettingsSection {
+88 -77
View File
@@ -6,97 +6,108 @@ import qs.Config
import qs.Components
import qs.Helpers
ColumnLayout {
Item {
id: root
spacing: 15
width: Math.min(parent ? parent.width : 600, 600)
Image {
id: imageView
Rectangle {
id: previewContainer
property real displayH: paintedHeight
property real displayW: paintedWidth
property real displayX: (width - paintedWidth) * 0.5
property real displayY: (height - paintedHeight) * 0.5
property real scaleX: sourceW / displayW
property real scaleY: sourceH / displayH
property real sourceH: sourceSize.height
property real sourceW: sourceSize.width
anchors.fill: parent
fillMode: Image.PreserveAspectFit
smooth: true
source: Wallpapers.current
}
Item {
id: overlay
Layout.fillHeight: true
Layout.preferredWidth: height * (Quickshell.screens.length > 0 ? (Quickshell.screens[0].height / Math.max(1, Quickshell.screens[0].width)) : 16 / 9)
clip: true
color: DynamicColors.palette.m3surfaceContainer
radius: Config.appearance.rounding.scale * 10
height: imageView.displayH
width: imageView.displayW
x: imageView.displayX
y: imageView.displayY
Image {
id: img
CustomRect {
id: cropRect
property real aspectRatio: Quickshell.screens[0].width / Quickshell.screens[0].height
readonly property rect sourceRect: Qt.rect(x * imageView.scaleX, y * imageView.scaleY, width * imageView.scaleX, height * imageView.scaleY)
property real zoom: Config.background.zoom
function clampToBounds() {
x = Math.max(0, Math.min(x, overlay.width - width));
y = Math.max(0, Math.min(y, overlay.height - height));
}
border.color: DynamicColors.palette.m3primary
border.width: 2
color: DynamicColors.tPalette.m3primary
height: width / aspectRatio
radius: Appearance.rounding.small
visible: imageView.status === Image.Ready
width: Math.min(overlay.width / zoom, overlay.height * aspectRatio / zoom)
x: Config.background.sourceClipX / imageView.scaleX
y: Config.background.sourceClipY / imageView.scaleY
}
MouseArea {
function updateCrop(mouseX, mouseY) {
let nx = mouseX - cropRect.width * 0.5;
let ny = mouseY - cropRect.height * 0.5;
nx = Math.max(0, Math.min(nx, overlay.width - cropRect.width));
ny = Math.max(0, Math.min(ny, overlay.height - cropRect.height));
cropRect.x = nx;
cropRect.y = ny;
}
anchors.fill: parent
asynchronous: true
fillMode: Image.PreserveAspectFit
source: Wallpapers.current
hoverEnabled: true
preventStealing: true
Rectangle {
id: cropRect
onPositionChanged: mouse => {
if (pressed)
updateCrop(mouse.x, mouse.y);
}
onPressed: mouse => {
updateCrop(mouse.x, mouse.y);
}
onReleased: {
Config.background.sourceClipX = cropRect.sourceRect.x;
Config.background.sourceClipY = cropRect.sourceRect.y;
Config.background.sourceClipW = cropRect.sourceRect.width;
Config.background.sourceClipH = cropRect.sourceRect.height;
Config.save();
}
onWheel: wheel => {
let oldCenterX = cropRect.x + cropRect.width * 0.5;
let oldCenterY = cropRect.y + cropRect.height * 0.5;
property real cropHeight: (imageAspect > screenAspect ? paintedHeight : paintedWidth / screenAspect) / Config.background.zoom
property real cropWidth: (imageAspect > screenAspect ? paintedHeight * screenAspect : paintedWidth) / Config.background.zoom
property real imageAspect: Math.max(1, paintedWidth) / Math.max(1, paintedHeight)
property real paintedHeight: img.paintedHeight > 0 ? img.paintedHeight : img.height
property real paintedWidth: img.paintedWidth > 0 ? img.paintedWidth : img.width
property real paintedX: (img.width - paintedWidth) / 2
property real paintedY: (img.height - paintedHeight) / 2
property real screenAspect: Quickshell.screens.length > 0 ? (Quickshell.screens[0].width / Math.max(1, Quickshell.screens[0].height)) : 16 / 9
if (wheel.angleDelta.y > 0)
cropRect.zoom *= 1.1;
else
cropRect.zoom /= 1.1;
border.color: DynamicColors.palette.m3primary
border.width: 2
color: Qt.alpha(DynamicColors.palette.m3primaryContainer, 0.3)
height: cropHeight
width: cropWidth
x: paintedX + (paintedWidth - width) * Config.background.alignX
y: paintedY + (paintedHeight - height) * Config.background.alignY
cropRect.zoom = Math.max(1.0, Math.min(cropRect.zoom, 10.0));
Config.background.zoom = cropRect.zoom;
DragHandler {
target: null
cropRect.x = oldCenterX - cropRect.width * 0.5;
cropRect.y = oldCenterY - cropRect.height * 0.5;
onActiveTranslationChanged: {
if (active) {
let newX = cropRect.x - cropRect.paintedX + translation.x;
let newY = cropRect.y - cropRect.paintedY + translation.y;
let rangeX = cropRect.paintedWidth - cropRect.width;
let rangeY = cropRect.paintedHeight - cropRect.height;
if (rangeX > 0) {
let valX = newX / rangeX;
Config.background.alignX = Math.max(0.0, Math.min(1.0, valX));
Config.save();
}
if (rangeY > 0) {
let valY = newY / rangeY;
Config.background.alignY = Math.max(0.0, Math.min(1.0, valY));
Config.save();
}
}
}
}
PinchHandler {
maximumScale: 5.0
minimumScale: 1.0
target: null
onActiveScaleChanged: {
if (active) {
let newZoom = Config.background.zoom * (1 / (1 + (activeScale - 1) * 0.1));
Config.background.zoom = Math.max(1.0, Math.min(newZoom, 5.0));
}
}
}
cropRect.clampToBounds();
}
}
}
SettingSpinBox {
max: 5.0
min: 1.0
name: "Zoom"
object: Config.background
setting: "zoom"
step: 0.1
}
}