add basic.

This commit is contained in:
amass 2024-08-31 04:13:21 +08:00
parent 7f5f273e14
commit 8b6bce4e3d
48 changed files with 3029 additions and 632 deletions

View File

@ -2,10 +2,12 @@
#include "Rectangle.h" #include "Rectangle.h"
#include <QGuiApplication> #include <QGuiApplication>
#include <QQmlApplicationEngine> #include <QQmlApplicationEngine>
#include <QQuickStyle>
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
LOG(info) << "app start..."; LOG(info) << "app start...";
QGuiApplication app(argc, argv); QGuiApplication app(argc, argv);
QQuickStyle::setStyle("Basic");
QQmlApplicationEngine engine; QQmlApplicationEngine engine;
QObject::connect( QObject::connect(
&engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); }, &engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); },

4
Fluent/AccentColor.cpp Normal file
View File

@ -0,0 +1,4 @@
#include "AccentColor.h"
AccentColor::AccentColor(QObject *parent) : QObject{parent} {
}

22
Fluent/AccentColor.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef __ACCENTCOLOR_H__
#define __ACCENTCOLOR_H__
#include "Utilities.h"
#include <QObject>
class AccentColor : public QObject {
Q_OBJECT
Q_PROPERTY_AUTO(QColor, darkest)
Q_PROPERTY_AUTO(QColor, darker)
Q_PROPERTY_AUTO(QColor, dark)
Q_PROPERTY_AUTO(QColor, normal)
Q_PROPERTY_AUTO(QColor, light)
Q_PROPERTY_AUTO(QColor, lighter)
Q_PROPERTY_AUTO(QColor, lightest)
QML_ELEMENT
public:
AccentColor(QObject *parent = nullptr);
};
#endif // __ACCENTCOLOR_H__

View File

