add basic.
@ -2,10 +2,12 @@
|
|||||||
#include "Rectangle.h"
|
#include "Rectangle.h"
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
|
#include <QQuickStyle>
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
LOG(info) << "app start...";
|
LOG(info) << "app start...";
|
||||||
QGuiApplication app(argc, argv);
|
QGuiApplication app(argc, argv);
|
||||||
|
QQuickStyle::setStyle("Basic");
|
||||||
QQmlApplicationEngine engine;
|
QQmlApplicationEngine engine;
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
&engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); },
|
&engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); },
|
||||||
|
4
Fluent/AccentColor.cpp
Normal file
@ -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 NAMES Qt6 Qt5 REQUIRED COMPONENTS Gui Quick QuickControls2)
|
||||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Gui Quick)
|
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Gui Quick QuickControls2)
|
||||||
|
|
||||||
qt_standard_project_setup(REQUIRES 6.5)
|
qt_standard_project_setup(REQUIRES 6.5)
|
||||||
|
|
||||||
@ -16,25 +16,41 @@ qt6_add_qml_module(Fluent
|
|||||||
URI Fluent
|
URI Fluent
|
||||||
VERSION 1.0
|
VERSION 1.0
|
||||||
SOURCES
|
SOURCES
|
||||||
|
AccentColor.h AccentColor.cpp
|
||||||
App.h App.cpp
|
App.h App.cpp
|
||||||
|
CircularReveal.h CircularReveal.cpp
|
||||||
|
Colors.h Colors.cpp
|
||||||
Frameless.h Frameless.cpp
|
Frameless.h Frameless.cpp
|
||||||
Icons.h
|
Icons.h
|
||||||
Rectangle.h Rectangle.cpp
|
Rectangle.h Rectangle.cpp
|
||||||
|
TextStyle.h TextStyle.cpp
|
||||||
Theme.h Theme.cpp
|
Theme.h Theme.cpp
|
||||||
Utilities.h Utilities.cpp
|
Utilities.h Utilities.cpp
|
||||||
QML_FILES
|
QML_FILES
|
||||||
qml/Acrylic.qml
|
qml/Acrylic.qml
|
||||||
qml/AppBar.qml
|
qml/AppBar.qml
|
||||||
|
qml/Button.qml
|
||||||
|
qml/ContentDialog.qml
|
||||||
|
qml/ControlBackground.qml
|
||||||
|
qml/FilledButton.qml
|
||||||
|
qml/FocusRectangle.qml
|
||||||
qml/Icon.qml
|
qml/Icon.qml
|
||||||
qml/IconButton.qml
|
qml/IconButton.qml
|
||||||
|
qml/ImageButton.qml
|
||||||
qml/InfoBar.qml
|
qml/InfoBar.qml
|
||||||
|
qml/Loader.qml
|
||||||
qml/Object.qml
|
qml/Object.qml
|
||||||
|
qml/Popup.qml
|
||||||
|
qml/ProgressRing.qml
|
||||||
qml/Router.qml
|
qml/Router.qml
|
||||||
|
qml/ScrollBar.qml
|
||||||
qml/Shadow.qml
|
qml/Shadow.qml
|
||||||
qml/Text.qml
|
qml/Text.qml
|
||||||
|
qml/Tooltip.qml
|
||||||
qml/Window.qml
|
qml/Window.qml
|
||||||
RESOURCES
|
RESOURCES
|
||||||
resources/noise.png
|
resources/noise.png
|
||||||
|
resources/FluentIcons.ttf
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(Fluent
|
target_include_directories(Fluent
|
||||||
@ -44,4 +60,5 @@ target_include_directories(Fluent
|
|||||||
target_link_libraries(Fluent
|
target_link_libraries(Fluent
|
||||||
PUBLIC Qt${QT_VERSION_MAJOR}::Gui
|
PUBLIC Qt${QT_VERSION_MAJOR}::Gui
|
||||||
PRIVATE Qt${QT_VERSION_MAJOR}::Quick
|
PRIVATE Qt${QT_VERSION_MAJOR}::Quick
|
||||||
|
INTERFACE Qt${QT_VERSION_MAJOR}::QuickControls2
|
||||||
)
|
)
|
||||||
|
66
Fluent/CircularReveal.cpp
Normal file
@ -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 "Frameless.h"
|
||||||
|
#include "Theme.h"
|
||||||
#include "Utilities.h"
|
#include "Utilities.h"
|
||||||
#include <QQuickWindow>
|
#include <QQuickWindow>
|
||||||
#include <dwmapi.h>
|
#include <dwmapi.h>
|
||||||
@ -19,6 +20,121 @@ static inline void setShadow(HWND hwnd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum WINDOWCOMPOSITIONATTRIB {
|
||||||
|
WCA_UNDEFINED = 0,
|
||||||
|
WCA_NCRENDERING_ENABLED = 1,
|
||||||
|
WCA_NCRENDERING_POLICY = 2,
|
||||||
|
WCA_TRANSITIONS_FORCEDISABLED = 3,
|
||||||
|
WCA_ALLOW_NCPAINT = 4,
|
||||||
|
WCA_CAPTION_BUTTON_BOUNDS = 5,
|
||||||
|
WCA_NONCLIENT_RTL_LAYOUT = 6,
|
||||||
|
WCA_FORCE_ICONIC_REPRESENTATION = 7,
|
||||||
|
WCA_EXTENDED_FRAME_BOUNDS = 8,
|
||||||
|
WCA_HAS_ICONIC_BITMAP = 9,
|
||||||
|
WCA_THEME_ATTRIBUTES = 10,
|
||||||
|
WCA_NCRENDERING_EXILED = 11,
|
||||||
|
WCA_NCADORNMENTINFO = 12,
|
||||||
|
WCA_EXCLUDED_FROM_LIVEPREVIEW = 13,
|
||||||
|
WCA_VIDEO_OVERLAY_ACTIVE = 14,
|
||||||
|
WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15,
|
||||||
|
WCA_DISALLOW_PEEK = 16,
|
||||||
|
WCA_CLOAK = 17,
|
||||||
|
WCA_CLOAKED = 18,
|
||||||
|
WCA_ACCENT_POLICY = 19,
|
||||||
|
WCA_FREEZE_REPRESENTATION = 20,
|
||||||
|
WCA_EVER_UNCLOAKED = 21,
|
||||||
|
WCA_VISUAL_OWNER = 22,
|
||||||
|
WCA_HOLOGRAPHIC = 23,
|
||||||
|
WCA_EXCLUDED_FROM_DDA = 24,
|
||||||
|
WCA_PASSIVEUPDATEMODE = 25,
|
||||||
|
WCA_USEDARKMODECOLORS = 26,
|
||||||
|
WCA_CORNER_STYLE = 27,
|
||||||
|
WCA_PART_COLOR = 28,
|
||||||
|
WCA_DISABLE_MOVESIZE_FEEDBACK = 29,
|
||||||
|
WCA_LAST = 30
|
||||||
|
};
|
||||||
|
|
||||||
|
enum _DWM_SYSTEMBACKDROP_TYPE {
|
||||||
|
_DWMSBT_AUTO, // [Default] Let DWM automatically decide the system-drawn backdrop for this
|
||||||
|
// window.
|
||||||
|
_DWMSBT_NONE, // [Disable] Do not draw any system backdrop.
|
||||||
|
_DWMSBT_MAINWINDOW, // [Mica] Draw the backdrop material effect corresponding to a
|
||||||
|
// long-lived window.
|
||||||
|
_DWMSBT_TRANSIENTWINDOW, // [Acrylic] Draw the backdrop material effect corresponding to a
|
||||||
|
// transient window.
|
||||||
|
_DWMSBT_TABBEDWINDOW, // [Mica Alt] Draw the backdrop material effect corresponding to a
|
||||||
|
// window with a tabbed title bar.
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ACCENT_STATE {
|
||||||
|
ACCENT_DISABLED = 0,
|
||||||
|
ACCENT_ENABLE_GRADIENT = 1,
|
||||||
|
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
|
||||||
|
ACCENT_ENABLE_BLURBEHIND = 3, // Traditional DWM blur
|
||||||
|
ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, // RS4 1803
|
||||||
|
ACCENT_ENABLE_HOST_BACKDROP = 5, // RS5 1809
|
||||||
|
ACCENT_INVALID_STATE = 6 // Using this value will remove the window background
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ACCENT_FLAG {
|
||||||
|
ACCENT_NONE = 0,
|
||||||
|
ACCENT_ENABLE_ACRYLIC = 1,
|
||||||
|
ACCENT_ENABLE_ACRYLIC_WITH_LUMINOSITY = 482,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WINDOWCOMPOSITIONATTRIBDATA {
|
||||||
|
WINDOWCOMPOSITIONATTRIB Attrib;
|
||||||
|
PVOID pvData;
|
||||||
|
SIZE_T cbData;
|
||||||
|
};
|
||||||
|
using PWINDOWCOMPOSITIONATTRIBDATA = WINDOWCOMPOSITIONATTRIBDATA *;
|
||||||
|
|
||||||
|
struct ACCENT_POLICY {
|
||||||
|
DWORD dwAccentState;
|
||||||
|
DWORD dwAccentFlags;
|
||||||
|
DWORD dwGradientColor; // #AABBGGRR
|
||||||
|
DWORD dwAnimationId;
|
||||||
|
};
|
||||||
|
using PACCENT_POLICY = ACCENT_POLICY *;
|
||||||
|
|
||||||
|
typedef HRESULT(WINAPI *DwmSetWindowAttributeFunc)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute,
|
||||||
|
DWORD cbAttribute);
|
||||||
|
typedef HRESULT(WINAPI *DwmExtendFrameIntoClientAreaFunc)(HWND hwnd, const MARGINS *pMarInset);
|
||||||
|
typedef HRESULT(WINAPI *DwmIsCompositionEnabledFunc)(BOOL *pfEnabled);
|
||||||
|
typedef HRESULT(WINAPI *DwmEnableBlurBehindWindowFunc)(HWND hWnd, const DWM_BLURBEHIND *pBlurBehind);
|
||||||
|
typedef BOOL(WINAPI *SetWindowCompositionAttributeFunc)(HWND hwnd, const WINDOWCOMPOSITIONATTRIBDATA *);
|
||||||
|
|
||||||
|
static DwmSetWindowAttributeFunc pDwmSetWindowAttribute = nullptr;
|
||||||
|
static DwmExtendFrameIntoClientAreaFunc pDwmExtendFrameIntoClientArea = nullptr;
|
||||||
|
static DwmIsCompositionEnabledFunc pDwmIsCompositionEnabled = nullptr;
|
||||||
|
static DwmEnableBlurBehindWindowFunc pDwmEnableBlurBehindWindow = nullptr;
|
||||||
|
static SetWindowCompositionAttributeFunc pSetWindowCompositionAttribute = nullptr;
|
||||||
|
static RTL_OSVERSIONINFOW GetRealOSVersionImpl() {
|
||||||
|
HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
|
||||||
|
using RtlGetVersionPtr = NTSTATUS(WINAPI *)(PRTL_OSVERSIONINFOW);
|
||||||
|
auto pRtlGetVersion = reinterpret_cast<RtlGetVersionPtr>(::GetProcAddress(hMod, "RtlGetVersion"));
|
||||||
|
RTL_OSVERSIONINFOW rovi{};
|
||||||
|
rovi.dwOSVersionInfoSize = sizeof(rovi);
|
||||||
|
pRtlGetVersion(&rovi);
|
||||||
|
return rovi;
|
||||||
|
}
|
||||||
|
|
||||||
|
RTL_OSVERSIONINFOW GetRealOSVersion() {
|
||||||
|
static const auto result = GetRealOSVersionImpl();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isWin7Only() {
|
||||||
|
RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
|
||||||
|
return rovi.dwMajorVersion = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isWin11OrGreater() {
|
||||||
|
RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
|
||||||
|
return (rovi.dwMajorVersion > 10) ||
|
||||||
|
(rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0 && rovi.dwBuildNumber >= 22000);
|
||||||
|
}
|
||||||
|
|
||||||
static bool containsCursorToItem(QQuickItem *item) {
|
static bool containsCursorToItem(QQuickItem *item) {
|
||||||
auto window = item->window();
|
auto window = item->window();
|
||||||
if ((window == nullptr) || !item || !item->isVisible()) {
|
if ((window == nullptr) || !item || !item->isVisible()) {
|
||||||
@ -32,8 +148,189 @@ static bool containsCursorToItem(QQuickItem *item) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool initializeFunctionPointers() {
|
||||||
|
HMODULE module = LoadLibraryW(L"dwmapi.dll");
|
||||||
|
if (module) {
|
||||||
|
if (!pDwmSetWindowAttribute) {
|
||||||
|
pDwmSetWindowAttribute =
|
||||||
|
reinterpret_cast<DwmSetWindowAttributeFunc>(GetProcAddress(module, "DwmSetWindowAttribute"));
|
||||||
|
if (!pDwmSetWindowAttribute) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pDwmExtendFrameIntoClientArea) {
|
||||||
|
pDwmExtendFrameIntoClientArea = reinterpret_cast<DwmExtendFrameIntoClientAreaFunc>(
|
||||||
|
GetProcAddress(module, "DwmExtendFrameIntoClientArea"));
|
||||||
|
if (!pDwmExtendFrameIntoClientArea) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pDwmIsCompositionEnabled) {
|
||||||
|
pDwmIsCompositionEnabled =
|
||||||
|
reinterpret_cast<DwmIsCompositionEnabledFunc>(::GetProcAddress(module, "DwmIsCompositionEnabled"));
|
||||||
|
if (!pDwmIsCompositionEnabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pDwmEnableBlurBehindWindow) {
|
||||||
|
pDwmEnableBlurBehindWindow =
|
||||||
|
reinterpret_cast<DwmEnableBlurBehindWindowFunc>(GetProcAddress(module, "DwmEnableBlurBehindWindow"));
|
||||||
|
if (!pDwmEnableBlurBehindWindow) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pSetWindowCompositionAttribute) {
|
||||||
|
HMODULE user32 = LoadLibraryW(L"user32.dll");
|
||||||
|
if (!user32) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pSetWindowCompositionAttribute = reinterpret_cast<SetWindowCompositionAttributeFunc>(
|
||||||
|
GetProcAddress(user32, "SetWindowCompositionAttribute"));
|
||||||
|
if (!pSetWindowCompositionAttribute) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isWin1122H2OrGreater() {
|
||||||
|
RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
|
||||||
|
return (rovi.dwMajorVersion > 10) ||
|
||||||
|
(rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0 && rovi.dwBuildNumber >= 22621);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool setWindowDarkMode(HWND hwnd, const BOOL enable) {
|
||||||
|
if (!initializeFunctionPointers()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return bool(pDwmSetWindowAttribute(hwnd, 20, &enable, sizeof(BOOL)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isCompositionEnabled() {
|
||||||
|
if (initializeFunctionPointers()) {
|
||||||
|
BOOL composition_enabled = false;
|
||||||
|
pDwmIsCompositionEnabled(&composition_enabled);
|
||||||
|
return composition_enabled;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isWin8OrGreater() {
|
||||||
|
RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
|
||||||
|
return (rovi.dwMajorVersion > 6) || (rovi.dwMajorVersion == 6 && rovi.dwMinorVersion >= 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool setWindowEffect(HWND hwnd, const QString &key, const bool &enable) {
|
||||||
|
static constexpr const MARGINS extendedMargins = {-1, -1, -1, -1};
|
||||||
|
if (key == QStringLiteral("mica")) {
|
||||||
|
if (!isWin11OrGreater() || !initializeFunctionPointers()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (enable) {
|
||||||
|
pDwmExtendFrameIntoClientArea(hwnd, &extendedMargins);
|
||||||
|
if (isWin1122H2OrGreater()) {
|
||||||
|
const DWORD backdropType = _DWMSBT_MAINWINDOW;
|
||||||
|
pDwmSetWindowAttribute(hwnd, 38, &backdropType, sizeof(backdropType));
|
||||||
|
} else {
|
||||||
|
const BOOL enable = TRUE;
|
||||||
|
pDwmSetWindowAttribute(hwnd, 1029, &enable, sizeof(enable));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isWin1122H2OrGreater()) {
|
||||||
|
const DWORD backdropType = _DWMSBT_AUTO;
|
||||||
|
pDwmSetWindowAttribute(hwnd, 38, &backdropType, sizeof(backdropType));
|
||||||
|
} else {
|
||||||
|
const BOOL enable = FALSE;
|
||||||
|
pDwmSetWindowAttribute(hwnd, 1029, &enable, sizeof(enable));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BOOL isDark = Theme::instance()->dark();
|
||||||
|
setWindowDarkMode(hwnd, isDark);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == QStringLiteral("mica-alt")) {
|
||||||
|
if (!isWin1122H2OrGreater() || !initializeFunctionPointers()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (enable) {
|
||||||
|
pDwmExtendFrameIntoClientArea(hwnd, &extendedMargins);
|
||||||
|
const DWORD backdropType = _DWMSBT_TABBEDWINDOW;
|
||||||
|
pDwmSetWindowAttribute(hwnd, 38, &backdropType, sizeof(backdropType));
|
||||||
|
} else {
|
||||||
|
const DWORD backdropType = _DWMSBT_AUTO;
|
||||||
|
pDwmSetWindowAttribute(hwnd, 38, &backdropType, sizeof(backdropType));
|
||||||
|
}
|
||||||
|
BOOL isDark = Theme::instance()->dark();
|
||||||
|
setWindowDarkMode(hwnd, isDark);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == QStringLiteral("acrylic")) {
|
||||||
|
if (!isWin11OrGreater() || !initializeFunctionPointers()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (enable) {
|
||||||
|
pDwmExtendFrameIntoClientArea(hwnd, &extendedMargins);
|
||||||
|
DWORD system_backdrop_type = _DWMSBT_TRANSIENTWINDOW;
|
||||||
|
pDwmSetWindowAttribute(hwnd, 38, &system_backdrop_type, sizeof(DWORD));
|
||||||
|
} else {
|
||||||
|
const DWORD backdropType = _DWMSBT_AUTO;
|
||||||
|
pDwmSetWindowAttribute(hwnd, 38, &backdropType, sizeof(backdropType));
|
||||||
|
}
|
||||||
|
BOOL isDark = Theme::instance()->dark();
|
||||||
|
setWindowDarkMode(hwnd, isDark);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == QStringLiteral("dwm-blur")) {
|
||||||
|
if ((isWin7Only() && !isCompositionEnabled()) || !initializeFunctionPointers()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
BOOL isDark = Theme::instance()->dark();
|
||||||
|
setWindowDarkMode(hwnd, isDark && enable);
|
||||||
|
if (enable) {
|
||||||
|
if (isWin8OrGreater()) {
|
||||||
|
ACCENT_POLICY policy{};
|
||||||
|
policy.dwAccentState = ACCENT_ENABLE_BLURBEHIND;
|
||||||
|
policy.dwAccentFlags = ACCENT_NONE;
|
||||||
|
WINDOWCOMPOSITIONATTRIBDATA wcad{};
|
||||||
|
wcad.Attrib = WCA_ACCENT_POLICY;
|
||||||
|
wcad.pvData = &policy;
|
||||||
|
wcad.cbData = sizeof(policy);
|
||||||
|
pSetWindowCompositionAttribute(hwnd, &wcad);
|
||||||
|
} else {
|
||||||
|
DWM_BLURBEHIND bb{};
|
||||||
|
bb.fEnable = TRUE;
|
||||||
|
bb.dwFlags = DWM_BB_ENABLE;
|
||||||
|
pDwmEnableBlurBehindWindow(hwnd, &bb);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isWin8OrGreater()) {
|
||||||
|
ACCENT_POLICY policy{};
|
||||||
|
policy.dwAccentState = ACCENT_DISABLED;
|
||||||
|
policy.dwAccentFlags = ACCENT_NONE;
|
||||||
|
WINDOWCOMPOSITIONATTRIBDATA wcad{};
|
||||||
|
wcad.Attrib = WCA_ACCENT_POLICY;
|
||||||
|
wcad.pvData = &policy;
|
||||||
|
wcad.cbData = sizeof(policy);
|
||||||
|
pSetWindowCompositionAttribute(hwnd, &wcad);
|
||||||
|
} else {
|
||||||
|
DWM_BLURBEHIND bb{};
|
||||||
|
bb.fEnable = FALSE;
|
||||||
|
bb.dwFlags = DWM_BB_ENABLE;
|
||||||
|
pDwmEnableBlurBehindWindow(hwnd, &bb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Frameless::Frameless(QQuickItem *parent) : QQuickItem{parent} {
|
Frameless::Frameless(QQuickItem *parent) : QQuickItem{parent} {
|
||||||
m_isWindows11OrGreater = Utilities::instance()->isWindows11OrGreater();
|
m_isWindows11OrGreater = Utilities::instance()->isWindows11OrGreater();
|
||||||
|
m_effect = "normal";
|
||||||
}
|
}
|
||||||
|
|
||||||
QQuickItem *Frameless::appBar() const {
|
QQuickItem *Frameless::appBar() const {
|
||||||
@ -119,12 +416,36 @@ void Frameless::setHitTestVisible(QQuickItem *item) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Frameless::showMaximized() {
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
HWND hwnd = reinterpret_cast<HWND>(window()->winId());
|
||||||
|
::ShowWindow(hwnd, 3);
|
||||||
|
#else
|
||||||
|
window()->setVisibility(QQuickWindow::Maximized);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Frameless::showMinimized() {
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
HWND hwnd = reinterpret_cast<HWND>(window()->winId());
|
||||||
|
::ShowWindow(hwnd, 2);
|
||||||
|
#else
|
||||||
|
window()->setVisibility(QQuickWindow::Minimized);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Frameless::showNormal() {
|
||||||
|
window()->setVisibility(QQuickWindow::Windowed);
|
||||||
|
}
|
||||||
|
|
||||||
void Frameless::onDestruction() {
|
void Frameless::onDestruction() {
|
||||||
QGuiApplication::instance()->removeNativeEventFilter(this);
|
QGuiApplication::instance()->removeNativeEventFilter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Frameless::componentComplete() {
|
void Frameless::componentComplete() {
|
||||||
if (m_disabled) return;
|
if (m_disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
int w = window()->width();
|
int w = window()->width();
|
||||||
int h = window()->height();
|
int h = window()->height();
|
||||||
m_current = window()->winId();
|
m_current = window()->winId();
|
||||||
@ -150,8 +471,12 @@ void Frameless::componentComplete() {
|
|||||||
#endif
|
#endif
|
||||||
HWND hwnd = reinterpret_cast<HWND>(window()->winId());
|
HWND hwnd = reinterpret_cast<HWND>(window()->winId());
|
||||||
DWORD style = ::GetWindowLongPtr(hwnd, GWL_STYLE);
|
DWORD style = ::GetWindowLongPtr(hwnd, GWL_STYLE);
|
||||||
|
#if (QT_VERSION == QT_VERSION_CHECK(6, 7, 2))
|
||||||
|
style &= ~(WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU);
|
||||||
|
#endif
|
||||||
if (m_fixSize) {
|
if (m_fixSize) {
|
||||||
::SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_THICKFRAME | WS_CAPTION);
|
::SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_THICKFRAME | WS_CAPTION);
|
||||||
|
;
|
||||||
for (int i = 0; i <= QGuiApplication::screens().count() - 1; ++i) {
|
for (int i = 0; i <= QGuiApplication::screens().count() - 1; ++i) {
|
||||||
connect(QGuiApplication::screens().at(i), &QScreen::logicalDotsPerInchChanged, this, [=] {
|
connect(QGuiApplication::screens().at(i), &QScreen::logicalDotsPerInchChanged, this, [=] {
|
||||||
SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
|
SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
|
||||||
@ -171,6 +496,42 @@ void Frameless::componentComplete() {
|
|||||||
if (!window()->property("_hideShadow").toBool()) {
|
if (!window()->property("_hideShadow").toBool()) {
|
||||||
setShadow(hwnd);
|
setShadow(hwnd);
|
||||||
}
|
}
|
||||||
|
if (isWin11OrGreater()) {
|
||||||
|
availableEffects({"mica", "mica-alt", "acrylic", "dwm-blur", "normal"});
|
||||||
|
} else if (isWin7Only()) {
|
||||||
|
availableEffects({"dwm-blur", "normal"});
|
||||||
|
}
|
||||||
|
if (!m_effect.isEmpty()) {
|
||||||
|
effective(setWindowEffect(hwnd, m_effect, true));
|
||||||
|
if (effective()) {
|
||||||
|
m_currentEffect = effect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
connect(this, &Frameless::effectChanged, this, [hwnd, this] {
|
||||||
|
if (effect() == m_currentEffect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (effective()) {
|
||||||
|
setWindowEffect(hwnd, m_currentEffect, false);
|
||||||
|
}
|
||||||
|
effective(setWindowEffect(hwnd, effect(), true));
|
||||||
|
if (effective()) {
|
||||||
|
m_currentEffect = effect();
|
||||||
|
} else {
|
||||||
|
m_effect = "normal";
|
||||||
|
m_currentEffect = "normal";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
connect(Theme::instance(), &Theme::blurBehindWindowEnabledChanged, this, [this] {
|
||||||
|
if (Theme::instance()->blurBehindWindowEnabled()) {
|
||||||
|
effect("normal");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
connect(Theme::instance(), &Theme::darkChanged, this, [hwnd, this] {
|
||||||
|
if (effective() && !m_currentEffect.isEmpty() && m_currentEffect != "normal") {
|
||||||
|
setWindowDarkMode(hwnd, Theme::instance()->dark());
|
||||||
|
}
|
||||||
|
});
|
||||||
#endif
|
#endif
|
||||||
auto appBarHeight = m_appBar->height();
|
auto appBarHeight = m_appBar->height();
|
||||||
h = qRound(h + appBarHeight);
|
h = qRound(h + appBarHeight);
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
#ifndef FRAMELESS_H
|
#ifndef FRAMELESS_H
|
||||||
#define FRAMELESS_H
|
#define FRAMELESS_H
|
||||||
|
|
||||||
|
#include "Utilities.h"
|
||||||
#include <QAbstractNativeEventFilter>
|
#include <QAbstractNativeEventFilter>
|
||||||
#include <QQuickItem>
|
#include <QQuickItem>
|
||||||
|
|
||||||
class Frameless : public QQuickItem, QAbstractNativeEventFilter {
|
class Frameless : public QQuickItem, QAbstractNativeEventFilter {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
|
Q_PROPERTY_AUTO(QString, effect)
|
||||||
|
Q_PROPERTY_READONLY_AUTO(bool, effective)
|
||||||
|
Q_PROPERTY_READONLY_AUTO(QStringList, availableEffects)
|
||||||
Q_PROPERTY(QQuickItem *appBar READ appBar WRITE setAppBar NOTIFY appBarChanged)
|
Q_PROPERTY(QQuickItem *appBar READ appBar WRITE setAppBar NOTIFY appBarChanged)
|
||||||
Q_PROPERTY(QQuickItem *maximizeButton READ maximizeButton WRITE setMaximizeButton NOTIFY maximizeButtonChanged)
|
Q_PROPERTY(QQuickItem *maximizeButton READ maximizeButton WRITE setMaximizeButton NOTIFY maximizeButtonChanged)
|
||||||
Q_PROPERTY(QQuickItem *minimizedButton READ minimizedButton WRITE setMinimizedButton NOTIFY minimizedButtonChanged)
|
Q_PROPERTY(QQuickItem *minimizedButton READ minimizedButton WRITE setMinimizedButton NOTIFY minimizedButtonChanged)
|
||||||
@ -39,6 +43,10 @@ public:
|
|||||||
bool disabled() const;
|
bool disabled() const;
|
||||||
void setDisabled(bool disabled);
|
void setDisabled(bool disabled);
|
||||||
|
|
||||||
|
Q_INVOKABLE void showMaximized();
|
||||||
|
Q_INVOKABLE void showMinimized();
|
||||||
|
Q_INVOKABLE void showNormal();
|
||||||
|
|
||||||
Q_INVOKABLE void setHitTestVisible(QQuickItem *item);
|
Q_INVOKABLE void setHitTestVisible(QQuickItem *item);
|
||||||
Q_INVOKABLE void onDestruction();
|
Q_INVOKABLE void onDestruction();
|
||||||
void componentComplete() final;
|
void componentComplete() final;
|
||||||
@ -77,6 +85,7 @@ private:
|
|||||||
int m_margins = 8;
|
int m_margins = 8;
|
||||||
QList<QPointer<QQuickItem>> m_hitTestList;
|
QList<QPointer<QQuickItem>> m_hitTestList;
|
||||||
bool m_isWindows11OrGreater = false;
|
bool m_isWindows11OrGreater = false;
|
||||||
|
QString m_currentEffect;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FRAMELESS_H
|
#endif // FRAMELESS_H
|
||||||
|
48
Fluent/TextStyle.cpp
Normal file
@ -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 "Theme.h"
|
||||||
|
#include "Colors.h"
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QPalette>
|
||||||
|
#include <QThreadPool>
|
||||||
|
|
||||||
|
static bool systemDark() {
|
||||||
|
QPalette palette = QGuiApplication::palette();
|
||||||
|
QColor color = palette.color(QPalette::Window).rgb();
|
||||||
|
return color.red() * 0.2126 + color.green() * 0.7152 + color.blue() * 0.0722 <= 255.0f / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Theme *Theme::instance() {
|
||||||
|
static Theme *self = nullptr;
|
||||||
|
if (self == nullptr) {
|
||||||
|
self = new Theme();
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
Theme *Theme::create(QQmlEngine *, QJSEngine *) {
|
||||||
|
auto ret = instance();
|
||||||
|
QJSEngine::setObjectOwnership(ret, QJSEngine::CppOwnership);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
Theme::Theme(QObject *parent) : QObject{parent} {
|
Theme::Theme(QObject *parent) : QObject{parent} {
|
||||||
|
m_accentColor = Colors::instance()->Blue();
|
||||||
|
m_darkMode = ThemeType::DarkMode::Light;
|
||||||
|
m_nativeText = false;
|
||||||
|
m_animationEnabled = true;
|
||||||
|
m_systemDark = systemDark();
|
||||||
|
m_desktopImagePath = "";
|
||||||
|
m_blurBehindWindowEnabled = false;
|
||||||
|
QGuiApplication::instance()->installEventFilter(this);
|
||||||
|
refreshColors();
|
||||||
|
connect(this, &Theme::darkModeChanged, this, [=] { Q_EMIT darkChanged(); });
|
||||||
|
connect(this, &Theme::darkChanged, this, [=] { refreshColors(); });
|
||||||
|
connect(this, &Theme::accentColorChanged, this, [=] { refreshColors(); });
|
||||||
|
connect(&m_watcher, &QFileSystemWatcher::fileChanged, this,
|
||||||
|
[=](const QString &path) { Q_EMIT desktopImagePathChanged(); });
|
||||||
|
connect(this, &Theme::blurBehindWindowEnabledChanged, this, [=] { checkUpdateDesktopImage(); });
|
||||||
|
startTimer(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Theme::dark() const {
|
||||||
|
if (m_darkMode == ThemeType::DarkMode::Dark) {
|
||||||
|
return true;
|
||||||
|
} else if (m_darkMode == ThemeType::DarkMode::System) {
|
||||||
|
return m_systemDark;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor Theme::fontPrimaryColor() const {
|
QColor Theme::fontPrimaryColor() const {
|
||||||
@ -79,3 +129,53 @@ void Theme::setBlurBehindWindowEnabled(bool enabled) {
|
|||||||
emit blurBehindWindowEnabledChanged();
|
emit blurBehindWindowEnabledChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Theme::refreshColors() {
|
||||||
|
auto isDark = dark();
|
||||||
|
primaryColor(isDark ? m_accentColor->lighter() : m_accentColor->dark());
|
||||||
|
backgroundColor(isDark ? QColor(0, 0, 0, 255) : QColor(255, 255, 255, 255));
|
||||||
|
dividerColor(isDark ? QColor(80, 80, 80, 255) : QColor(210, 210, 210, 255));
|
||||||
|
setWindowBackgroundColor(isDark ? QColor(32, 32, 32, 255) : QColor(237, 237, 237, 255));
|
||||||
|
setWindowActiveBackgroundColor(isDark ? QColor(26, 26, 26, 255) : QColor(243, 243, 243, 255));
|
||||||
|
setFontPrimaryColor(isDark ? QColor(248, 248, 248, 255) : QColor(7, 7, 7, 255));
|
||||||
|
fontSecondaryColor(isDark ? QColor(222, 222, 222, 255) : QColor(102, 102, 102, 255));
|
||||||
|
fontTertiaryColor(isDark ? QColor(200, 200, 200, 255) : QColor(153, 153, 153, 255));
|
||||||
|
setItemNormalColor(isDark ? QColor(255, 255, 255, 0) : QColor(0, 0, 0, 0));
|
||||||
|
frameColor(isDark ? QColor(56, 56, 56, qRound(255 * 0.8)) : QColor(243, 243, 243, qRound(255 * 0.8)));
|
||||||
|
frameActiveColor(isDark ? QColor(48, 48, 48, qRound(255 * 0.8)) : QColor(255, 255, 255, qRound(255 * 0.8)));
|
||||||
|
setItemHoverColor(isDark ? QColor(255, 255, 255, qRound(255 * 0.06)) : QColor(0, 0, 0, qRound(255 * 0.03)));
|
||||||
|
itemPressColor(isDark ? QColor(255, 255, 255, qRound(255 * 0.09)) : QColor(0, 0, 0, qRound(255 * 0.06)));
|
||||||
|
itemCheckColor(isDark ? QColor(255, 255, 255, qRound(255 * 0.12)) : QColor(0, 0, 0, qRound(255 * 0.09)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Theme::checkUpdateDesktopImage() {
|
||||||
|
if (!m_blurBehindWindowEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QThreadPool::globalInstance()->start([=]() {
|
||||||
|
m_mutex.lock();
|
||||||
|
auto path = Utilities::instance()->getWallpaperFilePath();
|
||||||
|
if (m_desktopImagePath != path) {
|
||||||
|
if (!m_desktopImagePath.isEmpty()) {
|
||||||
|
m_watcher.removePath(m_desktopImagePath);
|
||||||
|
}
|
||||||
|
setDesktopImagePath(path);
|
||||||
|
m_watcher.addPath(path);
|
||||||
|
}
|
||||||
|
m_mutex.unlock();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Theme::eventFilter(QObject *, QEvent *event) {
|
||||||
|
if (event->type() == QEvent::ApplicationPaletteChange || event->type() == QEvent::ThemeChange) {
|
||||||
|
m_systemDark = systemDark();
|
||||||
|
Q_EMIT darkChanged();
|
||||||
|
event->accept();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Theme::timerEvent(QTimerEvent *event) {
|
||||||
|
checkUpdateDesktopImage();
|
||||||
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
#ifndef THEME_H
|
#ifndef THEME_H
|
||||||
#define THEME_H
|
#define THEME_H
|
||||||
|
|
||||||
|
#include "AccentColor.h"
|
||||||
|
#include "Utilities.h"
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
#include <QFileSystemWatcher>
|
||||||
|
#include <QMutex>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
|
|
||||||
@ -9,7 +13,21 @@ class Theme : public QObject {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
QML_SINGLETON
|
QML_SINGLETON
|
||||||
|
Q_PROPERTY(bool dark READ dark NOTIFY darkChanged)
|
||||||
|
Q_PROPERTY_AUTO_P(AccentColor *, accentColor)
|
||||||
|
Q_PROPERTY_AUTO(int, darkMode)
|
||||||
|
Q_PROPERTY_AUTO(QColor, primaryColor)
|
||||||
|
Q_PROPERTY_AUTO(QColor, backgroundColor)
|
||||||
|
Q_PROPERTY_AUTO(QColor, dividerColor)
|
||||||
|
Q_PROPERTY_AUTO(QColor, itemPressColor)
|
||||||
|
Q_PROPERTY_AUTO(bool, nativeText)
|
||||||
|
Q_PROPERTY_AUTO(bool, animationEnabled)
|
||||||
Q_PROPERTY(QColor fontPrimaryColor READ fontPrimaryColor WRITE setFontPrimaryColor NOTIFY fontPrimaryColorChanged)
|
Q_PROPERTY(QColor fontPrimaryColor READ fontPrimaryColor WRITE setFontPrimaryColor NOTIFY fontPrimaryColorChanged)
|
||||||
|
Q_PROPERTY_AUTO(QColor, fontSecondaryColor)
|
||||||
|
Q_PROPERTY_AUTO(QColor, fontTertiaryColor)
|
||||||
|
Q_PROPERTY_AUTO(QColor, frameColor)
|
||||||
|
Q_PROPERTY_AUTO(QColor, frameActiveColor)
|
||||||
|
Q_PROPERTY_AUTO(QColor, itemCheckColor)
|
||||||
Q_PROPERTY(QColor itemNormalColor READ itemNormalColor WRITE setItemNormalColor NOTIFY itemNormalColorChanged)
|
Q_PROPERTY(QColor itemNormalColor READ itemNormalColor WRITE setItemNormalColor NOTIFY itemNormalColorChanged)
|
||||||
Q_PROPERTY(QColor itemHoverColor READ itemHoverColor WRITE setItemHoverColor NOTIFY itemHoverColorChanged)
|
Q_PROPERTY(QColor itemHoverColor READ itemHoverColor WRITE setItemHoverColor NOTIFY itemHoverColorChanged)
|
||||||
|
|
||||||
@ -23,7 +41,9 @@ class Theme : public QObject {
|
|||||||
blurBehindWindowEnabledChanged)
|
blurBehindWindowEnabledChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Theme(QObject *parent = nullptr);
|
static Theme *instance();
|
||||||
|
static Theme *create(QQmlEngine *, QJSEngine *);
|
||||||
|
bool dark() const;
|
||||||
|
|
||||||
QColor fontPrimaryColor() const;
|
QColor fontPrimaryColor() const;
|
||||||
void setFontPrimaryColor(const QColor &color);
|
void setFontPrimaryColor(const QColor &color);
|
||||||
@ -47,6 +67,7 @@ public:
|
|||||||
void setBlurBehindWindowEnabled(bool enabled);
|
void setBlurBehindWindowEnabled(bool enabled);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void darkChanged();
|
||||||
void fontPrimaryColorChanged();
|
void fontPrimaryColorChanged();
|
||||||
void itemNormalColorChanged();
|
void itemNormalColorChanged();
|
||||||
void windowBackgroundColorChanged();
|
void windowBackgroundColorChanged();
|
||||||
@ -55,7 +76,17 @@ signals:
|
|||||||
void blurBehindWindowEnabledChanged();
|
void blurBehindWindowEnabledChanged();
|
||||||
void itemHoverColorChanged();
|
void itemHoverColorChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Theme(QObject *parent = nullptr);
|
||||||
|
void refreshColors();
|
||||||
|
void checkUpdateDesktopImage();
|
||||||
|
void timerEvent(QTimerEvent *event) final;
|
||||||
|
bool eventFilter(QObject *obj, QEvent *event) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool m_systemDark = false;
|
||||||
|
QMutex m_mutex;
|
||||||
|
QFileSystemWatcher m_watcher;
|
||||||
QColor m_fontPrimaryColor;
|
QColor m_fontPrimaryColor;
|
||||||
QColor m_itemNormalColor;
|
QColor m_itemNormalColor;
|
||||||
QColor m_itemHoverColor;
|
QColor m_itemHoverColor;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "Utilities.h"
|
#include "Utilities.h"
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
#include <qt_windows.h>
|
||||||
|
|
||||||
Utilities *Utilities::instance() {
|
Utilities *Utilities::instance() {
|
||||||
static Utilities *self = nullptr;
|
static Utilities *self = nullptr;
|
||||||
@ -18,10 +19,70 @@ Utilities *Utilities::create(QQmlEngine *, QJSEngine *) {
|
|||||||
Utilities::Utilities(QObject *parent) : QObject{parent} {
|
Utilities::Utilities(QObject *parent) : QObject{parent} {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Utilities::isSoftware() {
|
||||||
|
return QQuickWindow::sceneGraphBackend() == "software";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utilities::deleteLater(QObject *p) {
|
||||||
|
if (p) {
|
||||||
|
p->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor Utilities::withOpacity(const QColor &color, qreal opacity) {
|
||||||
|
int alpha = qRound(opacity * 255) & 0xff;
|
||||||
|
return QColor::fromRgba((alpha << 24) | (color.rgba() & 0xffffff));
|
||||||
|
}
|
||||||
|
|
||||||
QRect Utilities::desktopAvailableGeometry(QQuickWindow *window) {
|
QRect Utilities::desktopAvailableGeometry(QQuickWindow *window) {
|
||||||
return window->screen()->availableGeometry();
|
return window->screen()->availableGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Utilities::getWallpaperFilePath() {
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
wchar_t path[MAX_PATH] = {};
|
||||||
|
if (::SystemParametersInfoW(SPI_GETDESKWALLPAPER, MAX_PATH, path, FALSE) == FALSE) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return QString::fromWCharArray(path);
|
||||||
|
#elif defined(Q_OS_LINUX)
|
||||||
|
auto type = QSysInfo::productType();
|
||||||
|
if (type == "uos") {
|
||||||
|
QProcess process;
|
||||||
|
QStringList args;
|
||||||
|
args << "--session";
|
||||||
|
args << "--type=method_call";
|
||||||
|
args << "--print-reply";
|
||||||
|
args << "--dest=com.deepin.wm";
|
||||||
|
args << "/com/deepin/wm";
|
||||||
|
args << "com.deepin.wm.GetCurrentWorkspaceBackgroundForMonitor";
|
||||||
|
args << QString("string:'%1'").arg(currentTimestamp());
|
||||||
|
process.start("dbus-send", args);
|
||||||
|
process.waitForFinished();
|
||||||
|
QByteArray result = process.readAllStandardOutput().trimmed();
|
||||||
|
int startIndex = result.indexOf("file:///");
|
||||||
|
if (startIndex != -1) {
|
||||||
|
auto path = result.mid(startIndex + 7, result.length() - startIndex - 8);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined(Q_OS_MACOS)
|
||||||
|
QProcess process;
|
||||||
|
QStringList args;
|
||||||
|
args << "-e";
|
||||||
|
args << R"(tell application "Finder" to get POSIX path of (desktop picture as alias))";
|
||||||
|
process.start("osascript", args);
|
||||||
|
process.waitForFinished();
|
||||||
|
QByteArray result = process.readAllStandardOutput().trimmed();
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
return "/System/Library/CoreServices/DefaultDesktop.heic";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
#else
|
||||||
|
return {};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
QUrl Utilities::getUrlByFilePath(const QString &path) {
|
QUrl Utilities::getUrlByFilePath(const QString &path) {
|
||||||
return QUrl::fromLocalFile(path);
|
return QUrl::fromLocalFile(path);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,84 @@
|
|||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#include <QQuickWindow>
|
#include <QQuickWindow>
|
||||||
|
|
||||||
|
#define Q_PROPERTY_AUTO(TYPE, M) \
|
||||||
|
Q_PROPERTY(TYPE M MEMBER m_##M NOTIFY M##Changed) \
|
||||||
|
public: \
|
||||||
|
Q_SIGNAL void M##Changed(); \
|
||||||
|
void M(const TYPE &in_##M) { \
|
||||||
|
m_##M = in_##M; \
|
||||||
|
Q_EMIT M##Changed(); \
|
||||||
|
} \
|
||||||
|
TYPE M() { \
|
||||||
|
return m_##M; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
private: \
|
||||||
|
TYPE m_##M;
|
||||||
|
|
||||||
|
#define Q_PROPERTY_READONLY_AUTO(TYPE, M) \
|
||||||
|
Q_PROPERTY(TYPE M READ M NOTIFY M##Changed FINAL) \
|
||||||
|
public: \
|
||||||
|
Q_SIGNAL void M##Changed(); \
|
||||||
|
void M(const TYPE &in_##M) { \
|
||||||
|
m_##M = in_##M; \
|
||||||
|
Q_EMIT M##Changed(); \
|
||||||
|
} \
|
||||||
|
TYPE M() { \
|
||||||
|
return m_##M; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
private: \
|
||||||
|
TYPE m_##M;
|
||||||
|
|
||||||
|
#define Q_PROPERTY_AUTO_P(TYPE, M) \
|
||||||
|
Q_PROPERTY(TYPE M MEMBER m_##M NOTIFY M##Changed) \
|
||||||
|
public: \
|
||||||
|
Q_SIGNAL void M##Changed(); \
|
||||||
|
void M(TYPE in_##M) { \
|
||||||
|
m_##M = in_##M; \
|
||||||
|
Q_EMIT M##Changed(); \
|
||||||
|
} \
|
||||||
|
TYPE M() { \
|
||||||
|
return m_##M; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
private: \
|
||||||
|
TYPE m_##M;
|
||||||
|
|
||||||
|
namespace WindowType {
|
||||||
|
Q_NAMESPACE
|
||||||
|
enum LaunchMode {
|
||||||
|
Standard = 0x0000,
|
||||||
|
SingleTask = 0x0001,
|
||||||
|
SingleInstance = 0x0002,
|
||||||
|
};
|
||||||
|
Q_ENUM_NS(LaunchMode)
|
||||||
|
QML_ELEMENT
|
||||||
|
} // namespace WindowType
|
||||||
|
|
||||||
|
namespace ThemeType {
|
||||||
|
Q_NAMESPACE
|
||||||
|
enum DarkMode {
|
||||||
|
System = 0x0000,
|
||||||
|
Light = 0x0001,
|
||||||
|
Dark = 0x0002,
|
||||||
|
};
|
||||||
|
Q_ENUM_NS(DarkMode)
|
||||||
|
QML_ELEMENT
|
||||||
|
} // namespace ThemeType
|
||||||
|
|
||||||
|
namespace ContentDialogType {
|
||||||
|
Q_NAMESPACE
|
||||||
|
enum ButtonFlag {
|
||||||
|
NeutralButton = 0x0001,
|
||||||
|
NegativeButton = 0x0002,
|
||||||
|
PositiveButton = 0x0004,
|
||||||
|
};
|
||||||
|
Q_ENUM_NS(ButtonFlag)
|
||||||
|
QML_ELEMENT
|
||||||
|
} // namespace ContentDialogType
|
||||||
|
|
||||||
class Utilities : public QObject {
|
class Utilities : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
@ -18,6 +96,10 @@ public:
|
|||||||
Q_INVOKABLE bool isMacos();
|
Q_INVOKABLE bool isMacos();
|
||||||
Q_INVOKABLE QRect desktopAvailableGeometry(QQuickWindow *window);
|
Q_INVOKABLE QRect desktopAvailableGeometry(QQuickWindow *window);
|
||||||
Q_INVOKABLE QUrl getUrlByFilePath(const QString &path);
|
Q_INVOKABLE QUrl getUrlByFilePath(const QString &path);
|
||||||
|
Q_INVOKABLE bool isSoftware();
|
||||||
|
Q_INVOKABLE void deleteLater(QObject *p);
|
||||||
|
Q_INVOKABLE QColor withOpacity(const QColor &, qreal alpha);
|
||||||
|
Q_INVOKABLE QString getWallpaperFilePath();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Utilities(QObject *parent = nullptr);
|
Utilities(QObject *parent = nullptr);
|
||||||
|
@ -1,26 +1,88 @@
|
|||||||
import QtQuick as Quick
|
import QtQuick as Quick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Window
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Fluent
|
import Fluent
|
||||||
|
|
||||||
Quick.Rectangle {
|
Quick.Rectangle{
|
||||||
id: root
|
property string title: ""
|
||||||
|
property string darkText : qsTr("Dark")
|
||||||
|
property string lightText : qsTr("Light")
|
||||||
|
property string minimizeText : qsTr("Minimize")
|
||||||
|
property string restoreText : qsTr("Restore")
|
||||||
|
property string maximizeText : qsTr("Maximize")
|
||||||
|
property string closeText : qsTr("Close")
|
||||||
|
property string stayTopText : qsTr("Sticky on Top")
|
||||||
|
property string stayTopCancelText : qsTr("Sticky on Top cancelled")
|
||||||
|
property color textColor: Theme.fontPrimaryColor
|
||||||
|
property color minimizeNormalColor: Theme.itemNormalColor
|
||||||
|
property color minimizeHoverColor: Theme.itemHoverColor
|
||||||
|
property color minimizePressColor: Theme.itemPressColor
|
||||||
|
property color maximizeNormalColor: Theme.itemNormalColor
|
||||||
|
property color maximizeHoverColor: Theme.itemHoverColor
|
||||||
|
property color maximizePressColor: Theme.itemPressColor
|
||||||
|
property color closeNormalColor: Qt.rgba(0,0,0,0)
|
||||||
|
property color closeHoverColor: Qt.rgba(251/255,115/255,115/255,1)
|
||||||
|
property color closePressColor: Qt.rgba(251/255,115/255,115/255,0.8)
|
||||||
|
property bool showDark: false
|
||||||
|
property bool showClose: true
|
||||||
property bool showMinimize: true
|
property bool showMinimize: true
|
||||||
property bool showMaximize: true
|
property bool showMaximize: true
|
||||||
property bool showClose: true
|
|
||||||
property bool showStayTop: true
|
property bool showStayTop: true
|
||||||
property bool showDark: false
|
property bool titleVisible: true
|
||||||
property string title: ""
|
|
||||||
property url icon
|
property url icon
|
||||||
property string maximizeText : qsTr("Maximize")
|
property int iconSize: 20
|
||||||
property Quick.color textColor: Theme.fontPrimaryColor
|
|
||||||
property Quick.color maximizeNormalColor: Theme.itemNormalColor
|
|
||||||
property Quick.color maximizeHoverColor: Theme.itemHoverColor
|
|
||||||
property bool isMac: Utilities.isMacos()
|
property bool isMac: Utilities.isMacos()
|
||||||
|
property color borerlessColor : Theme.primaryColor
|
||||||
|
property alias buttonStayTop: btn_stay_top
|
||||||
|
property alias buttonMinimize: btn_minimize
|
||||||
property alias buttonMaximize: btn_maximize
|
property alias buttonMaximize: btn_maximize
|
||||||
|
property alias buttonClose: btn_close
|
||||||
|
property alias buttonDark: btn_dark
|
||||||
property alias layoutMacosButtons: layout_macos_buttons
|
property alias layoutMacosButtons: layout_macos_buttons
|
||||||
property alias layoutStandardbuttons: layout_standard_buttons
|
property alias layoutStandardbuttons: layout_standard_buttons
|
||||||
|
property var maxClickListener : function(){
|
||||||
Quick.Item{
|
if(Utilities.isMacos()){
|
||||||
|
if (d.win.visibility === Window.FullScreen || d.win.visibility === Window.Maximized)
|
||||||
|
d.win.showNormal()
|
||||||
|
else
|
||||||
|
d.win.showFullScreen()
|
||||||
|
}else{
|
||||||
|
if (d.win.visibility === Window.Maximized || d.win.visibility === Window.FullScreen)
|
||||||
|
d.win.showNormal()
|
||||||
|
else
|
||||||
|
d.win.showMaximized()
|
||||||
|
d.hoverMaxBtn = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property var minClickListener: function(){
|
||||||
|
if(d.win.transientParent != null){
|
||||||
|
d.win.transientParent.showMinimized()
|
||||||
|
}else{
|
||||||
|
d.win.showMinimized()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property var closeClickListener : function(){
|
||||||
|
d.win.close()
|
||||||
|
}
|
||||||
|
property var stayTopClickListener: function(){
|
||||||
|
if(d.win instanceof Window){
|
||||||
|
d.win.stayTop = !d.win.stayTop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property var darkClickListener: function(){
|
||||||
|
if(Theme.dark){
|
||||||
|
Theme.darkMode = ThemeType.Light
|
||||||
|
}else{
|
||||||
|
Theme.darkMode = ThemeType.Dark
|
||||||
|
}
|
||||||
|
}
|
||||||
|
id:control
|
||||||
|
color: Qt.rgba(0,0,0,0)
|
||||||
|
height: visible ? 30 : 0
|
||||||
|
opacity: visible
|
||||||
|
z: 65535
|
||||||
|
Item{
|
||||||
id:d
|
id:d
|
||||||
property var hitTestList: []
|
property var hitTestList: []
|
||||||
property bool hoverMaxBtn: false
|
property bool hoverMaxBtn: false
|
||||||
@ -42,13 +104,125 @@ Quick.Rectangle {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Row{
|
||||||
RowLayout {
|
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
|
id:layout_standard_buttons
|
||||||
height: parent.height
|
height: parent.height
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
IconButton{
|
||||||
|
id:btn_dark
|
||||||
|
Layout.preferredWidth: 40
|
||||||
|
Layout.preferredHeight: 30
|
||||||
|
padding: 0
|
||||||
|
verticalPadding: 0
|
||||||
|
horizontalPadding: 0
|
||||||
|
rightPadding: 2
|
||||||
|
iconSource: Theme.dark ? Icons.Brightness : Icons.QuietHours
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
iconSize: 15
|
||||||
|
visible: showDark
|
||||||
|
text: Theme.dark ? control.lightText : control.darkText
|
||||||
|
radius: 0
|
||||||
|
iconColor:control.textColor
|
||||||
|
onClicked:()=> darkClickListener(btn_dark)
|
||||||
|
}
|
||||||
|
IconButton{
|
||||||
|
id:btn_stay_top
|
||||||
|
Layout.preferredWidth: 40
|
||||||
|
Layout.preferredHeight: 30
|
||||||
|
padding: 0
|
||||||
|
verticalPadding: 0
|
||||||
|
horizontalPadding: 0
|
||||||
|
iconSource : Icons.Pinned
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
iconSize: 14
|
||||||
|
visible: {
|
||||||
|
if(!(d.win instanceof Window)){
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return showStayTop
|
||||||
|
}
|
||||||
|
text:d.stayTop ? control.stayTopCancelText : control.stayTopText
|
||||||
|
radius: 0
|
||||||
|
iconColor: d.stayTop ? Theme.primaryColor : control.textColor
|
||||||
|
onClicked: stayTopClickListener()
|
||||||
|
}
|
||||||
|
IconButton{
|
||||||
|
id:btn_minimize
|
||||||
|
Layout.preferredWidth: 40
|
||||||
|
Layout.preferredHeight: 30
|
||||||
|
padding: 0
|
||||||
|
verticalPadding: 0
|
||||||
|
horizontalPadding: 0
|
||||||
|
iconSource : Icons.ChromeMinimize
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
iconSize: 11
|
||||||
|
text:minimizeText
|
||||||
|
radius: 0
|
||||||
|
visible: !isMac && showMinimize
|
||||||
|
iconColor: control.textColor
|
||||||
|
color: {
|
||||||
|
if(pressed){
|
||||||
|
return minimizePressColor
|
||||||
|
}
|
||||||
|
return hovered ? minimizeHoverColor : minimizeNormalColor
|
||||||
|
}
|
||||||
|
onClicked: minClickListener()
|
||||||
|
}
|
||||||
IconButton{
|
IconButton{
|
||||||
id:btn_maximize
|
id:btn_maximize
|
||||||
property bool hover: btn_maximize.hovered
|
property bool hover: btn_maximize.hovered
|
||||||
@ -67,14 +241,35 @@ Quick.Rectangle {
|
|||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
visible: d.resizable && !isMac && showMaximize
|
visible: d.resizable && !isMac && showMaximize
|
||||||
radius: 0
|
radius: 0
|
||||||
iconColor: root.textColor
|
iconColor: control.textColor
|
||||||
text:d.isRestore?restoreText:maximizeText
|
text:d.isRestore?restoreText:maximizeText
|
||||||
iconSize: 11
|
iconSize: 11
|
||||||
onClicked: maxClickListener()
|
onClicked: maxClickListener()
|
||||||
}
|
}
|
||||||
|
IconButton{
|
||||||
|
id:btn_close
|
||||||
|
Layout.preferredWidth: 40
|
||||||
|
Layout.preferredHeight: 30
|
||||||
|
padding: 0
|
||||||
|
verticalPadding: 0
|
||||||
|
horizontalPadding: 0
|
||||||
|
iconSource : Icons.ChromeClose
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
text:closeText
|
||||||
|
visible: !isMac && showClose
|
||||||
|
radius: 0
|
||||||
|
iconSize: 10
|
||||||
|
iconColor: hovered ? Qt.rgba(1,1,1,1) : control.textColor
|
||||||
|
color:{
|
||||||
|
if(pressed){
|
||||||
|
return closePressColor
|
||||||
}
|
}
|
||||||
|
return hovered ? closeHoverColor : closeNormalColor
|
||||||
Quick.Loader{
|
}
|
||||||
|
onClicked: closeClickListener()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loader{
|
||||||
id:layout_macos_buttons
|
id:layout_macos_buttons
|
||||||
anchors{
|
anchors{
|
||||||
verticalCenter: parent.verticalCenter
|
verticalCenter: parent.verticalCenter
|
||||||
@ -82,6 +277,5 @@ Quick.Rectangle {
|
|||||||
leftMargin: 10
|
leftMargin: 10
|
||||||
}
|
}
|
||||||
sourceComponent: isMac ? com_macos_buttons : undefined
|
sourceComponent: isMac ? com_macos_buttons : undefined
|
||||||
Quick.Component.onDestruction: sourceComponent = undefined
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
64
Fluent/qml/Button.qml
Normal file
@ -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
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Fluent
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
property int iconSource
|
property int iconSource
|
||||||
property int iconSize: 20
|
property int iconSize: 20
|
||||||
property color iconColor: FluTheme.dark ? "#FFFFFF" : "#000000"
|
property color iconColor: Theme.dark ? "#FFFFFF" : "#000000"
|
||||||
id:control
|
id:control
|
||||||
font.family: font_loader.name
|
font.family: font_loader.name
|
||||||
font.pixelSize: iconSize
|
font.pixelSize: iconSize
|
||||||
@ -14,6 +16,6 @@ Text {
|
|||||||
opacity: iconSource>0
|
opacity: iconSource>0
|
||||||
FontLoader{
|
FontLoader{
|
||||||
id: font_loader
|
id: font_loader
|
||||||
source: "qrc:/qt/qml/FluentUI/Font/FluentIcons.ttf"
|
source: "qrc:/qt/qml/Fluent/resources/FluentIcons.ttf"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,21 @@
|
|||||||
import QtQuick
|
import QtQuick as Quick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls as Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Fluent
|
||||||
|
|
||||||
Button {
|
Controls.Button {
|
||||||
|
display: Controls.Button.IconOnly
|
||||||
property int iconSize: 20
|
property int iconSize: 20
|
||||||
property int iconSource
|
property int iconSource
|
||||||
|
property bool disabled: false
|
||||||
property int radius:4
|
property int radius:4
|
||||||
property color color: {
|
property string contentDescription: ""
|
||||||
|
property Quick.color hoverColor: Theme.itemHoverColor
|
||||||
|
property Quick.color pressedColor: Theme.itemPressColor
|
||||||
|
property Quick.color normalColor: Theme.itemNormalColor
|
||||||
|
property Quick.color disableColor: Theme.itemNormalColor
|
||||||
|
property Quick.Component iconDelegate: com_icon
|
||||||
|
property Quick.color color: {
|
||||||
if(!enabled){
|
if(!enabled){
|
||||||
return disableColor
|
return disableColor
|
||||||
}
|
}
|
||||||
@ -14,17 +24,106 @@ Button {
|
|||||||
}
|
}
|
||||||
return hovered ? hoverColor : normalColor
|
return hovered ? hoverColor : normalColor
|
||||||
}
|
}
|
||||||
property color iconColor: {
|
property Quick.color iconColor: {
|
||||||
if (FluTheme.dark) {
|
if(Theme.dark){
|
||||||
if (!enabled) {
|
if(!enabled){
|
||||||
return Qt.rgba(130 / 255, 130 / 255, 130 / 255, 1)
|
return Qt.rgba(130/255,130/255,130/255,1)
|
||||||
}
|
}
|
||||||
return Qt.rgba(1, 1, 1, 1)
|
return Qt.rgba(1,1,1,1)
|
||||||
} else {
|
}else{
|
||||||
if (!enabled) {
|
if(!enabled){
|
||||||
return Qt.rgba(161 / 255, 161 / 255, 161 / 255, 1)
|
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 as Quick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import Fluent
|
|
||||||
|
|
||||||
Object {
|
Object {
|
||||||
property var root
|
property var root
|
||||||
@ -39,7 +38,7 @@ Object {
|
|||||||
screenLayout.z = 100000
|
screenLayout.z = 100000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Quick.Component {
|
Quick.Component{
|
||||||
id:screenlayoutComponent
|
id:screenlayoutComponent
|
||||||
Quick.Column{
|
Quick.Column{
|
||||||
parent: Overlay.overlay
|
parent: Overlay.overlay
|
||||||
@ -86,7 +85,7 @@ Object {
|
|||||||
repeat: duration > 0
|
repeat: duration > 0
|
||||||
onTriggered: content.close()
|
onTriggered: content.close()
|
||||||
}
|
}
|
||||||
Quick.Loader{
|
Loader{
|
||||||
id:loader
|
id:loader
|
||||||
x:(parent.width - width) / 2
|
x:(parent.width - width) / 2
|
||||||
property var _super: content
|
property var _super: content
|
||||||
@ -100,7 +99,6 @@ Object {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sourceComponent:itemcomponent ? itemcomponent : mcontrol.fluent_sytle
|
sourceComponent:itemcomponent ? itemcomponent : mcontrol.fluent_sytle
|
||||||
Quick.Component.onDestruction: sourceComponent = undefined
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,7 +124,7 @@ Object {
|
|||||||
return Qt.rgba(1,1,1,1)
|
return Qt.rgba(1,1,1,1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Shadow {
|
Shadow{
|
||||||
radius: 4
|
radius: 4
|
||||||
}
|
}
|
||||||
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
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id:root
|
|
||||||
default property list<QtObject> children
|
default property list<QtObject> children
|
||||||
|
id:control
|
||||||
}
|
}
|
||||||
|
54
Fluent/qml/Popup.qml
Normal file
@ -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
|
pragma Singleton
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
import QtQml
|
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
|
property var routes : ({})
|
||||||
property var windows: []
|
property var windows: []
|
||||||
function addWindow(window){
|
function addWindow(window){
|
||||||
if(!window.transientParent){
|
if(!window.transientParent){
|
||||||
windows.push(window)
|
windows.push(window)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function removeWindow(win) {
|
||||||
|
if(!win.transientParent){
|
||||||
|
var index = windows.indexOf(win)
|
||||||
|
if (index !== -1) {
|
||||||
|
windows.splice(index, 1)
|
||||||
|
win.deleteLater()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function exit(retCode){
|
||||||
|
for(var i =0 ;i< windows.length; i++){
|
||||||
|
var win = windows[i]
|
||||||
|
win.deleteLater()
|
||||||
|
}
|
||||||
|
windows = []
|
||||||
|
Qt.exit(retCode)
|
||||||
|
}
|
||||||
|
function navigate(route,argument={},windowRegister = undefined){
|
||||||
|
if(!routes.hasOwnProperty(route)){
|
||||||
|
console.error("Not Found Route",route)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var windowComponent = Qt.createComponent(routes[route])
|
||||||
|
if (windowComponent.status !== Component.Ready) {
|
||||||
|
console.error(windowComponent.errorString())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var properties = {}
|
||||||
|
properties._route = route
|
||||||
|
if(windowRegister){
|
||||||
|
properties._windowRegister = windowRegister
|
||||||
|
}
|
||||||
|
properties.argument = argument
|
||||||
|
var win = undefined
|
||||||
|
for(var i =0 ;i< windows.length; i++){
|
||||||
|
var item = windows[i]
|
||||||
|
if(route === item._route){
|
||||||
|
win = item
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(win){
|
||||||
|
var launchMode = win.launchMode
|
||||||
|
if(launchMode === 1){
|
||||||
|
win.argument = argument
|
||||||
|
win.show()
|
||||||
|
win.raise()
|
||||||
|
win.requestActivate()
|
||||||
|
return
|
||||||
|
}else if(launchMode === 2){
|
||||||
|
win.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
win = windowComponent.createObject(null,properties)
|
||||||
|
if(windowRegister){
|
||||||
|
windowRegister._to = win
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
187
Fluent/qml/ScrollBar.qml
Normal file
@ -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 {
|
Quick.Item {
|
||||||
property color color: FluTheme.dark ? "#000000" : "#999999"
|
property Quick.color color: Theme.dark ? "#000000" : "#999999"
|
||||||
property int elevation: 5
|
property int elevation: 5
|
||||||
property int radius: 4
|
property int radius: 4
|
||||||
id:control
|
id:control
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
Repeater{
|
Quick.Repeater{
|
||||||
model: elevation
|
model: elevation
|
||||||
Rectangle{
|
Quick.Rectangle{
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: "#00000000"
|
color: "#00000000"
|
||||||
opacity: 0.01 * (elevation-index+1)
|
opacity: 0.01 * (elevation-index+1)
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import QtQuick as Quick
|
import QtQuick as Quick
|
||||||
|
|
||||||
import Fluent
|
import Fluent
|
||||||
|
|
||||||
Quick.Text {
|
Quick.Text {
|
||||||
property Quick.color textColor: FluTheme.fontPrimaryColor
|
property Quick.color textColor: Theme.fontPrimaryColor
|
||||||
id:text
|
id:text
|
||||||
color: textColor
|
color: textColor
|
||||||
renderType: FluTheme.nativeText ? Text.NativeRendering : Text.QtRendering
|
renderType: Theme.nativeText ? Text.NativeRendering : Text.QtRendering
|
||||||
font: FluTextStyle.Body
|
font: TextStyle.Body
|
||||||
}
|
}
|
||||||
|
31
Fluent/qml/Tooltip.qml
Normal file
@ -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 as Quick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
import Fluent
|
import Fluent
|
||||||
|
|
||||||
Quick.Window {
|
Quick.Window {
|
||||||
id: root
|
id: window
|
||||||
|
default property alias contentData : layout_content.data
|
||||||
property string windowIcon: App.windowIcon
|
property string windowIcon: App.windowIcon
|
||||||
property bool showStayTop: false
|
property int launchMode: WindowType.Standard
|
||||||
property bool showMaximize: true
|
property var argument:({})
|
||||||
property bool showMinimize: true
|
|
||||||
property bool showClose: true
|
|
||||||
property bool showDark: false
|
|
||||||
property bool fixSize: false
|
|
||||||
property bool stayTop: false
|
|
||||||
property int __margins: 0
|
|
||||||
property var background : com_background
|
property var background : com_background
|
||||||
|
property bool fixSize: false
|
||||||
|
property Quick.Component loadingItem: com_loading
|
||||||
|
property bool fitsAppBarWindows: false
|
||||||
|
property var tintOpacity: Theme.dark ? 0.80 : 0.75
|
||||||
|
property int blurRadius: 60
|
||||||
|
property alias effect: frameless.effect
|
||||||
|
readonly property alias effective: frameless.effective
|
||||||
|
readonly property var availableEffects: frameless.availableEffects
|
||||||
|
property Quick.Item appBar: AppBar {
|
||||||
|
title: window.title
|
||||||
|
height: 30
|
||||||
|
showDark: window.showDark
|
||||||
|
showClose: window.showClose
|
||||||
|
showMinimize: window.showMinimize
|
||||||
|
showMaximize: window.showMaximize
|
||||||
|
showStayTop: window.showStayTop
|
||||||
|
icon: window.windowIcon
|
||||||
|
}
|
||||||
property Quick.color backgroundColor: {
|
property Quick.color backgroundColor: {
|
||||||
|
if(frameless.effective && active){
|
||||||
|
var backcolor
|
||||||
|
if(frameless.effect==="dwm-blur"){
|
||||||
|
backcolor = Utilities.withOpacity(Theme.windowActiveBackgroundColor, window.tintOpacity)
|
||||||
|
}else{
|
||||||
|
backcolor = "transparent"
|
||||||
|
}
|
||||||
|
return backcolor
|
||||||
|
}
|
||||||
if(active){
|
if(active){
|
||||||
return Theme.windowActiveBackgroundColor
|
return Theme.windowActiveBackgroundColor
|
||||||
}
|
}
|
||||||
return Theme.windowBackgroundColor
|
return Theme.windowBackgroundColor
|
||||||
}
|
}
|
||||||
property Quick.Item appBar: AppBar {
|
property bool stayTop: false
|
||||||
title: root.title
|
property bool showDark: false
|
||||||
height: 30
|
property bool showClose: true
|
||||||
showDark: root.showDark
|
property bool showMinimize: true
|
||||||
showClose: root.showClose
|
property bool showMaximize: true
|
||||||
showMinimize: root.showMinimize
|
property bool showStayTop: false
|
||||||
showMaximize: root.showMaximize
|
property bool autoMaximize: false
|
||||||
showStayTop: root.showStayTop
|
property bool autoVisible: true
|
||||||
icon: root.windowIcon
|
property bool autoCenter: true
|
||||||
|
property bool autoDestroy: true
|
||||||
|
property bool useSystemAppBar
|
||||||
|
property int __margins: 0
|
||||||
|
property Quick.color resizeBorderColor: {
|
||||||
|
if(window.active){
|
||||||
|
return Theme.dark ? Qt.rgba(51/255,51/255,51/255,1) : Qt.rgba(110/255,110/255,110/255,1)
|
||||||
}
|
}
|
||||||
Frameless {
|
return Theme.dark ? Qt.rgba(61/255,61/255,61/255,1) : Qt.rgba(167/255,167/255,167/255,1)
|
||||||
|
}
|
||||||
|
property int resizeBorderWidth: 1
|
||||||
|
property var closeListener: function(event){
|
||||||
|
if(autoDestroy){
|
||||||
|
Router.removeWindow(window)
|
||||||
|
}else{
|
||||||
|
window.visibility = Window.Hidden
|
||||||
|
event.accepted = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signal initArgument(var argument)
|
||||||
|
signal lazyLoad()
|
||||||
|
property var _windowRegister
|
||||||
|
property string _route
|
||||||
|
property bool _hideShadow: false
|
||||||
|
color: Utilities.isSoftware() ? window.backgroundColor : "transparent"
|
||||||
|
Quick.Component.onCompleted: {
|
||||||
|
Router.addWindow(window)
|
||||||
|
useSystemAppBar = App.useSystemAppBar
|
||||||
|
if(!useSystemAppBar && autoCenter){
|
||||||
|
moveWindowToDesktopCenter()
|
||||||
|
}
|
||||||
|
fixWindowSize()
|
||||||
|
initArgument(argument)
|
||||||
|
if(window.autoVisible){
|
||||||
|
if(window.autoMaximize){
|
||||||
|
window.visibility = Window.Maximized
|
||||||
|
}else{
|
||||||
|
window.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onVisibleChanged: {
|
||||||
|
if(visible && d.isLazyInit){
|
||||||
|
window.lazyLoad()
|
||||||
|
d.isLazyInit = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Quick.QtObject{
|
||||||
|
id:d
|
||||||
|
property bool isLazyInit: true
|
||||||
|
}
|
||||||
|
Quick.Connections{
|
||||||
|
target: window
|
||||||
|
function onClosing(event){closeListener(event)}
|
||||||
|
}
|
||||||
|
Frameless{
|
||||||
id: frameless
|
id: frameless
|
||||||
appBar: root.appBar
|
appBar: window.appBar
|
||||||
maximizeButton: appBar.buttonMaximize
|
maximizeButton: appBar.buttonMaximize
|
||||||
fixSize: root.fixSize
|
fixSize: window.fixSize
|
||||||
topmost: root.stayTop
|
topmost: window.stayTop
|
||||||
disabled: App.useSystemAppBar
|
disabled: App.useSystemAppBar
|
||||||
Quick.Component.onCompleted: {
|
Quick.Component.onCompleted: {
|
||||||
frameless.setHitTestVisible(appBar.layoutMacosButtons)
|
frameless.setHitTestVisible(appBar.layoutMacosButtons)
|
||||||
@ -43,90 +120,18 @@ Quick.Window {
|
|||||||
Quick.Component.onDestruction: {
|
Quick.Component.onDestruction: {
|
||||||
frameless.onDestruction()
|
frameless.onDestruction()
|
||||||
}
|
}
|
||||||
}
|
onEffectiveChanged: {
|
||||||
Quick.Component.onCompleted: {
|
if(effective){
|
||||||
Router.addWindow(root)
|
Theme.blurBehindWindowEnabled = false
|
||||||
}
|
|
||||||
|
|
||||||
Quick.Component {
|
|
||||||
id:com_app_bar
|
|
||||||
Quick.Item{
|
|
||||||
data: root.appBar
|
|
||||||
Quick.Component.onCompleted: {
|
|
||||||
root.appBar.width = Qt.binding(function(){
|
|
||||||
return this.parent.width
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Quick.Component{
|
||||||
|
|
||||||
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 {
|
|
||||||
id:com_background
|
id:com_background
|
||||||
Quick.Item{
|
Quick.Item{
|
||||||
Rectangle{
|
Quick.Rectangle{
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: root.backgroundColor
|
color: window.backgroundColor
|
||||||
}
|
}
|
||||||
Quick.Image{
|
Quick.Image{
|
||||||
id:img_back
|
id:img_back
|
||||||
@ -139,13 +144,13 @@ Quick.Window {
|
|||||||
source = Utilities.getUrlByFilePath(Theme.desktopImagePath)
|
source = Utilities.getUrlByFilePath(Theme.desktopImagePath)
|
||||||
}
|
}
|
||||||
Quick.Connections{
|
Quick.Connections{
|
||||||
target: root
|
target: window
|
||||||
function onScreenChanged(){
|
function onScreenChanged(){
|
||||||
img_back.updateLayout()
|
img_back.updateLayout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function updateLayout(){
|
function updateLayout(){
|
||||||
var geometry = Utilities.desktopAvailableGeometry(root)
|
var geometry = Utilities.desktopAvailableGeometry(window)
|
||||||
img_back.width = geometry.width
|
img_back.width = geometry.width
|
||||||
img_back.height = geometry.height
|
img_back.height = geometry.height
|
||||||
img_back.sourceSize = Qt.size(img_back.width,img_back.height)
|
img_back.sourceSize = Qt.size(img_back.width,img_back.height)
|
||||||
@ -175,12 +180,208 @@ Quick.Window {
|
|||||||
Acrylic{
|
Acrylic{
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
target: img_back
|
target: img_back
|
||||||
tintOpacity: Theme.dark ? 0.80 : 0.75
|
tintOpacity: window.tintOpacity
|
||||||
blurRadius: 64
|
blurRadius: window.blurRadius
|
||||||
visible: root.active && Theme.blurBehindWindowEnabled
|
visible: window.active && Theme.blurBehindWindowEnabled
|
||||||
tintColor: Theme.dark ? Qt.rgba(0, 0, 0, 1) : Qt.rgba(1, 1, 1, 1)
|
tintColor: Theme.dark ? Qt.rgba(0, 0, 0, 1) : Qt.rgba(1, 1, 1, 1)
|
||||||
targetRect: Qt.rect(root.x-root.screen.virtualX,root.y-root.screen.virtualY,root.width,root.height)
|
targetRect: Qt.rect(window.x-window.screen.virtualX,window.y-window.screen.virtualY,window.width,window.height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Quick.Component{
|
||||||
|
id:com_app_bar
|
||||||
|
Quick.Item{
|
||||||
|
data: window.appBar
|
||||||
|
Quick.Component.onCompleted: {
|
||||||
|
window.appBar.width = Qt.binding(function(){
|
||||||
|
return this.parent.width
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Quick.Component{
|
||||||
|
id:com_loading
|
||||||
|
Popup{
|
||||||
|
id:popup_loading
|
||||||
|
focus: true
|
||||||
|
width: window.width
|
||||||
|
height: window.height
|
||||||
|
anchors.centerIn: Overlay.overlay
|
||||||
|
closePolicy: {
|
||||||
|
if(cancel){
|
||||||
|
return Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||||
|
}
|
||||||
|
return Popup.NoAutoClose
|
||||||
|
}
|
||||||
|
Overlay.modal: Quick.Item {}
|
||||||
|
onVisibleChanged: {
|
||||||
|
if(!visible){
|
||||||
|
loader_loading.sourceComponent = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
padding: 0
|
||||||
|
opacity: 0
|
||||||
|
visible:true
|
||||||
|
Quick.Behavior on opacity {
|
||||||
|
Quick.SequentialAnimation {
|
||||||
|
Quick.PauseAnimation {
|
||||||
|
duration: 83
|
||||||
|
}
|
||||||
|
Quick.NumberAnimation{
|
||||||
|
duration: 167
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Quick.Component.onCompleted: {
|
||||||
|
opacity = 1
|
||||||
|
}
|
||||||
|
background: Quick.Rectangle{
|
||||||
|
color:"#44000000"
|
||||||
|
}
|
||||||
|
contentItem: Quick.Item{
|
||||||
|
Quick.MouseArea{
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
if (cancel){
|
||||||
|
popup_loading.visible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ColumnLayout{
|
||||||
|
spacing: 8
|
||||||
|
anchors.centerIn: parent
|
||||||
|
ProgressRing{
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
}
|
||||||
|
Text{
|
||||||
|
text:loadingText
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Quick.Component{
|
||||||
|
id:com_border
|
||||||
|
Quick.Rectangle{
|
||||||
|
color:"transparent"
|
||||||
|
border.width: window.resizeBorderWidth
|
||||||
|
border.color: window.resizeBorderColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Quick.Item{
|
||||||
|
id: layout_container
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: window.__margins
|
||||||
|
Loader{
|
||||||
|
anchors.fill: parent
|
||||||
|
sourceComponent: background
|
||||||
|
}
|
||||||
|
Loader{
|
||||||
|
id:loader_app_bar
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
height: {
|
||||||
|
if(window.useSystemAppBar){
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return window.fitsAppBarWindows ? 0 : window.appBar.height
|
||||||
|
}
|
||||||
|
sourceComponent: window.useSystemAppBar ? undefined : com_app_bar
|
||||||
|
}
|
||||||
|
Quick.Item{
|
||||||
|
id: layout_content
|
||||||
|
anchors{
|
||||||
|
top: loader_app_bar.bottom
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
clip: true
|
||||||
|
}
|
||||||
|
Loader{
|
||||||
|
property string loadingText
|
||||||
|
property bool cancel: false
|
||||||
|
id:loader_loading
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
InfoBar{
|
||||||
|
id:info_bar
|
||||||
|
root: layout_container
|
||||||
|
}
|
||||||
|
Loader{
|
||||||
|
id:loader_border
|
||||||
|
anchors.fill: parent
|
||||||
|
sourceComponent: {
|
||||||
|
if(window.useSystemAppBar || Utilities.isWin() || window.visibility === Window.Maximized || window.visibility === Window.FullScreen){
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return com_border
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function hideLoading(){
|
||||||
|
loader_loading.sourceComponent = undefined
|
||||||
|
}
|
||||||
|
function showSuccess(text,duration,moremsg){
|
||||||
|
return info_bar.showSuccess(text,duration,moremsg)
|
||||||
|
}
|
||||||
|
function showInfo(text,duration,moremsg){
|
||||||
|
return info_bar.showInfo(text,duration,moremsg)
|
||||||
|
}
|
||||||
|
function showWarning(text,duration,moremsg){
|
||||||
|
return info_bar.showWarning(text,duration,moremsg)
|
||||||
|
}
|
||||||
|
function showError(text,duration,moremsg){
|
||||||
|
return info_bar.showError(text,duration,moremsg)
|
||||||
|
}
|
||||||
|
function clearAllInfo(){
|
||||||
|
return info_bar.clearAllInfo()
|
||||||
|
}
|
||||||
|
function moveWindowToDesktopCenter(){
|
||||||
|
var availableGeometry = Utilities.desktopAvailableGeometry(window)
|
||||||
|
window.setGeometry((availableGeometry.width-window.width)/2+Quick.Screen.virtualX,(availableGeometry.height-window.height)/2+Quick.Screen.virtualY,window.width,window.height)
|
||||||
|
}
|
||||||
|
function fixWindowSize(){
|
||||||
|
if(fixSize){
|
||||||
|
window.maximumWidth = window.width
|
||||||
|
window.maximumHeight = window.height
|
||||||
|
window.minimumWidth = window.width
|
||||||
|
window.minimumHeight = window.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function setResult(data){
|
||||||
|
if(_windowRegister){
|
||||||
|
_windowRegister.setResult(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function showMaximized(){
|
||||||
|
frameless.showMaximized()
|
||||||
|
}
|
||||||
|
function showMinimized(){
|
||||||
|
frameless.showMinimized()
|
||||||
|
}
|
||||||
|
function showNormal(){
|
||||||
|
frameless.showNormal()
|
||||||
|
}
|
||||||
|
function showLoading(text = "",cancel = true){
|
||||||
|
if(text===""){
|
||||||
|
text = qsTr("Loading...")
|
||||||
|
}
|
||||||
|
loader_loading.loadingText = text
|
||||||
|
loader_loading.cancel = cancel
|
||||||
|
loader_loading.sourceComponent = com_loading
|
||||||
|
}
|
||||||
|
function setHitTestVisible(val){
|
||||||
|
frameless.setHitTestVisible(val)
|
||||||
|
}
|
||||||
|
function deleteLater(){
|
||||||
|
Utilities.deleteLater(window)
|
||||||
|
}
|
||||||
|
function containerItem(){
|
||||||
|
return layout_container
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
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 |