add basic.
@ -2,10 +2,12 @@
|
||||
#include "Rectangle.h"
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQuickStyle>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
LOG(info) << "app start...";
|
||||
QGuiApplication app(argc, argv);
|
||||
QQuickStyle::setStyle("Basic");
|
||||
QQmlApplicationEngine engine;
|
||||
QObject::connect(
|
||||
&engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); },
|
||||
|
4
Fluent/AccentColor.cpp
Normal file
@ -0,0 +1,4 @@
|
||||
#include "AccentColor.h"
|
||||
|
||||
AccentColor::AccentColor(QObject *parent) : QObject{parent} {
|
||||
}
|
22
Fluent/AccentColor.h
Normal 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__
|
@ -1,5 +1,5 @@
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Gui Quick)
|
||||
find_package(Qt${QT_VERSION_MAJOR} 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 QuickControls2)
|
||||
|
||||
qt_standard_project_setup(REQUIRES 6.5)
|
||||
|
||||
@ -16,25 +16,41 @@ qt6_add_qml_module(Fluent
|
||||
URI Fluent
|
||||
VERSION 1.0
|
||||
SOURCES
|
||||
AccentColor.h AccentColor.cpp
|
||||
App.h App.cpp
|
||||
CircularReveal.h CircularReveal.cpp
|
||||
Colors.h Colors.cpp
|
||||
Frameless.h Frameless.cpp
|
||||
Icons.h
|
||||
Rectangle.h Rectangle.cpp
|
||||
TextStyle.h TextStyle.cpp
|
||||
Theme.h Theme.cpp
|
||||
Utilities.h Utilities.cpp
|
||||
QML_FILES
|
||||
qml/Acrylic.qml
|
||||
qml/AppBar.qml
|
||||
qml/Button.qml
|
||||
qml/ContentDialog.qml
|
||||
qml/ControlBackground.qml
|
||||
qml/FilledButton.qml
|
||||
qml/FocusRectangle.qml
|
||||
qml/Icon.qml
|
||||
qml/IconButton.qml
|
||||
qml/ImageButton.qml
|
||||
qml/InfoBar.qml
|
||||
qml/Loader.qml
|
||||
qml/Object.qml
|
||||
qml/Popup.qml
|
||||
qml/ProgressRing.qml
|
||||
qml/Router.qml
|
||||
qml/ScrollBar.qml
|
||||
qml/Shadow.qml
|
||||
qml/Text.qml
|
||||
qml/Tooltip.qml
|
||||
qml/Window.qml
|
||||
RESOURCES
|
||||
resources/noise.png
|
||||
resources/FluentIcons.ttf
|
||||
)
|
||||
|
||||
target_include_directories(Fluent
|
||||
@ -44,4 +60,5 @@ target_include_directories(Fluent
|
||||
target_link_libraries(Fluent
|
||||
PUBLIC Qt${QT_VERSION_MAJOR}::Gui
|
||||
PRIVATE Qt${QT_VERSION_MAJOR}::Quick
|
||||
INTERFACE Qt${QT_VERSION_MAJOR}::QuickControls2
|
||||
)
|
||||
|
66
Fluent/CircularReveal.cpp
Normal 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 ¢er, 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
@ -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 ¢er, 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
@ -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
@ -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__
|
@ -1,4 +1,5 @@
|
||||
#include "Frameless.h"
|
||||
#include "Theme.h"
|
||||
#include "Utilities.h"
|
||||
#include <QQuickWindow>
|
||||
#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) {
|
||||
auto window = item->window();
|
||||
if ((window == nullptr) || !item || !item->isVisible()) {
|
||||
@ -32,8 +148,189 @@ static bool containsCursorToItem(QQuickItem *item) {
|
||||
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} {
|
||||
m_isWindows11OrGreater = Utilities::instance()->isWindows11OrGreater();
|
||||
m_effect = "normal";
|
||||
}
|
||||
|
||||
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() {
|
||||
QGuiApplication::instance()->removeNativeEventFilter(this);
|
||||
}
|
||||
|
||||
void Frameless::componentComplete() {
|
||||
if (m_disabled) return;
|
||||
if (m_disabled) {
|
||||
return;
|
||||
}
|
||||
int w = window()->width();
|
||||
int h = window()->height();
|
||||
m_current = window()->winId();
|
||||
@ -150,8 +471,12 @@ void Frameless::componentComplete() {
|
||||
#endif
|
||||
HWND hwnd = reinterpret_cast<HWND>(window()->winId());
|
||||
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) {
|
||||
::SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_THICKFRAME | WS_CAPTION);
|
||||
;
|
||||
for (int i = 0; i <= QGuiApplication::screens().count() - 1; ++i) {
|
||||
connect(QGuiApplication::screens().at(i), &QScreen::logicalDotsPerInchChanged, this, [=] {
|
||||
SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
|
||||
@ -171,6 +496,42 @@ void Frameless::componentComplete() {
|
||||
if (!window()->property("_hideShadow").toBool()) {
|
||||
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
|
||||
auto appBarHeight = m_appBar->height();
|
||||
h = qRound(h + appBarHeight);
|
||||
|
@ -1,12 +1,16 @@
|
||||
#ifndef FRAMELESS_H
|
||||
#define FRAMELESS_H
|
||||
|
||||
#include "Utilities.h"
|
||||
#include <QAbstractNativeEventFilter>
|
||||
#include <QQuickItem>
|
||||
|
||||
class Frameless : public QQuickItem, QAbstractNativeEventFilter {
|
||||
Q_OBJECT
|
||||
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 *maximizeButton READ maximizeButton WRITE setMaximizeButton NOTIFY maximizeButtonChanged)
|
||||
Q_PROPERTY(QQuickItem *minimizedButton READ minimizedButton WRITE setMinimizedButton NOTIFY minimizedButtonChanged)
|
||||
@ -39,6 +43,10 @@ public:
|
||||
bool disabled() const;
|
||||
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 onDestruction();
|
||||
void componentComplete() final;
|
||||
@ -77,6 +85,7 @@ private:
|
||||
int m_margins = 8;
|
||||
QList<QPointer<QQuickItem>> m_hitTestList;
|
||||
bool m_isWindows11OrGreater = false;
|
||||
QString m_currentEffect;
|
||||
};
|
||||
|
||||
#endif // FRAMELESS_H
|
||||
|
48
Fluent/TextStyle.cpp
Normal 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
@ -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__
|
100
Fluent/Theme.cpp
@ -1,6 +1,56 @@
|
||||
#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} {
|
||||
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 {
|
||||
@ -79,3 +129,53 @@ void Theme::setBlurBehindWindowEnabled(bool enabled) {
|
||||
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();
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
#ifndef THEME_H
|
||||
#define THEME_H
|
||||
|
||||
#include "AccentColor.h"
|
||||
#include "Utilities.h"
|
||||
#include <QColor>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
|
||||
@ -9,7 +13,21 @@ class Theme : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
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_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 itemHoverColor READ itemHoverColor WRITE setItemHoverColor NOTIFY itemHoverColorChanged)
|
||||
|
||||
@ -23,7 +41,9 @@ class Theme : public QObject {
|
||||
blurBehindWindowEnabledChanged)
|
||||
|
||||
public:
|
||||
Theme(QObject *parent = nullptr);
|
||||
static Theme *instance();
|
||||
static Theme *create(QQmlEngine *, QJSEngine *);
|
||||
bool dark() const;
|
||||
|
||||
QColor fontPrimaryColor() const;
|
||||
void setFontPrimaryColor(const QColor &color);
|
||||
@ -47,6 +67,7 @@ public:
|
||||
void setBlurBehindWindowEnabled(bool enabled);
|
||||
|
||||
signals:
|
||||
void darkChanged();
|
||||
void fontPrimaryColorChanged();
|
||||
void itemNormalColorChanged();
|
||||
void windowBackgroundColorChanged();
|
||||
@ -55,7 +76,17 @@ signals:
|
||||
void blurBehindWindowEnabledChanged();
|
||||
void itemHoverColorChanged();
|
||||
|
||||
protected:
|
||||
Theme(QObject *parent = nullptr);
|
||||
void refreshColors();
|
||||
void checkUpdateDesktopImage();
|
||||
void timerEvent(QTimerEvent *event) final;
|
||||
bool eventFilter(QObject *obj, QEvent *event) final;
|
||||
|
||||
private:
|
||||
bool m_systemDark = false;
|
||||
QMutex m_mutex;
|
||||
QFileSystemWatcher m_watcher;
|
||||
QColor m_fontPrimaryColor;
|
||||
QColor m_itemNormalColor;
|
||||
QColor m_itemHoverColor;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "Utilities.h"
|
||||
#include <QSettings>
|
||||
#include <qt_windows.h>
|
||||
|
||||
Utilities *Utilities::instance() {
|
||||
static Utilities *self = nullptr;
|
||||
@ -18,10 +19,70 @@ Utilities *Utilities::create(QQmlEngine *, QJSEngine *) {
|
||||
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) {
|
||||
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) {
|
||||
return QUrl::fromLocalFile(path);
|
||||
}
|
||||
|
@ -5,6 +5,84 @@
|
||||
#include <QQmlEngine>
|
||||
#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 {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
@ -18,6 +96,10 @@ public:
|
||||
Q_INVOKABLE bool isMacos();
|
||||
Q_INVOKABLE QRect desktopAvailableGeometry(QQuickWindow *window);
|
||||
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:
|
||||
Utilities(QObject *parent = nullptr);
|
||||
|
@ -1,26 +1,88 @@
|
||||
import QtQuick as Quick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Window
|
||||
import QtQuick.Layouts
|
||||
import Fluent
|
||||
|
||||
Quick.Rectangle {
|
||||
id: root
|
||||
Quick.Rectangle{
|
||||
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 showMaximize: true
|
||||
property bool showClose: true
|
||||
property bool showStayTop: true
|
||||
property bool showDark: false
|
||||
property string title: ""
|
||||
property bool titleVisible: true
|
||||
property url icon
|
||||
property string maximizeText : qsTr("Maximize")
|
||||
property Quick.color textColor: Theme.fontPrimaryColor
|
||||
property Quick.color maximizeNormalColor: Theme.itemNormalColor
|
||||
property Quick.color maximizeHoverColor: Theme.itemHoverColor
|
||||
property int iconSize: 20
|
||||
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 buttonClose: btn_close
|
||||
property alias buttonDark: btn_dark
|
||||
property alias layoutMacosButtons: layout_macos_buttons
|
||||
property alias layoutStandardbuttons: layout_standard_buttons
|
||||
|
||||
Quick.Item{
|
||||
property var maxClickListener : function(){
|
||||
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
|
||||
property var hitTestList: []
|
||||
property bool hoverMaxBtn: false
|
||||
@ -42,13 +104,125 @@ Quick.Rectangle {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
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{
|
||||
id:layout_standard_buttons
|
||||
height: parent.height
|
||||
anchors.right: parent.right
|
||||
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{
|
||||
id:btn_maximize
|
||||
property bool hover: btn_maximize.hovered
|
||||
@ -67,14 +241,35 @@ Quick.Rectangle {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
visible: d.resizable && !isMac && showMaximize
|
||||
radius: 0
|
||||
iconColor: root.textColor
|
||||
iconColor: control.textColor
|
||||
text:d.isRestore?restoreText:maximizeText
|
||||
iconSize: 11
|
||||
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
|
||||
}
|
||||
onClicked: closeClickListener()
|
||||
}
|
||||
}
|
||||
|
||||
Quick.Loader{
|
||||
Loader{
|
||||
id:layout_macos_buttons
|
||||
anchors{
|
||||
verticalCenter: parent.verticalCenter
|
||||
@ -82,6 +277,5 @@ Quick.Rectangle {
|
||||
leftMargin: 10
|
||||
}
|
||||
sourceComponent: isMac ? com_macos_buttons : undefined
|
||||
Quick.Component.onDestruction: sourceComponent = undefined
|
||||
}
|
||||
}
|
||||
|
64
Fluent/qml/Button.qml
Normal 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
|
||||
}
|
||||
}
|
164
Fluent/qml/ContentDialog.qml
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
52
Fluent/qml/ControlBackground.qml
Normal 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
|
||||
}
|
||||
}
|
60
Fluent/qml/FilledButton.qml
Normal 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
|
||||
}
|
||||
}
|
20
Fluent/qml/FocusRectangle.qml
Normal 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
|
||||
}
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Fluent
|
||||
|
||||
Text {
|
||||
property int iconSource
|
||||
property int iconSize: 20
|
||||
property color iconColor: FluTheme.dark ? "#FFFFFF" : "#000000"
|
||||
property color iconColor: Theme.dark ? "#FFFFFF" : "#000000"
|
||||
id:control
|
||||
font.family: font_loader.name
|
||||
font.pixelSize: iconSize
|
||||
@ -14,6 +16,6 @@ Text {
|
||||
opacity: iconSource>0
|
||||
FontLoader{
|
||||
id: font_loader
|
||||
source: "qrc:/qt/qml/FluentUI/Font/FluentIcons.ttf"
|
||||
source: "qrc:/qt/qml/Fluent/resources/FluentIcons.ttf"
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,21 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick as Quick
|
||||
import QtQuick.Controls as Controls
|
||||
import QtQuick.Layouts
|
||||
import Fluent
|
||||
|
||||
Button {
|
||||
Controls.Button {
|
||||
display: Controls.Button.IconOnly
|
||||
property int iconSize: 20
|
||||
property int iconSource
|
||||
property bool disabled: false
|
||||
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){
|
||||
return disableColor
|
||||
}
|
||||
@ -14,17 +24,106 @@ Button {
|
||||
}
|
||||
return hovered ? hoverColor : normalColor
|
||||
}
|
||||
property color iconColor: {
|
||||
if (FluTheme.dark) {
|
||||
if (!enabled) {
|
||||
return Qt.rgba(130 / 255, 130 / 255, 130 / 255, 1)
|
||||
property Quick.color iconColor: {
|
||||
if(Theme.dark){
|
||||
if(!enabled){
|
||||
return Qt.rgba(130/255,130/255,130/255,1)
|
||||
}
|
||||
return Qt.rgba(1, 1, 1, 1)
|
||||
} else {
|
||||
if (!enabled) {
|
||||
return Qt.rgba(161 / 255, 161 / 255, 161 / 255, 1)
|
||||
return Qt.rgba(1,1,1,1)
|
||||
}else{
|
||||
if(!enabled){
|
||||
return Qt.rgba(161/255,161/255,161/255,1)
|
||||
}
|
||||
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
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
17
Fluent/qml/ImageButton.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
import QtQuick as Quick
|
||||
import QtQuick.Controls
|
||||
import Fluent
|
||||
|
||||
Object {
|
||||
property var root
|
||||
@ -39,7 +38,7 @@ Object {
|
||||
screenLayout.z = 100000
|
||||
}
|
||||
}
|
||||
Quick.Component {
|
||||
Quick.Component{
|
||||
id:screenlayoutComponent
|
||||
Quick.Column{
|
||||
parent: Overlay.overlay
|
||||
@ -86,7 +85,7 @@ Object {
|
||||
repeat: duration > 0
|
||||
onTriggered: content.close()
|
||||
}
|
||||
Quick.Loader{
|
||||
Loader{
|
||||
id:loader
|
||||
x:(parent.width - width) / 2
|
||||
property var _super: content
|
||||
@ -100,7 +99,6 @@ Object {
|
||||
}
|
||||
}
|
||||
sourceComponent:itemcomponent ? itemcomponent : mcontrol.fluent_sytle
|
||||
Quick.Component.onDestruction: sourceComponent = undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -126,7 +124,7 @@ Object {
|
||||
return Qt.rgba(1,1,1,1)
|
||||
}
|
||||
}
|
||||
Shadow {
|
||||
Shadow{
|
||||
radius: 4
|
||||
}
|
||||
radius: 4
|
||||
|
5
Fluent/qml/Loader.qml
Normal file
@ -0,0 +1,5 @@
|
||||
import QtQuick
|
||||
|
||||
Loader {
|
||||
Component.onDestruction: sourceComponent = undefined
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
QtObject {
|
||||
id:root
|
||||
default property list<QtObject> children
|
||||
|
||||
id:control
|
||||
}
|
||||
|
54
Fluent/qml/Popup.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
92
Fluent/qml/ProgressRing.qml
Normal 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
|
||||
}
|
||||
}
|
@ -1,12 +1,71 @@
|
||||
pragma Singleton
|
||||
import QtQuick
|
||||
|
||||
import QtQml
|
||||
|
||||
QtObject {
|
||||
property var routes : ({})
|
||||
property var windows: []
|
||||
function addWindow(window){
|
||||
if(!window.transientParent){
|
||||
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
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -1,14 +1,15 @@
|
||||
import QtQuick
|
||||
import QtQuick as Quick
|
||||
import Fluent
|
||||
|
||||
Item {
|
||||
property color color: FluTheme.dark ? "#000000" : "#999999"
|
||||
Quick.Item {
|
||||
property Quick.color color: Theme.dark ? "#000000" : "#999999"
|
||||
property int elevation: 5
|
||||
property int radius: 4
|
||||
id:control
|
||||
anchors.fill: parent
|
||||
Repeater{
|
||||
Quick.Repeater{
|
||||
model: elevation
|
||||
Rectangle{
|
||||
Quick.Rectangle{
|
||||
anchors.fill: parent
|
||||
color: "#00000000"
|
||||
opacity: 0.01 * (elevation-index+1)
|
||||
|
@ -1,11 +1,10 @@
|
||||
import QtQuick as Quick
|
||||
|
||||
import Fluent
|
||||
|
||||
Quick.Text {
|
||||
property Quick.color textColor: FluTheme.fontPrimaryColor
|
||||
property Quick.color textColor: Theme.fontPrimaryColor
|
||||
id:text
|
||||
color: textColor
|
||||
renderType: FluTheme.nativeText ? Text.NativeRendering : Text.QtRendering
|
||||
font: FluTextStyle.Body
|
||||
renderType: Theme.nativeText ? Text.NativeRendering : Text.QtRendering
|
||||
font: TextStyle.Body
|
||||
}
|
||||
|
31
Fluent/qml/Tooltip.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
@ -1,40 +1,117 @@
|
||||
import QtQuick as Quick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Fluent
|
||||
|
||||
Quick.Window {
|
||||
id: root
|
||||
id: window
|
||||
default property alias contentData : layout_content.data
|
||||
property string windowIcon: App.windowIcon
|
||||
property bool showStayTop: false
|
||||
property bool showMaximize: true
|
||||
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 int launchMode: WindowType.Standard
|
||||
property var argument:({})
|
||||
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: {
|
||||
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){
|
||||
return Theme.windowActiveBackgroundColor
|
||||
}
|
||||
return Theme.windowBackgroundColor
|
||||
}
|
||||
property Quick.Item appBar: AppBar {
|
||||
title: root.title
|
||||
height: 30
|
||||
showDark: root.showDark
|
||||
showClose: root.showClose
|
||||
showMinimize: root.showMinimize
|
||||
showMaximize: root.showMaximize
|
||||
showStayTop: root.showStayTop
|
||||
icon: root.windowIcon
|
||||
property bool stayTop: false
|
||||
property bool showDark: false
|
||||
property bool showClose: true
|
||||
property bool showMinimize: true
|
||||
property bool showMaximize: true
|
||||
property bool showStayTop: false
|
||||
property bool autoMaximize: false
|
||||
property bool autoVisible: true
|
||||
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)
|
||||
}
|
||||
Frameless {
|
||||
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{
|
||||
id: frameless
|
||||
appBar: root.appBar
|
||||
appBar: window.appBar
|
||||
maximizeButton: appBar.buttonMaximize
|
||||
fixSize: root.fixSize
|
||||
topmost: root.stayTop
|
||||
fixSize: window.fixSize
|
||||
topmost: window.stayTop
|
||||
disabled: App.useSystemAppBar
|
||||
Quick.Component.onCompleted: {
|
||||
frameless.setHitTestVisible(appBar.layoutMacosButtons)
|
||||
@ -43,90 +120,18 @@ Quick.Window {
|
||||
Quick.Component.onDestruction: {
|
||||
frameless.onDestruction()
|
||||
}
|
||||
}
|
||||
Quick.Component.onCompleted: {
|
||||
Router.addWindow(root)
|
||||
}
|
||||
|
||||
Quick.Component {
|
||||
id:com_app_bar
|
||||
Quick.Item{
|
||||
data: root.appBar
|
||||
Quick.Component.onCompleted: {
|
||||
root.appBar.width = Qt.binding(function(){
|
||||
return this.parent.width
|
||||
})
|
||||
onEffectiveChanged: {
|
||||
if(effective){
|
||||
Theme.blurBehindWindowEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
Quick.Item{
|
||||
Rectangle{
|
||||
Quick.Rectangle{
|
||||
anchors.fill: parent
|
||||
color: root.backgroundColor
|
||||
color: window.backgroundColor
|
||||
}
|
||||
Quick.Image{
|
||||
id:img_back
|
||||
@ -134,18 +139,18 @@ Quick.Window {
|
||||
cache: false
|
||||
fillMode: Quick.Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
Quick.Component.onCompleted: {
|
||||
Quick.Component.onCompleted: {
|
||||
img_back.updateLayout()
|
||||
source = Utilities.getUrlByFilePath(Theme.desktopImagePath)
|
||||
}
|
||||
Quick.Connections{
|
||||
target: root
|
||||
target: window
|
||||
function onScreenChanged(){
|
||||
img_back.updateLayout()
|
||||
}
|
||||
}
|
||||
function updateLayout(){
|
||||
var geometry = Utilities.desktopAvailableGeometry(root)
|
||||
var geometry = Utilities.desktopAvailableGeometry(window)
|
||||
img_back.width = geometry.width
|
||||
img_back.height = geometry.height
|
||||
img_back.sourceSize = Qt.size(img_back.width,img_back.height)
|
||||
@ -175,12 +180,208 @@ Quick.Window {
|
||||
Acrylic{
|
||||
anchors.fill: parent
|
||||
target: img_back
|
||||
tintOpacity: Theme.dark ? 0.80 : 0.75
|
||||
blurRadius: 64
|
||||
visible: root.active && Theme.blurBehindWindowEnabled
|
||||
tintOpacity: window.tintOpacity
|
||||
blurRadius: window.blurRadius
|
||||
visible: window.active && Theme.blurBehindWindowEnabled
|
||||
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
|
||||
}
|
||||
}
|
||||
|
BIN
Fluent/resources/FluentIcons.ttf
Normal file
BIN
Fluent/resources/btn_close_hovered.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
Fluent/resources/btn_close_normal.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
Fluent/resources/btn_close_pushed.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
Fluent/resources/btn_max_hovered.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
Fluent/resources/btn_max_normal.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
Fluent/resources/btn_max_pushed.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
Fluent/resources/btn_min_hovered.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
Fluent/resources/btn_min_normal.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
Fluent/resources/btn_min_pushed.png
Normal file
After Width: | Height: | Size: 10 KiB |