fixed applying crop being overwritten by multiple write calls, added wallpaper fade anim
This commit is contained in:
+15
-12
@@ -32,33 +32,26 @@ Searcher {
|
|||||||
showPreview = true;
|
showPreview = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setCrop(screen: string, rect: rect, scaledRect: rect, zoom: real): void {
|
function setCrop(screen: string, rect: rect, zoom: real): void {
|
||||||
let updated = Object.assign({}, root.crops);
|
|
||||||
|
|
||||||
if (zoom <= 0)
|
if (zoom <= 0)
|
||||||
zoom = 1.0;
|
zoom = 1.0;
|
||||||
else if (zoom > 5.0)
|
else if (zoom > 5.0)
|
||||||
zoom = 5.0;
|
zoom = 5.0;
|
||||||
|
|
||||||
updated[screen] = {
|
root.crops[screen] = {
|
||||||
x: rect.x,
|
x: rect.x,
|
||||||
y: rect.y,
|
y: rect.y,
|
||||||
width: rect.width,
|
width: rect.width,
|
||||||
height: rect.height,
|
height: rect.height,
|
||||||
scaledX: scaledRect.x,
|
|
||||||
scaledY: scaledRect.y,
|
|
||||||
scaledWidth: scaledRect.width,
|
|
||||||
scaledHeight: scaledRect.height,
|
|
||||||
zoom: zoom
|
zoom: zoom
|
||||||
};
|
};
|
||||||
|
// root.crops = updated;
|
||||||
root.crops = updated;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setWallpaper(path: string): void {
|
function setWallpaper(path: string): void {
|
||||||
actualCurrent = path;
|
actualCurrent = path;
|
||||||
WallpaperPath.currentWallpaperPath = path;
|
WallpaperPath.currentWallpaperPath = path;
|
||||||
Quickshell.screens.forEach(n => setCrop(n.name, Qt.rect(0, 0, 1, 1), Qt.rect(0, 0, 0, 0), 1.0));
|
Quickshell.screens.forEach(n => setCrop(n.name, Qt.rect(0, 0, 1, 1), 1.0));
|
||||||
Quickshell.execDetached(["zshell-cli", "wallpaper", "lockscreen", "--input-image", `${root.actualCurrent}`, "--output-path", `${Paths.state}/lockscreen_bg.png`, "--blur-amount", `${Config.lock.blurAmount}`]);
|
Quickshell.execDetached(["zshell-cli", "wallpaper", "lockscreen", "--input-image", `${root.actualCurrent}`, "--output-path", `${Paths.state}/lockscreen_bg.png`, "--blur-amount", `${Config.lock.blurAmount}`]);
|
||||||
if (Config.general.color.schemeGeneration)
|
if (Config.general.color.schemeGeneration)
|
||||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--image-path", `${root.actualCurrent}`, "--scheme", `${Config.colors.schemeType}`, "--mode", `${Config.general.color.mode}`]);
|
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--image-path", `${root.actualCurrent}`, "--scheme", `${Config.colors.schemeType}`, "--mode", `${Config.general.color.mode}`]);
|
||||||
@@ -91,7 +84,7 @@ Searcher {
|
|||||||
path: `${Paths.state}/wallpaper-crops.json`
|
path: `${Paths.state}/wallpaper-crops.json`
|
||||||
watchChanges: true
|
watchChanges: true
|
||||||
|
|
||||||
onAdapterUpdated: writeAdapter()
|
onAdapterUpdated: cropWriteDelay.restart()
|
||||||
onFileChanged: reload()
|
onFileChanged: reload()
|
||||||
|
|
||||||
JsonAdapter {
|
JsonAdapter {
|
||||||
@@ -101,6 +94,16 @@ Searcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: cropWriteDelay
|
||||||
|
|
||||||
|
interval: 100
|
||||||
|
repeat: false
|
||||||
|
running: false
|
||||||
|
|
||||||
|
onTriggered: monitorCrops.writeAdapter()
|
||||||
|
}
|
||||||
|
|
||||||
FileSystemModel {
|
FileSystemModel {
|
||||||
id: wallpapers
|
id: wallpapers
|
||||||
|
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ Item {
|
|||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
// retainWhileLoading: true
|
retainWhileLoading: true
|
||||||
source: Wallpapers.current
|
source: Wallpapers.current
|
||||||
sourceSize.height: parent.height
|
sourceSize.height: parent.height
|
||||||
sourceSize.width: parent.width
|
sourceSize.width: parent.width
|
||||||
@@ -200,7 +200,7 @@ Item {
|
|||||||
Loader {
|
Loader {
|
||||||
id: cropRectLoader
|
id: cropRectLoader
|
||||||
|
|
||||||
active: scaledImg.paintedWidth > 0 && scaledImg.status == Image.Ready
|
active: scaledImg.paintedWidth > 0
|
||||||
|
|
||||||
sourceComponent: Component {
|
sourceComponent: Component {
|
||||||
CustomRect {
|
CustomRect {
|
||||||
|
|||||||
@@ -11,82 +11,98 @@ import ZShell.Internal
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool completed
|
||||||
|
property real cropHeight: displayData.height ?? 1.0
|
||||||
|
property real cropWidth: displayData.width ?? 1.0
|
||||||
|
property real cropX: displayData.x ?? 0.0
|
||||||
|
property real cropY: displayData.y ?? 0.0
|
||||||
|
property WallpaperImage current
|
||||||
|
readonly property var displayData: Wallpapers.getCrop(screen.name)
|
||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
|
property size screenResolution: Qt.size(screen.width * screenScale, screen.height * screenScale)
|
||||||
|
property real screenScale: Hyprland.monitorFor(screen).scale
|
||||||
property string source: Wallpapers.current
|
property string source: Wallpapers.current
|
||||||
|
|
||||||
function refreshData(): void {
|
|
||||||
Hyprland.refreshMonitors();
|
|
||||||
let scale = Hyprland.monitorFor(root.screen).scale;
|
|
||||||
if (scale <= 0)
|
|
||||||
scale = 1.0; // Fallback to avoid zeroes on initialization
|
|
||||||
|
|
||||||
if (root.screen.width > 0 && root.screen.height > 0) {
|
|
||||||
img.screenResolution = Qt.size(root.screen.width * scale, root.screen.height * scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
const displayData = Wallpapers.getCrop(root.screen.name);
|
|
||||||
|
|
||||||
if (displayData) {
|
|
||||||
img.cropX = displayData.x !== undefined ? displayData.x : 0.0;
|
|
||||||
img.cropY = displayData.y !== undefined ? displayData.y : 0.0;
|
|
||||||
img.cropWidth = (displayData.width !== undefined && displayData.width > 0) ? displayData.width : 1.0;
|
|
||||||
img.cropHeight = (displayData.height !== undefined && displayData.height > 0) ? displayData.height : 1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
Component.onCompleted: root.refreshData()
|
Component.onCompleted: {
|
||||||
|
Hyprland.refreshMonitors();
|
||||||
|
|
||||||
Connections {
|
if (source)
|
||||||
function onHeightChanged() {
|
Qt.callLater(() => {
|
||||||
root.refreshData();
|
current = imgComp.createObject(this, {
|
||||||
}
|
source
|
||||||
|
});
|
||||||
function onWidthChanged() {
|
completed = true;
|
||||||
root.refreshData();
|
});
|
||||||
}
|
}
|
||||||
|
onSourceChanged: {
|
||||||
target: root.screen
|
if (!source)
|
||||||
|
current = null;
|
||||||
|
else
|
||||||
|
current = imgComp.createObject(this, {
|
||||||
|
source: source
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
WallpaperImage {
|
Component {
|
||||||
id: img
|
id: imgComp
|
||||||
|
|
||||||
anchors.fill: parent
|
WallpaperImage {
|
||||||
source: root.source
|
id: img
|
||||||
|
|
||||||
Behavior on cropHeight {
|
anchors.fill: parent
|
||||||
Anim {
|
cropHeight: root.cropHeight
|
||||||
}
|
cropWidth: root.cropWidth
|
||||||
}
|
cropX: root.cropX
|
||||||
Behavior on cropWidth {
|
cropY: root.cropY
|
||||||
Anim {
|
opacity: 0
|
||||||
}
|
screenResolution: root.screenResolution
|
||||||
}
|
source: root.source
|
||||||
Behavior on cropX {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on cropY {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on zoom {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
Behavior on cropHeight {
|
||||||
function onAdapterUpdated(): void {
|
Anim {
|
||||||
root.refreshData();
|
id: heightAnim
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on cropWidth {
|
||||||
|
Anim {
|
||||||
|
id: widthAnim
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on cropX {
|
||||||
|
Anim {
|
||||||
|
id: xAnim
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on cropY {
|
||||||
|
Anim {
|
||||||
|
id: yAnim
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Anim on opacity {
|
||||||
|
id: anim
|
||||||
|
|
||||||
|
from: 0
|
||||||
|
running: false
|
||||||
|
to: 1
|
||||||
|
type: Anim.SlowEffects
|
||||||
}
|
}
|
||||||
|
|
||||||
function onLoaded(): void {
|
onStatusChanged: {
|
||||||
root.refreshData();
|
if (status === Image.Ready) {
|
||||||
|
anim.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
target: Wallpapers.monitorCrops
|
Timer {
|
||||||
|
id: destroyTimer
|
||||||
|
|
||||||
|
interval: anim.duration * 2
|
||||||
|
running: root.current !== img && root.current?.status === Image.Ready
|
||||||
|
|
||||||
|
onTriggered: Qt.callLater(() => img.destroy())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
#include <QSGImageNode>
|
#include <QSGImageNode>
|
||||||
#include <QQuickWindow>
|
#include <QQuickWindow>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
namespace ZShell::internal {
|
namespace ZShell::internal {
|
||||||
|
|
||||||
@@ -21,10 +22,20 @@ WallpaperImage::~WallpaperImage() {
|
|||||||
if (m_texture) delete m_texture;
|
if (m_texture) delete m_texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WallpaperImage::setStatus(const Status s) {
|
||||||
|
if (m_status == s)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_status = s;
|
||||||
|
emit statusChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void WallpaperImage::setSource(const QUrl &source) {
|
void WallpaperImage::setSource(const QUrl &source) {
|
||||||
if (m_source == source) return;
|
if (m_source == source) return;
|
||||||
m_source = source;
|
m_source = source;
|
||||||
emit sourceChanged();
|
emit sourceChanged();
|
||||||
|
|
||||||
|
setStatus(Loading);
|
||||||
loadImage();
|
loadImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,28 +68,27 @@ void WallpaperImage::setCropY(qreal y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WallpaperImage::setCropWidth(qreal w) {
|
void WallpaperImage::setCropWidth(qreal w) {
|
||||||
if (w <= 0.0) w = 1.0;
|
if (w <= 0.0) w = 1.0;
|
||||||
if (qFuzzyCompare(m_cropWidth, w)) return;
|
if (qFuzzyCompare(m_cropWidth, w)) return;
|
||||||
m_cropWidth = w;
|
m_cropWidth = w;
|
||||||
emit cropWidthChanged();
|
emit cropWidthChanged();
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WallpaperImage::setCropHeight(qreal h) {
|
void WallpaperImage::setCropHeight(qreal h) {
|
||||||
if (h <= 0.0) h = 1.0;
|
if (h <= 0.0) h = 1.0;
|
||||||
if (qFuzzyCompare(m_cropHeight, h)) return;
|
if (qFuzzyCompare(m_cropHeight, h)) return;
|
||||||
m_cropHeight = h;
|
m_cropHeight = h;
|
||||||
emit cropHeightChanged();
|
emit cropHeightChanged();
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString WallpaperImage::getCacheFilePath() const {
|
QString WallpaperImage::getCacheFilePath() const {
|
||||||
if (m_source.isEmpty() || m_screenResolution.isEmpty()) return QString();
|
if (m_source.isEmpty() || m_screenResolution.isEmpty()) return QString();
|
||||||
|
|
||||||
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/zshell/imagecache";
|
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/zshell/imagecache";
|
||||||
QDir().mkpath(cachePath);
|
QDir().mkpath(cachePath);
|
||||||
|
|
||||||
// Hash the source URL + resolution
|
|
||||||
QString id = m_source.toString() + "_" + QString::number(m_screenResolution.width()) + "x" + QString::number(m_screenResolution.height());
|
QString id = m_source.toString() + "_" + QString::number(m_screenResolution.width()) + "x" + QString::number(m_screenResolution.height());
|
||||||
QByteArray hash = QCryptographicHash::hash(id.toUtf8(), QCryptographicHash::Md5).toHex();
|
QByteArray hash = QCryptographicHash::hash(id.toUtf8(), QCryptographicHash::Md5).toHex();
|
||||||
|
|
||||||
@@ -86,52 +96,53 @@ QString WallpaperImage::getCacheFilePath() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WallpaperImage::loadImage() {
|
void WallpaperImage::loadImage() {
|
||||||
if (m_source.isEmpty()) return;
|
if (m_source.isEmpty()) {
|
||||||
|
setStatus(Null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QString cacheFile = getCacheFilePath();
|
QString cacheFile = getCacheFilePath();
|
||||||
QString sourceFile = m_source.isLocalFile() ? m_source.toLocalFile() : m_source.toString();
|
QString sourceFile = m_source.isLocalFile() ? m_source.toLocalFile() : m_source.toString();
|
||||||
|
|
||||||
// Qt resource path correction if passed as a standard URL string
|
if (sourceFile.startsWith("qrc:/")) {
|
||||||
if (sourceFile.startsWith("qrc:/")) {
|
sourceFile = sourceFile.mid(3);
|
||||||
sourceFile = sourceFile.mid(3); // Converts "qrc:/" to ":/"
|
}
|
||||||
}
|
|
||||||
|
|
||||||
QSize targetRes = m_screenResolution;
|
QSize targetRes = m_screenResolution;
|
||||||
|
|
||||||
// Run off the main thread to avoid blocking the UI
|
QFuture<QImage> future = QtConcurrent::run([sourceFile, cacheFile, targetRes]() -> QImage {
|
||||||
QFuture<QImage> future = QtConcurrent::run([sourceFile, cacheFile, targetRes]() -> QImage {
|
if (!targetRes.isEmpty() && !cacheFile.isEmpty() && QFileInfo::exists(cacheFile)) {
|
||||||
if (!targetRes.isEmpty() && !cacheFile.isEmpty() && QFileInfo::exists(cacheFile)) {
|
QImage cached(cacheFile);
|
||||||
QImage cached(cacheFile);
|
if (!cached.isNull()) return cached;
|
||||||
if (!cached.isNull()) return cached;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
QImage original(sourceFile);
|
QImage original(sourceFile);
|
||||||
if (original.isNull()) return QImage();
|
if (original.isNull()) return QImage();
|
||||||
|
|
||||||
if (targetRes.isEmpty()) {
|
if (targetRes.isEmpty()) {
|
||||||
// Screen resolution not set yet by QML, return the unscaled original for now to prevent a black screen
|
return original;
|
||||||
return original;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Check if original is strictly larger than screen resolution
|
if (original.width() > targetRes.width() || original.height() > targetRes.height()) {
|
||||||
if (original.width() > targetRes.width() || original.height() > targetRes.height()) {
|
QImage scaled = original.scaled(targetRes, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||||
QImage scaled = original.scaled(targetRes, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
if (!cacheFile.isEmpty()) scaled.save(cacheFile, "PNG");
|
||||||
if (!cacheFile.isEmpty()) scaled.save(cacheFile, "PNG");
|
return scaled;
|
||||||
return scaled;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise just cache and return the original
|
if (!cacheFile.isEmpty()) original.save(cacheFile, "PNG");
|
||||||
if (!cacheFile.isEmpty()) original.save(cacheFile, "PNG");
|
return original;
|
||||||
return original;
|
});
|
||||||
});
|
|
||||||
|
|
||||||
m_imageWatcher.setFuture(future);
|
m_imageWatcher.setFuture(future);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WallpaperImage::handleImageLoaded() {
|
void WallpaperImage::handleImageLoaded() {
|
||||||
m_image = m_imageWatcher.result();
|
m_image = m_imageWatcher.result();
|
||||||
|
|
||||||
|
setStatus(m_image.isNull() ? Error : Ready);
|
||||||
|
|
||||||
m_textureDirty = true;
|
m_textureDirty = true;
|
||||||
update(); // Request redraw
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSGNode *WallpaperImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) {
|
QSGNode *WallpaperImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) {
|
||||||
@@ -148,7 +159,7 @@ QSGNode *WallpaperImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
|
|||||||
|
|
||||||
if (m_textureDirty) {
|
if (m_textureDirty) {
|
||||||
if (m_texture) delete m_texture;
|
if (m_texture) delete m_texture;
|
||||||
m_texture = window()->createTextureFromImage(m_image, QQuickWindow::TextureHasAlphaChannel);
|
m_texture = window()->createTextureFromImage(m_image, QQuickWindow::TextureHasAlphaChannel);
|
||||||
m_textureDirty = false;
|
m_textureDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,40 +168,61 @@ QSGNode *WallpaperImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
|
|||||||
node->setRect(boundingRect());
|
node->setRect(boundingRect());
|
||||||
node->setFiltering(QSGTexture::Linear);
|
node->setFiltering(QSGTexture::Linear);
|
||||||
|
|
||||||
qreal cW = m_cropWidth / m_zoom;
|
qreal cW = m_cropWidth / m_zoom;
|
||||||
qreal cH = m_cropHeight / m_zoom;
|
qreal cH = m_cropHeight / m_zoom;
|
||||||
|
|
||||||
QRectF reqRect(
|
QRectF reqRect(
|
||||||
m_cropX * m_texture->textureSize().width(),
|
m_cropX * m_texture->textureSize().width(),
|
||||||
m_cropY * m_texture->textureSize().height(),
|
m_cropY * m_texture->textureSize().height(),
|
||||||
cW * m_texture->textureSize().width(),
|
cW * m_texture->textureSize().width(),
|
||||||
cH * m_texture->textureSize().height()
|
cH * m_texture->textureSize().height()
|
||||||
);
|
);
|
||||||
|
|
||||||
QRectF bounds = boundingRect();
|
QRectF bounds = boundingRect();
|
||||||
if (bounds.isEmpty() || reqRect.isEmpty()) return node;
|
if (bounds.isEmpty() || reqRect.isEmpty()) return node;
|
||||||
|
|
||||||
qreal targetRatio = bounds.width() / bounds.height();
|
qreal targetRatio = bounds.width() / bounds.height();
|
||||||
qreal reqRatio = reqRect.width() / reqRect.height();
|
qreal reqRatio = reqRect.width() / reqRect.height();
|
||||||
|
|
||||||
QRectF sourceRect = reqRect;
|
QRectF sourceRect = reqRect;
|
||||||
|
|
||||||
// Force 'PreserveAspectCrop' behavior on the requested region
|
if (reqRatio > targetRatio) {
|
||||||
if (reqRatio > targetRatio) {
|
qreal newWidth = reqRect.height() * targetRatio;
|
||||||
// Requested region is too wide, center-crop the sides
|
qreal xOffset = (reqRect.width() - newWidth) / 2.0;
|
||||||
qreal newWidth = reqRect.height() * targetRatio;
|
sourceRect.setX(reqRect.x() + xOffset);
|
||||||
qreal xOffset = (reqRect.width() - newWidth) / 2.0;
|
sourceRect.setWidth(newWidth);
|
||||||
sourceRect.setX(reqRect.x() + xOffset);
|
} else if (reqRatio < targetRatio) {
|
||||||
sourceRect.setWidth(newWidth);
|
qreal newHeight = reqRect.width() / targetRatio;
|
||||||
} else if (reqRatio < targetRatio) {
|
qreal yOffset = (reqRect.height() - newHeight) / 2.0;
|
||||||
// Requested region is too tall, center-crop the top/bottom
|
sourceRect.setY(reqRect.y() + yOffset);
|
||||||
qreal newHeight = reqRect.width() / targetRatio;
|
sourceRect.setHeight(newHeight);
|
||||||
qreal yOffset = (reqRect.height() - newHeight) / 2.0;
|
}
|
||||||
sourceRect.setY(reqRect.y() + yOffset);
|
|
||||||
sourceRect.setHeight(newHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
node->setSourceRect(sourceRect);
|
QRectF normalizedActual(
|
||||||
|
sourceRect.x() / m_texture->textureSize().width(),
|
||||||
|
sourceRect.y() / m_texture->textureSize().height(),
|
||||||
|
sourceRect.width() / m_texture->textureSize().width(),
|
||||||
|
sourceRect.height() / m_texture->textureSize().height()
|
||||||
|
);
|
||||||
|
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
auto updateIfChanged = [&](qreal &dst, qreal value) {
|
||||||
|
if (!qFuzzyCompare(dst, value)) {
|
||||||
|
dst = value;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
updateIfChanged(m_actualCropX, normalizedActual.x());
|
||||||
|
updateIfChanged(m_actualCropY, normalizedActual.y());
|
||||||
|
updateIfChanged(m_actualCropWidth, normalizedActual.width());
|
||||||
|
updateIfChanged(m_actualCropHeight, normalizedActual.height());
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
emit actualCropChanged();
|
||||||
|
|
||||||
|
node->setSourceRect(sourceRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <QSGTexture>
|
#include <QSGTexture>
|
||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
#include <QtQml/qqml.h>
|
#include <QtQml/qqml.h>
|
||||||
|
#include <qtmetamacros.h>
|
||||||
|
|
||||||
namespace ZShell::internal {
|
namespace ZShell::internal {
|
||||||
|
|
||||||
@@ -15,6 +16,12 @@ QML_NAMED_ELEMENT(WallpaperImage)
|
|||||||
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
|
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
|
||||||
Q_PROPERTY(QSize screenResolution READ screenResolution WRITE setScreenResolution NOTIFY screenResolutionChanged)
|
Q_PROPERTY(QSize screenResolution READ screenResolution WRITE setScreenResolution NOTIFY screenResolutionChanged)
|
||||||
Q_PROPERTY(qreal zoom READ zoom WRITE setZoom NOTIFY zoomChanged)
|
Q_PROPERTY(qreal zoom READ zoom WRITE setZoom NOTIFY zoomChanged)
|
||||||
|
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(qreal actualCropX READ actualCropX NOTIFY actualCropChanged)
|
||||||
|
Q_PROPERTY(qreal actualCropY READ actualCropY NOTIFY actualCropChanged)
|
||||||
|
Q_PROPERTY(qreal actualCropWidth READ actualCropWidth NOTIFY actualCropChanged)
|
||||||
|
Q_PROPERTY(qreal actualCropHeight READ actualCropHeight NOTIFY actualCropChanged)
|
||||||
|
|
||||||
Q_PROPERTY(qreal cropX READ cropX WRITE setCropX NOTIFY cropXChanged)
|
Q_PROPERTY(qreal cropX READ cropX WRITE setCropX NOTIFY cropXChanged)
|
||||||
Q_PROPERTY(qreal cropY READ cropY WRITE setCropY NOTIFY cropYChanged)
|
Q_PROPERTY(qreal cropY READ cropY WRITE setCropY NOTIFY cropYChanged)
|
||||||
@@ -25,6 +32,18 @@ public:
|
|||||||
explicit WallpaperImage(QQuickItem *parent = nullptr);
|
explicit WallpaperImage(QQuickItem *parent = nullptr);
|
||||||
~WallpaperImage() override;
|
~WallpaperImage() override;
|
||||||
|
|
||||||
|
enum Status {
|
||||||
|
Null,
|
||||||
|
Ready,
|
||||||
|
Loading,
|
||||||
|
Error
|
||||||
|
};
|
||||||
|
Q_ENUM(Status)
|
||||||
|
|
||||||
|
Status status() const {
|
||||||
|
return m_status;
|
||||||
|
}
|
||||||
|
|
||||||
QUrl source() const {
|
QUrl source() const {
|
||||||
return m_source;
|
return m_source;
|
||||||
}
|
}
|
||||||
@@ -40,6 +59,22 @@ qreal zoom() const {
|
|||||||
}
|
}
|
||||||
void setZoom(qreal zoom);
|
void setZoom(qreal zoom);
|
||||||
|
|
||||||
|
qreal actualCropX() const {
|
||||||
|
return m_actualCropX;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal actualCropY() const {
|
||||||
|
return m_actualCropY;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal actualCropWidth() const {
|
||||||
|
return m_actualCropWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal actualCropHeight() const {
|
||||||
|
return m_actualCropHeight;
|
||||||
|
}
|
||||||
|
|
||||||
qreal cropX() const {
|
qreal cropX() const {
|
||||||
return m_cropX;
|
return m_cropX;
|
||||||
}
|
}
|
||||||
@@ -67,20 +102,29 @@ signals:
|
|||||||
void sourceChanged();
|
void sourceChanged();
|
||||||
void screenResolutionChanged();
|
void screenResolutionChanged();
|
||||||
void zoomChanged();
|
void zoomChanged();
|
||||||
|
void actualCropChanged();
|
||||||
void cropXChanged();
|
void cropXChanged();
|
||||||
void cropYChanged();
|
void cropYChanged();
|
||||||
void cropWidthChanged();
|
void cropWidthChanged();
|
||||||
void cropHeightChanged();
|
void cropHeightChanged();
|
||||||
|
void statusChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadImage();
|
void loadImage();
|
||||||
void handleImageLoaded();
|
void handleImageLoaded();
|
||||||
QString getCacheFilePath() const;
|
QString getCacheFilePath() const;
|
||||||
|
void setStatus(const Status s);
|
||||||
|
|
||||||
|
Status m_status = Null;
|
||||||
QUrl m_source;
|
QUrl m_source;
|
||||||
QSize m_screenResolution;
|
QSize m_screenResolution;
|
||||||
qreal m_zoom = 1.0;
|
qreal m_zoom = 1.0;
|
||||||
|
|
||||||
|
qreal m_actualCropX = 0.0;
|
||||||
|
qreal m_actualCropY = 0.0;
|
||||||
|
qreal m_actualCropWidth = 1.0;
|
||||||
|
qreal m_actualCropHeight = 1.0;
|
||||||
|
|
||||||
qreal m_cropX = 0.0;
|
qreal m_cropX = 0.0;
|
||||||
qreal m_cropY = 0.0;
|
qreal m_cropY = 0.0;
|
||||||
qreal m_cropWidth = 1.0;
|
qreal m_cropWidth = 1.0;
|
||||||
|
|||||||
Reference in New Issue
Block a user