diff --git a/example/example_en_US.ts b/example/example_en_US.ts
index af16a652..e49fa5ec 100644
--- a/example/example_en_US.ts
+++ b/example/example_en_US.ts
@@ -2190,6 +2190,11 @@ Some contents...
+
+
+
+
+
T_TimePicker
diff --git a/example/example_zh_CN.ts b/example/example_zh_CN.ts
index ce01e5a8..5f4c183e 100644
--- a/example/example_zh_CN.ts
+++ b/example/example_zh_CN.ts
@@ -2280,6 +2280,11 @@ Some contents...
开启动画
+
+
+
+
+
T_TimePicker
diff --git a/example/qml/page/T_Theme.qml b/example/qml/page/T_Theme.qml
index a7e4a01d..308c1e92 100644
--- a/example/qml/page/T_Theme.qml
+++ b/example/qml/page/T_Theme.qml
@@ -13,7 +13,7 @@ FluScrollablePage{
FluFrame{
Layout.fillWidth: true
- Layout.preferredHeight: 340
+ Layout.preferredHeight: 400
padding: 10
ColumnLayout{
@@ -119,6 +119,17 @@ FluScrollablePage{
FluTheme.animationEnabled = !FluTheme.animationEnabled
}
}
+ FluText{
+ text: qsTr("Open Blur Window")
+ Layout.topMargin: 20
+ }
+ FluToggleSwitch{
+ Layout.topMargin: 5
+ checked: FluTheme.blurBehindWindowEnabled
+ onClicked: {
+ FluTheme.blurBehindWindowEnabled = !FluTheme.blurBehindWindowEnabled
+ }
+ }
}
}
CodeExpander{
diff --git a/src/FluTheme.cpp b/src/FluTheme.cpp
index 4948f3e8..ff2b760b 100644
--- a/src/FluTheme.cpp
+++ b/src/FluTheme.cpp
@@ -2,9 +2,11 @@
#include
#include
+#include
#include "Def.h"
#include "FluentIconDef.h"
#include "FluColors.h"
+#include "FluTools.h"
bool systemDark() {
QPalette palette = QGuiApplication::palette();
@@ -18,13 +20,20 @@ FluTheme::FluTheme(QObject *parent) : QObject{parent} {
_nativeText = false;
_animationEnabled = true;
_systemDark = systemDark();
+ _desktopImagePath = "";
+ _blurBehindWindowEnabled = false;
QGuiApplication::instance()->installEventFilter(this);
+ refreshColors();
+ updateDesktopImage();
connect(this, &FluTheme::darkModeChanged, this, [=] {
Q_EMIT darkChanged();
});
connect(this, &FluTheme::darkChanged, this, [=] { refreshColors(); });
connect(this, &FluTheme::accentColorChanged, this, [=] { refreshColors(); });
- refreshColors();
+ connect(&_watcher, &QFileSystemWatcher::fileChanged, this, [=](const QString &path){
+ Q_EMIT desktopImagePathChanged();
+ });
+ startTimer(500);
}
void FluTheme::refreshColors() {
@@ -38,6 +47,8 @@ void FluTheme::refreshColors() {
fontSecondaryColor(isDark ? QColor(222, 222, 222, 255) : QColor(102, 102, 102, 255));
fontTertiaryColor(isDark ? QColor(200, 200, 200, 255) : QColor(153, 153, 153, 255));
itemNormalColor(isDark ? QColor(255, 255, 255, 0) : QColor(0, 0, 0, 0));
+ frameColor(isDark ? QColor(255, 255, 255, qRound(255 * 0.12)) : QColor(0, 0, 0, qRound(255 * 0.09)));
+ frameActiveColor(isDark ? QColor(32, 32, 32, qRound(255 * 0.8)) : QColor(255, 255, 255, qRound(255 * 0.6)));
itemHoverColor(isDark ? QColor(255, 255, 255, qRound(255 * 0.06)) : QColor(0, 0, 0, qRound(255 * 0.03)));
itemPressColor(isDark ? QColor(255, 255, 255, qRound(255 * 0.09)) : QColor(0, 0, 0, qRound(255 * 0.06)));
itemCheckColor(isDark ? QColor(255, 255, 255, qRound(255 * 0.12)) : QColor(0, 0, 0, qRound(255 * 0.09)));
@@ -78,3 +89,19 @@ bool FluTheme::dark() const {
return false;
}
}
+
+void FluTheme::updateDesktopImage(){
+ auto path = FluTools::getInstance()->getWallpaperFilePath();
+ if(_desktopImagePath != path){
+ if(!_desktopImagePath.isEmpty()){
+ _watcher.removePath(_desktopImagePath);
+ }
+ desktopImagePath(path);
+ _watcher.addPath(path);
+ }
+}
+
+void FluTheme::timerEvent(QTimerEvent *event)
+{
+ updateDesktopImage();
+}
diff --git a/src/FluTheme.h b/src/FluTheme.h
index e1b15ee8..2d95a39b 100644
--- a/src/FluTheme.h
+++ b/src/FluTheme.h
@@ -6,6 +6,8 @@
#include
#include
#include
+#include
+#include
#include "FluAccentColor.h"
#include "stdafx.h"
#include "singleton.h"
@@ -15,7 +17,7 @@
*/
class FluTheme : public QObject {
Q_OBJECT
- Q_PROPERTY(bool dark READ dark NOTIFY darkChanged)
+Q_PROPERTY(bool dark READ dark NOTIFY darkChanged)
Q_PROPERTY_AUTO_P(FluAccentColor*, accentColor);
Q_PROPERTY_AUTO(QColor, primaryColor);
Q_PROPERTY_AUTO(QColor, backgroundColor);
@@ -26,12 +28,16 @@ Q_PROPERTY_AUTO(QColor, fontPrimaryColor);
Q_PROPERTY_AUTO(QColor, fontSecondaryColor);
Q_PROPERTY_AUTO(QColor, fontTertiaryColor);
Q_PROPERTY_AUTO(QColor, itemNormalColor);
+Q_PROPERTY_AUTO(QColor, frameColor);
+Q_PROPERTY_AUTO(QColor, frameActiveColor);
Q_PROPERTY_AUTO(QColor, itemHoverColor);
Q_PROPERTY_AUTO(QColor, itemPressColor);
Q_PROPERTY_AUTO(QColor, itemCheckColor);
+Q_PROPERTY_AUTO(QString, desktopImagePath);
Q_PROPERTY_AUTO(int, darkMode);
Q_PROPERTY_AUTO(bool, nativeText);
Q_PROPERTY_AUTO(bool, animationEnabled);
+Q_PROPERTY_AUTO(bool, blurBehindWindowEnabled);
QML_NAMED_ELEMENT(FluTheme)
QML_SINGLETON
@@ -42,6 +48,14 @@ private:
void refreshColors();
+ void updateBackgroundMainColor();
+
+protected:
+
+ void timerEvent(QTimerEvent *event) override;
+
+ void updateDesktopImage();
+
public:
SINGLETON(FluTheme)
@@ -55,6 +69,7 @@ SINGLETON(FluTheme)
private:
bool _systemDark;
+ QFileSystemWatcher _watcher;
};
#endif // FLUTHEME_H
diff --git a/src/FluTools.cpp b/src/FluTools.cpp
index bed2f651..fbea119c 100644
--- a/src/FluTools.cpp
+++ b/src/FluTools.cpp
@@ -16,6 +16,14 @@
#include
#include
+#ifdef Q_OS_WIN
+#pragma comment (lib, "user32.lib")
+
+#include
+#include
+
+#endif
+
FluTools::FluTools(QObject *parent) : QObject{parent} {
}
@@ -244,3 +252,32 @@ bool FluTools::isWindows10OrGreater() {
QRect FluTools::desktopAvailableGeometry(QQuickWindow *window) {
return window->screen()->availableGeometry();
}
+
+QString FluTools::getWallpaperFilePath() {
+#if defined(Q_OS_WIN)
+ wchar_t path[MAX_PATH] = {};
+ if (::SystemParametersInfoW(SPI_GETDESKWALLPAPER, MAX_PATH, path, FALSE) == FALSE) {
+ return {};
+ }
+ return QString::fromWCharArray(path);
+#endif
+ return {};
+}
+
+QColor FluTools::imageMainColor(const QImage& image, double bright) {
+ int step = 20;
+ int t = 0;
+ int r = 0, g = 0, b = 0;
+ for (int i = 0; i < image.width(); i += step) {
+ for (int j = 0; j < image.height(); j += step) {
+ if (image.valid(i, j)) {
+ t++;
+ QColor c = image.pixel(i, j);
+ r += c.red();
+ b += c.blue();
+ g += c.green();
+ }
+ }
+ }
+ return QColor(int(bright * r / t) > 255 ? 255 : int(bright * r / t), int(bright * g / t) > 255 ? 255 : int(bright * g / t), int(bright * b / t) > 255 ? 255 : int(bright * b / t));
+}
diff --git a/src/FluTools.h b/src/FluTools.h
index f1b4bb95..2ba82887 100644
--- a/src/FluTools.h
+++ b/src/FluTools.h
@@ -92,4 +92,8 @@ SINGLETON(FluTools)
Q_INVOKABLE bool isWindows10OrGreater();
Q_INVOKABLE QRect desktopAvailableGeometry(QQuickWindow *window);
-};
\ No newline at end of file
+
+ Q_INVOKABLE QString getWallpaperFilePath();
+
+ Q_INVOKABLE QColor imageMainColor(const QImage& image, double bright = 1);
+};
diff --git a/src/Qt5/imports/FluentUI/Controls/FluAcrylic.qml b/src/Qt5/imports/FluentUI/Controls/FluAcrylic.qml
index 66d06fb1..58137df7 100644
--- a/src/Qt5/imports/FluentUI/Controls/FluAcrylic.qml
+++ b/src/Qt5/imports/FluentUI/Controls/FluAcrylic.qml
@@ -8,7 +8,7 @@ Item {
property real tintOpacity: 0.65
property real luminosity: 0.01
property real noiseOpacity: 0.02
- property alias target: effect_source.sourceItem
+ property var target
property int blurRadius: 32
property rect targetRect: Qt.rect(control.x, control.y, control.width,control.height)
ShaderEffectSource {
@@ -16,6 +16,7 @@ Item {
anchors.fill: parent
visible: false
sourceRect: control.targetRect
+ sourceItem: control.target
}
FastBlur {
id: fast_blur
@@ -33,7 +34,7 @@ Item {
}
Image {
anchors.fill: parent
- source: "../Image/noise.png"
+ source: "qrc:/qt/qml/FluentUI/Image/noise.png"
fillMode: Image.Tile
opacity: control.noiseOpacity
}
diff --git a/src/Qt5/imports/FluentUI/Controls/FluCalendarPicker.qml b/src/Qt5/imports/FluentUI/Controls/FluCalendarPicker.qml
index 8badce7a..5b1e932a 100644
--- a/src/Qt5/imports/FluentUI/Controls/FluCalendarPicker.qml
+++ b/src/Qt5/imports/FluentUI/Controls/FluCalendarPicker.qml
@@ -76,10 +76,11 @@ FluButton {
}
contentItem: Item{
clip: true
- FluFrame{
+ Rectangle{
id:container
width: 300
height: 360
+ color: FluTheme.dark ? Qt.rgba(51/255,48/255,48/255,1) : Qt.rgba(248/255,250/255,253/255,1)
ColumnLayout {
anchors.fill: parent
spacing: 0
diff --git a/src/Qt5/imports/FluentUI/Controls/FluExpander.qml b/src/Qt5/imports/FluentUI/Controls/FluExpander.qml
index d43d9991..b076b3f9 100644
--- a/src/Qt5/imports/FluentUI/Controls/FluExpander.qml
+++ b/src/Qt5/imports/FluentUI/Controls/FluExpander.qml
@@ -27,7 +27,12 @@ Item {
height: 45
radius: 4
border.color: FluTheme.dividerColor
- color: FluTheme.dark ? Window.active ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
+ color: {
+ if(Window.active){
+ return FluTheme.frameActiveColor
+ }
+ return FluTheme.frameColor
+ }
MouseArea{
id:control_mouse
anchors.fill: parent
@@ -84,12 +89,18 @@ Item {
height: contentHeight+container.anchors.topMargin
width: parent.width
z:-999
+ clip: true
Rectangle{
id:container
anchors.fill: parent
radius: 4
clip: true
- color: FluTheme.dark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
+ color: {
+ if(Window.active){
+ return FluTheme.frameActiveColor
+ }
+ return FluTheme.frameColor
+ }
border.color: FluTheme.dividerColor
anchors.topMargin: -contentHeight
states: [
diff --git a/src/Qt5/imports/FluentUI/Controls/FluFrame.qml b/src/Qt5/imports/FluentUI/Controls/FluFrame.qml
index 963b2af0..b18609d2 100644
--- a/src/Qt5/imports/FluentUI/Controls/FluFrame.qml
+++ b/src/Qt5/imports/FluentUI/Controls/FluFrame.qml
@@ -19,6 +19,11 @@ T.Frame {
id:d
radius: 4
border.color: FluTheme.dividerColor
- color: FluTheme.dark ? Window.active ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(251/255,251/255,253/255,1)
+ color: {
+ if(Window.active){
+ return FluTheme.frameActiveColor
+ }
+ return FluTheme.frameColor
+ }
}
}
diff --git a/src/Qt5/imports/FluentUI/Controls/FluGroupBox.qml b/src/Qt5/imports/FluentUI/Controls/FluGroupBox.qml
index 443651f1..f602a7b6 100644
--- a/src/Qt5/imports/FluentUI/Controls/FluGroupBox.qml
+++ b/src/Qt5/imports/FluentUI/Controls/FluGroupBox.qml
@@ -8,8 +8,13 @@ import FluentUI 1.0
T.GroupBox {
id: control
property int borderWidth : 1
- property color borderColor : FluTheme.dark ? Window.active ? Qt.rgba(55/255,55/255,55/255,1):Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(226/255,229/255,234/255,1)
- property color color: FluTheme.dark ? Window.active ? Qt.rgba(38/255,44/255,54/255,1) : Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
+ property color borderColor : FluTheme.dividerColor
+ property color color: {
+ if(Window.active){
+ return FluTheme.frameActiveColor
+ }
+ return FluTheme.frameColor
+ }
property int radius: 4
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
contentWidth + leftPadding + rightPadding,
diff --git a/src/Qt5/imports/FluentUI/Controls/FluWindow.qml b/src/Qt5/imports/FluentUI/Controls/FluWindow.qml
index 4cfd90bb..3be637de 100644
--- a/src/Qt5/imports/FluentUI/Controls/FluWindow.qml
+++ b/src/Qt5/imports/FluentUI/Controls/FluWindow.qml
@@ -109,8 +109,53 @@ Window {
}
Component{
id:com_background
- Rectangle{
- color: window.backgroundColor
+ Item{
+ Rectangle{
+ anchors.fill: parent
+ color: window.backgroundColor
+ }
+ Image{
+ id:img_back
+ visible: false
+ cache: false
+ Component.onCompleted: {
+ var geometry = FluTools.desktopAvailableGeometry(window)
+ width = geometry.width
+ height = geometry.height
+ sourceSize = Qt.size(width,height)
+ source = FluTools.getUrlByFilePath(FluTheme.desktopImagePath)
+ }
+ Connections{
+ target: FluTheme
+ function onDesktopImagePathChanged(){
+ timer_update_image.restart()
+ }
+ function onBlurBehindWindowEnabledChanged(){
+ if(FluTheme.blurBehindWindowEnabled){
+ img_back.source = FluTools.getUrlByFilePath(FluTheme.desktopImagePath)
+ }else{
+ img_back.source = ""
+ }
+ }
+ }
+ Timer{
+ id:timer_update_image
+ interval: 500
+ onTriggered: {
+ img_back.source = ""
+ img_back.source = FluTools.getUrlByFilePath(FluTheme.desktopImagePath)
+ }
+ }
+ }
+ FluAcrylic{
+ anchors.fill: parent
+ target: img_back
+ tintOpacity: FluTheme.dark ? 0.80 : 0.75
+ blurRadius: 64
+ visible: window.active && FluTheme.blurBehindWindowEnabled
+ tintColor: FluTheme.dark ? Qt.rgba(0, 0, 0, 1) : Qt.rgba(1, 1, 1, 1)
+ targetRect: Qt.rect(window.x,window.y,window.width,window.height)
+ }
}
}
Component{
diff --git a/src/Qt6/imports/FluentUI/Controls/FluAcrylic.qml b/src/Qt6/imports/FluentUI/Controls/FluAcrylic.qml
index 7a76e91f..9dd417e7 100644
--- a/src/Qt6/imports/FluentUI/Controls/FluAcrylic.qml
+++ b/src/Qt6/imports/FluentUI/Controls/FluAcrylic.qml
@@ -8,7 +8,7 @@ Item {
property real tintOpacity: 0.65
property real luminosity: 0.01
property real noiseOpacity: 0.02
- property alias target: effect_source.sourceItem
+ property var target
property int blurRadius: 32
property rect targetRect: Qt.rect(control.x, control.y, control.width,control.height)
ShaderEffectSource {
@@ -16,6 +16,7 @@ Item {
anchors.fill: parent
visible: false
sourceRect: control.targetRect
+ sourceItem: control.target
}
FastBlur {
id: fast_blur
@@ -33,7 +34,7 @@ Item {
}
Image {
anchors.fill: parent
- source: "../Image/noise.png"
+ source: "qrc:/qt/qml/FluentUI/Image/noise.png"
fillMode: Image.Tile
opacity: control.noiseOpacity
}
diff --git a/src/Qt6/imports/FluentUI/Controls/FluCalendarPicker.qml b/src/Qt6/imports/FluentUI/Controls/FluCalendarPicker.qml
index ab11b054..444bdd7a 100644
--- a/src/Qt6/imports/FluentUI/Controls/FluCalendarPicker.qml
+++ b/src/Qt6/imports/FluentUI/Controls/FluCalendarPicker.qml
@@ -75,10 +75,11 @@ FluButton {
}
contentItem: Item{
clip: true
- FluFrame{
+ Rectangle{
id:container
width: 300
height: 360
+ color: FluTheme.dark ? Qt.rgba(51/255,48/255,48/255,1) : Qt.rgba(248/255,250/255,253/255,1)
ColumnLayout {
anchors.fill: parent
spacing: 0
diff --git a/src/Qt6/imports/FluentUI/Controls/FluExpander.qml b/src/Qt6/imports/FluentUI/Controls/FluExpander.qml
index 24018e34..4e6d8d86 100644
--- a/src/Qt6/imports/FluentUI/Controls/FluExpander.qml
+++ b/src/Qt6/imports/FluentUI/Controls/FluExpander.qml
@@ -27,7 +27,12 @@ Item {
height: 45
radius: 4
border.color: FluTheme.dividerColor
- color: FluTheme.dark ? Window.active ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
+ color: {
+ if(Window.active){
+ return FluTheme.frameActiveColor
+ }
+ return FluTheme.frameColor
+ }
MouseArea{
id:control_mouse
anchors.fill: parent
@@ -84,12 +89,18 @@ Item {
height: contentHeight+container.anchors.topMargin
width: parent.width
z:-999
+ clip: true
Rectangle{
id:container
anchors.fill: parent
radius: 4
clip: true
- color: FluTheme.dark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
+ color: {
+ if(Window.active){
+ return FluTheme.frameActiveColor
+ }
+ return FluTheme.frameColor
+ }
border.color: FluTheme.dividerColor
anchors.topMargin: -contentHeight
states: [
diff --git a/src/Qt6/imports/FluentUI/Controls/FluFrame.qml b/src/Qt6/imports/FluentUI/Controls/FluFrame.qml
index f830d529..a98edff7 100644
--- a/src/Qt6/imports/FluentUI/Controls/FluFrame.qml
+++ b/src/Qt6/imports/FluentUI/Controls/FluFrame.qml
@@ -17,6 +17,11 @@ T.Frame {
id:d
radius: 4
border.color: FluTheme.dividerColor
- color: FluTheme.dark ? Window.active ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(251/255,251/255,253/255,1)
+ color: {
+ if(Window.active){
+ return FluTheme.frameActiveColor
+ }
+ return FluTheme.frameColor
+ }
}
}
diff --git a/src/Qt6/imports/FluentUI/Controls/FluGroupBox.qml b/src/Qt6/imports/FluentUI/Controls/FluGroupBox.qml
index b93f576e..4ee5e444 100644
--- a/src/Qt6/imports/FluentUI/Controls/FluGroupBox.qml
+++ b/src/Qt6/imports/FluentUI/Controls/FluGroupBox.qml
@@ -8,8 +8,13 @@ import FluentUI
T.GroupBox {
id: control
property int borderWidth : 1
- property color borderColor : FluTheme.dark ? Window.active ? Qt.rgba(55/255,55/255,55/255,1):Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(226/255,229/255,234/255,1)
- property color color: FluTheme.dark ? Window.active ? Qt.rgba(38/255,44/255,54/255,1) : Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
+ property color borderColor : FluTheme.dividerColor
+ property color color: {
+ if(Window.active){
+ return FluTheme.frameActiveColor
+ }
+ return FluTheme.frameColor
+ }
property int radius: 4
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
contentWidth + leftPadding + rightPadding,
diff --git a/src/Qt6/imports/FluentUI/Controls/FluWindow.qml b/src/Qt6/imports/FluentUI/Controls/FluWindow.qml
index ea046575..4474285a 100644
--- a/src/Qt6/imports/FluentUI/Controls/FluWindow.qml
+++ b/src/Qt6/imports/FluentUI/Controls/FluWindow.qml
@@ -108,8 +108,53 @@ Window {
}
Component{
id:com_background
- Rectangle{
- color: window.backgroundColor
+ Item{
+ Rectangle{
+ anchors.fill: parent
+ color: window.backgroundColor
+ }
+ Image{
+ id:img_back
+ visible: false
+ cache: false
+ Component.onCompleted: {
+ var geometry = FluTools.desktopAvailableGeometry(window)
+ width = geometry.width
+ height = geometry.height
+ sourceSize = Qt.size(width,height)
+ source = FluTools.getUrlByFilePath(FluTheme.desktopImagePath)
+ }
+ Connections{
+ target: FluTheme
+ function onDesktopImagePathChanged(){
+ timer_update_image.restart()
+ }
+ function onBlurBehindWindowEnabledChanged(){
+ if(FluTheme.blurBehindWindowEnabled){
+ img_back.source = FluTools.getUrlByFilePath(FluTheme.desktopImagePath)
+ }else{
+ img_back.source = ""
+ }
+ }
+ }
+ Timer{
+ id:timer_update_image
+ interval: 500
+ onTriggered: {
+ img_back.source = ""
+ img_back.source = FluTools.getUrlByFilePath(FluTheme.desktopImagePath)
+ }
+ }
+ }
+ FluAcrylic{
+ anchors.fill: parent
+ target: img_back
+ tintOpacity: FluTheme.dark ? 0.80 : 0.75
+ blurRadius: 64
+ visible: window.active && FluTheme.blurBehindWindowEnabled
+ tintColor: FluTheme.dark ? Qt.rgba(0, 0, 0, 1) : Qt.rgba(1, 1, 1, 1)
+ targetRect: Qt.rect(window.x,window.y,window.width,window.height)
+ }
}
}
Component{