diff --git a/qml/AppUI/AppPageContent.qml b/qml/AppUI/AppPageContent.qml index d0e3574..5311452 100644 --- a/qml/AppUI/AppPageContent.qml +++ b/qml/AppUI/AppPageContent.qml @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + import QtQuick 2.0 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.5 diff --git a/qml/AppUI/FullScreenContent.qml b/qml/AppUI/FullScreenContent.qml index 2e8b685..c335f37 100644 --- a/qml/AppUI/FullScreenContent.qml +++ b/qml/AppUI/FullScreenContent.qml @@ -2,7 +2,6 @@ import QtQuick 2.12 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 import QtQml.Models 2.12 - import org.ukui.menu.core 1.0 import AppControls2 1.0 as AppControls2 diff --git a/qml/AppUI/FullScreenHeader.qml b/qml/AppUI/FullScreenHeader.qml index 51df2f2..b80028e 100644 --- a/qml/AppUI/FullScreenHeader.qml +++ b/qml/AppUI/FullScreenHeader.qml @@ -1,7 +1,6 @@ import QtQuick 2.0 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 - import AppControls2 1.0 as AppControls2 import org.ukui.menu.core 1.0 @@ -23,10 +22,7 @@ Item { width: 48 height: 48 buttonIcon: "image://appicon/view-restore-symbolic" - onClicked: { - mainWindow.isFullScreen = false; - } + onClicked: mainWindow.exitFullScreen() } } - diff --git a/qml/AppUI/FullScreenUI.qml b/qml/AppUI/FullScreenUI.qml index 3bde267..aafb911 100644 --- a/qml/AppUI/FullScreenUI.qml +++ b/qml/AppUI/FullScreenUI.qml @@ -1,6 +1,11 @@ import QtQuick 2.0 import QtQuick.Layouts 1.12 -Item { +import AppControls2 1.0 as AppControls2 +import org.ukui.menu.core 1.0 + +AppControls2.StyleBackground { + paletteRole: Palette.Dark + ColumnLayout { anchors.fill: parent anchors.leftMargin: 35 diff --git a/qml/AppUI/NormalUI.qml b/qml/AppUI/NormalUI.qml index 48a6051..d7edef0 100644 --- a/qml/AppUI/NormalUI.qml +++ b/qml/AppUI/NormalUI.qml @@ -3,9 +3,7 @@ import QtQuick.Controls 2.0 as QQC2 import AppControls2 1.0 as AppControls2 import org.ukui.menu.core 1.0 -AppControls2.StyleBackground { - paletteRole: Palette.Window - radius: 12 +Item { Row { anchors.fill: parent; diff --git a/qml/AppUI/Sidebar.qml b/qml/AppUI/Sidebar.qml index 663ec34..b573fc3 100644 --- a/qml/AppUI/Sidebar.qml +++ b/qml/AppUI/Sidebar.qml @@ -58,20 +58,20 @@ Item { } } - Item { - width: 34 - height: 34 - Rectangle { - anchors.fill: parent - radius: height / 2 - color: "lightblue" + AppControls2.StyleBackground { + width: 34; height: width + radius: 4 + useStyleTransparent: false + alpha: buttonMouseArea.containsPress ? 0.65 : buttonMouseArea.containsMouse ? 0.40 : 0.00 + Image { + anchors.centerIn: parent + width: parent.width / 2; height: width + source: "image://appicon/view-fullscreen-symbolic" MouseArea { + id: buttonMouseArea + hoverEnabled: true anchors.fill: parent - onClicked: { - // 全屏 - console.log("==开始全屏==") - mainWindow.isFullScreen = true; - } + onClicked: mainWindow.isFullScreen = true } } } diff --git a/qml/main.qml b/qml/main.qml index 500b917..74be2f8 100644 --- a/qml/main.qml +++ b/qml/main.qml @@ -17,8 +17,6 @@ */ import QtQuick 2.12 -import QtQml 2.12 - import AppUI 1.0 as AppUI import AppControls2 1.0 as AppControls2 import org.ukui.menu.core 1.0 @@ -26,35 +24,48 @@ import org.ukui.menu.core 1.0 Item { id: root clip: true - property int animationDuration: 150 + + property int animationDuration: menuSetting.get("animationDuration") + property var normalGeometry: mainWindow.normalScreenSize() + property double transparency: mainWindow.transparency + property bool onComlpeted: false Component.onCompleted: { - loader.reloadUI(); - mainWindow.beforeFullScreenChanged.connect(beforeFullScreenSlot); - mainWindow.fullScreenChanged.connect(fullScreenChangedSlot); + mainWindow.fullScreenChanged.connect(enterFullScreen); + mainWindow.beforeFullScreenExited.connect(exitFullScreen); + menuSetting.changed.connect(updateAnimationDuration); + onComlpeted = true; } - function fullScreenChangedSlot() { - loader.opacity = 0; - fullScreenAnimation.start(); - } - - function beforeFullScreenSlot(status) { - if (!status) { - loader.sourceComponent = undefined; + function enterFullScreen() { + if (mainWindow.isFullScreen) { + normalHide.start(); + fullShow.start(); + backgroundMask.state = "fullScreen"; + if (root.transparency <= 0.6) { + maskHide.start(); + } } - backgroundMask.alpha = status ? 0.5 : 0 - backgroundMask.enableSizeChange = false; } - ParallelAnimation { - id: fullScreenAnimation - NumberAnimation { target: backgroundMask; property: "width"; to: root.width; duration: root.animationDuration } - NumberAnimation { target: backgroundMask; property: "height"; to: root.height; duration: root.animationDuration } + function exitFullScreen() { + normalShow.start(); + fullHide.start(); + backgroundMask.state = "normalScreen"; + if (root.transparency <= 0.6) { + maskShow.start(); + } + } - onFinished: { - backgroundMask.enableSizeChange = true; - loader.reloadUI(); + function updateAnimationDuration(key) { + if (key === "animationDuration") { + root.animationDuration = menuSetting.get("animationDuration"); + } + } + + onTransparencyChanged: { + if (transparency > 0.6) { + backgroundMask.opacity = 1; } } @@ -62,44 +73,101 @@ Item { id: backgroundMask anchors.left: parent.left anchors.bottom: parent.bottom - alpha: 0 - useStyleTransparent: false - paletteRole: Palette.Dark + radius: 12 + state: "normalScreen" - property bool enableSizeChange: true + onHeightChanged: { + if (root.transparency <= 0.6 && root.onComlpeted) { + mainWindow.changeWindowBlurRegion(0, root.height - height, width, height) + } + } + + NumberAnimation { + id: maskHide + target: backgroundMask; property: "opacity" + from: 1.0; to: 0; + duration: root.animationDuration / 4; easing.type: Easing.InOutQuad + } + + NumberAnimation { + id: maskShow + target: backgroundMask; property: "opacity" + from: 0; to: 1.0; + duration: root.animationDuration * 2; easing.type: Easing.InOutExpo + } states: [ State { - name: "disableSizeChange" - when: !backgroundMask.enableSizeChange - AnchorChanges { - target: backgroundMask - anchors.top: undefined - anchors.right: undefined - } + name: "normalScreen" + PropertyChanges { target: backgroundMask; height: root.normalGeometry.height; width: root.normalGeometry.width } }, State { - name: "enableSizeChange" - when: backgroundMask.enableSizeChange - AnchorChanges { - target: backgroundMask - anchors.top: parent.top - anchors.right: parent.right - } + name: "fullScreen" + PropertyChanges { target: backgroundMask; height: root.height; width: root.width } + PropertyChanges { target: normalScreenLoader; anchors.margins: 8 } + AnchorChanges { target: normalScreenLoader; anchors.bottom: root.bottom; anchors.left: root.left } } ] - Loader { - id: loader - anchors.fill: parent - Behavior on opacity { - NumberAnimation { duration: root.animationDuration } + transitions: [ + Transition { + to: "fullScreen" + SequentialAnimation { + ScriptAction { + script: { + normalScreenLoader.anchors.left = root.left; + normalScreenLoader.anchors.bottom = root.bottom; + normalScreenLoader.anchors.margins = 8; + fullScreenLoader.active = true; + } + } + NumberAnimation { properties: "height,width"; duration: root.animationDuration; easing.type: Easing.InOutQuad } + ScriptAction { + script: { + normalScreenLoader.active = false; + mainWindow.enableWindowBlur(true); + } + } + } + }, + Transition { + to: "normalScreen" + SequentialAnimation { + ScriptAction { + script: { + normalScreenLoader.active = true; + mainWindow.enableWindowBlur(false); + } + } + NumberAnimation { properties: "height,width"; duration: root.animationDuration; easing.type: Easing.InOutQuad } + ScriptAction { + script: { + fullScreenLoader.active = false; + mainWindow.isFullScreen = false; + } + } + } } - function reloadUI() { - loader.sourceComponent = mainWindow.isFullScreen ? fullSceenComponent : normalComponent; - loader.opacity = 1; - } - } + ] + } + + Loader { + id: normalScreenLoader + height: root.normalGeometry.height; width: root.normalGeometry.width + anchors.bottom: root.bottom + anchors.left: root.left + sourceComponent: normalComponent + NumberAnimation { id: normalShow; target: normalScreenLoader; properties: "opacity"; from: 0; to: 1; duration: root.animationDuration; easing.type: Easing.InQuint } + NumberAnimation { id: normalHide; target: normalScreenLoader; properties: "opacity"; from: 1; to: 0; duration: root.animationDuration; easing.type: Easing.OutQuint } + } + + Loader { + id: fullScreenLoader + anchors.fill: parent + sourceComponent: fullSceenComponent + opacity: 0 + NumberAnimation { id: fullShow; target: fullScreenLoader; properties: "opacity"; from: 0; to: 1; duration: root.animationDuration; easing.type: Easing.InQuint } + NumberAnimation { id: fullHide; target: fullScreenLoader; properties: "opacity"; from: 1; to: 0; duration: root.animationDuration; easing.type: Easing.OutQuint } } Component { diff --git a/src/settings/settings.cpp b/src/settings/settings.cpp index 6cef7dc..5290be4 100644 --- a/src/settings/settings.cpp +++ b/src/settings/settings.cpp @@ -25,6 +25,7 @@ #define UKUI_MENU_SCHEMA "org.ukui.menu.settings" #define CONTROL_CENTER_SETTING "org.ukui.control-center.personalise" #define CONTROL_CENTER_TRANSPARENCY_KEY "transparency" +#define CONTROL_CENTER_EFFECT_KEY "effect" #define UKUI_STYLE_SCHEMA "org.ukui.style" #define UKUI_STYLE_NAME_KEY "styleName" @@ -54,6 +55,7 @@ void GlobalSetting::initStyleSetting() m_cache.insert(StyleName, UKUI_STYLE_VALUE_LIGHT); m_cache.insert(ThemeColor, UKUI_STYLE_THEME_COLOR_KEY); m_cache.insert(Transparency, 1); + m_cache.insert(EffectEnabled, false); if (QGSettings::isSchemaInstalled(UKUI_STYLE_SCHEMA)) { QGSettings *settings = new QGSettings(UKUI_STYLE_SCHEMA, {}, this); @@ -84,12 +86,19 @@ void GlobalSetting::initStyleSetting() if (keys.contains(CONTROL_CENTER_TRANSPARENCY_KEY)) { m_cache.insert(Transparency, settings->get(CONTROL_CENTER_TRANSPARENCY_KEY).toReal()); } + if (keys.contains(CONTROL_CENTER_EFFECT_KEY)) { + m_cache.insert(EffectEnabled, settings->get(CONTROL_CENTER_EFFECT_KEY).toBool()); + } connect(settings, &QGSettings::changed, this, [this, settings] (const QString &key) { if (key == CONTROL_CENTER_TRANSPARENCY_KEY) { updateData(Transparency, settings->get(key).toReal()); Q_EMIT styleChanged(Transparency); } + if (key == CONTROL_CENTER_EFFECT_KEY) { + updateData(EffectEnabled, settings->get(key).toReal()); + Q_EMIT styleChanged(EffectEnabled); + } }); } } diff --git a/src/settings/settings.h b/src/settings/settings.h index e955ec1..30994f2 100644 --- a/src/settings/settings.h +++ b/src/settings/settings.h @@ -52,7 +52,8 @@ public: UnKnowKey = 0, StyleName, ThemeColor, - Transparency + Transparency, + EffectEnabled }; Q_ENUM(Key) diff --git a/src/windows/menu-main-window.cpp b/src/windows/menu-main-window.cpp index 43f796e..5157407 100644 --- a/src/windows/menu-main-window.cpp +++ b/src/windows/menu-main-window.cpp @@ -129,13 +129,13 @@ void WindowHelper::removeHeaderBar(QWindow *window) } } -void WindowHelper::windowBlur(QWindow *window, bool enable) +void WindowHelper::windowBlur(QWindow *window, bool enable, const QRegion ®ion) { if (!window) { return; } //use KWindowEffects - KWindowEffects::enableBlurBehind(window->winId(), enable); + KWindowEffects::enableBlurBehind(window->winId(), enable, region); } //======MenuMainWindow======// @@ -396,6 +396,15 @@ void MenuWindow::init() QCoreApplication::sendEvent(this, &event); }); + connect(GlobalSetting::instance(), &GlobalSetting::styleChanged, this , [this] (const GlobalSetting::Key& key) { + if (key == GlobalSetting::EffectEnabled) { + Q_EMIT effectEnabledChanged(); + } + if (key == GlobalSetting::Transparency) { + Q_EMIT transparencyChanged(); + } + }); + updateGeometry(); } @@ -414,6 +423,11 @@ bool MenuWindow::isFullScreen() const return m_isFullScreen; } +QRect MenuWindow::normalScreenSize() +{ + return m_geometryHelper->normalGeometry(); +} + /** * beforeFullScreenChanged -> (qml)onWidthChanged -> fullScreenChanged * @param isFullScreen @@ -424,9 +438,8 @@ void MenuWindow::setFullScreen(bool isFullScreen) return; } - Q_EMIT beforeFullScreenChanged(isFullScreen); - m_isFullScreen = isFullScreen; + WindowHelper::windowBlur(this, !m_isFullScreen); updateGeometry(); @@ -438,6 +451,22 @@ void MenuWindow::setFullScreen(bool isFullScreen) Q_EMIT fullScreenChanged(); } +void MenuWindow::changeWindowBlurRegion(int x, int y, int width, int height) +{ + QRegion region(x, y, width, height); + WindowHelper::windowBlur(this, true, region); +} + +void MenuWindow::exitFullScreen() +{ + Q_EMIT beforeFullScreenExited(); +} + +void MenuWindow::enableWindowBlur(bool enable) +{ + WindowHelper::windowBlur(this, enable); +} + void MenuWindow::exposeEvent(QExposeEvent *event) { if (isExposed()) { @@ -471,4 +500,14 @@ void MenuWindow::onActiveFocusItemChanged() setVisible(false); } +bool MenuWindow::effectEnabled() const +{ + return GlobalSetting::instance()->get(GlobalSetting::EffectEnabled).toBool(); +} + +double MenuWindow::transparency() const +{ + return GlobalSetting::instance()->get(GlobalSetting::Transparency).toDouble(); +} + } // UkuiMenu diff --git a/src/windows/menu-main-window.h b/src/windows/menu-main-window.h index ce51749..2e93c60 100644 --- a/src/windows/menu-main-window.h +++ b/src/windows/menu-main-window.h @@ -39,7 +39,7 @@ public: static void setWindowGeometry(QWindow *window, const QRect &rect); static void setWindowAttribute(QWindow *window); static void removeHeaderBar(QWindow *window); - static void windowBlur(QWindow *window, bool enable); + static void windowBlur(QWindow *window, bool enable, const QRegion ®ion = QRegion()); }; class WindowGeometryHelper final : public QObject @@ -105,17 +105,29 @@ class MenuWindow : public QQuickView { Q_OBJECT Q_PROPERTY(bool isFullScreen READ isFullScreen WRITE setFullScreen NOTIFY fullScreenChanged) + Q_PROPERTY(bool effectEnabled READ effectEnabled NOTIFY effectEnabledChanged) + Q_PROPERTY(double transparency READ transparency NOTIFY transparencyChanged) public: explicit MenuWindow(QWindow *parent = nullptr); MenuWindow(QQmlEngine* engine, QWindow *parent); + bool effectEnabled() const; bool isFullScreen() const; + double transparency() const; void setFullScreen(bool isFullScreen); + Q_INVOKABLE void changeWindowBlurRegion(int x, int y, int width, int height); + Q_INVOKABLE QRect normalScreenSize(); + Q_INVOKABLE void exitFullScreen(); + Q_INVOKABLE void enableWindowBlur(bool enable); + Q_SIGNALS: + void effectEnabledChanged(); + void transparencyChanged(); void fullScreenChanged(); - void beforeFullScreenChanged(bool isToFullScreen); + void beforeFullScreenChanged(); + void beforeFullScreenExited(); private Q_SLOTS: void onActiveFocusItemChanged();