From d4eaf693c653da42441b06c98c4b4300dc651c72 Mon Sep 17 00:00:00 2001 From: Micah Stanley Date: Fri, 27 Jun 2025 18:27:30 +0000 Subject: [PATCH] Folio/Halcyon: Expand Background Blur Effect using a MaskLayer This merge request expands upon the folio and halcyon background blur effects, making the folio background blur include the backgrounds of folder icons, the favorites bar, and wallpaper selector, and for halcyon, it now includes the folder icons, app library, search, and wallpaper selector. To accomplish this, a mask layer plugin was created to easily attach to these elements. This way, we can use a `OpacityMask` to cut out from the existing blur layer, thus hopefully keeping the performance cost low. And with my limited testing, it does at least seems to run about the same on my oneplus 6t, though it is not really a low end device, so I can not fairly judge the impact for something slower (eg. PinePhone). To be on the safe side, a third option was also added to the folio settings, allowing for the ability to toggle back to the old functionality if needed. ![Screenshot_20250613_135521](/uploads/d5aa81d6589b61fbba675e4a6e621b55/Screenshot_20250613_135521.png) ![Screenshot_20250613_135536](/uploads/bd726459a131f736e2711ced3fe90d4f/Screenshot_20250613_135536.png) ![Screenshot_20250613_135505](/uploads/c603627b4e65d4b956a1e0b6463d28f3/Screenshot_20250613_135505.png) ![Screenshot_20250627_093729](/uploads/e5f1ad672361c2b9bae23e57905336eb/Screenshot_20250627_093729.png) --- components/mobileshell/CMakeLists.txt | 3 + .../mobileshell/masklayer/masklayer.cpp | 268 ++++++++++++++++++ components/mobileshell/masklayer/masklayer.h | 33 +++ .../mobileshell/masklayer/maskmanager.cpp | 43 +++ .../mobileshell/masklayer/maskmanager.h | 29 ++ .../mobileshell/qml/homescreen/BlurEffect.qml | 90 ++++++ .../mobileshell/qml/homescreen/HomeScreen.qml | 2 +- .../homescreen/HomeScreenWallpaperBlur.qml | 40 --- .../qml/homescreen/WallpaperSelector.qml | 37 ++- .../homescreens/folio/foliosettings.cpp | 24 +- .../homescreens/folio/foliosettings.h | 17 +- .../package/contents/ui/DelegateDragItem.qml | 9 +- .../package/contents/ui/FavouritesBar.qml | 15 +- .../folio/package/contents/ui/HomeScreen.qml | 27 +- .../package/contents/ui/HomeScreenPage.qml | 39 +-- .../package/contents/ui/HomeScreenPages.qml | 12 +- .../contents/ui/delegate/AbstractDelegate.qml | 11 +- .../contents/ui/delegate/AppDelegate.qml | 6 + .../ui/delegate/AppFolderDelegate.qml | 1 + .../ui/delegate/DelegateFolderIcon.qml | 8 + .../ui/delegate/DelegateIconLoader.qml | 3 + .../folio/package/contents/ui/main.qml | 120 +++++++- .../ui/settings/SettingsComponent.qml | 28 +- .../contents/ui/settings/SettingsWindow.qml | 30 +- .../homescreens/halcyon/halcyonsettings.cpp | 27 +- .../homescreens/halcyon/halcyonsettings.h | 19 +- .../contents/ui/FavoritesAppDelegate.qml | 15 +- .../package/contents/ui/FavoritesGrid.qml | 2 + .../package/contents/ui/FavoritesView.qml | 2 + .../package/contents/ui/HomeScreen.qml | 4 + .../halcyon/package/contents/ui/main.qml | 111 +++++++- .../contents/ui/settings/SettingsScreen.qml | 28 +- .../contents/ui/settings/SettingsWindow.qml | 27 +- 33 files changed, 890 insertions(+), 240 deletions(-) create mode 100644 components/mobileshell/masklayer/masklayer.cpp create mode 100644 components/mobileshell/masklayer/masklayer.h create mode 100644 components/mobileshell/masklayer/maskmanager.cpp create mode 100644 components/mobileshell/masklayer/maskmanager.h create mode 100644 components/mobileshell/qml/homescreen/BlurEffect.qml delete mode 100644 components/mobileshell/qml/homescreen/HomeScreenWallpaperBlur.qml diff --git a/components/mobileshell/CMakeLists.txt b/components/mobileshell/CMakeLists.txt index 4daf7068..83914359 100644 --- a/components/mobileshell/CMakeLists.txt +++ b/components/mobileshell/CMakeLists.txt @@ -11,9 +11,12 @@ set(mobileshellplugin_SRCS notifications/notificationthumbnailer.cpp notifications/notificationfilemenu.cpp notifications/notificationfileinfo.cpp + masklayer/masklayer.cpp + masklayer/maskmanager.cpp ) target_include_directories(mobileshellplugin PRIVATE components) target_include_directories(mobileshellplugin PRIVATE notifications) +target_include_directories(mobileshellplugin PRIVATE masklayer) target_sources(mobileshellplugin PRIVATE ${mobileshellplugin_SRCS}) # Singleton declarations diff --git a/components/mobileshell/masklayer/masklayer.cpp b/components/mobileshell/masklayer/masklayer.cpp new file mode 100644 index 00000000..04cc732a --- /dev/null +++ b/components/mobileshell/masklayer/masklayer.cpp @@ -0,0 +1,268 @@ +// SPDX-FileCopyrightText: 2025 Micah Stanley +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "masklayer.h" + +#include + +// helper function for creating rounded rectangles +static void createRoundedRectGeometry(QSGGeometry *geometry, const QRectF &rect, qreal radius) +{ + geometry->setDrawingMode(QSGGeometry::DrawTriangles); + radius = qMin(radius, qMin(rect.width(), rect.height()) / 2.0); // clamp radius + + // if the radius is too small, draw a simple rectangle instead + if (radius < 0.1) { + // 4 vertices, 6 indices (2 triangles * 3 indices) + geometry->allocate(4, 6); + + // fill vertex data + QSGGeometry::Point2D *vertices = geometry->vertexDataAsPoint2D(); + vertices[0].set(rect.left(), rect.top()); + vertices[1].set(rect.right(), rect.top()); + vertices[2].set(rect.left(), rect.bottom()); + vertices[3].set(rect.right(), rect.bottom()); + + // fill index data + quint16 *indices = geometry->indexDataAsUShort(); + indices[0] = 0; indices[1] = 2; indices[2] = 1; // first triangle (TL, BL, TR) + indices[3] = 1; indices[4] = 2; indices[5] = 3; // second triangle (TR, BL, BR) + + geometry->markVertexDataDirty(); + geometry->markIndexDataDirty(); + return; + } + + const int segments_per_corner = 16; + const int perimeter_verts = segments_per_corner * 4; + const int vertex_count = 1 + perimeter_verts; + const int index_count = perimeter_verts * 3; + + geometry->allocate(vertex_count, index_count); + + QSGGeometry::Point2D *vertices = geometry->vertexDataAsPoint2D(); + quint16 *indices = geometry->indexDataAsUShort(); + + int vertIndex = 0; + int indexPos = 0; + + // define the center vertex + const quint16 center_vert_index = vertIndex; + vertices[vertIndex++].set(rect.center().x(), rect.center().y()); + + // define the center of the corners + const QPointF tl_c = {rect.left() + radius, rect.top() + radius}; + const QPointF tr_c = {rect.right() - radius, rect.top() + radius}; + const QPointF br_c = {rect.right() - radius, rect.bottom() - radius}; + const QPointF bl_c = {rect.left() + radius, rect.bottom() - radius}; + + // create all perimeter vertices + // top-right + for (int i = 0; i < segments_per_corner; ++i) { + const qreal angle = M_PI * 1.5 + (M_PI_2 * i / segments_per_corner); + vertices[vertIndex++].set(tr_c.x() + radius * cos(angle), tr_c.y() + radius * sin(angle)); + } + // bottom-right + for (int i = 0; i < segments_per_corner; ++i) { + const qreal angle = (M_PI_2 * i / segments_per_corner); + vertices[vertIndex++].set(br_c.x() + radius * cos(angle), br_c.y() + radius * sin(angle)); + } + // bottom-left + for (int i = 0; i < segments_per_corner; ++i) { + const qreal angle = M_PI_2 + (M_PI_2 * i / segments_per_corner); + vertices[vertIndex++].set(bl_c.x() + radius * cos(angle), bl_c.y() + radius * sin(angle)); + } + // top-left + for (int i = 0; i < segments_per_corner; ++i) { + const qreal angle = M_PI + (M_PI_2 * i / segments_per_corner); + vertices[vertIndex++].set(tl_c.x() + radius * cos(angle), tl_c.y() + radius * sin(angle)); + } + + // create the triangles using indices + // loop through all perimeter vertices and connect them to the center and the next vertex + for (quint16 i = 0; i < perimeter_verts; ++i) { + indices[indexPos++] = center_vert_index; // center vertex + indices[indexPos++] = center_vert_index + 1 + i; // current perimeter vertex + // the next perimeter vertex / wrapping around to the start at the end + indices[indexPos++] = center_vert_index + 1 + ((i + 1) % perimeter_verts); + } + + // tell renderer to mark all the data as dirty + geometry->markVertexDataDirty(); + geometry->markIndexDataDirty(); +} + +MaskLayer::MaskLayer(QQuickItem *parent) : QQuickItem(parent) +{ + setFlag(ItemHasContents, true); +} + +MaskLayer::~MaskLayer() = default; + +void MaskLayer::addItem(QQuickItem* item) +{ + if (!item || m_sourceItems.contains(item)) { + return; + } + + m_sourceItems.append(item); + + // we connect these signals so that any changes that affects the item's visual representation triggers an update + // we then store connections to be able to disconnect them later + auto& conns = m_connections[item]; + conns.append(QObject::connect(item, &QQuickItem::xChanged, this, &MaskLayer::scheduleUpdate)); + conns.append(QObject::connect(item, &QQuickItem::yChanged, this, &MaskLayer::scheduleUpdate)); + conns.append(QObject::connect(item, &QQuickItem::visibleChanged, this, &MaskLayer::scheduleUpdate)); + conns.append(QObject::connect(item, &QQuickItem::opacityChanged, this, &MaskLayer::scheduleUpdate)); + conns.append(QObject::connect(item, &QObject::destroyed, this, [this, item]() { + removeItem(item); + })); + + const QMetaObject* metaObject = item->metaObject(); + + // due to not being about to tell when the item's transform value changes + // we check for 'scaleAmountChanged()' to use as a sort of work around + int scaleAmountIndex = metaObject->indexOfProperty("scaleAmount"); + if (scaleAmountIndex != -1 && metaObject->property(scaleAmountIndex).hasNotifySignal()) { + conns.append(QObject::connect(item, SIGNAL(scaleAmountChanged()), this, SLOT(scheduleUpdate()))); + } + + // connect the parents signal changes, as this affects the final visible outcome + QQuickItem* currentParent = item->parentItem(); + while (currentParent) { + conns.append(QObject::connect(currentParent, &QQuickItem::xChanged, this, &MaskLayer::scheduleUpdate)); + conns.append(QObject::connect(currentParent, &QQuickItem::yChanged, this, &MaskLayer::scheduleUpdate)); + conns.append(QObject::connect(currentParent, &QQuickItem::opacityChanged, this, &MaskLayer::scheduleUpdate)); + + const QMetaObject* metaObject = currentParent->metaObject(); + + // check for 'scaleAmountChanged()' + int scaleAmountIndex = metaObject->indexOfProperty("scaleAmount"); + if (scaleAmountIndex != -1 && metaObject->property(scaleAmountIndex).hasNotifySignal()) { + conns.append(QObject::connect(currentParent, SIGNAL(scaleAmountChanged()), this, SLOT(scheduleUpdate()))); + } + + currentParent = currentParent->parentItem(); + } + + scheduleUpdate(); +} + +void MaskLayer::removeItem(QQuickItem* item) +{ + if (!item) return; + + disconnectItemSignals(item); + m_connections.remove(item); + m_sourceItems.removeAll(item); + scheduleUpdate(); +} + +void MaskLayer::disconnectItemSignals(QQuickItem* item) +{ + if (m_connections.contains(item)) { + for (const auto &conn : m_connections.value(item)) { + QObject::disconnect(conn); + } + } +} + +void MaskLayer::scheduleUpdate() +{ + // marks this item for an update. + // the renderer will call updatePaintNode before the next frame + update(); +} + +QSGNode *MaskLayer::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) +{ + // if oldNode is null, we need to create a new root node for our content + // otherwise, we can reuse it and manage its children + QSGNode *rootNode = oldNode; + if (!rootNode) { + rootNode = new QSGNode(); + } + + int currentChildIndex = 0; + + for (const QPointer& itemPtr : m_sourceItems) { + QQuickItem* item = itemPtr.data(); + // item was deleted + if (!item) { + continue; + } + + // calculate opacity and visibility + qreal accumulatedOpacity = item->opacity(); + bool isVisible = item->isVisible(); + QQuickItem* currentParent = item->parentItem(); + while (currentParent) { + if (!currentParent->isVisible()) { + isVisible = false; + break; + } + accumulatedOpacity *= currentParent->opacity(); + if (currentParent == this) break; + currentParent = currentParent->parentItem(); + } + + // skip this item if it is invisible or fully transparent + if (!isVisible || qFuzzyCompare(accumulatedOpacity, 0)) { + continue; + } + + // calculate position and size + bool transformOk = false; + const QTransform transform = item->itemTransform(this, &transformOk); + if (!transformOk) continue; + + qreal radius = item->property("radius").toReal(); + + QSGTransformNode *transformNode = nullptr; + QSGGeometryNode *geometryNode = nullptr; + + if (currentChildIndex < rootNode->childCount()) { + transformNode = static_cast(rootNode->childAtIndex(currentChildIndex)); + geometryNode = static_cast(transformNode->firstChild()); + } else { + transformNode = new QSGTransformNode(); + geometryNode = new QSGGeometryNode(); + + QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 0); + + geometryNode->setGeometry(geometry); + + QSGFlatColorMaterial *material = new QSGFlatColorMaterial(); + geometryNode->setMaterial(material); + geometryNode->setFlags(QSGNode::OwnsMaterial); + + transformNode->appendChildNode(geometryNode); + rootNode->appendChildNode(transformNode); + } + + transformNode->setMatrix(QMatrix4x4(transform)); + + QSGFlatColorMaterial *material = static_cast(geometryNode->material()); + QColor color = Qt::white; + color.setAlphaF(accumulatedOpacity); + if (material->color() != color) material->setColor(color); + + QRectF rect(0, 0, item->width(), item->height()); + createRoundedRectGeometry(geometryNode->geometry(), rect, radius); + geometryNode->markDirty(QSGNode::DirtyGeometry); + + + currentChildIndex++; + } + + // if we have more nodes than items this frame, remove the extras + if (currentChildIndex < rootNode->childCount()) { + for (int i = rootNode->childCount() - 1; i >= currentChildIndex; --i) { + QSGNode *nodeToRemove = rootNode->childAtIndex(i); + rootNode->removeChildNode(nodeToRemove); + delete nodeToRemove; + } + } + + return rootNode; +} diff --git a/components/mobileshell/masklayer/masklayer.h b/components/mobileshell/masklayer/masklayer.h new file mode 100644 index 00000000..137a8eb3 --- /dev/null +++ b/components/mobileshell/masklayer/masklayer.h @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: 2025 Micah Stanley +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +class QSGNode; + +class MaskLayer : public QQuickItem +{ + Q_OBJECT + QML_ELEMENT + +public: + explicit MaskLayer(QQuickItem *parent = nullptr); + ~MaskLayer() override; + + Q_INVOKABLE void addItem(QQuickItem* item); + Q_INVOKABLE void removeItem(QQuickItem* item); + +protected: + QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) override; + +private slots: + void scheduleUpdate(); + +private: + void disconnectItemSignals(QQuickItem* item); + + QVector> m_sourceItems; + QHash> m_connections; +}; diff --git a/components/mobileshell/masklayer/maskmanager.cpp b/components/mobileshell/masklayer/maskmanager.cpp new file mode 100644 index 00000000..26bef0e2 --- /dev/null +++ b/components/mobileshell/masklayer/maskmanager.cpp @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2025 Micah Stanley +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "maskmanager.h" +#include "masklayer.h" + +MaskManager::MaskManager(QQuickItem *parent) +: QQuickItem(parent), +m_maskLayer(new MaskLayer(this)) +{ +} + +MaskManager::~MaskManager() = default; + +void MaskManager::componentComplete() { + QQuickItem::componentComplete(); + // ensure the mask layers fill the dimensions + m_maskLayer->setX(0); + m_maskLayer->setY(0); + m_maskLayer->setWidth(width()); + m_maskLayer->setHeight(height()); + m_maskLayer->setZ(z()); + + connect(this, &QQuickItem::widthChanged, this, [this]() { + m_maskLayer->setWidth(width()); + }); + connect(this, &QQuickItem::heightChanged, this, [this]() { + m_maskLayer->setHeight(height()); + }); +} + +QQuickItem* MaskManager::maskLayer() const { + return m_maskLayer; +} + +void MaskManager::assignToMask(QQuickItem* item) { + if (!item) { + qWarning() << "Cannot assign a null item to a mask."; + return; + } + + m_maskLayer->addItem(item); +} diff --git a/components/mobileshell/masklayer/maskmanager.h b/components/mobileshell/masklayer/maskmanager.h new file mode 100644 index 00000000..59bab0c3 --- /dev/null +++ b/components/mobileshell/masklayer/maskmanager.h @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2025 Micah Stanley +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +class MaskLayer; + +class MaskManager : public QQuickItem +{ + Q_OBJECT + QML_ELEMENT + Q_PROPERTY(QQuickItem* maskLayer READ maskLayer CONSTANT) + +public: + explicit MaskManager(QQuickItem *parent = nullptr); + ~MaskManager() override; + + QQuickItem* maskLayer() const; + + Q_INVOKABLE void assignToMask(QQuickItem* item); + +protected: + void componentComplete() override; + +private: + MaskLayer* m_maskLayer; +}; diff --git a/components/mobileshell/qml/homescreen/BlurEffect.qml b/components/mobileshell/qml/homescreen/BlurEffect.qml new file mode 100644 index 00000000..163e0ebd --- /dev/null +++ b/components/mobileshell/qml/homescreen/BlurEffect.qml @@ -0,0 +1,90 @@ +// SPDX-FileCopyrightText: 2023-2025 Devin Lin +// SPDX-FileCopyrightText: 2025 Micah Stanley +// SPDX-License-Identifier: LGPL-2.0-or-later + +import QtQuick +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects + +Loader { + id: root + + property Item sourceLayer + property Item maskSourceLayer + // this value is used to switch between blurring the whole wallpaper or just behind the mask areas + property real fullBlur: 1 + // gets multiplied against the screen size to set the texture size + readonly property real blurTextureQuality: 0.5 + readonly property var textureSize: Qt.size(Math.round(root.width * root.blurTextureQuality), Math.round(root.height * root.blurTextureQuality)) + readonly property int fastBlurRadius: 42 + + sourceComponent: Item { + // only take samples from wallpaper when we need the blur for performance + ShaderEffectSource { + id: controlledWallpaperSource + anchors.fill: parent + + // this layer will be blurred, so it looks fine to have a lower texture quality to help with performance + textureSize: root.textureSize + + hideSource: false + opacity: root.fullBlur + visible: opacity > 0 + + // wallpaper blur + // we attempted to use MultiEffect in the past, but it had very poor performance on the PinePhone + sourceItem: FastBlur { + height: controlledWallpaperSource.textureSize.height + width: controlledWallpaperSource.textureSize.width + + cached: true + radius: root.fastBlurRadius + + source: ShaderEffectSource { + anchors.fill: parent + + textureSize: controlledWallpaperSource.textureSize + + sourceItem: root.sourceLayer + hideSource: false + } + } + } + + // load in the layer mask so we can utilize it with the OpacityMask + Item { + id: blurMask + anchors.fill: parent + layer.enabled: true + layer.smooth: true + opacity: 0 + + Loader { + asynchronous: true + active: root.maskSourceLayer != null && root.fullBlur != 1 + anchors.fill: parent + + sourceComponent: maskSource + + property Component maskSource: Item { + ShaderEffectSource { + anchors.fill: parent + + sourceItem: root.maskSourceLayer + hideSource: false + live: true + } + } + + } + } + + // here we utilize the mask on the blur layer so we can blur behind the some homescreen items + OpacityMask { + anchors.fill: parent + source: controlledWallpaperSource + maskSource: blurMask + visible: opacity > 0 && root.maskSourceLayer != null + } + } +} diff --git a/components/mobileshell/qml/homescreen/HomeScreen.qml b/components/mobileshell/qml/homescreen/HomeScreen.qml index 24d0eb82..78def76c 100644 --- a/components/mobileshell/qml/homescreen/HomeScreen.qml +++ b/components/mobileshell/qml/homescreen/HomeScreen.qml @@ -105,7 +105,7 @@ Item { } } -//END API implementation + //END API implementation Component.onCompleted: { // determine the margins used diff --git a/components/mobileshell/qml/homescreen/HomeScreenWallpaperBlur.qml b/components/mobileshell/qml/homescreen/HomeScreenWallpaperBlur.qml deleted file mode 100644 index 04b73620..00000000 --- a/components/mobileshell/qml/homescreen/HomeScreenWallpaperBlur.qml +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-FileCopyrightText: 2023-2025 Devin Lin -// SPDX-License-Identifier: LGPL-2.0-or-later - -import QtQuick -import QtQuick.Layouts -import Qt5Compat.GraphicalEffects - -Loader { - id: root - property real blurOpacity - property Item wallpaperItem - - sourceComponent: Item { - id: wallpaper - anchors.fill: parent - - // only take samples from wallpaper when we need the blur for performance - ShaderEffectSource { - id: controlledWallpaperSource - anchors.fill: parent - - live: blur.visible - hideSource: false - visible: false - sourceItem: root.wallpaperItem - } - - // wallpaper blur - // we attempted to use MultiEffect in the past, but it had very poor performance on the PinePhone - FastBlur { - id: blur - radius: 50 - cached: true - source: controlledWallpaperSource - anchors.fill: parent - visible: opacity > 0 - opacity: root.blurOpacity - } - } -} \ No newline at end of file diff --git a/components/mobileshell/qml/homescreen/WallpaperSelector.qml b/components/mobileshell/qml/homescreen/WallpaperSelector.qml index 8bee788e..ad51c246 100644 --- a/components/mobileshell/qml/homescreen/WallpaperSelector.qml +++ b/components/mobileshell/qml/homescreen/WallpaperSelector.qml @@ -11,11 +11,14 @@ import org.kde.kirigami 2.20 as Kirigami import org.kde.plasma.wallpapers.image 2.0 as Wallpaper import org.kde.kquickcontrolsaddons 2.0 as Addons import org.kde.plasma.private.mobileshell.wallpaperimageplugin as WallpaperImagePlugin +import org.kde.plasma.private.mobileshell as MobileShell Controls.Drawer { id: imageWallpaperDrawer dragMargin: 0 + property MobileShell.MaskManager maskManager + required property bool horizontal signal wallpaperSettingsRequested() @@ -51,8 +54,8 @@ Controls.Drawer { header: Controls.ItemDelegate { id: openSettings - width: imageWallpaperDrawer.horizontal ? parent.width : height * (imageWallpaperDrawer.width / imageWallpaperDrawer.Screen.height) - height: imageWallpaperDrawer.horizontal ? width / (imageWallpaperDrawer.Screen.width / imageWallpaperDrawer.Screen.height) : parent.height + width: imageWallpaperDrawer.horizontal ? wallpapersView.width : height * (imageWallpaperDrawer.width / imageWallpaperDrawer.Screen.height) + height: imageWallpaperDrawer.horizontal ? width / (imageWallpaperDrawer.Screen.width / imageWallpaperDrawer.Screen.height) : wallpapersView.height padding: Kirigami.Units.gridUnit / 2 leftPadding: padding topPadding: padding @@ -62,6 +65,12 @@ Controls.Drawer { background: Rectangle { radius: Kirigami.Units.cornerRadius color: Qt.rgba(255, 255, 255, (openSettings.down || openSettings.highlighted) ? 0.3 : 0.2) + + Component.onCompleted: { + if (maskManager) { + maskManager.assignToMask(this) + } + } } contentItem: Item { @@ -81,11 +90,11 @@ Controls.Drawer { delegate: Controls.ItemDelegate { id: delegate - width: imageWallpaperDrawer.horizontal ? parent.width : height * (imageWallpaperDrawer.width / imageWallpaperDrawer.Screen.height) - height: imageWallpaperDrawer.horizontal ? width / (imageWallpaperDrawer.Screen.width / imageWallpaperDrawer.Screen.height) : (parent ? parent.height : 0) - padding: Kirigami.Units.largeSpacing - (ListView.isCurrentItem ? Kirigami.Units.smallSpacing : 0) - property real inset: ListView.isCurrentItem ? 0 : Kirigami.Units.smallSpacing - Behavior on inset { + width: imageWallpaperDrawer.horizontal ? wallpapersView.width : height * (imageWallpaperDrawer.width / imageWallpaperDrawer.Screen.height) + height: imageWallpaperDrawer.horizontal ? width / (imageWallpaperDrawer.Screen.width / imageWallpaperDrawer.Screen.height) : (wallpapersView ? wallpapersView.height : 0) + padding: Kirigami.Units.largeSpacing - (wallpapersView.currentIndex === index ? Kirigami.Units.smallSpacing : 0) + property real scaleAmount: wallpapersView.currentIndex === index ? 0 : Kirigami.Units.smallSpacing + Behavior on scaleAmount { NumberAnimation { duration: Kirigami.Units.longDuration easing.type: Easing.InOutQuad @@ -102,10 +111,10 @@ Controls.Drawer { topPadding: padding rightPadding: padding bottomPadding: padding - topInset: inset - bottomInset: inset - leftInset: inset - rightInset: inset + topInset: scaleAmount + bottomInset: scaleAmount + leftInset: scaleAmount + rightInset: scaleAmount property bool isCurrent: WallpaperImagePlugin.WallpaperPlugin.homescreenWallpaperPath == model.path onIsCurrentChanged: { @@ -143,6 +152,12 @@ Controls.Drawer { background: Rectangle { color: Qt.rgba(255, 255, 255, (delegate.down || delegate.highlighted) ? 0.4 : 0.2) radius: Kirigami.Units.cornerRadius + + Component.onCompleted: { + if (maskManager) { + maskManager.assignToMask(this) + } + } } } } diff --git a/containments/homescreens/folio/foliosettings.cpp b/containments/homescreens/folio/foliosettings.cpp index 9faeb751..19735aad 100644 --- a/containments/homescreens/folio/foliosettings.cpp +++ b/containments/homescreens/folio/foliosettings.cpp @@ -18,12 +18,12 @@ const QString CFG_KEY_LOCK_LAYOUT = QStringLiteral("lockLayout"); const QString CFG_KEY_DELEGATE_ICON_SIZE = QStringLiteral("delegateIconSize"); const QString CFG_KEY_SHOW_FAVORITES_BAR_BACKGROUND = QStringLiteral("showFavoritesBarBackground"); const QString CFG_KEY_PAGE_TRANSITION_EFFECT = QStringLiteral("pageTransitionEffect"); -const QString CFG_KEY_SHOW_WALLPAPER_BLUR = QStringLiteral("showWallpaperBlur"); +const QString CFG_KEY_SHOW_WALLPAPER_BLUR = QStringLiteral("wallpaperBlurEffect"); const QString CFG_KEY_DOUBLE_TAP_TO_LOCK = QStringLiteral("doubleTapToLock"); FolioSettings::FolioSettings(HomeScreen *parent) - : QObject{parent} - , m_homeScreen{parent} +: QObject{parent} +, m_homeScreen{parent} { } @@ -140,16 +140,16 @@ void FolioSettings::setPageTransitionEffect(PageTransitionEffect pageTransitionE } } -bool FolioSettings::showWallpaperBlur() const +FolioSettings::WallpaperBlurEffect FolioSettings::wallpaperBlurEffect() const { - return m_showWallpaperBlur; + return m_wallpaperBlurEffect; } -void FolioSettings::setShowWallpaperBlur(bool showWallpaperBlur) +void FolioSettings::setWallpaperBlurEffect(WallpaperBlurEffect wallpaperBlurEffect) { - if (m_showWallpaperBlur != showWallpaperBlur) { - m_showWallpaperBlur = showWallpaperBlur; - Q_EMIT showWallpaperBlurChanged(); + if (m_wallpaperBlurEffect != wallpaperBlurEffect) { + m_wallpaperBlurEffect = wallpaperBlurEffect; + Q_EMIT wallpaperBlurEffectChanged(); save(); } } @@ -182,7 +182,7 @@ void FolioSettings::save() m_homeScreen->config().writeEntry(CFG_KEY_DELEGATE_ICON_SIZE, m_delegateIconSize); m_homeScreen->config().writeEntry(CFG_KEY_SHOW_FAVORITES_BAR_BACKGROUND, m_showFavouritesBarBackground); m_homeScreen->config().writeEntry(CFG_KEY_PAGE_TRANSITION_EFFECT, (int)m_pageTransitionEffect); - m_homeScreen->config().writeEntry(CFG_KEY_SHOW_WALLPAPER_BLUR, m_showWallpaperBlur); + m_homeScreen->config().writeEntry(CFG_KEY_SHOW_WALLPAPER_BLUR, (int)m_wallpaperBlurEffect); m_homeScreen->config().writeEntry(CFG_KEY_DOUBLE_TAP_TO_LOCK, m_doubleTapToLock); Q_EMIT m_homeScreen->configNeedsSaving(); @@ -202,7 +202,7 @@ void FolioSettings::load() m_delegateIconSize = m_homeScreen->config().readEntry(CFG_KEY_DELEGATE_ICON_SIZE, 48); m_showFavouritesBarBackground = m_homeScreen->config().readEntry(CFG_KEY_SHOW_FAVORITES_BAR_BACKGROUND, true); m_pageTransitionEffect = static_cast(m_homeScreen->config().readEntry(CFG_KEY_PAGE_TRANSITION_EFFECT, (int)SlideTransition)); - m_showWallpaperBlur = m_homeScreen->config().readEntry(CFG_KEY_SHOW_WALLPAPER_BLUR, true); + m_wallpaperBlurEffect = static_cast(m_homeScreen->config().readEntry(CFG_KEY_SHOW_WALLPAPER_BLUR, (int)Full)); m_doubleTapToLock = m_homeScreen->config().readEntry(CFG_KEY_DOUBLE_TAP_TO_LOCK, true); Q_EMIT homeScreenRowsChanged(); @@ -211,7 +211,7 @@ void FolioSettings::load() Q_EMIT showFavouritesAppLabelsChanged(); Q_EMIT lockLayoutChanged(); Q_EMIT delegateIconSizeChanged(); - Q_EMIT showWallpaperBlurChanged(); + Q_EMIT wallpaperBlurEffectChanged(); Q_EMIT doubleTapToLockChanged(); } diff --git a/containments/homescreens/folio/foliosettings.h b/containments/homescreens/folio/foliosettings.h index f3743010..74371d2e 100644 --- a/containments/homescreens/folio/foliosettings.h +++ b/containments/homescreens/folio/foliosettings.h @@ -23,7 +23,7 @@ class FolioSettings : public QObject Q_PROPERTY(bool showFavouritesBarBackground READ showFavouritesBarBackground WRITE setShowFavouritesBarBackground NOTIFY showFavouritesBarBackgroundChanged) Q_PROPERTY( FolioSettings::PageTransitionEffect pageTransitionEffect READ pageTransitionEffect WRITE setPageTransitionEffect NOTIFY pageTransitionEffectChanged) - Q_PROPERTY(bool showWallpaperBlur READ showWallpaperBlur WRITE setShowWallpaperBlur NOTIFY showWallpaperBlurChanged) + Q_PROPERTY(FolioSettings::WallpaperBlurEffect wallpaperBlurEffect READ wallpaperBlurEffect WRITE setWallpaperBlurEffect NOTIFY wallpaperBlurEffectChanged) Q_PROPERTY(bool doubleTapToLock READ doubleTapToLock WRITE setDoubleTapToLock NOTIFY doubleTapToLockChanged) public: @@ -39,6 +39,13 @@ public: }; Q_ENUM(PageTransitionEffect) + enum WallpaperBlurEffect { + None = 0, + Simple = 1, + Full = 2, + }; + Q_ENUM(WallpaperBlurEffect) + // number of rows and columns in the config for the homescreen // NOTE: use HomeScreenState.pageRows() instead in UI logic since we may have the rows and // columns swapped (in landscape layouts) @@ -66,8 +73,8 @@ public: PageTransitionEffect pageTransitionEffect() const; void setPageTransitionEffect(PageTransitionEffect pageTransitionEffect); - bool showWallpaperBlur() const; - void setShowWallpaperBlur(bool showWallpaperBlur); + WallpaperBlurEffect wallpaperBlurEffect() const; + void setWallpaperBlurEffect(WallpaperBlurEffect wallpaperBlurEffect); bool doubleTapToLock() const; void setDoubleTapToLock(bool doubleTapToLock); @@ -86,7 +93,7 @@ Q_SIGNALS: void delegateIconSizeChanged(); void showFavouritesBarBackgroundChanged(); void pageTransitionEffectChanged(); - void showWallpaperBlurChanged(); + void wallpaperBlurEffectChanged(); void doubleTapToLockChanged(); private: @@ -102,6 +109,6 @@ private: qreal m_delegateIconSize{48}; bool m_showFavouritesBarBackground{false}; PageTransitionEffect m_pageTransitionEffect{SlideTransition}; - bool m_showWallpaperBlur{false}; + WallpaperBlurEffect m_wallpaperBlurEffect{Full}; bool m_doubleTapToLock{false}; }; diff --git a/containments/homescreens/folio/package/contents/ui/DelegateDragItem.qml b/containments/homescreens/folio/package/contents/ui/DelegateDragItem.qml index 5caae129..24d8cfb0 100644 --- a/containments/homescreens/folio/package/contents/ui/DelegateDragItem.qml +++ b/containments/homescreens/folio/package/contents/ui/DelegateDragItem.qml @@ -6,12 +6,14 @@ import QtQuick.Layouts import org.kde.kirigami 2.20 as Kirigami import org.kde.private.mobile.homescreen.folio 1.0 as Folio +import org.kde.plasma.private.mobileshell as MobileShell import "./delegate" Item { id: root property Folio.HomeScreen folio + property MobileShell.MaskManager maskManager property Folio.FolioDelegate delegate width: folio.HomeScreenState.pageCellWidth @@ -34,7 +36,7 @@ Item { } // animate drop x - XAnimator on x { + NumberAnimation on x { id: dragXAnim running: false duration: Kirigami.Units.longDuration @@ -46,7 +48,7 @@ Item { } // animate drop y - YAnimator on y { + NumberAnimation on y { id: dragYAnim running: false duration: Kirigami.Units.longDuration @@ -140,7 +142,7 @@ Item { // scale animation if we are creating, or inserting into a folder scaleAnim.restart(); - } + } } // if the drop has been abandoned, just hide @@ -158,6 +160,7 @@ Item { DelegateIconLoader { id: loader folio: root.folio + maskManager: root.maskManager Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom Layout.minimumWidth: folio.FolioSettings.delegateIconSize Layout.minimumHeight: folio.FolioSettings.delegateIconSize diff --git a/containments/homescreens/folio/package/contents/ui/FavouritesBar.qml b/containments/homescreens/folio/package/contents/ui/FavouritesBar.qml index f8a75cc0..0feb4e49 100644 --- a/containments/homescreens/folio/package/contents/ui/FavouritesBar.qml +++ b/containments/homescreens/folio/package/contents/ui/FavouritesBar.qml @@ -17,6 +17,7 @@ import "./delegate" MouseArea { id: root property Folio.HomeScreen folio + property MobileShell.MaskManager maskManager property var homeScreen @@ -53,11 +54,11 @@ MouseArea { readonly property var dragState: folio.HomeScreenState.dragState readonly property bool isDropPositionThis: dragState.candidateDropPosition.location === Folio.DelegateDragPosition.Favourites && - dragState.candidateDropPosition.favouritesPosition === delegate.index + dragState.candidateDropPosition.favouritesPosition === delegate.index readonly property bool isAppHoveredOver: folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate && - dragState.dropDelegate && - dragState.dropDelegate.type === Folio.FolioDelegate.Application && - isDropPositionThis + dragState.dropDelegate && + dragState.dropDelegate.type === Folio.FolioDelegate.Application && + isDropPositionThis readonly property bool isLocationBottom: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom @@ -111,6 +112,7 @@ MouseArea { AppDelegate { id: appDelegate folio: root.folio + maskManager: root.maskManager application: delegate.delegateModel.application name: folio.FolioSettings.showFavouritesAppLabels ? delegate.delegateModel.application.name : "" shadow: true @@ -184,14 +186,15 @@ MouseArea { AppFolderDelegate { id: appFolderDelegate folio: root.folio + maskManager: root.maskManager shadow: true folder: delegate.delegateModel.folder name: folio.FolioSettings.showFavouritesAppLabels ? delegate.delegateModel.folder.name : "" // do not show if the drop animation is running to this delegate, and the drop delegate is a folder visible: !(root.homeScreen.dropAnimationRunning && - delegate.isDropPositionThis && - delegate.dragState.dropDelegate.type === Folio.FolioDelegate.Folder) + delegate.isDropPositionThis && + delegate.dragState.dropDelegate.type === Folio.FolioDelegate.Folder) appHoveredOver: delegate.isAppHoveredOver diff --git a/containments/homescreens/folio/package/contents/ui/HomeScreen.qml b/containments/homescreens/folio/package/contents/ui/HomeScreen.qml index cb07b95f..4098c477 100644 --- a/containments/homescreens/folio/package/contents/ui/HomeScreen.qml +++ b/containments/homescreens/folio/package/contents/ui/HomeScreen.qml @@ -20,6 +20,7 @@ import "./settings" Item { id: root property Folio.HomeScreen folio + property MobileShell.MaskManager maskManager property Folio.HomeScreenState homeScreenState: folio.HomeScreenState property real topMargin: 0 @@ -43,6 +44,8 @@ Item { onLeftMarginChanged: folio.HomeScreenState.viewLeftPadding = root.leftMargin onRightMarginChanged: folio.HomeScreenState.viewRightPadding = root.rightMargin + signal wallpaperSelectorTriggered() + // called by any delegates when starting drag // returns the mapped coordinates to be used in the home screen state function prepareStartDelegateDrag(delegate, item, skipSwipeThreshold) { @@ -107,10 +110,10 @@ Item { interactive: root.interactive && settings.homeScreenInteractive && (appDrawer.flickable.contentY <= 10 || // disable the swipe area when we are swiping in the app drawer, and not in drag-and-drop - folio.HomeScreenState.swipeState === Folio.HomeScreenState.AwaitingDraggingDelegate || - folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate || - folio.HomeScreenState.swipeState === Folio.HomeScreenState.SwipingAppDrawerGrid || - folio.HomeScreenState.viewState !== Folio.HomeScreenState.AppDrawerView) + folio.HomeScreenState.swipeState === Folio.HomeScreenState.AwaitingDraggingDelegate || + folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate || + folio.HomeScreenState.swipeState === Folio.HomeScreenState.SwipingAppDrawerGrid || + folio.HomeScreenState.viewState !== Folio.HomeScreenState.AppDrawerView) onSwipeStarted: (currentPos, startPos) => { const deltaX = currentPos.x - startPos.x; @@ -182,6 +185,7 @@ Item { HomeScreenPages { id: homeScreenPages folio: root.folio + maskManager: root.maskManager homeScreen: root anchors.topMargin: root.topMargin @@ -247,6 +251,8 @@ Item { id: favouritesBarScrim color: Qt.rgba(255, 255, 255, 0.2) + Component.onCompleted: maskManager.assignToMask(this) + // don't show in settings mode opacity: 1 - folio.HomeScreenState.settingsOpenProgress visible: folio.FolioSettings.showFavouritesBarBackground @@ -266,6 +272,7 @@ Item { FavouritesBar { id: favouritesBar folio: root.folio + maskManager: root.maskManager homeScreen: root // don't show in settings mode @@ -399,18 +406,6 @@ Item { transform: Translate { y: folderView.opacity > 0 ? 0 : folderView.height } } - // drag and drop component - DelegateDragItem { - id: delegateDragItem - folio: root.folio - } - - // drag and drop for widgets - WidgetDragItem { - id: widgetDragItem - folio: root.folio - } - // bottom app drawer AppDrawer { id: appDrawer diff --git a/containments/homescreens/folio/package/contents/ui/HomeScreenPage.qml b/containments/homescreens/folio/package/contents/ui/HomeScreenPage.qml index 9eb8218a..e03df5fe 100644 --- a/containments/homescreens/folio/package/contents/ui/HomeScreenPage.qml +++ b/containments/homescreens/folio/package/contents/ui/HomeScreenPage.qml @@ -18,6 +18,7 @@ import "./private" Item { id: root property Folio.HomeScreen folio + property MobileShell.MaskManager maskManager property int pageNum @@ -50,10 +51,10 @@ Item { // only show if it is an empty spot on this page visible: folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate && - dropPosition.location === Folio.DelegateDragPosition.Pages && - dropPosition.page === root.pageNum && - !dropDelegateIsWidget && - folio.HomeScreenState.getPageDelegateAt(root.pageNum, dropPosition.pageRow, dropPosition.pageColumn) === null + dropPosition.location === Folio.DelegateDragPosition.Pages && + dropPosition.page === root.pageNum && + !dropDelegateIsWidget && + folio.HomeScreenState.getPageDelegateAt(root.pageNum, dropPosition.pageRow, dropPosition.pageColumn) === null x: dropPosition.pageColumn * folio.HomeScreenState.pageCellWidth y: dropPosition.pageRow * folio.HomeScreenState.pageCellHeight @@ -71,10 +72,10 @@ Item { // only show if the widget can be placed here visible: folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate && - dropPosition.location === Folio.DelegateDragPosition.Pages && - dropPosition.page === root.pageNum && - dropDelegateIsWidget && - pageModel.canAddDelegate(dropPosition.pageRow, dropPosition.pageColumn, dropDelegate) + dropPosition.location === Folio.DelegateDragPosition.Pages && + dropPosition.page === root.pageNum && + dropDelegateIsWidget && + pageModel.canAddDelegate(dropPosition.pageRow, dropPosition.pageColumn, dropDelegate) radius: Kirigami.Units.cornerRadius color: Qt.rgba(255, 255, 255, 0.3) @@ -100,14 +101,14 @@ Item { property var dragState: folio.HomeScreenState.dragState property bool isDropPositionThis: dragState.candidateDropPosition.location === Folio.DelegateDragPosition.Pages && - dragState.candidateDropPosition.page === root.pageNum && - dragState.candidateDropPosition.pageRow === delegate.pageDelegate.row && - dragState.candidateDropPosition.pageColumn === delegate.pageDelegate.column + dragState.candidateDropPosition.page === root.pageNum && + dragState.candidateDropPosition.pageRow === delegate.pageDelegate.row && + dragState.candidateDropPosition.pageColumn === delegate.pageDelegate.column property bool isAppHoveredOver: folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate && - dragState.dropDelegate && - dragState.dropDelegate.type === Folio.FolioDelegate.Application && - isDropPositionThis + dragState.dropDelegate && + dragState.dropDelegate.type === Folio.FolioDelegate.Application && + isDropPositionThis implicitWidth: loader.item ? loader.item.implicitWidth : 0 implicitHeight: loader.item ? loader.item.implicitHeight : 0 @@ -118,7 +119,7 @@ Item { y: row * folio.HomeScreenState.pageCellHeight visible: row >= 0 && row < folio.HomeScreenState.pageRows && - column >= 0 && column < folio.HomeScreenState.pageColumns + column >= 0 && column < folio.HomeScreenState.pageColumns // called when we want to delete this delegate function removeSelf() { @@ -161,6 +162,7 @@ Item { AppDelegate { id: appDelegate folio: root.folio + maskManager: root.maskManager name: folio.FolioSettings.showPagesAppLabels ? delegate.pageDelegate.application.name : "" application: delegate.pageDelegate.application turnToFolder: delegate.isAppHoveredOver @@ -238,6 +240,7 @@ Item { AppFolderDelegate { id: appFolderDelegate folio: root.folio + maskManager: root.maskManager name: folio.FolioSettings.showPagesAppLabels ? delegate.pageDelegate.folder.name : "" folder: delegate.pageDelegate.folder @@ -248,8 +251,8 @@ Item { // do not show if the drop animation is running to this delegate, and the drop delegate is a folder visible: !(root.homeScreen.dropAnimationRunning && - delegate.isDropPositionThis && - delegate.dragState.dropDelegate.type === Folio.FolioDelegate.Folder) + delegate.isDropPositionThis && + delegate.dragState.dropDelegate.type === Folio.FolioDelegate.Folder) // don't show label in drag and drop mode labelOpacity: delegate.opacity @@ -334,7 +337,7 @@ Item { // background: there is only one "visual" instance of the widget, once this delegate loads // it will reparent it to here (but we don't want it to happen while the drop animation is running) property bool suppressAppletReparent: (root.homeScreen.currentlyDraggedWidget === delegate.pageDelegate.widget) - && delegate.isDropPositionThis + && delegate.isDropPositionThis visible: !suppressAppletReparent widget: suppressAppletReparent ? null : delegate.pageDelegate.widget diff --git a/containments/homescreens/folio/package/contents/ui/HomeScreenPages.qml b/containments/homescreens/folio/package/contents/ui/HomeScreenPages.qml index 0493fbc1..b0670ea9 100644 --- a/containments/homescreens/folio/package/contents/ui/HomeScreenPages.qml +++ b/containments/homescreens/folio/package/contents/ui/HomeScreenPages.qml @@ -13,6 +13,7 @@ import org.kde.private.mobile.homescreen.folio 1.0 as Folio MouseArea { id: root property Folio.HomeScreen folio + property MobileShell.MaskManager maskManager property var homeScreen @@ -44,6 +45,7 @@ MouseArea { delegate: HomeScreenPage { id: homeScreenPage folio: root.folio + maskManager: root.maskManager pageNum: model.index pageModel: model.delegate homeScreen: root.homeScreen @@ -64,7 +66,7 @@ MouseArea { switch (folio.FolioSettings.pageTransitionEffect) { case Folio.FolioSettings.StackTransition: return (positionX < 0) ? progressToCenter : - ((progressToCenter < 0.3) ? 0 : ((1 / 0.7) * (progressToCenter - 0.3))) + ((progressToCenter < 0.3) ? 0 : ((1 / 0.7) * (progressToCenter - 0.3))) default: return progressToCenter; } @@ -109,8 +111,8 @@ MouseArea { Rotation { id: cubeTransitionRotation origin.x: (positionX < 0) ? - (folio.HomeScreenState.pageWidth / 2) * homeScreenPage.progressToCenter : - (folio.HomeScreenState.pageWidth / 2) + (folio.HomeScreenState.pageWidth / 2) * (1 - homeScreenPage.progressToCenter); + (folio.HomeScreenState.pageWidth / 2) * homeScreenPage.progressToCenter : + (folio.HomeScreenState.pageWidth / 2) + (folio.HomeScreenState.pageWidth / 2) * (1 - homeScreenPage.progressToCenter); origin.y: folio.HomeScreenState.pageHeight / 2; axis { x: 0; y: 1; z: 0 } angle: { @@ -121,8 +123,8 @@ MouseArea { Rotation { id: rotationTransitionRotation origin.x: (positionX < 0) ? - (folio.HomeScreenState.pageWidth / 2) * homeScreenPage.progressToCenter : - (folio.HomeScreenState.pageWidth / 2) + (folio.HomeScreenState.pageWidth / 2) * (1 - homeScreenPage.progressToCenter); + (folio.HomeScreenState.pageWidth / 2) * homeScreenPage.progressToCenter : + (folio.HomeScreenState.pageWidth / 2) + (folio.HomeScreenState.pageWidth / 2) * (1 - homeScreenPage.progressToCenter); origin.y: 0 axis { x: -0.2; y: 0.3; z: 0.5 } angle: { diff --git a/containments/homescreens/folio/package/contents/ui/delegate/AbstractDelegate.qml b/containments/homescreens/folio/package/contents/ui/delegate/AbstractDelegate.qml index 02768960..593499f4 100644 --- a/containments/homescreens/folio/package/contents/ui/delegate/AbstractDelegate.qml +++ b/containments/homescreens/folio/package/contents/ui/delegate/AbstractDelegate.qml @@ -18,6 +18,7 @@ import org.kde.plasma.private.mobileshell as MobileShell Folio.DelegateTouchArea { id: root property Folio.HomeScreen folio + property MobileShell.MaskManager maskManager property string name property bool shadow: false @@ -29,10 +30,10 @@ Folio.DelegateTouchArea { signal afterClickAnimation() // grow/shrink animation - property real zoomScale: 1 + property real scaleAmount: 1 property bool clickRequested: false - NumberAnimation on zoomScale { + NumberAnimation on scaleAmount { id: shrinkAnim running: false duration: ShellSettings.Settings.animationsEnabled ? 80 : 1 @@ -44,7 +45,7 @@ Folio.DelegateTouchArea { } } - NumberAnimation on zoomScale { + NumberAnimation on scaleAmount { id: growAnim running: false duration: ShellSettings.Settings.animationsEnabled ? 80 : 1 @@ -86,8 +87,8 @@ Folio.DelegateTouchArea { transform: Scale { origin.x: root.width / 2; origin.y: root.height / 2; - xScale: root.zoomScale - yScale: root.zoomScale + xScale: root.scaleAmount + yScale: root.scaleAmount } MobileShell.BaseItem { diff --git a/containments/homescreens/folio/package/contents/ui/delegate/AppDelegate.qml b/containments/homescreens/folio/package/contents/ui/delegate/AppDelegate.qml index f8ee9a93..7c810597 100644 --- a/containments/homescreens/folio/package/contents/ui/delegate/AppDelegate.qml +++ b/containments/homescreens/folio/package/contents/ui/delegate/AppDelegate.qml @@ -62,6 +62,12 @@ AbstractDelegate { color: Qt.rgba(255, 255, 255, 0.3) anchors.fill: parent + Component.onCompleted: { + if (maskManager) { + maskManager.assignToMask(this) + } + } + opacity: root.turnToFolder ? 1 : 0 property real scaleAmount: root.turnToFolder ? 1.2 : 1.0 diff --git a/containments/homescreens/folio/package/contents/ui/delegate/AppFolderDelegate.qml b/containments/homescreens/folio/package/contents/ui/delegate/AppFolderDelegate.qml index a63d1e78..f34d187b 100644 --- a/containments/homescreens/folio/package/contents/ui/delegate/AppFolderDelegate.qml +++ b/containments/homescreens/folio/package/contents/ui/delegate/AppFolderDelegate.qml @@ -19,6 +19,7 @@ AbstractDelegate { contentItem: DelegateFolderIcon { folio: root.folio + maskManager: root.maskManager folder: root.folder expandBackground: root.appHoveredOver } diff --git a/containments/homescreens/folio/package/contents/ui/delegate/DelegateFolderIcon.qml b/containments/homescreens/folio/package/contents/ui/delegate/DelegateFolderIcon.qml index 172e02e8..f1ee13ae 100644 --- a/containments/homescreens/folio/package/contents/ui/delegate/DelegateFolderIcon.qml +++ b/containments/homescreens/folio/package/contents/ui/delegate/DelegateFolderIcon.qml @@ -9,10 +9,12 @@ import QtQuick.Effects import org.kde.kirigami 2.20 as Kirigami import org.kde.private.mobile.homescreen.folio 1.0 as Folio +import org.kde.plasma.private.mobileshell as MobileShell Item { id: root property Folio.HomeScreen folio + property MobileShell.MaskManager maskManager property Folio.FolioApplicationFolder folder @@ -27,6 +29,12 @@ Item { color: Qt.rgba(255, 255, 255, 0.3) anchors.fill: parent + Component.onCompleted: { + if (maskManager) { + maskManager.assignToMask(this) + } + } + property real scaleAmount: root.expandBackground ? 1.2 : 1.0 Behavior on scaleAmount { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } } diff --git a/containments/homescreens/folio/package/contents/ui/delegate/DelegateIconLoader.qml b/containments/homescreens/folio/package/contents/ui/delegate/DelegateIconLoader.qml index 2681af2e..9a7eaf3b 100644 --- a/containments/homescreens/folio/package/contents/ui/delegate/DelegateIconLoader.qml +++ b/containments/homescreens/folio/package/contents/ui/delegate/DelegateIconLoader.qml @@ -9,10 +9,12 @@ import QtQuick.Effects import org.kde.kirigami 2.20 as Kirigami import org.kde.private.mobile.homescreen.folio 1.0 as Folio +import org.kde.plasma.private.mobileshell as MobileShell Loader { id: root property Folio.HomeScreen folio + property MobileShell.MaskManager maskManager height: folio.FolioSettings.delegateIconSize width: folio.FolioSettings.delegateIconSize @@ -50,6 +52,7 @@ Loader { DelegateFolderIcon { folio: root.folio + maskManager: root.maskManager folder: delegate.folder } } diff --git a/containments/homescreens/folio/package/contents/ui/main.qml b/containments/homescreens/folio/package/contents/ui/main.qml index f12002f2..9a24cdda 100644 --- a/containments/homescreens/folio/package/contents/ui/main.qml +++ b/containments/homescreens/folio/package/contents/ui/main.qml @@ -18,6 +18,8 @@ import org.kde.private.mobile.homescreen.folio 1.0 as Folio import org.kde.plasma.private.mobileshell.windowplugin as WindowPlugin import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings +import "./private" + ContainmentItem { id: root property Folio.HomeScreen folio: root.plasmoid @@ -31,19 +33,31 @@ ContainmentItem { forceActiveFocus(); } - MobileShell.HomeScreenWallpaperBlur { - id: wallpaperBlur - active: folio.FolioSettings.showWallpaperBlur - anchors.fill: parent - wallpaperItem: Plasmoid.wallpaperGraphicsObject + property MobileShell.MaskManager maskManager: MobileShell.MaskManager { + height: root.height + width: root.width + } - blurOpacity: Math.min(1, - Math.max( - 1 - homeScreen.contentOpacity, - folio.HomeScreenState.appDrawerOpenProgress * 2, // blur faster during swipe - folio.HomeScreenState.searchWidgetOpenProgress * 1.5, // blur faster during swipe - folio.HomeScreenState.folderOpenProgress - ) + property MobileShell.MaskManager frontMaskManager: MobileShell.MaskManager { + height: root.height + width: root.width + } + + // wallpaper blur layer + MobileShell.BlurEffect { + id: wallpaperBlur + active: folio.FolioSettings.wallpaperBlurEffect > 0 + anchors.fill: parent + sourceLayer: Plasmoid.wallpaperGraphicsObject + maskSourceLayer: folio.FolioSettings.wallpaperBlurEffect > 1 ? maskManager.maskLayer : null + + fullBlur: Math.min(1, + Math.max( + 1 - homeScreen.contentOpacity, + folio.HomeScreenState.appDrawerOpenProgress * 2, // blur faster during swipe + folio.HomeScreenState.searchWidgetOpenProgress * 1.5, // blur faster during swipe + folio.HomeScreenState.folderOpenProgress + ) ) } @@ -144,12 +158,94 @@ ContainmentItem { HomeScreen { id: folioHomeScreen folio: root.folio + maskManager: root.maskManager anchors.fill: parent topMargin: homeScreen.topMargin bottomMargin: homeScreen.bottomMargin leftMargin: homeScreen.leftMargin rightMargin: homeScreen.rightMargin + + onWallpaperSelectorTriggered: wallpaperSelectorLoader.active = true + } + } + } + + // top blur layer for items on top of the base homescreen + MobileShell.BlurEffect { + id: homescreenBlur + anchors.fill: parent + active: folio.FolioSettings.wallpaperBlurEffect > 1 && ((delegateDragItem.visible && folio.HomeScreenState.dragState.dropDelegate.type === Folio.FolioDelegate.Folder) || wallpaperSelectorLoader.active) + visible: active + fullBlur: 0 + + sourceLayer: homeScreenLayer + maskSourceLayer: frontMaskManager.maskLayer + + // stacking both wallpaper and homescreen layers so we can blur them in one pass + Item { + id: homeScreenLayer + anchors.fill: parent + opacity: 0 + + // wallpaper blur + ShaderEffectSource { + anchors.fill: parent + + textureSize: homescreenBlur.textureSize + sourceItem: Plasmoid.wallpaperGraphicsObject + hideSource: false + } + + // homescreen blur + ShaderEffectSource { + anchors.fill: parent + + textureSize: homescreenBlur.textureSize + sourceItem: homeScreen + hideSource: false + } + } + } + + // drag and drop component + DelegateDragItem { + id: delegateDragItem + folio: root.folio + maskManager: root.frontMaskManager + } + + // drag and drop for widgets + WidgetDragItem { + id: widgetDragItem + folio: root.folio + } + + // loader for wallpaper selector + Loader { + id: wallpaperSelectorLoader + anchors.fill: parent + asynchronous: true + active: false + + onLoaded: { + wallpaperSelectorLoader.item.open(); + } + + sourceComponent: MobileShell.WallpaperSelector { + maskManager: root.frontMaskManager + horizontal: root.width > root.height + edge: horizontal ? Qt.LeftEdge : Qt.BottomEdge + bottomMargin: horizontal ? 0 : folioHomeScreen.bottomMargin + leftMargin: horizontal ? folioHomeScreen.leftMargin : 0 + rightMargin: horizontal ? folioHomeScreen.rightMargin : 0 + onClosed: { + wallpaperSelectorLoader.active = false; + } + + onWallpaperSettingsRequested: { + close(); + folioHomeScreen.openConfigure(); } } } diff --git a/containments/homescreens/folio/package/contents/ui/settings/SettingsComponent.qml b/containments/homescreens/folio/package/contents/ui/settings/SettingsComponent.qml index 059b9653..89b4eb70 100644 --- a/containments/homescreens/folio/package/contents/ui/settings/SettingsComponent.qml +++ b/containments/homescreens/folio/package/contents/ui/settings/SettingsComponent.qml @@ -85,7 +85,7 @@ Item { } onClicked: { - wallpaperSelectorLoader.active = true; + homeScreen.wallpaperSelectorTriggered(); folio.HomeScreenState.closeSettingsView(); } } @@ -247,30 +247,4 @@ Item { homeScreen.openConfigure() } } - - Loader { - id: wallpaperSelectorLoader - asynchronous: true - active: false - - onLoaded: { - wallpaperSelectorLoader.item.open(); - } - - sourceComponent: MobileShell.WallpaperSelector { - horizontal: root.width > root.height - edge: horizontal ? Qt.LeftEdge : Qt.BottomEdge - bottomMargin: root.homeScreen.bottomMargin - leftMargin: root.homeScreen.leftMargin - rightMargin: root.homeScreen.rightMargin - onClosed: { - wallpaperSelectorLoader.active = false; - } - - onWallpaperSettingsRequested: { - close(); - homeScreen.openConfigure(); - } - } - } } diff --git a/containments/homescreens/folio/package/contents/ui/settings/SettingsWindow.qml b/containments/homescreens/folio/package/contents/ui/settings/SettingsWindow.qml index 6bdda6a5..376a1b22 100644 --- a/containments/homescreens/folio/package/contents/ui/settings/SettingsWindow.qml +++ b/containments/homescreens/folio/package/contents/ui/settings/SettingsWindow.qml @@ -116,7 +116,7 @@ Window { FormCard.FormCard { id: iconsCard readonly property bool isVerticalOrientation: folio.HomeScreenState.pageOrientation === Folio.HomeScreenState.RegularPosition || - folio.HomeScreenState.pageOrientation === Folio.HomeScreenState.RotateUpsideDown + folio.HomeScreenState.pageOrientation === Folio.HomeScreenState.RotateUpsideDown readonly property string numOfRowsText: i18n("Number of rows") readonly property string numOfColumnsText: i18n("Number of columns") @@ -269,15 +269,24 @@ Window { } FormCard.FormCard { - FormCard.FormSwitchDelegate { - id: showWallpaperBlur - text: i18nc("@option:check", "Show wallpaper blur effect") - checked: folio.FolioSettings.showWallpaperBlur - onCheckedChanged: { - if (checked != folio.FolioSettings.showWallpaperBlur) { - folio.FolioSettings.showWallpaperBlur = checked; - } + FormCard.FormComboBoxDelegate { + id: wallpaperBlurCombobox + text: i18n("Wallpaper blur effect") + + model: [ + {"name": i18nc("Wallpaper blur effect", "None"), "value": 0}, + {"name": i18nc("Wallpaper blur effect", "Simple"), "value": 1}, + {"name": i18nc("Wallpaper blur effect", "Full"), "value": 2} + ] + + textRole: "name" + valueRole: "value" + + Component.onCompleted: { + currentIndex = indexOfValue(folio.FolioSettings.wallpaperBlurEffect); + dialog.parent = root; } + onCurrentValueChanged: folio.FolioSettings.wallpaperBlurEffect = currentValue } } @@ -323,8 +332,7 @@ Window { onAccepted: { console.log('saving layout to ' + selectedFile); if (selectedFile) { - let status = folio.FolioSettings.saveLayoutToFile(selectedFile); - if (status) { + let status = folio.FolioSettings.saveLayoutToFile(selectedFile); if (status) { exportedSuccessfullyPrompt.open(); } else { exportFailedPrompt.open(); diff --git a/containments/homescreens/halcyon/halcyonsettings.cpp b/containments/homescreens/halcyon/halcyonsettings.cpp index f0608ebc..7f1b7287 100644 --- a/containments/homescreens/halcyon/halcyonsettings.cpp +++ b/containments/homescreens/halcyon/halcyonsettings.cpp @@ -3,26 +3,26 @@ #include "halcyonsettings.h" -const QString CFG_KEY_SHOW_WALLPAPER_BLUR = QStringLiteral("showWallpaperBlur"); +const QString CFG_KEY_SHOW_WALLPAPER_BLUR = QStringLiteral("wallpaperBlurEffect"); const QString CFG_KEY_DOUBLE_TAP_TO_LOCK = QStringLiteral("doubleTapToLock"); HalcyonSettings::HalcyonSettings(QObject *parent, KConfigGroup config) - : QObject{parent} - , m_config{config} +: QObject{parent} +, m_config{config} { load(); } -bool HalcyonSettings::showWallpaperBlur() const +HalcyonSettings::WallpaperBlurEffect HalcyonSettings::wallpaperBlurEffect() const { - return m_showWallpaperBlur; + return m_wallpaperBlurEffect; } -void HalcyonSettings::setShowWallpaperBlur(bool showWallpaperBlur) +void HalcyonSettings::setWallpaperBlurEffect(WallpaperBlurEffect wallpaperBlurEffect) { - if (m_showWallpaperBlur != showWallpaperBlur) { - m_showWallpaperBlur = showWallpaperBlur; - Q_EMIT showWallpaperBlurChanged(); + if (m_wallpaperBlurEffect != wallpaperBlurEffect) { + m_wallpaperBlurEffect = wallpaperBlurEffect; + Q_EMIT wallpaperBlurEffectChanged(); save(); } } @@ -43,7 +43,7 @@ void HalcyonSettings::setDoubleTapToLock(bool doubleTapToLock) void HalcyonSettings::save() { - m_config.writeEntry(CFG_KEY_SHOW_WALLPAPER_BLUR, m_showWallpaperBlur); + m_config.writeEntry(CFG_KEY_SHOW_WALLPAPER_BLUR, (int)m_wallpaperBlurEffect); m_config.writeEntry(CFG_KEY_DOUBLE_TAP_TO_LOCK, m_doubleTapToLock); m_config.sync(); @@ -51,6 +51,9 @@ void HalcyonSettings::save() void HalcyonSettings::load() { - m_showWallpaperBlur = m_config.readEntry(CFG_KEY_SHOW_WALLPAPER_BLUR, false); + m_wallpaperBlurEffect = static_cast(m_config.readEntry(CFG_KEY_SHOW_WALLPAPER_BLUR, (int)Full)); m_doubleTapToLock = m_config.readEntry(CFG_KEY_DOUBLE_TAP_TO_LOCK, true); -} \ No newline at end of file + + Q_EMIT doubleTapToLockChanged(); + Q_EMIT wallpaperBlurEffectChanged(); +} diff --git a/containments/homescreens/halcyon/halcyonsettings.h b/containments/homescreens/halcyon/halcyonsettings.h index 5fa13869..9863c564 100644 --- a/containments/homescreens/halcyon/halcyonsettings.h +++ b/containments/homescreens/halcyon/halcyonsettings.h @@ -10,28 +10,35 @@ class HalcyonSettings : public QObject { Q_OBJECT - Q_PROPERTY(bool showWallpaperBlur READ showWallpaperBlur WRITE setShowWallpaperBlur NOTIFY showWallpaperBlurChanged) + Q_PROPERTY(HalcyonSettings::WallpaperBlurEffect wallpaperBlurEffect READ wallpaperBlurEffect WRITE setWallpaperBlurEffect NOTIFY wallpaperBlurEffectChanged) Q_PROPERTY(bool doubleTapToLock READ doubleTapToLock WRITE setDoubleTapToLock NOTIFY doubleTapToLockChanged) public: HalcyonSettings(QObject *parent = nullptr, KConfigGroup config = {}); - bool showWallpaperBlur() const; - void setShowWallpaperBlur(bool blurWallpaper); + enum WallpaperBlurEffect { + None = 0, + Simple = 1, + Full = 2, + }; + Q_ENUM(WallpaperBlurEffect) + + WallpaperBlurEffect wallpaperBlurEffect() const; + void setWallpaperBlurEffect(WallpaperBlurEffect wallpaperBlurEffect); bool doubleTapToLock() const; void setDoubleTapToLock(bool doubleTapToLock); Q_SIGNALS: - void showWallpaperBlurChanged(); + void wallpaperBlurEffectChanged(); void doubleTapToLockChanged(); private: void save(); void load(); - bool m_showWallpaperBlur{false}; + WallpaperBlurEffect m_wallpaperBlurEffect{Full}; bool m_doubleTapToLock{true}; KConfigGroup m_config; -}; \ No newline at end of file +}; diff --git a/containments/homescreens/halcyon/package/contents/ui/FavoritesAppDelegate.qml b/containments/homescreens/halcyon/package/contents/ui/FavoritesAppDelegate.qml index 2b15683c..c552a3f4 100644 --- a/containments/homescreens/halcyon/package/contents/ui/FavoritesAppDelegate.qml +++ b/containments/homescreens/halcyon/package/contents/ui/FavoritesAppDelegate.qml @@ -20,6 +20,7 @@ import org.kde.kirigami 2.19 as Kirigami Item { id: delegate + property MobileShell.MaskManager maskManager property int visualIndex: 0 property real dragFolderAnimationProgress: 0 @@ -77,7 +78,7 @@ Item { } function launchAppWithAnim(x: int, y: int, source, title: string, storageId: string) { - if (source !== "") { + if (source !== "") { MobileShellState.ShellDBusClient.openAppLaunchAnimationWithPosition( Plasmoid.screen, source, @@ -265,6 +266,12 @@ Item { color: Qt.rgba(255, 255, 255, 0.2) radius: Kirigami.Units.cornerRadius opacity: delegate.dragFolderAnimationProgress + + Component.onCompleted: { + if (maskManager) { + maskManager.assignToMask(this) + } + } } Kirigami.Icon { @@ -319,6 +326,12 @@ Item { xScale: 1 + delegate.dragFolderAnimationProgress * 0.5 yScale: 1 + delegate.dragFolderAnimationProgress * 0.5 } + + Component.onCompleted: { + if (maskManager) { + maskManager.assignToMask(this) + } + } } Grid { diff --git a/containments/homescreens/halcyon/package/contents/ui/FavoritesGrid.qml b/containments/homescreens/halcyon/package/contents/ui/FavoritesGrid.qml index 2da8113b..e49acabd 100644 --- a/containments/homescreens/halcyon/package/contents/ui/FavoritesGrid.qml +++ b/containments/homescreens/halcyon/package/contents/ui/FavoritesGrid.qml @@ -15,6 +15,7 @@ import org.kde.private.mobile.homescreen.halcyon as Halcyon MobileShell.GridView { id: root + property MobileShell.MaskManager maskManager required property var searchWidget // don't set anchors.margins since we want everywhere to be draggable @@ -207,6 +208,7 @@ MobileShell.GridView { // actual visual delegate FavoritesAppDelegate { id: appDelegate + maskManager: root.maskManager visualIndex: delegateRoot.visualIndex isFolder: model.isFolder diff --git a/containments/homescreens/halcyon/package/contents/ui/FavoritesView.qml b/containments/homescreens/halcyon/package/contents/ui/FavoritesView.qml index cab175c5..43d46c37 100644 --- a/containments/homescreens/halcyon/package/contents/ui/FavoritesView.qml +++ b/containments/homescreens/halcyon/package/contents/ui/FavoritesView.qml @@ -16,6 +16,7 @@ import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings Item { id: root layer.enabled: true + property MobileShell.MaskManager maskManager required property bool interactive required property var searchWidget @@ -67,6 +68,7 @@ Item { property real openFolderProgress: 0 anchors.fill: parent + maskManager: root.maskManager interactive: root.interactive searchWidget: root.searchWidget diff --git a/containments/homescreens/halcyon/package/contents/ui/HomeScreen.qml b/containments/homescreens/halcyon/package/contents/ui/HomeScreen.qml index 0d400393..173baffb 100644 --- a/containments/homescreens/halcyon/package/contents/ui/HomeScreen.qml +++ b/containments/homescreens/halcyon/package/contents/ui/HomeScreen.qml @@ -19,6 +19,7 @@ import "settings" as Settings Item { id: root + property MobileShell.MaskManager maskManager required property real topMargin required property real bottomMargin @@ -33,6 +34,8 @@ Item { property bool settingsOpen: false property real settingsOpenFactor: settingsOpen ? 1 : 0 + signal wallpaperSelectorTriggered() + Behavior on settingsOpenFactor { NumberAnimation { duration: 200 } } @@ -121,6 +124,7 @@ Item { FavoritesView { id: favoritesView anchors.fill: parent + maskManager: root.maskManager searchWidget: root.searchWidget interactive: root.interactive && swipeView.contentItem.contentX === 0 onOpenConfigureRequested: root.openConfigure() diff --git a/containments/homescreens/halcyon/package/contents/ui/main.qml b/containments/homescreens/halcyon/package/contents/ui/main.qml index adcb2f88..5dddb3d8 100644 --- a/containments/homescreens/halcyon/package/contents/ui/main.qml +++ b/containments/homescreens/halcyon/package/contents/ui/main.qml @@ -56,26 +56,42 @@ ContainmentItem { screenGeometry: Plasmoid.containment.screenGeometry } - MobileShell.HomeScreenWallpaperBlur { - id: wallpaperBlur - active: Plasmoid.settings.showWallpaperBlur - anchors.fill: parent - wallpaperItem: Plasmoid.wallpaperGraphicsObject + property MobileShell.MaskManager maskManager: MobileShell.MaskManager { + height: root.height + width: root.width + } - blurOpacity: Math.min(1, - Math.max(1 - homeScreen.contentOpacity, - halcyonHomeScreen.settingsOpenFactor - ) + property MobileShell.MaskManager frontMaskManager: MobileShell.MaskManager { + height: root.height + width: root.width + } + + // wallpaper blur layer + MobileShell.BlurEffect { + id: wallpaperBlur + active: Plasmoid.settings.wallpaperBlurEffect > 0 + anchors.fill: parent + sourceLayer: Plasmoid.wallpaperGraphicsObject + maskSourceLayer: Plasmoid.settings.wallpaperBlurEffect > 1 ? maskManager.maskLayer : null + + fullBlur: Math.min(1, + Math.max(1 - homeScreen.contentOpacity, + halcyonHomeScreen.settingsOpenFactor, + root.darkenBackgroundFactor, + search.openFactor + ) ) } + property real darkenBackgroundFactor: halcyonHomeScreen.page == 1 ? 1 : 0 + Behavior on darkenBackgroundFactor { + NumberAnimation { duration: Kirigami.Units.longDuration } + } + Rectangle { id: darkenBackground - color: (halcyonHomeScreen.page == 1 ? Qt.rgba(0, 0, 0, 0.7) : Qt.rgba(0, 0, 0, 0.2)) + color: Qt.rgba(0, 0, 0, 0.2 + (0.5 * root.darkenBackgroundFactor)) anchors.fill: parent - Behavior on color { - ColorAnimation { duration: Kirigami.Units.longDuration } - } } Rectangle { @@ -106,6 +122,7 @@ ContainmentItem { HomeScreen { id: halcyonHomeScreen anchors.fill: parent + maskManager: root.maskManager topMargin: homeScreen.topMargin bottomMargin: homeScreen.bottomMargin @@ -114,6 +131,8 @@ ContainmentItem { searchWidget: search interactive: true + + onWallpaperSelectorTriggered: wallpaperSelectorLoader.active = true } // search component @@ -131,6 +150,72 @@ ContainmentItem { } } } + + // top blur layer for items on top of the base homescreen + MobileShell.BlurEffect { + id: homescreenBlur + anchors.fill: parent + active: Plasmoid.settings.wallpaperBlurEffect > 1 && wallpaperSelectorLoader.active + visible: active + fullBlur: 0 + + sourceLayer: homeScreenLayer + maskSourceLayer: frontMaskManager.maskLayer + + // stacking both wallpaper and homescreen layers so we can blur them in one pass + Item { + id: homeScreenLayer + anchors.fill: parent + opacity: 0 + + // wallpaper blur + ShaderEffectSource { + anchors.fill: parent + + textureSize: homescreenBlur.textureSize + sourceItem: Plasmoid.wallpaperGraphicsObject + hideSource: false + } + + // homescreen blur + ShaderEffectSource { + anchors.fill: parent + + textureSize: homescreenBlur.textureSize + sourceItem: homeScreen + hideSource: false + } + } + } + + // loader for wallpaper selector + Loader { + id: wallpaperSelectorLoader + anchors.fill: parent + asynchronous: true + active: false + + onLoaded: { + wallpaperSelectorLoader.item.open(); + } + + sourceComponent: MobileShell.WallpaperSelector { + maskManager: root.frontMaskManager + horizontal: root.width > root.height + edge: horizontal ? Qt.LeftEdge : Qt.BottomEdge + bottomMargin: horizontal ? 0 : halcyonHomeScreen.bottomMargin + leftMargin: horizontal ? halcyonHomeScreen.leftMargin : 0 + rightMargin: horizontal ? halcyonHomeScreen.rightMargin : 0 + onClosed: { + wallpaperSelectorLoader.active = false; + } + + onWallpaperSettingsRequested: { + close(); + halcyonHomeScreen.openContainmentSettings(); + } + } + } } diff --git a/containments/homescreens/halcyon/package/contents/ui/settings/SettingsScreen.qml b/containments/homescreens/halcyon/package/contents/ui/settings/SettingsScreen.qml index 8b284062..8cf5142c 100644 --- a/containments/homescreens/halcyon/package/contents/ui/settings/SettingsScreen.qml +++ b/containments/homescreens/halcyon/package/contents/ui/settings/SettingsScreen.qml @@ -75,7 +75,7 @@ Item { onClicked: { root.homeScreen.settingsOpen = false; - wallpaperSelectorLoader.active = true; + root.homeScreen.wallpaperSelectorTriggered(); } } @@ -135,30 +135,4 @@ Item { } } } - - // Only load wallpaper selector when visible - Loader { - id: wallpaperSelectorLoader - asynchronous: true - active: false - - onLoaded: { - wallpaperSelectorLoader.item.open(); - } - - sourceComponent: MobileShell.WallpaperSelector { - horizontal: root.width > root.height - edge: horizontal ? Qt.LeftEdge : Qt.BottomEdge - bottomMargin: root.bottomMargin - leftMargin: root.leftMargin - rightMargin: root.rightMargin - onClosed: { - wallpaperSelectorLoader.active = false; - } - onWallpaperSettingsRequested: { - close(); - root.homeScreen.openContainmentSettings(); - } - } - } } diff --git a/containments/homescreens/halcyon/package/contents/ui/settings/SettingsWindow.qml b/containments/homescreens/halcyon/package/contents/ui/settings/SettingsWindow.qml index 987b8c46..28b35bf4 100644 --- a/containments/homescreens/halcyon/package/contents/ui/settings/SettingsWindow.qml +++ b/containments/homescreens/halcyon/package/contents/ui/settings/SettingsWindow.qml @@ -87,18 +87,27 @@ Window { } FormCard.FormCard { - FormCard.FormSwitchDelegate { - id: showWallpaperBlur - text: i18nc("@option:check", "Show wallpaper blur effect") - checked: Plasmoid.settings.showWallpaperBlur - onCheckedChanged: { - if (checked != Plasmoid.settings.showWallpaperBlur) { - Plasmoid.settings.showWallpaperBlur = checked; - } + FormCard.FormComboBoxDelegate { + id: wallpaperBlurCombobox + text: i18n("Wallpaper blur effect") + + model: [ + {"name": i18nc("Wallpaper blur effect", "None"), "value": 0}, + {"name": i18nc("Wallpaper blur effect", "Simple"), "value": 1}, + {"name": i18nc("Wallpaper blur effect", "Full"), "value": 2} + ] + + textRole: "name" + valueRole: "value" + + Component.onCompleted: { + currentIndex = indexOfValue(Plasmoid.settings.wallpaperBlurEffect); + dialog.parent = root; } + onCurrentValueChanged: Plasmoid.settings.wallpaperBlurEffect = currentValue } - FormCard.FormDelegateSeparator { above: showWallpaperBlur; below: doubleTapToSleepSwitch } + FormCard.FormDelegateSeparator { above: wallpaperBlurCombobox; below: doubleTapToSleepSwitch } FormCard.FormSwitchDelegate { id: doubleTapToSleepSwitch