@ -1,5 +1,5 @@
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Gui Quick) find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Gui Quick QuickControls2)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Gui Quick) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Gui Quick QuickControls2)
qt_standard_project_setup(REQUIRES 6.5) qt_standard_project_setup(REQUIRES 6.5)
@ -16,25 +16,41 @@ qt6_add_qml_module(Fluent
URI Fluent URI Fluent
VERSION 1.0 VERSION 1.0
SOURCES SOURCES
AccentColor.h AccentColor.cpp
App.h App.cpp App.h App.cpp
CircularReveal.h CircularReveal.cpp
Colors.h Colors.cpp
Frameless.h Frameless.cpp Frameless.h Frameless.cpp
Icons.h Icons.h
Rectangle.h Rectangle.cpp Rectangle.h Rectangle.cpp
TextStyle.h TextStyle.cpp
Theme.h Theme.cpp Theme.h Theme.cpp
Utilities.h Utilities.cpp Utilities.h Utilities.cpp
QML_FILES QML_FILES
qml/Acrylic.qml qml/Acrylic.qml
qml/AppBar.qml qml/AppBar.qml
qml/Button.qml
qml/ContentDialog.qml
qml/ControlBackground.qml
qml/FilledButton.qml
qml/FocusRectangle.qml
qml/Icon.qml qml/Icon.qml
qml/IconButton.qml qml/IconButton.qml
qml/ImageButton.qml
qml/InfoBar.qml qml/InfoBar.qml
qml/Loader.qml
qml/Object.qml qml/Object.qml
qml/Popup.qml
qml/ProgressRing.qml
qml/Router.qml qml/Router.qml
qml/ScrollBar.qml
qml/Shadow.qml qml/Shadow.qml
qml/Text.qml qml/Text.qml
qml/Tooltip.qml
qml/Window.qml qml/Window.qml
RESOURCES RESOURCES
resources/noise.png resources/noise.png
resources/FluentIcons.ttf
) )
target_include_directories(Fluent target_include_directories(Fluent
@ -44,4 +60,5 @@ target_include_directories(Fluent
target_link_libraries(Fluent target_link_libraries(Fluent
PUBLIC Qt${QT_VERSION_MAJOR}::Gui PUBLIC Qt${QT_VERSION_MAJOR}::Gui
PRIVATE Qt${QT_VERSION_MAJOR}::Quick PRIVATE Qt${QT_VERSION_MAJOR}::Quick
INTERFACE Qt${QT_VERSION_MAJOR}::QuickControls2
) )

66
Fluent/CircularReveal.cpp Normal file
View File

@ -0,0 +1,66 @@
#include "CircularReveal.h"
#include <QGuiApplication>
#include <QQuickItemGrabResult>
#include <QPainterPath>
CircularReveal::CircularReveal(QQuickItem *parent) : QQuickPaintedItem(parent) {
m_target = nullptr;
m_radius = 0;
_anim = new QPropertyAnimation(this, "radius", this);
_anim->setDuration(333);
_anim->setEasingCurve(QEasingCurve::OutCubic);
setVisible(false);
connect(_anim, &QPropertyAnimation::finished, this, [=]() {
update();
setVisible(false);
Q_EMIT animationFinished();
});
connect(this, &CircularReveal::radiusChanged, this, [=]() { update(); });
}
void CircularReveal::paint(QPainter *painter) {
painter->save();
painter->drawImage(QRect(0, 0, static_cast<int>(width()), static_cast<int>(height())), _source);
QPainterPath path;
path.moveTo(_center.x(), _center.y());
path.addEllipse(QPointF(_center.x(), _center.y()), m_radius, m_radius);
painter->setCompositionMode(QPainter::CompositionMode_Clear);
if (m_darkToLight) {
painter->fillPath(path, Qt::white);
} else {
QPainterPath outerRect;
outerRect.addRect(0, 0, width(), height());
outerRect = outerRect.subtracted(path);
painter->fillPath(outerRect, Qt::black);
}
painter->restore();
}
[[maybe_unused]] void CircularReveal::start(int w, int h, const QPoint &center, int radius) {
if (_anim->state() == QAbstractAnimation::Running) {
_anim->stop();
int currentRadius = m_radius;
_anim->setStartValue(currentRadius);
_anim->setEndValue(m_darkToLight ? 0 : radius);
} else {
if (m_darkToLight) {
_anim->setStartValue(radius);
_anim->setEndValue(0);
} else {
_anim->setStartValue(0);
_anim->setEndValue(radius);
}
}
_center = center;
_grabResult = m_target->grabToImage(QSize(w, h));
connect(_grabResult.data(), &QQuickItemGrabResult::ready, this,
&CircularReveal::handleGrabResult);
}
void CircularReveal::handleGrabResult() {
_grabResult.data()->image().swap(_source);
update();
setVisible(true);
Q_EMIT imageChanged();
_anim->start();
}

31
Fluent/CircularReveal.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef __CIRCULARREVEAL_H__
#define __CIRCULARREVEAL_H__
#include "Utilities.h"
#include <QPainter>
#include <QPropertyAnimation>
#include <QQuickItem>
#include <QQuickPaintedItem>
class CircularReveal : public QQuickPaintedItem {
Q_OBJECT
QML_ELEMENT
Q_PROPERTY_AUTO_P(QQuickItem *, target)
Q_PROPERTY_AUTO(int, radius)
Q_PROPERTY_AUTO(bool, darkToLight)
public:
explicit CircularReveal(QQuickItem *parent = nullptr);
void paint(QPainter *painter) override;
Q_INVOKABLE void start(int w, int h, const QPoint &center, int radius);
Q_SIGNAL void imageChanged();
Q_SIGNAL void animationFinished();
Q_SLOT void handleGrabResult();
private:
QPropertyAnimation *_anim = nullptr;
QImage _source;
QPoint _center;
QSharedPointer<QQuickItemGrabResult> _grabResult;
};
#endif // __CIRCULARREVEAL_H__

135
Fluent/Colors.cpp Normal file
View File

@ -0,0 +1,135 @@
#include "Colors.h"
Colors *Colors::instance() {
static Colors *self = nullptr;
if (self == nullptr) {
self = new Colors();
}
return self;
}
Colors *Colors::create(QQmlEngine *, QJSEngine *) {
auto ret = instance();
QJSEngine::setObjectOwnership(ret, QJSEngine::CppOwnership);
return ret;
}
Colors::Colors(QObject *parent) : QObject{parent} {
m_Transparent = QColor(0, 0, 0, 0);
m_Black = QColor(0, 0, 0);
m_White = QColor(255, 255, 255);
m_Grey10 = QColor(250, 249, 248);
m_Grey20 = QColor(243, 242, 241);
m_Grey30 = QColor(237, 235, 233);
m_Grey40 = QColor(225, 223, 221);
m_Grey50 = QColor(210, 208, 206);
m_Grey60 = QColor(200, 198, 196);
m_Grey70 = QColor(190, 185, 184);
m_Grey80 = QColor(179, 176, 173);
m_Grey90 = QColor(161, 159, 157);
m_Grey100 = QColor(151, 149, 146);
m_Grey110 = QColor(138, 136, 134);
m_Grey120 = QColor(121, 119, 117);
m_Grey130 = QColor(96, 94, 92);
m_Grey140 = QColor(72, 70, 68);
m_Grey150 = QColor(59, 58, 57);
m_Grey160 = QColor(50, 49, 48);
m_Grey170 = QColor(41, 40, 39);
m_Grey180 = QColor(37, 36, 35);
m_Grey190 = QColor(32, 31, 30);
m_Grey200 = QColor(27, 26, 25);
m_Grey210 = QColor(22, 21, 20);
m_Grey220 = QColor(17, 16, 15);
auto yellow = new AccentColor(this);
yellow->darkest(QColor(249, 168, 37));
yellow->darker(QColor(251, 192, 45));
yellow->dark(QColor(253, 212, 53));
yellow->normal(QColor(255, 235, 59));
yellow->light(QColor(255, 238, 88));
yellow->lighter(QColor(255, 241, 118));
yellow->lightest(QColor(255, 245, 155));
m_Yellow = yellow;
auto orange = new AccentColor(this);
orange->darkest(QColor(153, 61, 7));
orange->darker(QColor(172, 68, 8));
orange->dark(QColor(209, 88, 10));
orange->normal(QColor(247, 99, 12));
orange->light(QColor(248, 122, 48));
orange->lighter(QColor(249, 145, 84));
orange->lightest(QColor(250, 192, 106));
m_Orange = orange;
auto red = new AccentColor(this);
red->darkest(QColor(143, 10, 21));
red->darker(QColor(162, 11, 24));
red->dark(QColor(185, 13, 28));
red->normal(QColor(232, 17, 35));
red->light(QColor(236, 64, 79));
red->lighter(QColor(238, 88, 101));
red->lightest(QColor(240, 107, 118));
m_Red = red;
auto magenta = new AccentColor(this);
magenta->darkest(QColor(111, 0, 79));
magenta->darker(QColor(160, 7, 108));
magenta->dark(QColor(181, 13, 125));
magenta->normal(QColor(227, 0, 140));
magenta->light(QColor(234, 77, 168));
magenta->lighter(QColor(238, 110, 193));
magenta->lightest(QColor(241, 140, 213));
m_Magenta = magenta;
auto purple = new AccentColor(this);
purple->darkest(QColor(44, 15, 118));
purple->darker(QColor(61, 15, 153));
purple->dark(QColor(78, 17, 174));
purple->normal(QColor(104, 33, 122));
purple->light(QColor(123, 76, 157));
purple->lighter(QColor(141, 110, 189));
purple->lightest(QColor(158, 142, 217));
m_Purple = purple;
auto blue = new AccentColor(this);
blue->darkest(QColor(0, 74, 131));
blue->darker(QColor(0, 84, 148));
blue->dark(QColor(0, 102, 180));
blue->normal(QColor(0, 120, 212));
blue->light(QColor(38, 140, 220));
blue->lighter(QColor(76, 160, 224));
blue->lightest(QColor(96, 171, 228));
m_Blue = blue;
auto teal = new AccentColor(this);
teal->darkest(QColor(0, 110, 91));
teal->darker(QColor(0, 124, 103));
teal->dark(QColor(0, 151, 125));
teal->normal(QColor(0, 178, 148));
teal->light(QColor(38, 189, 164));
teal->lighter(QColor(77, 201, 180));
teal->lightest(QColor(96, 207, 188));
m_Teal = teal;
auto green = new AccentColor(this);
green->darkest(QColor(9, 76, 9));
green->darker(QColor(12, 93, 12));
green->dark(QColor(14, 111, 14));
green->normal(QColor(16, 124, 16));
green->light(QColor(39, 137, 57));
green->lighter(QColor(76, 156, 76));
green->lightest(QColor(106, 173, 106));
m_Green = green;
}
AccentColor *Colors::createAccentColor(const QColor &primaryColor) {
auto accentColor = new AccentColor(this);
accentColor->normal(primaryColor);
accentColor->dark(Utilities::instance()->withOpacity(primaryColor, 0.9));
accentColor->light(Utilities::instance()->withOpacity(primaryColor, 0.9));
accentColor->darker(Utilities::instance()->withOpacity(accentColor->dark(), 0.8));
accentColor->lighter(Utilities::instance()->withOpacity(accentColor->light(), 0.8));
accentColor->darkest(Utilities::instance()->withOpacity(accentColor->darker(), 0.7));
accentColor->lightest(Utilities::instance()->withOpacity(accentColor->lighter(), 0.7));
return accentColor;
}

56
Fluent/Colors.h Normal file
View File

@ -0,0 +1,56 @@
#ifndef __COLORS_H__
#define __COLORS_H__
#include "AccentColor.h"
#include "Utilities.h"
#include <QObject>
class Colors : public QObject {
Q_OBJECT
Q_PROPERTY_AUTO(QColor, Transparent)
Q_PROPERTY_AUTO(QColor, Black)
Q_PROPERTY_AUTO(QColor, White)
Q_PROPERTY_AUTO(QColor, Grey10)
Q_PROPERTY_AUTO(QColor, Grey20)
Q_PROPERTY_AUTO(QColor, Grey30)
Q_PROPERTY_AUTO(QColor, Grey40)
Q_PROPERTY_AUTO(QColor, Grey50)
Q_PROPERTY_AUTO(QColor, Grey60)
Q_PROPERTY_AUTO(QColor, Grey70)
Q_PROPERTY_AUTO(QColor, Grey80)
Q_PROPERTY_AUTO(QColor, Grey90)
Q_PROPERTY_AUTO(QColor, Grey100)
Q_PROPERTY_AUTO(QColor, Grey110)
Q_PROPERTY_AUTO(QColor, Grey120)
Q_PROPERTY_AUTO(QColor, Grey130)
Q_PROPERTY_AUTO(QColor, Grey140)
Q_PROPERTY_AUTO(QColor, Grey150)
Q_PROPERTY_AUTO(QColor, Grey160)
Q_PROPERTY_AUTO(QColor, Grey170)
Q_PROPERTY_AUTO(QColor, Grey180)
Q_PROPERTY_AUTO(QColor, Grey190)
Q_PROPERTY_AUTO(QColor, Grey200)
Q_PROPERTY_AUTO(QColor, Grey210)
Q_PROPERTY_AUTO(QColor, Grey220)
Q_PROPERTY_AUTO_P(AccentColor *, Yellow)
Q_PROPERTY_AUTO_P(AccentColor *, Orange)
Q_PROPERTY_AUTO_P(AccentColor *, Red)
Q_PROPERTY_AUTO_P(AccentColor *, Magenta)
Q_PROPERTY_AUTO_P(AccentColor *, Purple)
Q_PROPERTY_AUTO_P(AccentColor *, Blue)
Q_PROPERTY_AUTO_P(AccentColor *, Teal)
Q_PROPERTY_AUTO_P(AccentColor *, Green)
QML_ELEMENT
QML_SINGLETON
public:
static Colors *instance();
static Colors *create(QQmlEngine *, QJSEngine *);
Q_INVOKABLE AccentColor *createAccentColor(const QColor &primaryColor);
protected:
Colors(QObject *parent = nullptr);
};
#endif // __COLORS_H__

View File

@ -1,4 +1,5 @@
#include "Frameless.h" #include "Frameless.h"
#include "Theme.h"
#include "Utilities.h" #include "Utilities.h"
#include <QQuickWindow> #include <QQuickWindow>
#include <dwmapi.h> #include <dwmapi.h>
@ -19,6 +20,121 @@ static inline void setShadow(HWND hwnd) {
} }
} }
enum WINDOWCOMPOSITIONATTRIB {
WCA_UNDEFINED = 0,
WCA_NCRENDERING_ENABLED = 1,
WCA_NCRENDERING_POLICY = 2,
WCA_TRANSITIONS_FORCEDISABLED = 3,
WCA_ALLOW_NCPAINT = 4,
WCA_CAPTION_BUTTON_BOUNDS = 5,
WCA_NONCLIENT_RTL_LAYOUT = 6,
WCA_FORCE_ICONIC_REPRESENTATION = 7,
WCA_EXTENDED_FRAME_BOUNDS = 8,
WCA_HAS_ICONIC_BITMAP = 9,
WCA_THEME_ATTRIBUTES = 10,
WCA_NCRENDERING_EXILED = 11,
WCA_NCADORNMENTINFO = 12,
WCA_EXCLUDED_FROM_LIVEPREVIEW = 13,
WCA_VIDEO_OVERLAY_ACTIVE = 14,
WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15,
WCA_DISALLOW_PEEK = 16,
WCA_CLOAK = 17,
WCA_CLOAKED = 18,
WCA_ACCENT_POLICY = 19,
WCA_FREEZE_REPRESENTATION = 20,
WCA_EVER_UNCLOAKED = 21,
WCA_VISUAL_OWNER = 22,
WCA_HOLOGRAPHIC = 23,
WCA_EXCLUDED_FROM_DDA = 24,
WCA_PASSIVEUPDATEMODE = 25,
WCA_USEDARKMODECOLORS = 26,
WCA_CORNER_STYLE = 27,
WCA_PART_COLOR = 28,
WCA_DISABLE_MOVESIZE_FEEDBACK = 29,
WCA_LAST = 30
};
enum _DWM_SYSTEMBACKDROP_TYPE {
_DWMSBT_AUTO, // [Default] Let DWM automatically decide the system-drawn backdrop for this
// window.
_DWMSBT_NONE, // [Disable] Do not draw any system backdrop.
_DWMSBT_MAINWINDOW, // [Mica] Draw the backdrop material effect corresponding to a
// long-lived window.
_DWMSBT_TRANSIENTWINDOW, // [Acrylic] Draw the backdrop material effect corresponding to a
// transient window.
_DWMSBT_TABBEDWINDOW, // [Mica Alt] Draw the backdrop material effect corresponding to a
// window with a tabbed title bar.
};
enum ACCENT_STATE {
ACCENT_DISABLED = 0,
ACCENT_ENABLE_GRADIENT = 1,
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
ACCENT_ENABLE_BLURBEHIND = 3, // Traditional DWM blur
ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, // RS4 1803
ACCENT_ENABLE_HOST_BACKDROP = 5, // RS5 1809
ACCENT_INVALID_STATE = 6 // Using this value will remove the window background
};
enum ACCENT_FLAG {
ACCENT_NONE = 0,
ACCENT_ENABLE_ACRYLIC = 1,
ACCENT_ENABLE_ACRYLIC_WITH_LUMINOSITY = 482,
};
struct WINDOWCOMPOSITIONATTRIBDATA {
WINDOWCOMPOSITIONATTRIB Attrib;
PVOID pvData;
SIZE_T cbData;
};
using PWINDOWCOMPOSITIONATTRIBDATA = WINDOWCOMPOSITIONATTRIBDATA *;
struct ACCENT_POLICY {
DWORD dwAccentState;
DWORD dwAccentFlags;
DWORD dwGradientColor; // #AABBGGRR
DWORD dwAnimationId;
};
using PACCENT_POLICY = ACCENT_POLICY *;
typedef HRESULT(WINAPI *DwmSetWindowAttributeFunc)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute,
DWORD cbAttribute);
typedef HRESULT(WINAPI *DwmExtendFrameIntoClientAreaFunc)(HWND hwnd, const MARGINS *pMarInset);
typedef HRESULT(WINAPI *DwmIsCompositionEnabledFunc)(BOOL *pfEnabled);
typedef HRESULT(WINAPI *DwmEnableBlurBehindWindowFunc)(HWND hWnd, const DWM_BLURBEHIND *pBlurBehind);
typedef BOOL(WINAPI *SetWindowCompositionAttributeFunc)(HWND hwnd, const WINDOWCOMPOSITIONATTRIBDATA *);
static DwmSetWindowAttributeFunc pDwmSetWindowAttribute = nullptr;
static DwmExtendFrameIntoClientAreaFunc pDwmExtendFrameIntoClientArea = nullptr;
static DwmIsCompositionEnabledFunc pDwmIsCompositionEnabled = nullptr;
static DwmEnableBlurBehindWindowFunc pDwmEnableBlurBehindWindow = nullptr;
static SetWindowCompositionAttributeFunc pSetWindowCompositionAttribute = nullptr;
static RTL_OSVERSIONINFOW GetRealOSVersionImpl() {
HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
using RtlGetVersionPtr = NTSTATUS(WINAPI *)(PRTL_OSVERSIONINFOW);
auto pRtlGetVersion = reinterpret_cast<RtlGetVersionPtr>(::GetProcAddress(hMod, "RtlGetVersion"));
RTL_OSVERSIONINFOW rovi{};
rovi.dwOSVersionInfoSize = sizeof(rovi);
pRtlGetVersion(&rovi);
return rovi;
}
RTL_OSVERSIONINFOW GetRealOSVersion() {
static const auto result = GetRealOSVersionImpl();
return result;
}
static inline bool isWin7Only() {
RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
return rovi.dwMajorVersion = 7;
}
static inline bool isWin11OrGreater() {
RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
return (rovi.dwMajorVersion > 10) ||
(rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0 && rovi.dwBuildNumber >= 22000);
}
static bool containsCursorToItem(QQuickItem *item) { static bool containsCursorToItem(QQuickItem *item) {
auto window = item->window(); auto window = item->window();
if ((window == nullptr) || !item || !item->isVisible()) { if ((window == nullptr) || !item || !item->isVisible()) {
@ -32,8 +148,189 @@ static bool containsCursorToItem(QQuickItem *item) {
return false; return false;
} }
static inline bool initializeFunctionPointers() {
HMODULE module = LoadLibraryW(L"dwmapi.dll");
if (module) {
if (!pDwmSetWindowAttribute) {
pDwmSetWindowAttribute =
reinterpret_cast<DwmSetWindowAttributeFunc>(GetProcAddress(module, "DwmSetWindowAttribute"));
if (!pDwmSetWindowAttribute) {
return false;
}
}
if (!pDwmExtendFrameIntoClientArea) {
pDwmExtendFrameIntoClientArea = reinterpret_cast<DwmExtendFrameIntoClientAreaFunc>(
GetProcAddress(module, "DwmExtendFrameIntoClientArea"));
if (!pDwmExtendFrameIntoClientArea) {
return false;
}
}
if (!pDwmIsCompositionEnabled) {
pDwmIsCompositionEnabled =
reinterpret_cast<DwmIsCompositionEnabledFunc>(::GetProcAddress(module, "DwmIsCompositionEnabled"));
if (!pDwmIsCompositionEnabled) {
return false;
}
}
if (!pDwmEnableBlurBehindWindow) {
pDwmEnableBlurBehindWindow =
reinterpret_cast<DwmEnableBlurBehindWindowFunc>(GetProcAddress(module, "DwmEnableBlurBehindWindow"));
if (!pDwmEnableBlurBehindWindow) {
return false;
}
}
if (!pSetWindowCompositionAttribute) {
HMODULE user32 = LoadLibraryW(L"user32.dll");
if (!user32) {
return false;
}
pSetWindowCompositionAttribute = reinterpret_cast<SetWindowCompositionAttributeFunc>(
GetProcAddress(user32, "SetWindowCompositionAttribute"));
if (!pSetWindowCompositionAttribute) {
return false;
}
}
}
return true;
}
static inline bool isWin1122H2OrGreater() {
RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
return (rovi.dwMajorVersion > 10) ||
(rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0 && rovi.dwBuildNumber >= 22621);
}
static inline bool setWindowDarkMode(HWND hwnd, const BOOL enable) {
if (!initializeFunctionPointers()) {
return false;
}
return bool(pDwmSetWindowAttribute(hwnd, 20, &enable, sizeof(BOOL)));
}
static inline bool isCompositionEnabled() {
if (initializeFunctionPointers()) {
BOOL composition_enabled = false;
pDwmIsCompositionEnabled(&composition_enabled);
return composition_enabled;
}
return false;
}
static inline bool isWin8OrGreater() {
RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
return (rovi.dwMajorVersion > 6) || (rovi.dwMajorVersion == 6 && rovi.dwMinorVersion >= 2);
}
static inline bool setWindowEffect(HWND hwnd, const QString &key, const bool &enable) {
static constexpr const MARGINS extendedMargins = {-1, -1, -1, -1};
if (key == QStringLiteral("mica")) {
if (!isWin11OrGreater() || !initializeFunctionPointers()) {
return false;
}
if (enable) {
pDwmExtendFrameIntoClientArea(hwnd, &extendedMargins);
if (isWin1122H2OrGreater()) {
const DWORD backdropType = _DWMSBT_MAINWINDOW;
pDwmSetWindowAttribute(hwnd, 38, &backdropType, sizeof(backdropType));
} else {
const BOOL enable = TRUE;
pDwmSetWindowAttribute(hwnd, 1029, &enable, sizeof(enable));
}
} else {
if (isWin1122H2OrGreater()) {
const DWORD backdropType = _DWMSBT_AUTO;
pDwmSetWindowAttribute(hwnd, 38, &backdropType, sizeof(backdropType));
} else {
const BOOL enable = FALSE;
pDwmSetWindowAttribute(hwnd, 1029, &enable, sizeof(enable));
}
}
BOOL isDark = Theme::instance()->dark();
setWindowDarkMode(hwnd, isDark);
return true;
}
if (key == QStringLiteral("mica-alt")) {
if (!isWin1122H2OrGreater() || !initializeFunctionPointers()) {
return false;
}
if (enable) {
pDwmExtendFrameIntoClientArea(hwnd, &extendedMargins);
const DWORD backdropType = _DWMSBT_TABBEDWINDOW;
pDwmSetWindowAttribute(hwnd, 38, &backdropType, sizeof(backdropType));
} else {
const DWORD backdropType = _DWMSBT_AUTO;
pDwmSetWindowAttribute(hwnd, 38, &backdropType, sizeof(backdropType));
}
BOOL isDark = Theme::instance()->dark();
setWindowDarkMode(hwnd, isDark);
return true;
}
if (key == QStringLiteral("acrylic")) {
if (!isWin11OrGreater() || !initializeFunctionPointers()) {
return false;
}
if (enable) {
pDwmExtendFrameIntoClientArea(hwnd, &extendedMargins);
DWORD system_backdrop_type = _DWMSBT_TRANSIENTWINDOW;
pDwmSetWindowAttribute(hwnd, 38, &system_backdrop_type, sizeof(DWORD));
} else {
const DWORD backdropType = _DWMSBT_AUTO;
pDwmSetWindowAttribute(hwnd, 38, &backdropType, sizeof(backdropType));
}
BOOL isDark = Theme::instance()->dark();
setWindowDarkMode(hwnd, isDark);
return true;
}
if (key == QStringLiteral("dwm-blur")) {
if ((isWin7Only() && !isCompositionEnabled()) || !initializeFunctionPointers()) {
return false;
}
BOOL isDark = Theme::instance()->dark();
setWindowDarkMode(hwnd, isDark && enable);
if (enable) {
if (isWin8OrGreater()) {
ACCENT_POLICY policy{};
policy.dwAccentState = ACCENT_ENABLE_BLURBEHIND;
policy.dwAccentFlags = ACCENT_NONE;
WINDOWCOMPOSITIONATTRIBDATA wcad{};
wcad.Attrib = WCA_ACCENT_POLICY;
wcad.pvData = &policy;
wcad.cbData = sizeof(policy);
pSetWindowCompositionAttribute(hwnd, &wcad);
} else {
DWM_BLURBEHIND bb{};
bb.fEnable = TRUE;
bb.dwFlags = DWM_BB_ENABLE;
pDwmEnableBlurBehindWindow(hwnd, &bb);
}
} else {
if (isWin8OrGreater()) {
ACCENT_POLICY policy{};
policy.dwAccentState = ACCENT_DISABLED;
policy.dwAccentFlags = ACCENT_NONE;
WINDOWCOMPOSITIONATTRIBDATA wcad{};
wcad.Attrib = WCA_ACCENT_POLICY;
wcad.pvData = &policy;
wcad.cbData = sizeof(policy);
pSetWindowCompositionAttribute(hwnd, &wcad);
} else {
DWM_BLURBEHIND bb{};
bb.fEnable = FALSE;
bb.dwFlags = DWM_BB_ENABLE;
pDwmEnableBlurBehindWindow(hwnd, &bb);
}
}
return true;
}
return false;
}
Frameless::Frameless(QQuickItem *parent) : QQuickItem{parent} { Frameless::Frameless(QQuickItem *parent) : QQuickItem{parent} {
m_isWindows11OrGreater = Utilities::instance()->isWindows11OrGreater(); m_isWindows11OrGreater = Utilities::instance()->isWindows11OrGreater();
m_effect = "normal";
} }
QQuickItem *Frameless::appBar() const { QQuickItem *Frameless::appBar() const {
@ -119,12 +416,36 @@ void Frameless::setHitTestVisible(QQuickItem *item) {
} }
} }
void Frameless::showMaximized() {
#ifdef Q_OS_WIN
HWND hwnd = reinterpret_cast<HWND>(window()->winId());
::ShowWindow(hwnd, 3);
#else
window()->setVisibility(QQuickWindow::Maximized);
#endif
}
void Frameless::showMinimized() {
#ifdef Q_OS_WIN
HWND hwnd = reinterpret_cast<HWND>(window()->winId());
::ShowWindow(hwnd, 2);
#else
window()->setVisibility(QQuickWindow::Minimized);
#endif
}
void Frameless::showNormal() {
window()->setVisibility(QQuickWindow::Windowed);
}
void Frameless::onDestruction() { void Frameless::onDestruction() {
QGuiApplication::instance()->removeNativeEventFilter(this); QGuiApplication::instance()->removeNativeEventFilter(this);
} }
void Frameless::componentComplete() { void Frameless::componentComplete() {
if (m_disabled) return; if (m_disabled) {
return;
}
int w = window()->width(); int w = window()->width();
int h = window()->height(); int h = window()->height();
m_current = window()->winId(); m_current = window()->winId();
@ -150,8 +471,12 @@ void Frameless::componentComplete() {
#endif #endif
HWND hwnd = reinterpret_cast<HWND>(window()->winId()); HWND hwnd = reinterpret_cast<HWND>(window()->winId());
DWORD style = ::GetWindowLongPtr(hwnd, GWL_STYLE); DWORD style = ::GetWindowLongPtr(hwnd, GWL_STYLE);
#if (QT_VERSION == QT_VERSION_CHECK(6, 7, 2))
style &= ~(WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU);
#endif
if (m_fixSize) { if (m_fixSize) {
::SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_THICKFRAME | WS_CAPTION); ::SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_THICKFRAME | WS_CAPTION);
;
for (int i = 0; i <= QGuiApplication::screens().count() - 1; ++i) { for (int i = 0; i <= QGuiApplication::screens().count() - 1; ++i) {
connect(QGuiApplication::screens().at(i), &QScreen::logicalDotsPerInchChanged, this, [=] { connect(QGuiApplication::screens().at(i), &QScreen::logicalDotsPerInchChanged, this, [=] {
SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
@ -171,6 +496,42 @@ void Frameless::componentComplete() {
if (!window()->property("_hideShadow").toBool()) { if (!window()->property("_hideShadow").toBool()) {
setShadow(hwnd); setShadow(hwnd);
} }
if (isWin11OrGreater()) {
availableEffects({"mica", "mica-alt", "acrylic", "dwm-blur", "normal"});
} else if (isWin7Only()) {
availableEffects({"dwm-blur", "normal"});
}
if (!m_effect.isEmpty()) {
effective(setWindowEffect(hwnd, m_effect, true));
if (effective()) {
m_currentEffect = effect();
}
}
connect(this, &Frameless::effectChanged, this, [hwnd, this] {
if (effect() == m_currentEffect) {
return;
}
if (effective()) {
setWindowEffect(hwnd, m_currentEffect, false);
}
effective(setWindowEffect(hwnd, effect(), true));
if (effective()) {
m_currentEffect = effect();
} else {
m_effect = "normal";
m_currentEffect = "normal";
}
});
connect(Theme::instance(), &Theme::blurBehindWindowEnabledChanged, this, [this] {
if (Theme::instance()->blurBehindWindowEnabled()) {
effect("normal");
}
});
connect(Theme::instance(), &Theme::darkChanged, this, [hwnd, this] {
if (effective() && !m_currentEffect.isEmpty() && m_currentEffect != "normal") {
setWindowDarkMode(hwnd, Theme::instance()->dark());
}
});
#endif #endif
auto appBarHeight = m_appBar->height(); auto appBarHeight = m_appBar->height();
h = qRound(h + appBarHeight); h = qRound(h + appBarHeight);

View File

@ -1,12 +1,16 @@
#ifndef FRAMELESS_H #ifndef FRAMELESS_H
#define FRAMELESS_H #define FRAMELESS_H
#include "Utilities.h"
#include <QAbstractNativeEventFilter> #include <QAbstractNativeEventFilter>
#include <QQuickItem> #include <QQuickItem>
class Frameless : public QQuickItem, QAbstractNativeEventFilter { class Frameless : public QQuickItem, QAbstractNativeEventFilter {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
Q_PROPERTY_AUTO(QString, effect)
Q_PROPERTY_READONLY_AUTO(bool, effective)
Q_PROPERTY_READONLY_AUTO(QStringList, availableEffects)
Q_PROPERTY(QQuickItem *appBar READ appBar WRITE setAppBar NOTIFY appBarChanged) Q_PROPERTY(QQuickItem *appBar READ appBar WRITE setAppBar NOTIFY appBarChanged)
Q_PROPERTY(QQuickItem *maximizeButton READ maximizeButton WRITE setMaximizeButton NOTIFY maximizeButtonChanged) Q_PROPERTY(QQuickItem *maximizeButton READ maximizeButton WRITE setMaximizeButton NOTIFY maximizeButtonChanged)
Q_PROPERTY(QQuickItem *minimizedButton READ minimizedButton WRITE setMinimizedButton NOTIFY minimizedButtonChanged) Q_PROPERTY(QQuickItem *minimizedButton READ minimizedButton WRITE setMinimizedButton NOTIFY minimizedButtonChanged)
@ -39,6 +43,10 @@ public:
bool disabled() const; bool disabled() const;
void setDisabled(bool disabled); void setDisabled(bool disabled);
Q_INVOKABLE void showMaximized();
Q_INVOKABLE void showMinimized();
Q_INVOKABLE void showNormal();
Q_INVOKABLE void setHitTestVisible(QQuickItem *item); Q_INVOKABLE void setHitTestVisible(QQuickItem *item);
Q_INVOKABLE void onDestruction(); Q_INVOKABLE void onDestruction();
void componentComplete() final; void componentComplete() final;
@ -77,6 +85,7 @@ private:
int m_margins = 8; int m_margins = 8;
QList<QPointer<QQuickItem>> m_hitTestList; QList<QPointer<QQuickItem>> m_hitTestList;
bool m_isWindows11OrGreater = false; bool m_isWindows11OrGreater = false;
QString m_currentEffect;
}; };
#endif // FRAMELESS_H #endif // FRAMELESS_H

48
Fluent/TextStyle.cpp Normal file
View File

@ -0,0 +1,48 @@
#include "TextStyle.h"
TextStyle::TextStyle(QObject *parent) : QObject{parent} {
m_family = QFont().defaultFamily();
#ifdef Q_OS_WIN
m_family = "微软雅黑";
#endif
QFont caption;
caption.setFamily(m_family);
caption.setPixelSize(12);
Caption(caption);
QFont body;
body.setFamily(m_family);
body.setPixelSize(13);
Body(body);
QFont bodyStrong;
bodyStrong.setFamily(m_family);
bodyStrong.setPixelSize(13);
bodyStrong.setWeight(QFont::DemiBold);
BodyStrong(bodyStrong);
QFont subtitle;
subtitle.setFamily(m_family);
subtitle.setPixelSize(20);
subtitle.setWeight(QFont::DemiBold);
Subtitle(subtitle);
QFont title;
title.setFamily(m_family);
title.setPixelSize(28);
title.setWeight(QFont::DemiBold);
Title(title);
QFont titleLarge;
titleLarge.setFamily(m_family);
titleLarge.setPixelSize(40);
titleLarge.setWeight(QFont::DemiBold);
TitleLarge(titleLarge);
QFont display;
display.setFamily(m_family);
display.setPixelSize(68);
display.setWeight(QFont::DemiBold);
Display(display);
}

25
Fluent/TextStyle.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef __TEXTSTYLE_H__
#define __TEXTSTYLE_H__
#include "Utilities.h"
#include <QFont>
#include <QObject>
class TextStyle : public QObject {
Q_OBJECT
QML_ELEMENT
QML_SINGLETON
Q_PROPERTY_AUTO(QString, family)
Q_PROPERTY_AUTO(QFont, Caption)
Q_PROPERTY_AUTO(QFont, Body)
Q_PROPERTY_AUTO(QFont, BodyStrong)
Q_PROPERTY_AUTO(QFont, Subtitle)
Q_PROPERTY_AUTO(QFont, Title)
Q_PROPERTY_AUTO(QFont, TitleLarge)
Q_PROPERTY_AUTO(QFont, Display)
public:
TextStyle(QObject *parent = nullptr);
};
#endif // __TEXTSTYLE_H__

View File

@ -1,6 +1,56 @@
#include "Theme.h" #include "Theme.h"
#include "Colors.h"
#include <QGuiApplication>
#include <QPalette>
#include <QThreadPool>
static bool systemDark() {
QPalette palette = QGuiApplication::palette();
QColor color = palette.color(QPalette::Window).rgb();
return color.red() * 0.2126 + color.green() * 0.7152 + color.blue() * 0.0722 <= 255.0f / 2;
}
Theme *Theme::instance() {
static Theme *self = nullptr;
if (self == nullptr) {
self = new Theme();
}
return self;
}
Theme *Theme::create(QQmlEngine *, QJSEngine *) {
auto ret = instance();
QJSEngine::setObjectOwnership(ret, QJSEngine::CppOwnership);
return ret;
}
Theme::Theme(QObject *parent) : QObject{parent} { Theme::Theme(QObject *parent) : QObject{parent} {
m_accentColor = Colors::instance()->Blue();
m_darkMode = ThemeType::DarkMode::Light;
m_nativeText = false;
m_animationEnabled = true;
m_systemDark = systemDark();
m_desktopImagePath = "";
m_blurBehindWindowEnabled = false;
QGuiApplication::instance()->installEventFilter(this);
refreshColors();
connect(this, &Theme::darkModeChanged, this, [=] { Q_EMIT darkChanged(); });
connect(this, &Theme::darkChanged, this, [=] { refreshColors(); });
connect(this, &Theme::accentColorChanged, this, [=] { refreshColors(); });
connect(&m_watcher, &QFileSystemWatcher::fileChanged, this,
[=](const QString &path) { Q_EMIT desktopImagePathChanged(); });
connect(this, &Theme::blurBehindWindowEnabledChanged, this, [=] { checkUpdateDesktopImage(); });
startTimer(1000);
}
bool Theme::dark() const {
if (m_darkMode == ThemeType::DarkMode::Dark) {
return true;
} else if (m_darkMode == ThemeType::DarkMode::System) {
return m_systemDark;
} else {
return false;
}
} }
QColor Theme::fontPrimaryColor() const { QColor Theme::fontPrimaryColor() const {
@ -79,3 +129,53 @@ void Theme::setBlurBehindWindowEnabled(bool enabled) {
emit blurBehindWindowEnabledChanged(); emit blurBehindWindowEnabledChanged();
} }
} }
void Theme::refreshColors() {
auto isDark = dark();
primaryColor(isDark ? m_accentColor->lighter() : m_accentColor->dark());
backgroundColor(isDark ? QColor(0, 0, 0, 255) : QColor(255, 255, 255, 255));
dividerColor(isDark ? QColor(80, 80, 80, 255) : QColor(210, 210, 210, 255));
setWindowBackgroundColor(isDark ? QColor(32, 32, 32, 255) : QColor(237, 237, 237, 255));
setWindowActiveBackgroundColor(isDark ? QColor(26, 26, 26, 255) : QColor(243, 243, 243, 255));
setFontPrimaryColor(isDark ? QColor(248, 248, 248, 255) : QColor(7, 7, 7, 255));
fontSecondaryColor(isDark ? QColor(222, 222, 222, 255) : QColor(102, 102, 102, 255));
fontTertiaryColor(isDark ? QColor(200, 200, 200, 255) : QColor(153, 153, 153, 255));
setItemNormalColor(isDark ? QColor(255, 255, 255, 0) : QColor(0, 0, 0, 0));
frameColor(isDark ? QColor(56, 56, 56, qRound(255 * 0.8)) : QColor(243, 243, 243, qRound(255 * 0.8)));
frameActiveColor(isDark ? QColor(48, 48, 48, qRound(255 * 0.8)) : QColor(255, 255, 255, qRound(255 * 0.8)));
setItemHoverColor(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)));
}
void Theme::checkUpdateDesktopImage() {
if (!m_blurBehindWindowEnabled) {
return;
}
QThreadPool::globalInstance()->start([=]() {
m_mutex.lock();
auto path = Utilities::instance()->getWallpaperFilePath();
if (m_desktopImagePath != path) {
if (!m_desktopImagePath.isEmpty()) {
m_watcher.removePath(m_desktopImagePath);
}
setDesktopImagePath(path);
m_watcher.addPath(path);
}
m_mutex.unlock();
});
}
bool Theme::eventFilter(QObject *, QEvent *event) {
if (event->type() == QEvent::ApplicationPaletteChange || event->type() == QEvent::ThemeChange) {
m_systemDark = systemDark();
Q_EMIT darkChanged();
event->accept();
return true;
}
return false;
}
void Theme::timerEvent(QTimerEvent *event) {
checkUpdateDesktopImage();
}

View File

@ -1,7 +1,11 @@
#ifndef THEME_H #ifndef THEME_H
#define THEME_H #define THEME_H
#include "AccentColor.h"
#include "Utilities.h"
#include <QColor> #include <QColor>
#include <QFileSystemWatcher>
#include <QMutex>
#include <QObject> #include <QObject>
#include <QQmlEngine> #include <QQmlEngine>
@ -9,7 +13,21 @@ class Theme : public QObject {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
QML_SINGLETON QML_SINGLETON
Q_PROPERTY(bool dark READ dark NOTIFY darkChanged)
Q_PROPERTY_AUTO_P(AccentColor *, accentColor)
Q_PROPERTY_AUTO(int, darkMode)
Q_PROPERTY_AUTO(QColor, primaryColor)
Q_PROPERTY_AUTO(QColor, backgroundColor)
Q_PROPERTY_AUTO(QColor, dividerColor)
Q_PROPERTY_AUTO(QColor, itemPressColor)
Q_PROPERTY_AUTO(bool, nativeText)
Q_PROPERTY_AUTO(bool, animationEnabled)
Q_PROPERTY(QColor fontPrimaryColor READ fontPrimaryColor WRITE setFontPrimaryColor NOTIFY fontPrimaryColorChanged) Q_PROPERTY(QColor fontPrimaryColor READ fontPrimaryColor WRITE setFontPrimaryColor NOTIFY fontPrimaryColorChanged)
Q_PROPERTY_AUTO(QColor, fontSecondaryColor)
Q_PROPERTY_AUTO(QColor, fontTertiaryColor)
Q_PROPERTY_AUTO(QColor, frameColor)
Q_PROPERTY_AUTO(QColor, frameActiveColor)
Q_PROPERTY_AUTO(QColor, itemCheckColor)
Q_PROPERTY(QColor itemNormalColor READ itemNormalColor WRITE setItemNormalColor NOTIFY itemNormalColorChanged) Q_PROPERTY(QColor itemNormalColor READ itemNormalColor WRITE setItemNormalColor NOTIFY itemNormalColorChanged)
Q_PROPERTY(QColor itemHoverColor READ itemHoverColor WRITE setItemHoverColor NOTIFY itemHoverColorChanged) Q_PROPERTY(QColor itemHoverColor READ itemHoverColor WRITE setItemHoverColor NOTIFY itemHoverColorChanged)
@ -23,7 +41,9 @@ class Theme : public QObject {
blurBehindWindowEnabledChanged) blurBehindWindowEnabledChanged)
public: public:
Theme(QObject *parent = nullptr); static Theme *instance();
static Theme *create(QQmlEngine *, QJSEngine *);
bool dark() const;
QColor fontPrimaryColor() const; QColor fontPrimaryColor() const;
void setFontPrimaryColor(const QColor &color); void setFontPrimaryColor(const QColor &color);
@ -47,6 +67,7 @@ public:
void setBlurBehindWindowEnabled(bool enabled); void setBlurBehindWindowEnabled(bool enabled);
signals: signals:
void darkChanged();
void fontPrimaryColorChanged(); void fontPrimaryColorChanged();
void itemNormalColorChanged(); void itemNormalColorChanged();
void windowBackgroundColorChanged(); void windowBackgroundColorChanged();
@ -55,7 +76,17 @@ signals:
void blurBehindWindowEnabledChanged(); void blurBehindWindowEnabledChanged();
void itemHoverColorChanged(); void itemHoverColorChanged();
protected:
Theme(QObject *parent = nullptr);
void refreshColors();
void checkUpdateDesktopImage();
void timerEvent(QTimerEvent *event) final;
bool eventFilter(QObject *obj, QEvent *event) final;
private: private:
bool m_systemDark = false;
QMutex m_mutex;
QFileSystemWatcher m_watcher;
QColor m_fontPrimaryColor; QColor m_fontPrimaryColor;
QColor m_itemNormalColor; QColor m_itemNormalColor;
QColor m_itemHoverColor; QColor m_itemHoverColor;

View File

@ -1,5 +1,6 @@
#include "Utilities.h" #include "Utilities.h"
#include <QSettings> #include <QSettings>
#include <qt_windows.h>
Utilities *Utilities::instance() { Utilities *Utilities::instance() {
static Utilities *self = nullptr; static Utilities *self = nullptr;
@ -18,10 +19,70 @@ Utilities *Utilities::create(QQmlEngine *, QJSEngine *) {
Utilities::Utilities(QObject *parent) : QObject{parent} { Utilities::Utilities(QObject *parent) : QObject{parent} {
} }
bool Utilities::isSoftware() {
return QQuickWindow::sceneGraphBackend() == "software";
}
void Utilities::deleteLater(QObject *p) {
if (p) {
p->deleteLater();
}
}
QColor Utilities::withOpacity(const QColor &color, qreal opacity) {
int alpha = qRound(opacity * 255) & 0xff;
return QColor::fromRgba((alpha << 24) | (color.rgba() & 0xffffff));
}
QRect Utilities::desktopAvailableGeometry(QQuickWindow *window) { QRect Utilities::desktopAvailableGeometry(QQuickWindow *window) {
return window->screen()->availableGeometry(); return window->screen()->availableGeometry();
} }
QString Utilities::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);
#elif defined(Q_OS_LINUX)
auto type = QSysInfo::productType();
if (type == "uos") {
QProcess process;
QStringList args;
args << "--session";
args << "--type=method_call";
args << "--print-reply";
args << "--dest=com.deepin.wm";
args << "/com/deepin/wm";
args << "com.deepin.wm.GetCurrentWorkspaceBackgroundForMonitor";
args << QString("string:'%1'").arg(currentTimestamp());
process.start("dbus-send", args);
process.waitForFinished();
QByteArray result = process.readAllStandardOutput().trimmed();
int startIndex = result.indexOf("file:///");
if (startIndex != -1) {
auto path = result.mid(startIndex + 7, result.length() - startIndex - 8);
return path;
}
}
#elif defined(Q_OS_MACOS)
QProcess process;
QStringList args;
args << "-e";
args << R"(tell application "Finder" to get POSIX path of (desktop picture as alias))";
process.start("osascript", args);
process.waitForFinished();
QByteArray result = process.readAllStandardOutput().trimmed();
if (result.isEmpty()) {
return "/System/Library/CoreServices/DefaultDesktop.heic";
}
return result;
#else
return {};
#endif
}
QUrl Utilities::getUrlByFilePath(const QString &path) { QUrl Utilities::getUrlByFilePath(const QString &path) {
return QUrl::fromLocalFile(path); return QUrl::fromLocalFile(path);
} }

View File

@ -5,6 +5,84 @@
#include <QQmlEngine> #include <QQmlEngine>
#include <QQuickWindow> #include <QQuickWindow>
#define Q_PROPERTY_AUTO(TYPE, M) \
Q_PROPERTY(TYPE M MEMBER m_##M NOTIFY M##Changed) \
public: \
Q_SIGNAL void M##Changed(); \
void M(const TYPE &in_##M) { \
m_##M = in_##M; \
Q_EMIT M##Changed(); \
} \
TYPE M() { \
return m_##M; \
} \
\
private: \
TYPE m_##M;
#define Q_PROPERTY_READONLY_AUTO(TYPE, M) \
Q_PROPERTY(TYPE M READ M NOTIFY M##Changed FINAL) \
public: \
Q_SIGNAL void M##Changed(); \
void M(const TYPE &in_##M) { \
m_##M = in_##M; \
Q_EMIT M##Changed(); \
} \
TYPE M() { \
return m_##M; \
} \
\
private: \
TYPE m_##M;
#define Q_PROPERTY_AUTO_P(TYPE, M) \
Q_PROPERTY(TYPE M MEMBER m_##M NOTIFY M##Changed) \
public: \
Q_SIGNAL void M##Changed(); \
void M(TYPE in_##M) { \
m_##M = in_##M; \
Q_EMIT M##Changed(); \
} \
TYPE M() { \
return m_##M; \
} \
\
private: \
TYPE m_##M;
namespace WindowType {
Q_NAMESPACE
enum LaunchMode {
Standard = 0x0000,
SingleTask = 0x0001,
SingleInstance = 0x0002,
};
Q_ENUM_NS(LaunchMode)
QML_ELEMENT
} // namespace WindowType
namespace ThemeType {
Q_NAMESPACE
enum DarkMode {
System = 0x0000,
Light = 0x0001,
Dark = 0x0002,
};
Q_ENUM_NS(DarkMode)
QML_ELEMENT
} // namespace ThemeType
namespace ContentDialogType {
Q_NAMESPACE
enum ButtonFlag {
NeutralButton = 0x0001,
NegativeButton = 0x0002,
PositiveButton = 0x0004,
};
Q_ENUM_NS(ButtonFlag)
QML_ELEMENT
} // namespace ContentDialogType
class Utilities : public QObject { class Utilities : public QObject {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
@ -18,6 +96,10 @@ public:
Q_INVOKABLE bool isMacos(); Q_INVOKABLE bool isMacos();
Q_INVOKABLE QRect desktopAvailableGeometry(QQuickWindow *window); Q_INVOKABLE QRect desktopAvailableGeometry(QQuickWindow *window);
Q_INVOKABLE QUrl getUrlByFilePath(const QString &path); Q_INVOKABLE QUrl getUrlByFilePath(const QString &path);
Q_INVOKABLE bool isSoftware();
Q_INVOKABLE void deleteLater(QObject *p);
Q_INVOKABLE QColor withOpacity(const QColor &, qreal alpha);
Q_INVOKABLE QString getWallpaperFilePath();
protected: protected:
Utilities(QObject *parent = nullptr); Utilities(QObject *parent = nullptr);

View File

@ -1,26 +1,88 @@
import QtQuick as Quick import QtQuick as Quick
import QtQuick.Controls
import QtQuick.Window
import QtQuick.Layouts import QtQuick.Layouts
import Fluent import Fluent
Quick.Rectangle{ Quick.Rectangle{
id: root property string title: ""
property string darkText : qsTr("Dark")
property string lightText : qsTr("Light")
property string minimizeText : qsTr("Minimize")
property string restoreText : qsTr("Restore")
property string maximizeText : qsTr("Maximize")
property string closeText : qsTr("Close")
property string stayTopText : qsTr("Sticky on Top")
property string stayTopCancelText : qsTr("Sticky on Top cancelled")
property color textColor: Theme.fontPrimaryColor
property color minimizeNormalColor: Theme.itemNormalColor
property color minimizeHoverColor: Theme.itemHoverColor
property color minimizePressColor: Theme.itemPressColor
property color maximizeNormalColor: Theme.itemNormalColor
property color maximizeHoverColor: Theme.itemHoverColor
property color maximizePressColor: Theme.itemPressColor
property color closeNormalColor: Qt.rgba(0,0,0,0)
property color closeHoverColor: Qt.rgba(251/255,115/255,115/255,1)
property color closePressColor: Qt.rgba(251/255,115/255,115/255,0.8)
property bool showDark: false
property bool showClose: true
property bool showMinimize: true property bool showMinimize: true
property bool showMaximize: true property bool showMaximize: true
property bool showClose: true
property bool showStayTop: true property bool showStayTop: true
property bool showDark: false property bool titleVisible: true
property string title: ""
property url icon property url icon
property string maximizeText : qsTr("Maximize") property int iconSize: 20
property Quick.color textColor: Theme.fontPrimaryColor
property Quick.color maximizeNormalColor: Theme.itemNormalColor
property Quick.color maximizeHoverColor: Theme.itemHoverColor
property bool isMac: Utilities.isMacos() property bool isMac: Utilities.isMacos()
property color borerlessColor : Theme.primaryColor
property alias buttonStayTop: btn_stay_top
property alias buttonMinimize: btn_minimize
property alias buttonMaximize: btn_maximize property alias buttonMaximize: btn_maximize
property alias buttonClose: btn_close
property alias buttonDark: btn_dark
property alias layoutMacosButtons: layout_macos_buttons property alias layoutMacosButtons: layout_macos_buttons
property alias layoutStandardbuttons: layout_standard_buttons property alias layoutStandardbuttons: layout_standard_buttons
property var maxClickListener : function(){
Quick.Item{ if(Utilities.isMacos()){
if (d.win.visibility === Window.FullScreen || d.win.visibility === Window.Maximized)
d.win.showNormal()
else
d.win.showFullScreen()
}else{
if (d.win.visibility === Window.Maximized || d.win.visibility === Window.FullScreen)
d.win.showNormal()
else
d.win.showMaximized()
d.hoverMaxBtn = false
}
}
property var minClickListener: function(){
if(d.win.transientParent != null){
d.win.transientParent.showMinimized()
}else{
d.win.showMinimized()
}
}
property var closeClickListener : function(){
d.win.close()
}
property var stayTopClickListener: function(){
if(d.win instanceof Window){
d.win.stayTop = !d.win.stayTop
}
}
property var darkClickListener: function(){
if(Theme.dark){
Theme.darkMode = ThemeType.Light
}else{
Theme.darkMode = ThemeType.Dark
}
}
id:control
color: Qt.rgba(0,0,0,0)
height: visible ? 30 : 0
opacity: visible
z: 65535
Item{
id:d id:d
property var hitTestList: [] property var hitTestList: []
property bool hoverMaxBtn: false property bool hoverMaxBtn: false
@ -42,13 +104,125 @@ Quick.Rectangle {
return false return false
} }
} }
Row{
anchors{
verticalCenter: parent.verticalCenter
left: isMac ? undefined : parent.left
leftMargin: isMac ? undefined : 10
horizontalCenter: isMac ? parent.horizontalCenter : undefined
}
spacing: 10
Image{
width: control.iconSize
height: control.iconSize
visible: status === Image.Ready ? true : false
source: control.icon
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: title
visible: control.titleVisible
color:control.textColor
anchors.verticalCenter: parent.verticalCenter
}
}
Component{
id:com_macos_buttons
RowLayout{
ImageButton{
Layout.preferredHeight: 12
Layout.preferredWidth: 12
normalImage: "../Image/btn_close_normal.png"
hoveredImage: "../Image/btn_close_hovered.png"
pushedImage: "../Image/btn_close_pushed.png"
visible: showClose
onClicked: closeClickListener()
}
ImageButton{
Layout.preferredHeight: 12
Layout.preferredWidth: 12
normalImage: "../Image/btn_min_normal.png"
hoveredImage: "../Image/btn_min_hovered.png"
pushedImage: "../Image/btn_min_pushed.png"
onClicked: minClickListener()
visible: showMinimize
}
ImageButton{
Layout.preferredHeight: 12
Layout.preferredWidth: 12
normalImage: "../Image/btn_max_normal.png"
hoveredImage: "../Image/btn_max_hovered.png"
pushedImage: "../Image/btn_max_pushed.png"
onClicked: maxClickListener()
visible: d.resizable && showMaximize
}
}
}
RowLayout{ RowLayout{
id:layout_standard_buttons id:layout_standard_buttons
height: parent.height height: parent.height
anchors.right: parent.right anchors.right: parent.right
spacing: 0 spacing: 0
IconButton{
id:btn_dark
Layout.preferredWidth: 40
Layout.preferredHeight: 30
padding: 0
verticalPadding: 0
horizontalPadding: 0
rightPadding: 2
iconSource: Theme.dark ? Icons.Brightness : Icons.QuietHours
Layout.alignment: Qt.AlignVCenter
iconSize: 15
visible: showDark
text: Theme.dark ? control.lightText : control.darkText
radius: 0
iconColor:control.textColor
onClicked:()=> darkClickListener(btn_dark)
}
IconButton{
id:btn_stay_top
Layout.preferredWidth: 40
Layout.preferredHeight: 30
padding: 0
verticalPadding: 0
horizontalPadding: 0
iconSource : Icons.Pinned
Layout.alignment: Qt.AlignVCenter
iconSize: 14
visible: {
if(!(d.win instanceof Window)){
return false
}
return showStayTop
}
text:d.stayTop ? control.stayTopCancelText : control.stayTopText
radius: 0
iconColor: d.stayTop ? Theme.primaryColor : control.textColor
onClicked: stayTopClickListener()
}
IconButton{
id:btn_minimize
Layout.preferredWidth: 40
Layout.preferredHeight: 30
padding: 0
verticalPadding: 0
horizontalPadding: 0
iconSource : Icons.ChromeMinimize
Layout.alignment: Qt.AlignVCenter
iconSize: 11
text:minimizeText
radius: 0
visible: !isMac && showMinimize
iconColor: control.textColor
color: {
if(pressed){
return minimizePressColor
}
return hovered ? minimizeHoverColor : minimizeNormalColor
}
onClicked: minClickListener()
}
IconButton{ IconButton{
id:btn_maximize id:btn_maximize
property bool hover: btn_maximize.hovered property bool hover: btn_maximize.hovered
@ -67,14 +241,35 @@ Quick.Rectangle {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
visible: d.resizable && !isMac && showMaximize visible: d.resizable && !isMac && showMaximize
radius: 0 radius: 0
iconColor: root.textColor iconColor: control.textColor
text:d.isRestore?restoreText:maximizeText text:d.isRestore?restoreText:maximizeText
iconSize: 11 iconSize: 11
onClicked: maxClickListener() onClicked: maxClickListener()
} }
IconButton{
id:btn_close
Layout.preferredWidth: 40
Layout.preferredHeight: 30
padding: 0
verticalPadding: 0
horizontalPadding: 0
iconSource : Icons.ChromeClose
Layout.alignment: Qt.AlignVCenter
text:closeText
visible: !isMac && showClose
radius: 0
iconSize: 10
iconColor: hovered ? Qt.rgba(1,1,1,1) : control.textColor
color:{
if(pressed){
return closePressColor
} }
return hovered ? closeHoverColor : closeNormalColor
Quick.Loader{ }
onClicked: closeClickListener()
}
}
Loader{
id:layout_macos_buttons id:layout_macos_buttons
anchors{ anchors{
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
@ -82,6 +277,5 @@ Quick.Rectangle {
leftMargin: 10 leftMargin: 10
} }
sourceComponent: isMac ? com_macos_buttons : undefined sourceComponent: isMac ? com_macos_buttons : undefined
Quick.Component.onDestruction: sourceComponent = undefined
} }
} }

64
Fluent/qml/Button.qml Normal file
View File

@ -0,0 +1,64 @@
import QtQuick as Quick
import QtQuick.Controls as Control
import Fluent
Control.Button {
property bool disabled: false
property string contentDescription: ""
property Quick.color normalColor: Theme.dark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(254/255,254/255,254/255,1)
property Quick.color hoverColor: Theme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(246/255,246/255,246/255,1)
property Quick.color disableColor: Theme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(251/255,251/255,251/255,1)
property Quick.color dividerColor: Theme.dark ? Qt.rgba(80/255,80/255,80/255,1) : Qt.rgba(233/255,233/255,233/255,1)
property Quick.color textColor: {
if(Theme.dark){
if(!enabled){
return Qt.rgba(131/255,131/255,131/255,1)
}
if(pressed){
return Qt.rgba(162/255,162/255,162/255,1)
}
return Qt.rgba(1,1,1,1)
}else{
if(!enabled){
return Qt.rgba(160/255,160/255,160/255,1)
}
if(pressed){
return Qt.rgba(96/255,96/255,96/255,1)
}
return Qt.rgba(0,0,0,1)
}
}
Quick.Accessible.role: Quick.Accessible.Button
Quick.Accessible.name: control.text
Quick.Accessible.description: contentDescription
Quick.Accessible.onPressAction: control.clicked()
id: control
enabled: !disabled
verticalPadding: 0
horizontalPadding:12
font:TextStyle.Body
focusPolicy:Qt.TabFocus
background: ControlBackground{
implicitWidth: 30
implicitHeight: 30
radius: 4
color: {
if(!enabled){
return disableColor
}
return hovered ? hoverColor :normalColor
}
shadow: !pressed && enabled
FocusRectangle{
visible: control.activeFocus
radius:4
}
}
contentItem: Text {
text: control.text
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font: control.font
color: control.textColor
}
}

View File

@ -0,0 +1,164 @@
import QtQuick as Quick
import QtQuick.Layouts
import QtQuick.Controls as Controls
import QtQuick.Window
import Fluent
Popup {
id: control
property string title: ""
property string message: ""
property string neutralText: qsTr("Close")
property string negativeText: qsTr("Cancel")
property string positiveText: qsTr("OK")
property int messageTextFormart: Text.AutoText
property int delayTime: 100
property int buttonFlags: FluContentDialogType.NegativeButton | FluContentDialogType.PositiveButton
property var contentDelegate: Component{
Item{
}
}
property var onNeutralClickListener
property var onNegativeClickListener
property var onPositiveClickListener
signal neutralClicked
signal negativeClicked
signal positiveClicked
implicitWidth: 400
implicitHeight: layout_content.height
focus: true
Component{
id:com_message
Flickable{
id:sroll_message
contentHeight: text_message.height
contentWidth: width
clip: true
boundsBehavior:Flickable.StopAtBounds
width: parent.width
height: message === "" ? 0 : Math.min(text_message.height,300)
Controls.ScrollBar.vertical: ScrollBar {}
Text{
id:text_message
font: TextStyle.Body
wrapMode: Text.WrapAnywhere
text:message
width: parent.width
topPadding: 4
leftPadding: 20
rightPadding: 20
bottomPadding: 4
}
}
}
Rectangle {
id:layout_content
width: parent.width
height: layout_column.childrenRect.height
color: 'transparent'
radius:5
ColumnLayout{
id:layout_column
width: parent.width
Text{
id:text_title
font: TextStyle.Title
text:title
topPadding: 20
leftPadding: 20
rightPadding: 20
wrapMode: Text.WrapAnywhere
}
Loader{
sourceComponent: com_message
Layout.fillWidth: true
Layout.preferredHeight: status===Loader.Ready ? item.height : 0
}
Loader{
sourceComponent:control.visible ? control.contentDelegate : undefined
Layout.fillWidth: true
onStatusChanged: {
if(status===Loader.Ready){
Layout.preferredHeight = item.implicitHeight
}else{
Layout.preferredHeight = 0
}
}
}
Rectangle{
id:layout_actions
Layout.fillWidth: true
Layout.preferredHeight: 60
radius: 5
color: Theme.dark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(243/255,243/255,243/255,1)
RowLayout{
anchors
{
centerIn: parent
margins: spacing
fill: parent
}
spacing: 10
Item{
Layout.fillWidth: true
Layout.fillHeight: true
Button{
id:neutral_btn
visible: control.buttonFlags&ContentDialogType.NeutralButton
text: neutralText
width: parent.width
anchors.centerIn: parent
onClicked: {
if(control.onNeutralClickListener){
control.onNeutralClickListener()
}else{
neutralClicked()
control.close()
}
}
}
}
Item{
Layout.fillWidth: true
Layout.fillHeight: true
Button{
id:negative_btn
visible: control.buttonFlags&ContentDialogType.NegativeButton
width: parent.width
anchors.centerIn: parent
text: negativeText
onClicked: {
if(control.onNegativeClickListener){
control.onNegativeClickListener()
}else{
negativeClicked()
control.close()
}
}
}
}
Item{
Layout.fillWidth: true
Layout.fillHeight: true
FilledButton{
id:positive_btn
visible: control.buttonFlags&ContentDialogType.PositiveButton
text: positiveText
width: parent.width
anchors.centerIn: parent
onClicked: {
if(control.onPositiveClickListener){
control.onPositiveClickListener()
}else{
positiveClicked()
control.close()
}
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,52 @@
import QtQuick as Quick
import QtQuick.Controls
import Fluent
Quick.Item{
id:control
property int radius: 4
property bool shadow: true
property alias border: d.border
property var bottomMargin: undefined
property var topMargin: undefined
property var leftMargin: undefined
property var rightMargin: undefined
property Quick.color color: Theme.dark ? Qt.rgba(42/255,42/255,42/255,1) : Qt.rgba(254/255,254/255,254/255,1)
property alias gradient : rect_border.gradient
Quick.Rectangle{
id:d
property Quick.color startColor: Qt.lighter(d.border.color,1.25)
property Quick.color endColor: shadow ? control.border.color : startColor
visible: false
border.color: Theme.dark ? Qt.rgba(48/255,48/255,48/255,1) : Qt.rgba(188/255,188/255,188/255,1)
}
Quick.Rectangle{
id:rect_border
anchors.fill: parent
radius: control.radius
gradient: Quick.Gradient {
Quick.GradientStop { position: 0.0; color: d.startColor }
Quick.GradientStop { position: 1 - 3/control.height; color: d.startColor }
Quick.GradientStop { position: 1.0; color: d.endColor}
}
}
Quick.Rectangle{
id:rect_back
anchors{
fill: parent
margins: control.border.width
topMargin: control.topMargin
bottomMargin: control.bottomMargin
leftMargin: control.leftMargin
rightMargin: control.rightMargin
}
Quick.Behavior on anchors.bottomMargin {
Quick.NumberAnimation{
easing.type: Easing.OutCubic
duration: 167
}
}
radius: control.radius
color: control.color
}
}

View File

@ -0,0 +1,60 @@
import QtQuick as Quick
import QtQuick.Controls
import Fluent
Button {
property bool disabled: false
property string contentDescription: ""
property Quick.color normalColor: Theme.primaryColor
property Quick.color hoverColor: Theme.dark ? Qt.darker(normalColor,1.1) : Qt.lighter(normalColor,1.1)
property Quick.color disableColor: Theme.dark ? Qt.rgba(82/255,82/255,82/255,1) : Qt.rgba(199/255,199/255,199/255,1)
property Quick.color pressedColor: Theme.dark ? Qt.darker(normalColor,1.2) : Qt.lighter(normalColor,1.2)
property Quick.color textColor: {
if(Theme.dark){
if(!enabled){
return Qt.rgba(173/255,173/255,173/255,1)
}
return Qt.rgba(0,0,0,1)
}else{
return Qt.rgba(1,1,1,1)
}
}
Quick.Accessible.role: Quick.Accessible.Button
Quick.Accessible.name: control.text
Quick.Accessible.description: contentDescription
Quick.Accessible.onPressAction: control.clicked()
id: control
enabled: !disabled
focusPolicy:Qt.TabFocus
font:TextStyle.Body
verticalPadding: 0
horizontalPadding:12
background: ControlBackground{
implicitWidth: 30
implicitHeight: 30
radius: 4
bottomMargin: enabled ? 2 : 0
border.width: enabled ? 1 : 0
border.color: enabled ? Qt.darker(control.normalColor,1.2) : disableColor
color:{
if(!enabled){
return disableColor
}
if(pressed){
return pressedColor
}
return hovered ? hoverColor :normalColor
}
FocusRectangle{
visible: control.visualFocus
radius:4
}
}
contentItem: Text {
text: control.text
font: control.font
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: control.textColor
}
}

View File

@ -0,0 +1,20 @@
import QtQuick as Quick
import QtQuick.Controls
import Fluent
Quick.Item {
property int radius: 4
id:control
anchors.fill: parent
Quick.Rectangle{
width: control.width
height: control.height
anchors.centerIn: parent
color: "#00000000"
border.width: 2
radius: control.radius
border.color: Theme.dark ? Qt.rgba(1,1,1,1) : Qt.rgba(0,0,0,1)
z: 65535
}
}

View File

@ -1,9 +1,11 @@
import QtQuick import QtQuick
import QtQuick.Controls
import Fluent
Text { Text {
property int iconSource property int iconSource
property int iconSize: 20 property int iconSize: 20
property color iconColor: FluTheme.dark ? "#FFFFFF" : "#000000" property color iconColor: Theme.dark ? "#FFFFFF" : "#000000"
id:control id:control
font.family: font_loader.name font.family: font_loader.name
font.pixelSize: iconSize font.pixelSize: iconSize
@ -14,6 +16,6 @@ Text {
opacity: iconSource>0 opacity: iconSource>0
FontLoader{ FontLoader{
id: font_loader id: font_loader
source: "qrc:/qt/qml/FluentUI/Font/FluentIcons.ttf" source: "qrc:/qt/qml/Fluent/resources/FluentIcons.ttf"
} }
} }

View File

@ -1,11 +1,21 @@
import QtQuick import QtQuick as Quick
import QtQuick.Controls import QtQuick.Controls as Controls
import QtQuick.Layouts
import Fluent
Button { Controls.Button {
display: Controls.Button.IconOnly
property int iconSize: 20 property int iconSize: 20
property int iconSource property int iconSource
property bool disabled: false
property int radius:4 property int radius:4
property color color: { property string contentDescription: ""
property Quick.color hoverColor: Theme.itemHoverColor
property Quick.color pressedColor: Theme.itemPressColor
property Quick.color normalColor: Theme.itemNormalColor
property Quick.color disableColor: Theme.itemNormalColor
property Quick.Component iconDelegate: com_icon
property Quick.color color: {
if(!enabled){ if(!enabled){
return disableColor return disableColor
} }
@ -14,8 +24,8 @@ Button {
} }
return hovered ? hoverColor : normalColor return hovered ? hoverColor : normalColor
} }
property color iconColor: { property Quick.color iconColor: {
if (FluTheme.dark) { if(Theme.dark){
if(!enabled){ if(!enabled){
return Qt.rgba(130/255,130/255,130/255,1) return Qt.rgba(130/255,130/255,130/255,1)
} }
@ -27,4 +37,93 @@ Button {
return Qt.rgba(0,0,0,1) return Qt.rgba(0,0,0,1)
} }
} }
property Quick.color textColor: Theme.fontPrimaryColor
Quick.Accessible.role: Quick.Accessible.Button
Quick.Accessible.name: control.text
Quick.Accessible.description: contentDescription
Quick.Accessible.onPressAction: control.clicked()
id:control
focusPolicy:Qt.TabFocus
padding: 0
verticalPadding: 8
horizontalPadding: 8
enabled: !disabled
font:TextStyle.Caption
background: Quick.Rectangle{
implicitWidth: 30
implicitHeight: 30
radius: control.radius
color:control.color
FocusRectangle{
visible: control.activeFocus
}
}
Quick.Component{
id:com_icon
Icon {
id:text_icon
font.pixelSize: iconSize
iconSize: control.iconSize
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
iconColor: control.iconColor
iconSource: control.iconSource
}
}
Quick.Component{
id:com_row
RowLayout{
Loader{
sourceComponent: iconDelegate
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
visible: display !== Button.TextOnly
}
Text{
text:control.text
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
visible: display !== Button.IconOnly
color: control.textColor
font: control.font
}
}
}
Quick.Component{
id:com_column
ColumnLayout{
Loader{
sourceComponent: iconDelegate
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
visible: display !== Button.TextOnly
}
Text{
text:control.text
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
visible: display !== Button.IconOnly
color: control.textColor
font: control.font
}
}
}
contentItem:Loader{
sourceComponent: {
if(display === Button.TextUnderIcon){
return com_column
}
return com_row
}
}
Tooltip{
id:tool_tip
visible: {
if(control.text === ""){
return false
}
if(control.display !== Button.IconOnly){
return false
}
return hovered
}
text:control.text
delay: 1000
}
} }

48
Fluent/qml/Image.qml Normal file
View File

@ -0,0 +1,48 @@
import QtQuick
import QtQuick.Controls
import FluentUI
Image {
property string errorButtonText: qsTr("Reload")
property var clickErrorListener : function(){
image.source = ""
image.source = control.source
}
property Component errorItem : com_error
property Component loadingItem: com_loading
id: control
FluLoader{
anchors.fill: parent
sourceComponent: {
if(control.status === Image.Loading){
return com_loading
}else if(control.status == Image.Error){
return com_error
}else{
return undefined
}
}
}
Component{
id:com_loading
Rectangle{
color: FluTheme.itemHoverColor
FluProgressRing{
anchors.centerIn: parent
visible: control.status === Image.Loading
}
}
}
Component{
id:com_error
Rectangle{
color: FluTheme.itemHoverColor
FluFilledButton{
text: control.errorButtonText
anchors.centerIn: parent
visible: control.status === Image.Error
onClicked: clickErrorListener()
}
}
}
}

View File

@ -0,0 +1,17 @@
import QtQuick
import QtQuick.Controls as Controls
Controls.Button{
id:control
property string normalImage: ""
property string hoveredImage: ""
property string pushedImage: ""
background: Item{
implicitHeight: 12
implicitWidth: 12
BorderImage {
anchors.fill: parent
source: control.hovered ? (control.pressed ? control.pushedImage : control.hoveredImage ) : control.normalImage
}
}
}

View File

@ -1,6 +1,5 @@
import QtQuick as Quick import QtQuick as Quick
import QtQuick.Controls import QtQuick.Controls
import Fluent
Object { Object {
property var root property var root
@ -86,7 +85,7 @@ Object {
repeat: duration > 0 repeat: duration > 0
onTriggered: content.close() onTriggered: content.close()
} }
Quick.Loader{ Loader{
id:loader id:loader
x:(parent.width - width) / 2 x:(parent.width - width) / 2
property var _super: content property var _super: content
@ -100,7 +99,6 @@ Object {
} }
} }
sourceComponent:itemcomponent ? itemcomponent : mcontrol.fluent_sytle sourceComponent:itemcomponent ? itemcomponent : mcontrol.fluent_sytle
Quick.Component.onDestruction: sourceComponent = undefined
} }
} }
} }

5
Fluent/qml/Loader.qml Normal file
View File

@ -0,0 +1,5 @@
import QtQuick
Loader {
Component.onDestruction: sourceComponent = undefined
}

View File

@ -1,7 +1,7 @@
import QtQuick import QtQuick
import QtQuick.Controls
QtObject { QtObject {
id:root
default property list<QtObject> children default property list<QtObject> children
id:control
} }

54
Fluent/qml/Popup.qml Normal file
View File

@ -0,0 +1,54 @@
import QtQuick as Quick
import QtQuick.Layouts
import QtQuick.Controls as Controls
import QtQuick.Window
import Fluent
Controls.Popup {
id: control
padding: 0
modal:true
parent: Controls.Overlay.overlay
x: Math.round((d.parentWidth - width) / 2)
y: Math.round((d.parentHeight - height) / 2)
closePolicy: Popup.NoAutoClose
enter: Transition {
NumberAnimation {
property: "opacity"
duration: Theme.animationEnabled ? 83 : 0
from:0
to:1
}
}
height:Math.min(implicitHeight,d.parentHeight)
exit:Transition {
NumberAnimation {
property: "opacity"
duration: Theme.animationEnabled ? 83 : 0
from:1
to:0
}
}
background: Rectangle{
radius: [5,5,5,5]
color: Theme.dark ? Qt.rgba(43/255,43/255,43/255,1) : Qt.rgba(1,1,1,1)
Shadow{
radius: 5
}
}
QtObject{
id:d
property int parentHeight: {
if(control.parent){
return control.parent.height
}
return control.height
}
property int parentWidth: {
if(control.parent){
return control.parent.width
}
return control.width
}
}
}

View File

@ -0,0 +1,92 @@
import QtQuick as Quick
import QtQuick.Controls
import Fluent
ProgressBar{
property int duration: 2000
property real strokeWidth: 6
property bool progressVisible: false
property Quick.color color: FluTheme.primaryColor
property Quick.color backgroundColor : FluTheme.dark ? Qt.rgba(99/255,99/255,99/255,1) : Qt.rgba(214/255,214/255,214/255,1)
id:control
indeterminate : true
clip: true
background: Quick.Rectangle {
implicitWidth: 56
implicitHeight: 56
radius: control.width/2
color:"transparent"
border.color: control.backgroundColor
border.width: control.strokeWidth
}
onIndeterminateChanged:{
canvas.requestPaint()
}
Quick.QtObject{
id:d
property real _radius: control.width/2-control.strokeWidth/2
property real _progress: control.indeterminate ? 0.0 : control.visualPosition
on_ProgressChanged: {
canvas.requestPaint()
}
}
Quick.Connections{
target: FluTheme
function onDarkChanged(){
canvas.requestPaint()
}
}
contentItem: Quick.Item {
id:layout_item
Quick.Canvas {
id:canvas
anchors.fill: parent
antialiasing: true
renderTarget: Canvas.Image
property real startAngle: 0
property real sweepAngle: 0
Quick.SequentialAnimation on startAngle {
loops: Animation.Infinite
running: control.visible && control.indeterminate
Quick.PropertyAnimation { from: 0; to: 450; duration: control.duration/2 }
Quick.PropertyAnimation { from: 450; to: 1080; duration: control.duration/2 }
}
Quick.SequentialAnimation on sweepAngle {
loops: Animation.Infinite
running: control.visible && control.indeterminate
Quick.PropertyAnimation { from: 0; to: 180; duration: control.duration/2 }
Quick.PropertyAnimation { from: 180; to: 0; duration: control.duration/2 }
}
onStartAngleChanged: {
requestPaint()
}
onPaint: {
var ctx = canvas.getContext("2d")
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.save()
ctx.lineWidth = control.strokeWidth
ctx.strokeStyle = control.color
ctx.lineCap = "round"
ctx.beginPath()
if(control.indeterminate){
ctx.arc(width/2, height/2, d._radius , Math.PI * (startAngle - 90) / 180, Math.PI * (startAngle - 90 + sweepAngle) / 180)
}else{
ctx.arc(width/2, height/2, d._radius , -0.5 * Math.PI , -0.5 * Math.PI + d._progress * 2 * Math.PI)
}
ctx.stroke()
ctx.closePath()
ctx.restore()
}
}
}
Text{
text:(control.visualPosition * 100).toFixed(0) + "%"
visible: {
if(control.indeterminate){
return false
}
return control.progressVisible
}
anchors.centerIn: parent
}
}

View File

@ -1,12 +1,71 @@
pragma Singleton pragma Singleton
import QtQuick
import QtQml
QtObject { QtObject {
property var routes : ({})
property var windows: [] property var windows: []
function addWindow(window){ function addWindow(window){
if(!window.transientParent){ if(!window.transientParent){
windows.push(window) windows.push(window)
} }
} }
function removeWindow(win) {
if(!win.transientParent){
var index = windows.indexOf(win)
if (index !== -1) {
windows.splice(index, 1)
win.deleteLater()
}
}
}
function exit(retCode){
for(var i =0 ;i< windows.length; i++){
var win = windows[i]
win.deleteLater()
}
windows = []
Qt.exit(retCode)
}
function navigate(route,argument={},windowRegister = undefined){
if(!routes.hasOwnProperty(route)){
console.error("Not Found Route",route)
return
}
var windowComponent = Qt.createComponent(routes[route])
if (windowComponent.status !== Component.Ready) {
console.error(windowComponent.errorString())
return
}
var properties = {}
properties._route = route
if(windowRegister){
properties._windowRegister = windowRegister
}
properties.argument = argument
var win = undefined
for(var i =0 ;i< windows.length; i++){
var item = windows[i]
if(route === item._route){
win = item
break
}
}
if(win){
var launchMode = win.launchMode
if(launchMode === 1){
win.argument = argument
win.show()
win.raise()
win.requestActivate()
return
}else if(launchMode === 2){
win.close()
}
}
win = windowComponent.createObject(null,properties)
if(windowRegister){
windowRegister._to = win
}
}
} }

187
Fluent/qml/ScrollBar.qml Normal file
View File

@ -0,0 +1,187 @@
import QtQuick
import QtQuick.Controls.impl
import QtQuick.Templates as T
import Fluent
T.ScrollBar {
id: control
property color color : Theme.dark ? Qt.rgba(159/255,159/255,159/255,1) : Qt.rgba(138/255,138/255,138/255,1)
property color pressedColor: Theme.dark ? Qt.darker(color,1.2) : Qt.lighter(color,1.2)
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding)
visible: control.policy !== T.ScrollBar.AlwaysOff
minimumSize: Math.max(orientation === Qt.Horizontal ? height / width : width / height,0.3)
QtObject{
id:d
property int minLine : 2
property int maxLine : 6
}
z: horizontal? 10 : 20
verticalPadding : vertical ? 15 : 3
horizontalPadding : horizontal ? 15 : 3
background: Rectangle{
id:back_rect
radius: 5
color:Theme.dark ? Qt.rgba(44/255,44/255,44/255,1) : Qt.rgba(255/255,255/255,255/255,1)
opacity:{
if(vertical){
return d.maxLine === Number(rect_bar.width)
}
return d.maxLine === Number(rect_bar.height)
}
Behavior on opacity {
NumberAnimation{
duration: 50
}
}
}
IconButton{
width: 12
height: 12
iconSize: 8
verticalPadding: 0
horizontalPadding: 0
visible: control.horizontal
opacity: back_rect.opacity
anchors{
left: parent.left
leftMargin: 2
verticalCenter: parent.verticalCenter
}
iconColor: control.color
iconSource: Icons.CaretLeftSolid8
onClicked: {
control.decrease()
}
}
IconButton{
width: 12
height: 12
iconSize: 8
verticalPadding: 0
horizontalPadding: 0
iconColor: control.color
opacity: back_rect.opacity
anchors{
right: parent.right
rightMargin: 2
verticalCenter: parent.verticalCenter
}
visible: control.horizontal
iconSource: Icons.CaretRightSolid8
onClicked: {
control.increase()
}
}
IconButton{
width: 12
height: 12
iconSize: 8
verticalPadding: 0
horizontalPadding: 0
iconColor: control.color
opacity: back_rect.opacity
anchors{
top: parent.top
topMargin: 2
horizontalCenter: parent.horizontalCenter
}
visible: control.vertical
iconSource: Icons.CaretUpSolid8
onClicked: {
control.decrease()
}
}
IconButton{
width: 12
height: 12
iconSize: 8
verticalPadding: 0
horizontalPadding: 0
iconColor: control.color
opacity: back_rect.opacity
anchors{
bottom: parent.bottom
bottomMargin: 2
horizontalCenter: parent.horizontalCenter
}
visible: control.vertical
iconSource: Icons.CaretDownSolid8
onClicked: {
control.increase()
}
}
contentItem: Item {
property bool collapsed: (control.policy === T.ScrollBar.AlwaysOn || (control.active && control.size < 1.0))
implicitWidth: control.interactive ? d.maxLine : d.minLine
implicitHeight: control.interactive ? d.maxLine : d.minLine
Rectangle{
id:rect_bar
width: vertical ? d.minLine : parent.width
height: horizontal ? d.minLine : parent.height
color:{
if(control.pressed){
return control.pressedColor
}
return control .color
}
anchors{
right: vertical ? parent.right : undefined
bottom: horizontal ? parent.bottom : undefined
}
radius: width / 2
visible: control.size < 1.0
}
states: [
State{
name:"show"
when: contentItem.collapsed
PropertyChanges {
target: rect_bar
width: vertical ? d.maxLine : parent.width
height: horizontal ? d.maxLine : parent.height
}
}
,State{
name:"hide"
when: !contentItem.collapsed
PropertyChanges {
target: rect_bar
width: vertical ? d.minLine : parent.width
height: horizontal ? d.minLine : parent.height
}
}
]
transitions:[
Transition {
to: "hide"
SequentialAnimation {
PauseAnimation { duration: 450 }
NumberAnimation {
target: rect_bar
properties: vertical ? "width" : "height"
duration: 167
easing.type: Easing.OutCubic
}
}
}
,Transition {
to: "show"
SequentialAnimation {
PauseAnimation { duration: 150 }
NumberAnimation {
target: rect_bar
properties: vertical ? "width" : "height"
duration: 167
easing.type: Easing.OutCubic
}
}
}
]
}
}

View File

@ -1,14 +1,15 @@
import QtQuick import QtQuick as Quick
import Fluent
Item { Quick.Item {
property color color: FluTheme.dark ? "#000000" : "#999999" property Quick.color color: Theme.dark ? "#000000" : "#999999"
property int elevation: 5 property int elevation: 5
property int radius: 4 property int radius: 4
id:control id:control
anchors.fill: parent anchors.fill: parent
Repeater{ Quick.Repeater{
model: elevation model: elevation
Rectangle{ Quick.Rectangle{
anchors.fill: parent anchors.fill: parent
color: "#00000000" color: "#00000000"
opacity: 0.01 * (elevation-index+1) opacity: 0.01 * (elevation-index+1)

View File

@ -1,11 +1,10 @@
import QtQuick as Quick import QtQuick as Quick
import Fluent import Fluent
Quick.Text { Quick.Text {
property Quick.color textColor: FluTheme.fontPrimaryColor property Quick.color textColor: Theme.fontPrimaryColor
id:text id:text
color: textColor color: textColor
renderType: FluTheme.nativeText ? Text.NativeRendering : Text.QtRendering renderType: Theme.nativeText ? Text.NativeRendering : Text.QtRendering
font: FluTextStyle.Body font: TextStyle.Body
} }

31
Fluent/qml/Tooltip.qml Normal file
View File

@ -0,0 +1,31 @@
import QtQuick as Quick
import QtQuick.Controls.impl
import QtQuick.Templates as T
import Fluent
T.ToolTip {
id: control
x: parent ? (parent.width - implicitWidth) / 2 : 0
y: -implicitHeight - 3
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
contentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
contentHeight + topPadding + bottomPadding)
margins: 6
padding: 6
font: TextStyle.Body
closePolicy: T.Popup.CloseOnEscape | T.Popup.CloseOnPressOutsideParent | T.Popup.CloseOnReleaseOutsideParent
contentItem: Text {
text: control.text
font: control.font
wrapMode: Text.Wrap
}
background: Quick.Rectangle {
color: Theme.dark ? Qt.rgba(50/255,49/255,48/255,1) : Qt.rgba(1,1,1,1)
radius: 3
Shadow{
radius: 3
}
}
}

View File

@ -1,40 +1,117 @@
import QtQuick as Quick import QtQuick as Quick
import QtQuick.Controls
import QtQuick.Layouts
import Fluent import Fluent
Quick.Window { Quick.Window {
id: root id: window
default property alias contentData : layout_content.data
property string windowIcon: App.windowIcon property string windowIcon: App.windowIcon
property bool showStayTop: false property int launchMode: WindowType.Standard
property bool showMaximize: true property var argument:({})
property bool showMinimize: true
property bool showClose: true
property bool showDark: false
property bool fixSize: false
property bool stayTop: false
property int __margins: 0
property var background : com_background property var background : com_background
property bool fixSize: false
property Quick.Component loadingItem: com_loading
property bool fitsAppBarWindows: false
property var tintOpacity: Theme.dark ? 0.80 : 0.75
property int blurRadius: 60
property alias effect: frameless.effect
readonly property alias effective: frameless.effective
readonly property var availableEffects: frameless.availableEffects
property Quick.Item appBar: AppBar {
title: window.title
height: 30
showDark: window.showDark
showClose: window.showClose
showMinimize: window.showMinimize
showMaximize: window.showMaximize
showStayTop: window.showStayTop
icon: window.windowIcon
}
property Quick.color backgroundColor: { property Quick.color backgroundColor: {
if(frameless.effective && active){
var backcolor
if(frameless.effect==="dwm-blur"){
backcolor = Utilities.withOpacity(Theme.windowActiveBackgroundColor, window.tintOpacity)
}else{
backcolor = "transparent"
}
return backcolor
}
if(active){ if(active){
return Theme.windowActiveBackgroundColor return Theme.windowActiveBackgroundColor
} }
return Theme.windowBackgroundColor return Theme.windowBackgroundColor
} }
property Quick.Item appBar: AppBar { property bool stayTop: false
title: root.title property bool showDark: false
height: 30 property bool showClose: true
showDark: root.showDark property bool showMinimize: true
showClose: root.showClose property bool showMaximize: true
showMinimize: root.showMinimize property bool showStayTop: false
showMaximize: root.showMaximize property bool autoMaximize: false
showStayTop: root.showStayTop property bool autoVisible: true
icon: root.windowIcon property bool autoCenter: true
property bool autoDestroy: true
property bool useSystemAppBar
property int __margins: 0
property Quick.color resizeBorderColor: {
if(window.active){
return Theme.dark ? Qt.rgba(51/255,51/255,51/255,1) : Qt.rgba(110/255,110/255,110/255,1)
}
return Theme.dark ? Qt.rgba(61/255,61/255,61/255,1) : Qt.rgba(167/255,167/255,167/255,1)
}
property int resizeBorderWidth: 1
property var closeListener: function(event){
if(autoDestroy){
Router.removeWindow(window)
}else{
window.visibility = Window.Hidden
event.accepted = false
}
}
signal initArgument(var argument)
signal lazyLoad()
property var _windowRegister
property string _route
property bool _hideShadow: false
color: Utilities.isSoftware() ? window.backgroundColor : "transparent"
Quick.Component.onCompleted: {
Router.addWindow(window)
useSystemAppBar = App.useSystemAppBar
if(!useSystemAppBar && autoCenter){
moveWindowToDesktopCenter()
}
fixWindowSize()
initArgument(argument)
if(window.autoVisible){
if(window.autoMaximize){
window.visibility = Window.Maximized
}else{
window.show()
}
}
}
onVisibleChanged: {
if(visible && d.isLazyInit){
window.lazyLoad()
d.isLazyInit = false
}
}
Quick.QtObject{
id:d
property bool isLazyInit: true
}
Quick.Connections{
target: window
function onClosing(event){closeListener(event)}
} }
Frameless{ Frameless{
id: frameless id: frameless
appBar: root.appBar appBar: window.appBar
maximizeButton: appBar.buttonMaximize maximizeButton: appBar.buttonMaximize
fixSize: root.fixSize fixSize: window.fixSize
topmost: root.stayTop topmost: window.stayTop
disabled: App.useSystemAppBar disabled: App.useSystemAppBar
Quick.Component.onCompleted: { Quick.Component.onCompleted: {
frameless.setHitTestVisible(appBar.layoutMacosButtons) frameless.setHitTestVisible(appBar.layoutMacosButtons)
@ -43,90 +120,18 @@ Quick.Window {
Quick.Component.onDestruction: { Quick.Component.onDestruction: {
frameless.onDestruction() frameless.onDestruction()
} }
} onEffectiveChanged: {
Quick.Component.onCompleted: { if(effective){
Router.addWindow(root) Theme.blurBehindWindowEnabled = false
}
Quick.Component {
id:com_app_bar
Quick.Item{
data: root.appBar
Quick.Component.onCompleted: {
root.appBar.width = Qt.binding(function(){
return this.parent.width
})
} }
} }
} }
Quick.Item{
id: layout_container
anchors.fill: parent
anchors.margins: root.__margins
Quick.Loader{
anchors.fill: parent
sourceComponent: background
Quick.Component.onDestruction: sourceComponent = undefined
}
Quick.Loader{
id:loader_app_bar
anchors {
top: parent.top
left: parent.left
right: parent.right
}
height: {
if(root.useSystemAppBar){
return 0
}
return root.fitsAppBarWindows ? 0 : root.appBar.height
}
sourceComponent: root.useSystemAppBar ? undefined : com_app_bar
Quick.Component.onDestruction: sourceComponent = undefined
}
Quick.Item{
id:layout_content
anchors{
top: loader_app_bar.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
}
clip: true
}
Quick.Loader{
property string loadingText
property bool cancel: false
id:loader_loading
anchors.fill: parent
Quick.Component.onDestruction: sourceComponent = undefined
}
InfoBar{
id:info_bar
root: layout_container
}
Quick.Loader{
id:loader_border
anchors.fill: parent
sourceComponent: {
if(root.useSystemAppBar || Utilities.isWin() || root.visibility === Window.Maximized || root.visibility === Window.FullScreen){
return undefined
}
return com_border
}
Quick.Component.onDestruction: sourceComponent = undefined
}
}
Quick.Component{ Quick.Component{
id:com_background id:com_background
Quick.Item{ Quick.Item{
Rectangle{ Quick.Rectangle{
anchors.fill: parent anchors.fill: parent
color: root.backgroundColor color: window.backgroundColor
} }
Quick.Image{ Quick.Image{
id:img_back id:img_back
@ -139,13 +144,13 @@ Quick.Window {
source = Utilities.getUrlByFilePath(Theme.desktopImagePath) source = Utilities.getUrlByFilePath(Theme.desktopImagePath)
} }
Quick.Connections{ Quick.Connections{
target: root target: window
function onScreenChanged(){ function onScreenChanged(){
img_back.updateLayout() img_back.updateLayout()
} }
} }
function updateLayout(){ function updateLayout(){
var geometry = Utilities.desktopAvailableGeometry(root) var geometry = Utilities.desktopAvailableGeometry(window)
img_back.width = geometry.width img_back.width = geometry.width
img_back.height = geometry.height img_back.height = geometry.height
img_back.sourceSize = Qt.size(img_back.width,img_back.height) img_back.sourceSize = Qt.size(img_back.width,img_back.height)
@ -175,12 +180,208 @@ Quick.Window {
Acrylic{ Acrylic{
anchors.fill: parent anchors.fill: parent
target: img_back target: img_back
tintOpacity: Theme.dark ? 0.80 : 0.75 tintOpacity: window.tintOpacity
blurRadius: 64 blurRadius: window.blurRadius
visible: root.active && Theme.blurBehindWindowEnabled visible: window.active && Theme.blurBehindWindowEnabled
tintColor: Theme.dark ? Qt.rgba(0, 0, 0, 1) : Qt.rgba(1, 1, 1, 1) tintColor: Theme.dark ? Qt.rgba(0, 0, 0, 1) : Qt.rgba(1, 1, 1, 1)
targetRect: Qt.rect(root.x-root.screen.virtualX,root.y-root.screen.virtualY,root.width,root.height) targetRect: Qt.rect(window.x-window.screen.virtualX,window.y-window.screen.virtualY,window.width,window.height)
}
}
}
Quick.Component{
id:com_app_bar
Quick.Item{
data: window.appBar
Quick.Component.onCompleted: {
window.appBar.width = Qt.binding(function(){
return this.parent.width
})
}
}
}
Quick.Component{
id:com_loading
Popup{
id:popup_loading
focus: true
width: window.width
height: window.height
anchors.centerIn: Overlay.overlay
closePolicy: {
if(cancel){
return Popup.CloseOnEscape | Popup.CloseOnPressOutside
}
return Popup.NoAutoClose
}
Overlay.modal: Quick.Item {}
onVisibleChanged: {
if(!visible){
loader_loading.sourceComponent = undefined
}
}
padding: 0
opacity: 0
visible:true
Quick.Behavior on opacity {
Quick.SequentialAnimation {
Quick.PauseAnimation {
duration: 83
}
Quick.NumberAnimation{
duration: 167
}
}
}
Quick.Component.onCompleted: {
opacity = 1
}
background: Quick.Rectangle{
color:"#44000000"
}
contentItem: Quick.Item{
Quick.MouseArea{
anchors.fill: parent
onClicked: {
if (cancel){
popup_loading.visible = false
}
}
}
ColumnLayout{
spacing: 8
anchors.centerIn: parent
ProgressRing{
Layout.alignment: Qt.AlignHCenter
}
Text{
text:loadingText
Layout.alignment: Qt.AlignHCenter
} }
} }
} }
} }
}
Quick.Component{
id:com_border
Quick.Rectangle{
color:"transparent"
border.width: window.resizeBorderWidth
border.color: window.resizeBorderColor
}
}
Quick.Item{
id: layout_container
anchors.fill: parent
anchors.margins: window.__margins
Loader{
anchors.fill: parent
sourceComponent: background
}
Loader{
id:loader_app_bar
anchors {
top: parent.top
left: parent.left
right: parent.right
}
height: {
if(window.useSystemAppBar){
return 0
}
return window.fitsAppBarWindows ? 0 : window.appBar.height
}
sourceComponent: window.useSystemAppBar ? undefined : com_app_bar
}
Quick.Item{
id: layout_content
anchors{
top: loader_app_bar.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
}
clip: true
}
Loader{
property string loadingText
property bool cancel: false
id:loader_loading
anchors.fill: parent
}
InfoBar{
id:info_bar
root: layout_container
}
Loader{
id:loader_border
anchors.fill: parent
sourceComponent: {
if(window.useSystemAppBar || Utilities.isWin() || window.visibility === Window.Maximized || window.visibility === Window.FullScreen){
return undefined
}
return com_border
}
}
}
function hideLoading(){
loader_loading.sourceComponent = undefined
}
function showSuccess(text,duration,moremsg){
return info_bar.showSuccess(text,duration,moremsg)
}
function showInfo(text,duration,moremsg){
return info_bar.showInfo(text,duration,moremsg)
}
function showWarning(text,duration,moremsg){
return info_bar.showWarning(text,duration,moremsg)
}
function showError(text,duration,moremsg){
return info_bar.showError(text,duration,moremsg)
}
function clearAllInfo(){
return info_bar.clearAllInfo()
}
function moveWindowToDesktopCenter(){
var availableGeometry = Utilities.desktopAvailableGeometry(window)
window.setGeometry((availableGeometry.width-window.width)/2+Quick.Screen.virtualX,(availableGeometry.height-window.height)/2+Quick.Screen.virtualY,window.width,window.height)
}
function fixWindowSize(){
if(fixSize){
window.maximumWidth = window.width
window.maximumHeight = window.height
window.minimumWidth = window.width
window.minimumHeight = window.height
}
}
function setResult(data){
if(_windowRegister){
_windowRegister.setResult(data)
}
}
function showMaximized(){
frameless.showMaximized()
}
function showMinimized(){
frameless.showMinimized()
}
function showNormal(){
frameless.showNormal()
}
function showLoading(text = "",cancel = true){
if(text===""){
text = qsTr("Loading...")
}
loader_loading.loadingText = text
loader_loading.cancel = cancel
loader_loading.sourceComponent = com_loading
}
function setHitTestVisible(val){
frameless.setHitTestVisible(val)
}
function deleteLater(){
Utilities.deleteLater(window)
}
function containerItem(){
return layout_container
}
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB